From 5b1ff23e0f7ead9dde6fa9561b1f801bb786ee23 Mon Sep 17 00:00:00 2001 From: Jeff Farrand Date: Sun, 12 Jan 2014 09:48:16 -0600 Subject: [PATCH] Initial Commit --- COPYING.txt | 345 + DOOM CLASSIC IOS v.2.1 README.txt | 24 + DoomClassic/base.parm | 2 + DoomClassic/base/prboom.wad | Bin 0 -> 281020 bytes DoomClassic/code/iphone/ControlsMenuView.xib | 255 + .../code/iphone/ControlsMenuViewController.h | 58 + .../code/iphone/ControlsMenuViewController.mm | 332 + .../code/iphone/ControlsMenuViewi5.xib | 256 + .../code/iphone/ControlsMenuView~ipad.xib | 255 + DoomClassic/code/iphone/CreditsMenuView.xib | 360 + .../code/iphone/CreditsMenuViewController.h | 38 + .../code/iphone/CreditsMenuViewController.mm | 97 + DoomClassic/code/iphone/CreditsMenuViewi5.xib | 362 + .../code/iphone/CreditsMenuView~ipad.xib | 369 + .../iphone/Doom.xcodeproj/_backup_project.bak | 1023 ++ .../iphone/Doom.xcodeproj/greghodges.mode1v3 | 1404 ++ .../iphone/Doom.xcodeproj/greghodges.pbxuser | 825 + .../Doom.xcodeproj/jeff.farrand.mode1v3 | 1396 ++ .../Doom.xcodeproj/jeff.farrand.pbxuser | 859 + .../code/iphone/Doom.xcodeproj/johnc.pbxuser | 13013 ++++++++++++++ .../iphone/Doom.xcodeproj/johnc.perspectivev3 | 2053 +++ .../iphone/Doom.xcodeproj/project.pbxproj | 1186 ++ .../contents.xcworkspacedata | 7 + .../UserInterfaceState.xcuserstate | 11874 +++++++++++++ .../UserInterfaceState.xcuserstate | Bin 0 -> 72861 bytes .../xcshareddata/xcschemes/DOOM.xcscheme | 86 + .../xcschemes/xcschememanagement.plist | 22 + .../xcschemes/Doom.xcscheme | 76 + .../xcschemes/xcschememanagement.plist | 22 + .../xcschemes/xcschememanagement.plist | 22 + DoomClassic/code/iphone/Doom_App.h | 26 + DoomClassic/code/iphone/Doom_App.m | 53 + DoomClassic/code/iphone/EpisodeMenuView.xib | 227 + .../code/iphone/EpisodeMenuViewController.h | 52 + .../code/iphone/EpisodeMenuViewController.mm | 188 + DoomClassic/code/iphone/EpisodeMenuViewi5.xib | 228 + .../code/iphone/EpisodeMenuView~ipad.xib | 1018 ++ DoomClassic/code/iphone/Info.plist | 75 + DoomClassic/code/iphone/LegalMenuView.xib | 69 + .../code/iphone/LegalMenuViewController.h | 35 + .../code/iphone/LegalMenuViewController.mm | 90 + DoomClassic/code/iphone/LegalMenuViewi5.xib | 70 + .../code/iphone/LegalMenuView~ipad.xib | 68 + DoomClassic/code/iphone/MainMenuView.xib | 419 + .../code/iphone/MainMenuViewController.h | 84 + .../code/iphone/MainMenuViewController.mm | 463 + DoomClassic/code/iphone/MainMenuViewi5.xib | 419 + DoomClassic/code/iphone/MainMenuView~ipad.xib | 419 + DoomClassic/code/iphone/MainNavController.h | 25 + DoomClassic/code/iphone/MainNavController.m | 50 + DoomClassic/code/iphone/MissionMenuView.xib | 980 + .../code/iphone/MissionMenuViewController.h | 124 + .../code/iphone/MissionMenuViewController.mm | 468 + DoomClassic/code/iphone/MissionMenuViewi5.xib | 977 + .../code/iphone/MissionMenuView~ipad.xib | 980 + DoomClassic/code/iphone/OpenGLView.xib | 22 + DoomClassic/code/iphone/OpenGLViewi5.xib | 22 + DoomClassic/code/iphone/OpenGLView~ipad.xib | 149 + DoomClassic/code/iphone/SettingsMenuView.xib | 300 + .../code/iphone/SettingsMenuViewController.h | 56 + .../code/iphone/SettingsMenuViewController.mm | 216 + .../code/iphone/SettingsMenuViewi5.xib | 300 + .../code/iphone/SettingsMenuView~ipad.xib | 299 + DoomClassic/code/iphone/dist.plist | 8 + DoomClassic/code/iphone/doom_Prefix.pch | 28 + DoomClassic/code/iphone/doom_wads.cpp | 186 + DoomClassic/code/iphone/doom_wads.h | 89 + DoomClassic/code/iphone/main.m | 50 + DoomClassic/doomtool/doomtool.1 | 79 + DoomClassic/doomtool/doomtool.h | 160 + .../doomtool.xcodeproj/greghodges.mode1v3 | 1393 ++ .../doomtool.xcodeproj/greghodges.pbxuser | 193 + .../doomtool/doomtool.xcodeproj/johnc.pbxuser | 602 + .../doomtool.xcodeproj/johnc.perspectivev3 | 1505 ++ .../doomtool.xcodeproj/project.pbxproj | 207 + .../xcschemes/doomtool.xcscheme | 84 + .../xcschemes/xcschememanagement.plist | 22 + DoomClassic/doomtool/main.c | 1716 ++ .../contents.xcworkspacedata | 10 + .../xcshareddata/DoomClassics.xccheckout | 41 + .../UserInterfaceState.xcuserstate | Bin 0 -> 178919 bytes .../WorkspaceSettings.xcsettings | 10 + .../xcdebugger/Breakpoints_v2.xcbkptlist | 69 + .../xcdebugger/Expressions.xcexplist | 14 + .../UserInterfaceState.xcuserstate | Bin 0 -> 103888 bytes .../xcdebugger/Breakpoints.xcbkptlist | 5 + .../xcdebugger/Expressions.xcexplist | 14 + .../UserInterfaceState.xcuserstate | Bin 0 -> 342960 bytes .../xcdebugger/Breakpoints.xcbkptlist | 21 + README.txt | 24 + common/SDL_shim/SDL_Mixer.h | 102 + common/SDL_shim/ios/SDL_Mixer.m | 517 + common/embeddedaudiosynthesis/Android.mk | 1 + common/embeddedaudiosynthesis/EASGlue.c | 211 + common/embeddedaudiosynthesis/EASGlue.h | 36 + .../MODULE_LICENSE_APACHE2 | 0 common/embeddedaudiosynthesis/NOTICE | 14 + .../ThirdPartyProject.prop | 9 + .../arm-fm-22k/Makefile | 63 + .../arm-fm-22k/bin/arm-fm-22k | Bin 0 -> 417659 bytes .../arm-fm-22k/host_src/arm-fm-22k.mak | 25 + .../arm-fm-22k/host_src/eas.h | 1062 ++ .../arm-fm-22k/host_src/eas_build.h | 36 + .../arm-fm-22k/host_src/eas_chorus.h | 53 + .../arm-fm-22k/host_src/eas_config.c | 619 + .../arm-fm-22k/host_src/eas_config.h | 191 + .../arm-fm-22k/host_src/eas_debugmsgs.h | 43 + .../arm-fm-22k/host_src/eas_host.h | 83 + .../arm-fm-22k/host_src/eas_hostmm.c | 660 + .../arm-fm-22k/host_src/eas_main.c | 461 + .../arm-fm-22k/host_src/eas_report.c | 264 + .../arm-fm-22k/host_src/eas_report.h | 77 + .../arm-fm-22k/host_src/eas_reverb.h | 54 + .../arm-fm-22k/host_src/eas_types.h | 268 + .../arm-fm-22k/host_src/eas_wave.c | 423 + .../arm-fm-22k/host_src/eas_wave.h | 74 + .../arm-fm-22k/lib/libarm-fm-22k.a | Bin 0 -> 114668 bytes .../arm-fm-22k/lib_src/arm-fm-22k_lib.mak | 25 + .../arm-fm-22k/lib_src/eas_audioconst.h | 97 + .../arm-fm-22k/lib_src/eas_chorus.c | 604 + .../arm-fm-22k/lib_src/eas_chorusdata.c | 34 + .../arm-fm-22k/lib_src/eas_chorusdata.h | 160 + .../arm-fm-22k/lib_src/eas_ctype.h | 41 + .../arm-fm-22k/lib_src/eas_data.c | 37 + .../arm-fm-22k/lib_src/eas_data.h | 131 + .../arm-fm-22k/lib_src/eas_effects.h | 61 + .../arm-fm-22k/lib_src/eas_fmengine.c | 785 + .../arm-fm-22k/lib_src/eas_fmengine.h | 121 + .../arm-fm-22k/lib_src/eas_fmsndlib.c | 1674 ++ .../arm-fm-22k/lib_src/eas_fmsynth.c | 910 + .../arm-fm-22k/lib_src/eas_fmsynth.h | 81 + .../arm-fm-22k/lib_src/eas_fmtables.c | 368 + .../arm-fm-22k/lib_src/eas_ima_tables.c | 54 + .../arm-fm-22k/lib_src/eas_imaadpcm.c | 368 + .../arm-fm-22k/lib_src/eas_imelody.c | 1738 ++ .../arm-fm-22k/lib_src/eas_imelodydata.c | 43 + .../arm-fm-22k/lib_src/eas_imelodydata.h | 73 + .../arm-fm-22k/lib_src/eas_math.c | 168 + .../arm-fm-22k/lib_src/eas_math.h | 412 + .../arm-fm-22k/lib_src/eas_midi.c | 569 + .../arm-fm-22k/lib_src/eas_midi.h | 71 + .../arm-fm-22k/lib_src/eas_midictrl.h | 64 + .../arm-fm-22k/lib_src/eas_mididata.c | 34 + .../arm-fm-22k/lib_src/eas_miditypes.h | 138 + .../arm-fm-22k/lib_src/eas_mixbuf.c | 36 + .../arm-fm-22k/lib_src/eas_mixer.c | 464 + .../arm-fm-22k/lib_src/eas_mixer.h | 137 + .../arm-fm-22k/lib_src/eas_ota.c | 1077 ++ .../arm-fm-22k/lib_src/eas_otadata.c | 41 + .../arm-fm-22k/lib_src/eas_otadata.h | 81 + .../arm-fm-22k/lib_src/eas_pan.c | 98 + .../arm-fm-22k/lib_src/eas_pan.h | 66 + .../arm-fm-22k/lib_src/eas_parser.h | 98 + .../arm-fm-22k/lib_src/eas_pcm.c | 1482 ++ .../arm-fm-22k/lib_src/eas_pcm.h | 359 + .../arm-fm-22k/lib_src/eas_pcmdata.c | 35 + .../arm-fm-22k/lib_src/eas_pcmdata.h | 157 + .../arm-fm-22k/lib_src/eas_public.c | 2597 +++ .../arm-fm-22k/lib_src/eas_reverb.c | 1154 ++ .../arm-fm-22k/lib_src/eas_reverbdata.c | 34 + .../arm-fm-22k/lib_src/eas_reverbdata.h | 486 + .../arm-fm-22k/lib_src/eas_rtttl.c | 1197 ++ .../arm-fm-22k/lib_src/eas_rtttldata.c | 41 + .../arm-fm-22k/lib_src/eas_rtttldata.h | 70 + .../arm-fm-22k/lib_src/eas_smf.c | 1203 ++ .../arm-fm-22k/lib_src/eas_smf.h | 49 + .../arm-fm-22k/lib_src/eas_smfdata.c | 66 + .../arm-fm-22k/lib_src/eas_smfdata.h | 66 + .../arm-fm-22k/lib_src/eas_sndlib.h | 406 + .../arm-fm-22k/lib_src/eas_synth.h | 395 + .../arm-fm-22k/lib_src/eas_synth_protos.h | 60 + .../arm-fm-22k/lib_src/eas_synthcfg.h | 70 + .../arm-fm-22k/lib_src/eas_vm_protos.h | 1086 ++ .../arm-fm-22k/lib_src/eas_voicemgt.c | 3971 +++++ .../arm-fm-22k/lib_src/eas_wavefile.c | 867 + .../arm-fm-22k/lib_src/eas_wavefile.h | 63 + .../arm-fm-22k/lib_src/eas_wavefiledata.c | 33 + .../arm-hybrid-22k/Makefile | 66 + .../arm-hybrid-22k/bin/arm-hybrid-22k | Bin 0 -> 485468 bytes .../host_src/arm-hybrid-22k.mak | 25 + .../arm-hybrid-22k/host_src/eas.h | 1062 ++ .../arm-hybrid-22k/host_src/eas_build.h | 36 + .../arm-hybrid-22k/host_src/eas_chorus.h | 53 + .../arm-hybrid-22k/host_src/eas_config.c | 619 + .../arm-hybrid-22k/host_src/eas_config.h | 191 + .../arm-hybrid-22k/host_src/eas_debugmsgs.h | 44 + .../arm-hybrid-22k/host_src/eas_host.h | 83 + .../arm-hybrid-22k/host_src/eas_hostmm.c | 660 + .../arm-hybrid-22k/host_src/eas_main.c | 461 + .../arm-hybrid-22k/host_src/eas_report.c | 264 + .../arm-hybrid-22k/host_src/eas_report.h | 77 + .../arm-hybrid-22k/host_src/eas_reverb.h | 54 + .../arm-hybrid-22k/host_src/eas_types.h | 268 + .../arm-hybrid-22k/host_src/eas_wave.c | 423 + .../arm-hybrid-22k/host_src/eas_wave.h | 74 + .../arm-hybrid-22k/lib/libarm-hybrid-22k.a | Bin 0 -> 189624 bytes .../arm-hybrid-22k/lib_src/ARM-E_filter_gnu.s | 134 + .../lib_src/ARM-E_interpolate_loop_gnu.s | 131 + .../lib_src/ARM-E_interpolate_noloop_gnu.s | 130 + .../lib_src/ARM-E_mastergain_gnu.s | 109 + .../lib_src/ARM-E_voice_gain_gnu.s | 166 + .../lib_src/ARM_synth_constants_gnu.inc | 153 + .../lib_src/arm-hybrid-22k_lib.mak | 25 + .../arm-hybrid-22k/lib_src/eas_audioconst.h | 97 + .../arm-hybrid-22k/lib_src/eas_chorus.c | 604 + .../arm-hybrid-22k/lib_src/eas_chorusdata.c | 34 + .../arm-hybrid-22k/lib_src/eas_chorusdata.h | 160 + .../arm-hybrid-22k/lib_src/eas_ctype.h | 41 + .../arm-hybrid-22k/lib_src/eas_data.c | 37 + .../arm-hybrid-22k/lib_src/eas_data.h | 131 + .../arm-hybrid-22k/lib_src/eas_effects.h | 61 + .../arm-hybrid-22k/lib_src/eas_fmengine.c | 785 + .../arm-hybrid-22k/lib_src/eas_fmengine.h | 121 + .../arm-hybrid-22k/lib_src/eas_fmsynth.c | 910 + .../arm-hybrid-22k/lib_src/eas_fmsynth.h | 81 + .../arm-hybrid-22k/lib_src/eas_fmtables.c | 368 + .../arm-hybrid-22k/lib_src/eas_ima_tables.c | 54 + .../arm-hybrid-22k/lib_src/eas_imaadpcm.c | 368 + .../arm-hybrid-22k/lib_src/eas_imelody.c | 1738 ++ .../arm-hybrid-22k/lib_src/eas_imelodydata.c | 43 + .../arm-hybrid-22k/lib_src/eas_imelodydata.h | 73 + .../arm-hybrid-22k/lib_src/eas_math.c | 168 + .../arm-hybrid-22k/lib_src/eas_math.h | 412 + .../arm-hybrid-22k/lib_src/eas_midi.c | 569 + .../arm-hybrid-22k/lib_src/eas_midi.h | 71 + .../arm-hybrid-22k/lib_src/eas_midictrl.h | 64 + .../arm-hybrid-22k/lib_src/eas_mididata.c | 34 + .../arm-hybrid-22k/lib_src/eas_miditypes.h | 138 + .../arm-hybrid-22k/lib_src/eas_mixbuf.c | 36 + .../arm-hybrid-22k/lib_src/eas_mixer.c | 464 + .../arm-hybrid-22k/lib_src/eas_mixer.h | 137 + .../arm-hybrid-22k/lib_src/eas_ota.c | 1077 ++ .../arm-hybrid-22k/lib_src/eas_otadata.c | 41 + .../arm-hybrid-22k/lib_src/eas_otadata.h | 81 + .../arm-hybrid-22k/lib_src/eas_pan.c | 98 + .../arm-hybrid-22k/lib_src/eas_pan.h | 66 + .../arm-hybrid-22k/lib_src/eas_parser.h | 98 + .../arm-hybrid-22k/lib_src/eas_pcm.c | 1482 ++ .../arm-hybrid-22k/lib_src/eas_pcm.h | 359 + .../arm-hybrid-22k/lib_src/eas_pcmdata.c | 35 + .../arm-hybrid-22k/lib_src/eas_pcmdata.h | 157 + .../arm-hybrid-22k/lib_src/eas_public.c | 2597 +++ .../arm-hybrid-22k/lib_src/eas_reverb.c | 1154 ++ .../arm-hybrid-22k/lib_src/eas_reverbdata.c | 34 + .../arm-hybrid-22k/lib_src/eas_reverbdata.h | 486 + .../arm-hybrid-22k/lib_src/eas_rtttl.c | 1197 ++ .../arm-hybrid-22k/lib_src/eas_rtttldata.c | 41 + .../arm-hybrid-22k/lib_src/eas_rtttldata.h | 70 + .../arm-hybrid-22k/lib_src/eas_smf.c | 1203 ++ .../arm-hybrid-22k/lib_src/eas_smf.h | 49 + .../arm-hybrid-22k/lib_src/eas_smfdata.c | 66 + .../arm-hybrid-22k/lib_src/eas_smfdata.h | 66 + .../arm-hybrid-22k/lib_src/eas_sndlib.h | 406 + .../arm-hybrid-22k/lib_src/eas_synth.h | 395 + .../arm-hybrid-22k/lib_src/eas_synth_protos.h | 60 + .../arm-hybrid-22k/lib_src/eas_synthcfg.h | 70 + .../arm-hybrid-22k/lib_src/eas_vm_protos.h | 1086 ++ .../arm-hybrid-22k/lib_src/eas_voicemgt.c | 3971 +++++ .../arm-hybrid-22k/lib_src/eas_wavefile.c | 867 + .../arm-hybrid-22k/lib_src/eas_wavefile.h | 63 + .../arm-hybrid-22k/lib_src/eas_wavefiledata.c | 33 + .../arm-hybrid-22k/lib_src/eas_wt_IPC_frame.h | 82 + .../arm-hybrid-22k/lib_src/eas_wtengine.c | 661 + .../arm-hybrid-22k/lib_src/eas_wtengine.h | 171 + .../arm-hybrid-22k/lib_src/eas_wtsynth.c | 1251 ++ .../arm-hybrid-22k/lib_src/eas_wtsynth.h | 66 + .../arm-hybrid-22k/lib_src/hybrid_22khz_mcu.c | 5149 ++++++ .../arm-wt-22k/Android.mk | 104 + .../arm-wt-22k/bin/arm-wt-22k | Bin 0 -> 610752 bytes .../arm-wt-22k/host_src/arm-wt-22k.mak | 25 + .../arm-wt-22k/host_src/eas.h | 1062 ++ .../arm-wt-22k/host_src/eas_build.h | 36 + .../arm-wt-22k/host_src/eas_chorus.h | 53 + .../arm-wt-22k/host_src/eas_config.c | 619 + .../arm-wt-22k/host_src/eas_config.h | 191 + .../arm-wt-22k/host_src/eas_debugmsgs.h | 87 + .../arm-wt-22k/host_src/eas_host.h | 87 + .../arm-wt-22k/host_src/eas_hostmm.c | 688 + .../arm-wt-22k/host_src/eas_main.c | 464 + .../arm-wt-22k/host_src/eas_report.c | 264 + .../arm-wt-22k/host_src/eas_report.h | 77 + .../arm-wt-22k/host_src/eas_reverb.h | 54 + .../arm-wt-22k/host_src/eas_types.h | 273 + .../arm-wt-22k/host_src/eas_wave.c | 423 + .../arm-wt-22k/host_src/eas_wave.h | 74 + .../arm-wt-22k/host_src/jet.h | 199 + .../EASLIb.xcodeproj/project.pbxproj | 361 + .../xcschemes/EASLIb.xcscheme | 57 + .../xcschemes/xcschememanagement.plist | 22 + .../xcschemes/EASLIb.xcscheme | 57 + .../xcschemes/xcschememanagement.plist | 22 + .../jetcreator_lib_src/darwin-x86/EASLib.c | 1809 ++ .../jetcreator_lib_src/darwin-x86/EASLib.h | 31 + .../jetcreator_lib_src/darwin-x86/EASLibVst.c | 1504 ++ .../jetcreator_lib_src/darwin-x86/README.txt | 9 + .../darwin-x86/eas_host_debug.h | 47 + .../darwin-x86/eastestv37.c | 999 ++ .../easwt_vst_lib.xcodeproj/project.pbxproj | 645 + .../xcschemes/easwt_vst_lib.xcscheme | 57 + .../xcschemes/xcschememanagement.plist | 22 + .../xcschemes/easwt_vst_lib.xcscheme | 57 + .../xcschemes/xcschememanagement.plist | 22 + .../jetcreator_lib_src/darwin-x86/wt_44khz.c | 14723 +++++++++++++++ .../arm-wt-22k/lib/libarm-wt-22k.a | Bin 0 -> 322180 bytes .../arm-wt-22k/lib_src/ARM-E_filter_gnu.s | 134 + .../lib_src/ARM-E_interpolate_loop_gnu.s | 131 + .../lib_src/ARM-E_interpolate_noloop_gnu.s | 130 + .../arm-wt-22k/lib_src/ARM-E_mastergain_gnu.s | 109 + .../arm-wt-22k/lib_src/ARM-E_voice_gain_gnu.s | 166 + .../lib_src/ARM_synth_constants_gnu.inc | 153 + .../arm-wt-22k/lib_src/arm-wt-22k_lib.mak | 25 + .../arm-wt-22k/lib_src/dls.h | 268 + .../arm-wt-22k/lib_src/dls2.h | 122 + .../arm-wt-22k/lib_src/eas_audioconst.h | 97 + .../arm-wt-22k/lib_src/eas_chorus.c | 604 + .../arm-wt-22k/lib_src/eas_chorusdata.c | 34 + .../arm-wt-22k/lib_src/eas_chorusdata.h | 160 + .../arm-wt-22k/lib_src/eas_ctype.h | 41 + .../arm-wt-22k/lib_src/eas_data.c | 37 + .../arm-wt-22k/lib_src/eas_data.h | 133 + .../arm-wt-22k/lib_src/eas_dlssynth.c | 578 + .../arm-wt-22k/lib_src/eas_dlssynth.h | 41 + .../arm-wt-22k/lib_src/eas_effects.h | 61 + .../arm-wt-22k/lib_src/eas_flog.c | 96 + .../arm-wt-22k/lib_src/eas_ima_tables.c | 54 + .../arm-wt-22k/lib_src/eas_imaadpcm.c | 368 + .../arm-wt-22k/lib_src/eas_imelody.c | 1747 ++ .../arm-wt-22k/lib_src/eas_imelodydata.c | 43 + .../arm-wt-22k/lib_src/eas_imelodydata.h | 74 + .../arm-wt-22k/lib_src/eas_math.c | 168 + .../arm-wt-22k/lib_src/eas_math.h | 412 + .../arm-wt-22k/lib_src/eas_mdls.c | 2668 +++ .../arm-wt-22k/lib_src/eas_mdls.h | 295 + .../arm-wt-22k/lib_src/eas_midi.c | 569 + .../arm-wt-22k/lib_src/eas_midi.h | 71 + .../arm-wt-22k/lib_src/eas_midictrl.h | 64 + .../arm-wt-22k/lib_src/eas_mididata.c | 34 + .../arm-wt-22k/lib_src/eas_miditypes.h | 138 + .../arm-wt-22k/lib_src/eas_mixbuf.c | 36 + .../arm-wt-22k/lib_src/eas_mixer.c | 464 + .../arm-wt-22k/lib_src/eas_mixer.h | 137 + .../arm-wt-22k/lib_src/eas_ota.c | 1077 ++ .../arm-wt-22k/lib_src/eas_otadata.c | 41 + .../arm-wt-22k/lib_src/eas_otadata.h | 81 + .../arm-wt-22k/lib_src/eas_pan.c | 98 + .../arm-wt-22k/lib_src/eas_pan.h | 66 + .../arm-wt-22k/lib_src/eas_parser.h | 98 + .../arm-wt-22k/lib_src/eas_pcm.c | 1482 ++ .../arm-wt-22k/lib_src/eas_pcm.h | 359 + .../arm-wt-22k/lib_src/eas_pcmdata.c | 35 + .../arm-wt-22k/lib_src/eas_pcmdata.h | 157 + .../arm-wt-22k/lib_src/eas_public.c | 2601 +++ .../arm-wt-22k/lib_src/eas_reverb.c | 1154 ++ .../arm-wt-22k/lib_src/eas_reverbdata.c | 34 + .../arm-wt-22k/lib_src/eas_reverbdata.h | 486 + .../arm-wt-22k/lib_src/eas_rtttl.c | 1197 ++ .../arm-wt-22k/lib_src/eas_rtttldata.c | 41 + .../arm-wt-22k/lib_src/eas_rtttldata.h | 70 + .../arm-wt-22k/lib_src/eas_smf.c | 1207 ++ .../arm-wt-22k/lib_src/eas_smf.h | 49 + .../arm-wt-22k/lib_src/eas_smfdata.c | 66 + .../arm-wt-22k/lib_src/eas_smfdata.h | 66 + .../arm-wt-22k/lib_src/eas_sndlib.h | 406 + .../arm-wt-22k/lib_src/eas_synth.h | 395 + .../arm-wt-22k/lib_src/eas_synth_protos.h | 60 + .../arm-wt-22k/lib_src/eas_synthcfg.h | 70 + .../arm-wt-22k/lib_src/eas_tcdata.c | 43 + .../arm-wt-22k/lib_src/eas_tcdata.h | 65 + .../arm-wt-22k/lib_src/eas_tonecontrol.c | 941 + .../arm-wt-22k/lib_src/eas_vm_protos.h | 1086 ++ .../arm-wt-22k/lib_src/eas_voicemgt.c | 3971 +++++ .../arm-wt-22k/lib_src/eas_wavefile.c | 867 + .../arm-wt-22k/lib_src/eas_wavefile.h | 63 + .../arm-wt-22k/lib_src/eas_wavefiledata.c | 33 + .../arm-wt-22k/lib_src/eas_wt_IPC_frame.h | 82 + .../arm-wt-22k/lib_src/eas_wtengine.c | 661 + .../arm-wt-22k/lib_src/eas_wtengine.h | 171 + .../arm-wt-22k/lib_src/eas_wtsynth.c | 1257 ++ .../arm-wt-22k/lib_src/eas_wtsynth.h | 66 + .../arm-wt-22k/lib_src/eas_xmf.c | 850 + .../arm-wt-22k/lib_src/eas_xmf.h | 60 + .../arm-wt-22k/lib_src/eas_xmfdata.c | 44 + .../arm-wt-22k/lib_src/eas_xmfdata.h | 55 + .../arm-wt-22k/lib_src/jet.c | 1129 ++ .../arm-wt-22k/lib_src/jet_data.h | 183 + .../arm-wt-22k/lib_src/wt_22khz.c | 14731 ++++++++++++++++ .../arm-wt-22k/misc/eas_host.c | 787 + .../arm-wt-22k/vectors/Leadsol.mxmf | Bin 0 -> 565820 bytes .../arm-wt-22k/vectors/Leadsol_out.wav | Bin 0 -> 2678828 bytes .../arm-wt-22k/vectors/WAVEtest.wav | Bin 0 -> 286838 bytes .../arm-wt-22k/vectors/WAVEtest_out.wav | Bin 0 -> 147500 bytes .../arm-wt-22k/vectors/abba.imy | 10 + .../arm-wt-22k/vectors/abba_out.wav | Bin 0 -> 2457644 bytes .../arm-wt-22k/vectors/ants.mid | Bin 0 -> 2956 bytes .../arm-wt-22k/vectors/ants_out.wav | Bin 0 -> 1728556 bytes .../arm-wt-22k/vectors/greensleeves.rtttl | 1 + .../arm-wt-22k/vectors/greensleeves_out.wav | Bin 0 -> 1712172 bytes .../arm-wt-22k/vectors/test.ota | Bin 0 -> 30 bytes .../arm-wt-22k/vectors/test_out.wav | Bin 0 -> 528428 bytes .../docs/EASLibrary3_5.odt | Bin 0 -> 158290 bytes .../docs/EASLibrary3_5.pdf | Bin 0 -> 371828 bytes .../docs/EAS_API_Reference.odt | Bin 0 -> 157184 bytes .../docs/EAS_API_Reference.pdf | Bin 0 -> 379444 bytes .../docs/EAS_Library_Integration_Guide.odt | Bin 0 -> 106537 bytes .../docs/EAS_Library_Integration_Guide.pdf | Bin 0 -> 169398 bytes .../docs/JET_Authoring_Guidelines.html | 2442 +++ .../JET_Authoring_Guidelines_files/header.htm | 202 + .../image001.jpg | Bin 0 -> 113715 bytes .../image002.emz | Bin 0 -> 3093 bytes .../image004.emz | Bin 0 -> 2896 bytes .../image006.emz | Bin 0 -> 2840 bytes .../image008.gif | Bin 0 -> 8332 bytes .../image010.gif | Bin 0 -> 4439 bytes .../image011.png | Bin 0 -> 84979 bytes .../image012.gif | Bin 0 -> 35354 bytes .../image013.gif | Bin 0 -> 8144 bytes .../image014.gif | Bin 0 -> 8546 bytes .../image015.emz | Bin 0 -> 2459 bytes .../docs/JET_Creator_User_Manual.html | 3032 ++++ .../JET_Creator_User_Manual_files/header.htm | 220 + .../image001.emz | Bin 0 -> 3093 bytes .../image002.gif | Bin 0 -> 8144 bytes .../image003.emz | Bin 0 -> 2896 bytes .../image004.gif | Bin 0 -> 8546 bytes .../image005.emz | Bin 0 -> 2840 bytes .../image006.gif | Bin 0 -> 8332 bytes .../image007.emz | Bin 0 -> 2459 bytes .../image008.gif | Bin 0 -> 4439 bytes .../image009.png | Bin 0 -> 17097 bytes .../image010.jpg | Bin 0 -> 15103 bytes .../image011.png | Bin 0 -> 62984 bytes .../image012.jpg | Bin 0 -> 31618 bytes .../image013.png | Bin 0 -> 49892 bytes .../image014.jpg | Bin 0 -> 25662 bytes .../image015.png | Bin 0 -> 54424 bytes .../image016.jpg | Bin 0 -> 24013 bytes .../image017.png | Bin 0 -> 21566 bytes .../image018.jpg | Bin 0 -> 21521 bytes .../image019.png | Bin 0 -> 21236 bytes .../image020.jpg | Bin 0 -> 21251 bytes .../image021.png | Bin 0 -> 16350 bytes .../image022.jpg | Bin 0 -> 16546 bytes .../image023.png | Bin 0 -> 38252 bytes .../image024.jpg | Bin 0 -> 32400 bytes .../image025.emz | Bin 0 -> 3414 bytes .../image026.gif | Bin 0 -> 8166 bytes .../image027.emz | Bin 0 -> 2194 bytes .../image028.gif | Bin 0 -> 3717 bytes .../image029.jpg | Bin 0 -> 113715 bytes .../image030.emz | Bin 0 -> 3093 bytes .../image031.emz | Bin 0 -> 2896 bytes .../image032.emz | Bin 0 -> 2840 bytes .../image033.emz | Bin 0 -> 2459 bytes .../image034.emz | Bin 0 -> 3414 bytes .../image035.emz | Bin 0 -> 2194 bytes .../docs/JET_Programming_Manual.html | 1333 ++ .../docs/JET_Programming_Manual.odt | Bin 0 -> 267431 bytes .../docs/JET_Programming_Manual.pdf | Bin 0 -> 226222 bytes .../JET_Programming_Manual_files/header.htm | 73 + .../JET_Programming_Manual_files/image002.png | Bin 0 -> 6098 bytes .../JET_Programming_Manual_files/image004.png | Bin 0 -> 6817 bytes .../JET_Programming_Manual_files/image006.png | Bin 0 -> 5332 bytes .../JET_Programming_Manual_files/image008.png | Bin 0 -> 3830 bytes .../JET_Programming_Manual_files/image010.png | Bin 0 -> 3054 bytes .../JET_Programming_Manual_files/image012.png | Bin 0 -> 8994 bytes .../JET_Programming_Manual_files/image013.emz | Bin 0 -> 3093 bytes .../JET_Programming_Manual_files/image014.emz | Bin 0 -> 2896 bytes .../JET_Programming_Manual_files/image015.emz | Bin 0 -> 2840 bytes .../JET_Programming_Manual_files/image016.emz | Bin 0 -> 2459 bytes .../JET_Programming_Manual_files/image017.emz | Bin 0 -> 2194 bytes .../JET_Programming_Manual_files/image018.emz | Bin 0 -> 3414 bytes common/idmobilelib/ios/AnimatedImage.h | 31 + common/idmobilelib/ios/AnimatedImage.mm | 67 + common/idmobilelib/ios/Carousel.h | 91 + common/idmobilelib/ios/Carousel.mm | 512 + common/idmobilelib/ios/GameCenter.h | 134 + common/idmobilelib/ios/GameCenter.mm | 712 + common/idmobilelib/ios/InAppStore.h | 95 + common/idmobilelib/ios/InAppStore.mm | 683 + common/idmobilelib/ios/Label.h | 30 + common/idmobilelib/ios/Label.mm | 55 + common/idmobilelib/ios/LabelButton.h | 40 + common/idmobilelib/ios/LabelButton.mm | 202 + common/idmobilelib/ios/Localization.h | 83 + common/idmobilelib/ios/Localization.mm | 134 + .../idmobilelib/ios/LocalizationObjectiveC.h | 39 + common/idmobilelib/ios/RenderContext.h | 70 + common/idmobilelib/ios/RenderContext.mm | 174 + common/idmobilelib/ios/Slider.h | 33 + common/idmobilelib/ios/Slider.mm | 52 + common/idmobilelib/ios/Switch.h | 31 + common/idmobilelib/ios/Switch.mm | 79 + common/idmobilelib/ios/View.h | 49 + common/idmobilelib/ios/View.mm | 165 + .../ios/idmobilelib.xcodeproj/project.pbxproj | 432 + .../contents.xcworkspacedata | 7 + .../xcschemes/idmobilelib.xcscheme | 59 + .../xcschemes/xcschememanagement.plist | 14 + .../xcschemes/xcschememanagement.plist | 24 + common/idmobilelib/ios/ios_interface.h | 28 + common/idmobilelib/ios/ios_interface.mm | 42 + common/idmobilelib/ios/objectivec_utilities.h | 47 + .../idmobilelib/ios/objectivec_utilities.mm | 67 + common/idmobilelib/sys/sys_defines.h | 44 + .../project.pbxproj | 612 + .../xcschemes/EmbeddedAudioSynthesis.xcscheme | 59 + .../xcschemes/xcschememanagement.plist | 22 + .../xcschemes/EmbeddedAudioSynthesis.xcscheme | 57 + .../xcschemes/xcschememanagement.plist | 24 + .../xcschemes/EmbeddedAudioSynthesis.xcscheme | 57 + .../xcschemes/xcschememanagement.plist | 22 + .../ios/doomengine.xcodeproj/project.pbxproj | 604 + .../contents.xcworkspacedata | 7 + .../UserInterfaceState.xcuserstate | Bin 0 -> 46621 bytes .../xcschemes/doomengine.xcscheme | 59 + .../xcschemes/xcschememanagement.plist | 22 + .../xcschemes/xcschememanagement.plist | 24 + .../xcschemes/xcschememanagement.plist | 22 + common/ios/doomengine/BackgroundMusic.cpp | 541 + common/ios/doomengine/DoomGameCenterMatch.cpp | 422 + common/ios/doomengine/DoomGameCenterMatch.h | 62 + common/ios/doomengine/EAGLView.h | 48 + common/ios/doomengine/EAGLView.m | 371 + common/ios/doomengine/SoundEngine.cpp | 1818 ++ common/ios/doomengine/SoundEngine.h | 383 + common/ios/doomengine/arialGlyphRects.h | 123 + common/ios/doomengine/cmd.c | 166 + common/ios/doomengine/cvar.c | 374 + common/ios/doomengine/cvar.h | 139 + common/ios/doomengine/doomiphone.h | 140 + common/ios/doomengine/gles_glue.c | 228 + common/ios/doomengine/gles_glue.h | 55 + common/ios/doomengine/hud.c | 235 + common/ios/doomengine/ipak.c | 408 + common/ios/doomengine/ipak.h | 183 + common/ios/doomengine/iphone_async.cpp | 952 + common/ios/doomengine/iphone_common.h | 35 + common/ios/doomengine/iphone_common.mm | 105 + common/ios/doomengine/iphone_delegate.h | 50 + common/ios/doomengine/iphone_delegate.mm | 225 + common/ios/doomengine/iphone_doom.h | 589 + common/ios/doomengine/iphone_email.h | 35 + common/ios/doomengine/iphone_email.m | 203 + .../ios/doomengine/iphone_glViewController.h | 36 + .../ios/doomengine/iphone_glViewController.mm | 164 + common/ios/doomengine/iphone_loop.c | 1792 ++ common/ios/doomengine/iphone_main.c | 519 + common/ios/doomengine/iphone_mapSelect.c | 236 + common/ios/doomengine/iphone_net.c | 631 + common/ios/doomengine/iphone_qgl.h | 2412 +++ common/ios/doomengine/iphone_qgl_enumerants.h | 40 + common/ios/doomengine/iphone_render.c | 1765 ++ common/ios/doomengine/iphone_sound.c | 293 + common/ios/doomengine/iphone_start.cpp | 261 + common/ios/doomengine/iphone_sys.mm | 93 + common/ios/doomengine/misc.c | 91 + common/ios/doomengine/misc.h | 74 + common/ios/doomengine/prboomInterface.c | 324 + .../prboom/prboom.xcodeproj/project.pbxproj | 842 + .../xcschemes/prboom.xcscheme | 59 + .../xcschemes/xcschememanagement.plist | 22 + .../xcschemes/prboom.xcscheme | 57 + .../xcschemes/xcschememanagement.plist | 24 + .../xcschemes/prboom.xcscheme | 57 + .../xcschemes/xcschememanagement.plist | 22 + .../ios/tess/tess.xcodeproj/project.pbxproj | 299 + .../xcschemes/tess.xcscheme | 59 + .../xcschemes/xcschememanagement.plist | 22 + .../xcschemes/tess.xcscheme | 57 + .../xcschemes/xcschememanagement.plist | 24 + .../xcschemes/tess.xcscheme | 57 + .../xcschemes/xcschememanagement.plist | 22 + common/libtess/README | 446 + common/libtess/alg-outline | 228 + common/libtess/dict-list.h | 100 + common/libtess/dict.c | 111 + common/libtess/dict.h | 100 + common/libtess/geom.c | 265 + common/libtess/geom.h | 84 + common/libtess/memalloc.c | 55 + common/libtess/memalloc.h | 54 + common/libtess/mesh.c | 790 + common/libtess/mesh.h | 266 + common/libtess/normal.c | 254 + common/libtess/normal.h | 45 + common/libtess/priorityq-heap.c | 253 + common/libtess/priorityq-heap.h | 107 + common/libtess/priorityq-sort.h | 117 + common/libtess/priorityq.c | 264 + common/libtess/priorityq.h | 117 + common/libtess/render.c | 499 + common/libtess/render.h | 52 + common/libtess/sweep.c | 1358 ++ common/libtess/sweep.h | 77 + common/libtess/tess.c | 632 + common/libtess/tess.h | 166 + common/libtess/tessmono.c | 202 + common/libtess/tessmono.h | 71 + common/prboom/Makefile.am | 72 + common/prboom/SDL/i_sound.c | 808 + common/prboom/SDL_opengl.h | 215 + common/prboom/am_map.c | 1595 ++ common/prboom/am_map.h | 111 + common/prboom/config.h | 109 + common/prboom/d_client.c | 541 + common/prboom/d_deh.c | 3115 ++++ common/prboom/d_deh.h | 1118 ++ common/prboom/d_englsh.h | 707 + common/prboom/d_event.h | 125 + common/prboom/d_ipxgate.c | 291 + common/prboom/d_items.c | 140 + common/prboom/d_items.h | 56 + common/prboom/d_main.c | 1764 ++ common/prboom/d_main.h | 78 + common/prboom/d_net.h | 211 + common/prboom/d_player.h | 231 + common/prboom/d_server.c | 754 + common/prboom/d_think.h | 91 + common/prboom/d_ticcmd.h | 56 + common/prboom/doomdata.h | 204 + common/prboom/doomdef.c | 48 + common/prboom/doomdef.h | 331 + common/prboom/doomstat.c | 108 + common/prboom/doomstat.h | 333 + common/prboom/doomtype.h | 128 + common/prboom/dstrings.c | 85 + common/prboom/dstrings.h | 80 + common/prboom/f_finale.c | 668 + common/prboom/f_finale.h | 56 + common/prboom/f_wipe.c | 202 + common/prboom/f_wipe.h | 45 + common/prboom/g_game.c | 3010 ++++ common/prboom/g_game.h | 179 + common/prboom/gl_intern.h | 228 + common/prboom/gl_main.c | 2961 ++++ common/prboom/gl_struct.h | 67 + common/prboom/gl_texture.c | 1112 ++ common/prboom/hu_lib.c | 762 + common/prboom/hu_lib.h | 247 + common/prboom/hu_stuff.c | 1601 ++ common/prboom/hu_stuff.h | 90 + common/prboom/i_joy.h | 47 + common/prboom/i_main.h | 44 + common/prboom/i_network.h | 74 + common/prboom/i_sound.h | 120 + common/prboom/i_system.h | 85 + common/prboom/i_video.h | 79 + common/prboom/info.c | 4899 +++++ common/prboom/info.h | 1498 ++ common/prboom/lprintf.c | 388 + common/prboom/lprintf.h | 68 + common/prboom/m_argv.c | 58 + common/prboom/m_argv.h | 47 + common/prboom/m_bbox.c | 58 + common/prboom/m_bbox.h | 56 + common/prboom/m_cheat.c | 744 + common/prboom/m_cheat.h | 58 + common/prboom/m_fixed.h | 219 + common/prboom/m_menu.c | 5589 ++++++ common/prboom/m_menu.h | 182 + common/prboom/m_misc.c | 1088 ++ common/prboom/m_misc.h | 111 + common/prboom/m_random.c | 147 + common/prboom/m_random.h | 154 + common/prboom/m_swap.h | 131 + common/prboom/md5.c | 240 + common/prboom/md5.h | 47 + common/prboom/mmus2mid.c | 847 + common/prboom/mmus2mid.h | 76 + common/prboom/p_ceilng.c | 467 + common/prboom/p_checksum.c | 100 + common/prboom/p_checksum.h | 4 + common/prboom/p_doors.c | 711 + common/prboom/p_enemy.c | 2584 +++ common/prboom/p_enemy.h | 118 + common/prboom/p_floor.c | 1042 ++ common/prboom/p_genlin.c | 1164 ++ common/prboom/p_inter.c | 919 + common/prboom/p_inter.h | 72 + common/prboom/p_lights.c | 443 + common/prboom/p_map.c | 2335 +++ common/prboom/p_map.h | 92 + common/prboom/p_maputl.c | 683 + common/prboom/p_maputl.h | 89 + common/prboom/p_mobj.c | 1527 ++ common/prboom/p_mobj.h | 403 + common/prboom/p_plats.c | 437 + common/prboom/p_pspr.c | 865 + common/prboom/p_pspr.h | 116 + common/prboom/p_saveg.c | 1029 ++ common/prboom/p_saveg.h | 66 + common/prboom/p_setup.c | 1688 ++ common/prboom/p_setup.h | 54 + common/prboom/p_sight.c | 338 + common/prboom/p_spec.c | 3354 ++++ common/prboom/p_spec.h | 1141 ++ common/prboom/p_switch.c | 1159 ++ common/prboom/p_telept.c | 345 + common/prboom/p_tick.c | 291 + common/prboom/p_tick.h | 75 + common/prboom/p_user.c | 452 + common/prboom/p_user.h | 47 + common/prboom/protocol.h | 96 + common/prboom/r_bsp.c | 664 + common/prboom/r_bsp.h | 64 + common/prboom/r_data.c | 781 + common/prboom/r_data.h | 106 + common/prboom/r_defs.h | 438 + common/prboom/r_demo.c | 88 + common/prboom/r_demo.h | 45 + common/prboom/r_draw.c | 1130 ++ common/prboom/r_draw.h | 160 + common/prboom/r_drawcolpipeline.inl | 51 + common/prboom/r_drawcolumn.inl | 386 + common/prboom/r_drawflush.inl | 300 + common/prboom/r_drawspan.inl | 164 + common/prboom/r_filter.c | 119 + common/prboom/r_filter.h | 174 + common/prboom/r_fps.c | 450 + common/prboom/r_fps.h | 76 + common/prboom/r_main.c | 614 + common/prboom/r_main.h | 120 + common/prboom/r_patch.c | 788 + common/prboom/r_patch.h | 111 + common/prboom/r_plane.c | 468 + common/prboom/r_plane.h | 67 + common/prboom/r_segs.c | 854 + common/prboom/r_segs.h | 44 + common/prboom/r_sky.c | 56 + common/prboom/r_sky.h | 55 + common/prboom/r_state.h | 113 + common/prboom/r_things.c | 1079 ++ common/prboom/r_things.h | 72 + common/prboom/s_sound.c | 751 + common/prboom/s_sound.h | 97 + common/prboom/sounds.c | 247 + common/prboom/sounds.h | 305 + common/prboom/st_lib.c | 374 + common/prboom/st_lib.h | 209 + common/prboom/st_stuff.c | 1161 ++ common/prboom/st_stuff.h | 102 + common/prboom/tables.c | 128 + common/prboom/tables.h | 93 + common/prboom/v_video.c | 1034 ++ common/prboom/v_video.h | 207 + common/prboom/version.c | 38 + common/prboom/version.h | 40 + common/prboom/w_memcache.c | 165 + common/prboom/w_mmap.c | 334 + common/prboom/w_wad.c | 478 + common/prboom/w_wad.h | 143 + common/prboom/wi_stuff.c | 2013 +++ common/prboom/wi_stuff.h | 64 + common/prboom/z_bmalloc.c | 123 + common/prboom/z_bmalloc.h | 52 + common/prboom/z_zone.c | 705 + common/prboom/z_zone.h | 129 + gpl.txt | 345 + readme_iDoom.txt | 22 + 759 files changed, 319871 insertions(+) create mode 100755 COPYING.txt create mode 100755 DOOM CLASSIC IOS v.2.1 README.txt create mode 100755 DoomClassic/base.parm create mode 100755 DoomClassic/base/prboom.wad create mode 100755 DoomClassic/code/iphone/ControlsMenuView.xib create mode 100755 DoomClassic/code/iphone/ControlsMenuViewController.h create mode 100755 DoomClassic/code/iphone/ControlsMenuViewController.mm create mode 100755 DoomClassic/code/iphone/ControlsMenuViewi5.xib create mode 100755 DoomClassic/code/iphone/ControlsMenuView~ipad.xib create mode 100755 DoomClassic/code/iphone/CreditsMenuView.xib create mode 100755 DoomClassic/code/iphone/CreditsMenuViewController.h create mode 100755 DoomClassic/code/iphone/CreditsMenuViewController.mm create mode 100755 DoomClassic/code/iphone/CreditsMenuViewi5.xib create mode 100755 DoomClassic/code/iphone/CreditsMenuView~ipad.xib create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/_backup_project.bak create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/greghodges.mode1v3 create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/greghodges.pbxuser create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/jeff.farrand.mode1v3 create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/jeff.farrand.pbxuser create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/johnc.pbxuser create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/johnc.perspectivev3 create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/project.pbxproj create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/project.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/UserInterfaceState.xcuserstate create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/project.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/UserInterfaceState.xcuserstate create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/xcshareddata/xcschemes/DOOM.xcscheme create mode 100644 DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/Doom.xcscheme create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 DoomClassic/code/iphone/Doom_App.h create mode 100755 DoomClassic/code/iphone/Doom_App.m create mode 100755 DoomClassic/code/iphone/EpisodeMenuView.xib create mode 100755 DoomClassic/code/iphone/EpisodeMenuViewController.h create mode 100755 DoomClassic/code/iphone/EpisodeMenuViewController.mm create mode 100755 DoomClassic/code/iphone/EpisodeMenuViewi5.xib create mode 100755 DoomClassic/code/iphone/EpisodeMenuView~ipad.xib create mode 100755 DoomClassic/code/iphone/Info.plist create mode 100755 DoomClassic/code/iphone/LegalMenuView.xib create mode 100755 DoomClassic/code/iphone/LegalMenuViewController.h create mode 100755 DoomClassic/code/iphone/LegalMenuViewController.mm create mode 100755 DoomClassic/code/iphone/LegalMenuViewi5.xib create mode 100755 DoomClassic/code/iphone/LegalMenuView~ipad.xib create mode 100755 DoomClassic/code/iphone/MainMenuView.xib create mode 100755 DoomClassic/code/iphone/MainMenuViewController.h create mode 100755 DoomClassic/code/iphone/MainMenuViewController.mm create mode 100755 DoomClassic/code/iphone/MainMenuViewi5.xib create mode 100755 DoomClassic/code/iphone/MainMenuView~ipad.xib create mode 100644 DoomClassic/code/iphone/MainNavController.h create mode 100644 DoomClassic/code/iphone/MainNavController.m create mode 100755 DoomClassic/code/iphone/MissionMenuView.xib create mode 100755 DoomClassic/code/iphone/MissionMenuViewController.h create mode 100755 DoomClassic/code/iphone/MissionMenuViewController.mm create mode 100755 DoomClassic/code/iphone/MissionMenuViewi5.xib create mode 100755 DoomClassic/code/iphone/MissionMenuView~ipad.xib create mode 100755 DoomClassic/code/iphone/OpenGLView.xib create mode 100755 DoomClassic/code/iphone/OpenGLViewi5.xib create mode 100755 DoomClassic/code/iphone/OpenGLView~ipad.xib create mode 100755 DoomClassic/code/iphone/SettingsMenuView.xib create mode 100755 DoomClassic/code/iphone/SettingsMenuViewController.h create mode 100755 DoomClassic/code/iphone/SettingsMenuViewController.mm create mode 100755 DoomClassic/code/iphone/SettingsMenuViewi5.xib create mode 100755 DoomClassic/code/iphone/SettingsMenuView~ipad.xib create mode 100755 DoomClassic/code/iphone/dist.plist create mode 100755 DoomClassic/code/iphone/doom_Prefix.pch create mode 100755 DoomClassic/code/iphone/doom_wads.cpp create mode 100755 DoomClassic/code/iphone/doom_wads.h create mode 100755 DoomClassic/code/iphone/main.m create mode 100755 DoomClassic/doomtool/doomtool.1 create mode 100755 DoomClassic/doomtool/doomtool.h create mode 100755 DoomClassic/doomtool/doomtool.xcodeproj/greghodges.mode1v3 create mode 100755 DoomClassic/doomtool/doomtool.xcodeproj/greghodges.pbxuser create mode 100755 DoomClassic/doomtool/doomtool.xcodeproj/johnc.pbxuser create mode 100755 DoomClassic/doomtool/doomtool.xcodeproj/johnc.perspectivev3 create mode 100755 DoomClassic/doomtool/doomtool.xcodeproj/project.pbxproj create mode 100755 DoomClassic/doomtool/doomtool.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/doomtool.xcscheme create mode 100755 DoomClassic/doomtool/doomtool.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 DoomClassic/doomtool/main.c create mode 100755 DoomClassics.xcworkspace/contents.xcworkspacedata create mode 100644 DoomClassics.xcworkspace/xcshareddata/DoomClassics.xccheckout create mode 100644 DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/WorkspaceSettings.xcsettings create mode 100644 DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/xcdebugger/Expressions.xcexplist create mode 100755 DoomClassics.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/UserInterfaceState.xcuserstate create mode 100755 DoomClassics.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist create mode 100755 DoomClassics.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/xcdebugger/Expressions.xcexplist create mode 100755 DoomClassics.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/UserInterfaceState.xcuserstate create mode 100755 DoomClassics.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist create mode 100755 README.txt create mode 100755 common/SDL_shim/SDL_Mixer.h create mode 100755 common/SDL_shim/ios/SDL_Mixer.m create mode 100755 common/embeddedaudiosynthesis/Android.mk create mode 100755 common/embeddedaudiosynthesis/EASGlue.c create mode 100755 common/embeddedaudiosynthesis/EASGlue.h create mode 100755 common/embeddedaudiosynthesis/MODULE_LICENSE_APACHE2 create mode 100755 common/embeddedaudiosynthesis/NOTICE create mode 100755 common/embeddedaudiosynthesis/ThirdPartyProject.prop create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/Makefile create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/bin/arm-fm-22k create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/arm-fm-22k.mak create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_build.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_chorus.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_config.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_config.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_debugmsgs.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_host.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_hostmm.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_main.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_report.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_report.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_reverb.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_types.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_wave.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_wave.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib/libarm-fm-22k.a create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/arm-fm-22k_lib.mak create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_audioconst.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_chorus.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_chorusdata.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_chorusdata.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_ctype.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_data.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_data.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_effects.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmengine.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmengine.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmsndlib.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmsynth.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmsynth.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmtables.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_ima_tables.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imaadpcm.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imelody.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imelodydata.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imelodydata.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_math.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_math.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_midi.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_midi.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_midictrl.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mididata.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_miditypes.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixbuf.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixer.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixer.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_ota.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_otadata.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_otadata.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pan.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pan.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_parser.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcm.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcm.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcmdata.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcmdata.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_public.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_reverb.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_reverbdata.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_reverbdata.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_rtttl.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_rtttldata.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_rtttldata.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smf.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smf.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smfdata.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smfdata.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_sndlib.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_synth.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_synth_protos.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_synthcfg.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_vm_protos.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_voicemgt.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_wavefile.c create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_wavefile.h create mode 100755 common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_wavefiledata.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/Makefile create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/bin/arm-hybrid-22k create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/arm-hybrid-22k.mak create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_build.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_chorus.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_config.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_config.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_debugmsgs.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_host.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_hostmm.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_main.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_report.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_report.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_reverb.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_types.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_wave.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_wave.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib/libarm-hybrid-22k.a create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_filter_gnu.s create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_interpolate_loop_gnu.s create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_interpolate_noloop_gnu.s create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_mastergain_gnu.s create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_voice_gain_gnu.s create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM_synth_constants_gnu.inc create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/arm-hybrid-22k_lib.mak create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_audioconst.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_chorus.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_chorusdata.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_chorusdata.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_ctype.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_data.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_data.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_effects.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmengine.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmengine.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmsynth.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmsynth.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmtables.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_ima_tables.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imaadpcm.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imelody.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imelodydata.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imelodydata.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_math.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_math.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_midi.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_midi.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_midictrl.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mididata.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_miditypes.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mixbuf.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mixer.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mixer.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_ota.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_otadata.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_otadata.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pan.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pan.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_parser.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcm.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcm.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcmdata.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcmdata.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_public.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_reverb.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_reverbdata.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_reverbdata.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_rtttl.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_rtttldata.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_rtttldata.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smf.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smf.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smfdata.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smfdata.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_sndlib.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_synth.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_synth_protos.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_synthcfg.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_vm_protos.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_voicemgt.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wavefile.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wavefile.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wavefiledata.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wt_IPC_frame.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtengine.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtengine.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtsynth.c create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtsynth.h create mode 100755 common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/hybrid_22khz_mcu.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/Android.mk create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/bin/arm-wt-22k create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/arm-wt-22k.mak create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_build.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_chorus.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_config.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_config.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_debugmsgs.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_host.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_hostmm.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_main.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_report.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_report.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_reverb.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_types.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_wave.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_wave.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/host_src/jet.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/project.pbxproj create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/EASLIb.xcscheme create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/EASLIb.xcscheme create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLib.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLib.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLibVst.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/README.txt create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/eas_host_debug.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/eastestv37.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/project.pbxproj create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/easwt_vst_lib.xcscheme create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/easwt_vst_lib.xcscheme create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/wt_44khz.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib/libarm-wt-22k.a create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_filter_gnu.s create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_interpolate_loop_gnu.s create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_interpolate_noloop_gnu.s create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_mastergain_gnu.s create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_voice_gain_gnu.s create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM_synth_constants_gnu.inc create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/arm-wt-22k_lib.mak create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/dls.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/dls2.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_audioconst.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_chorus.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_chorusdata.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_chorusdata.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_ctype.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_data.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_data.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_dlssynth.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_dlssynth.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_effects.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_flog.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_ima_tables.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imaadpcm.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imelody.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imelodydata.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imelodydata.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_math.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_math.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mdls.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mdls.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_midi.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_midi.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_midictrl.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mididata.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_miditypes.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mixbuf.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mixer.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mixer.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_ota.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_otadata.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_otadata.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pan.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pan.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_parser.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcm.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcm.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcmdata.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcmdata.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_public.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_reverb.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_reverbdata.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_reverbdata.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_rtttl.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_rtttldata.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_rtttldata.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smf.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smf.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smfdata.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smfdata.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_sndlib.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_synth.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_synth_protos.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_synthcfg.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_tcdata.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_tcdata.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_tonecontrol.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_vm_protos.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_voicemgt.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wavefile.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wavefile.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wavefiledata.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wt_IPC_frame.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtengine.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtengine.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtsynth.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtsynth.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmf.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmf.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmfdata.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmfdata.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/jet.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/jet_data.h create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/lib_src/wt_22khz.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/misc/eas_host.c create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/vectors/Leadsol.mxmf create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/vectors/Leadsol_out.wav create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/vectors/WAVEtest.wav create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/vectors/WAVEtest_out.wav create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/vectors/abba.imy create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/vectors/abba_out.wav create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/vectors/ants.mid create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/vectors/ants_out.wav create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/vectors/greensleeves.rtttl create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/vectors/greensleeves_out.wav create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/vectors/test.ota create mode 100755 common/embeddedaudiosynthesis/arm-wt-22k/vectors/test_out.wav create mode 100755 common/embeddedaudiosynthesis/docs/EASLibrary3_5.odt create mode 100755 common/embeddedaudiosynthesis/docs/EASLibrary3_5.pdf create mode 100755 common/embeddedaudiosynthesis/docs/EAS_API_Reference.odt create mode 100755 common/embeddedaudiosynthesis/docs/EAS_API_Reference.pdf create mode 100755 common/embeddedaudiosynthesis/docs/EAS_Library_Integration_Guide.odt create mode 100755 common/embeddedaudiosynthesis/docs/EAS_Library_Integration_Guide.pdf create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines.html create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/header.htm create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image001.jpg create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image002.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image004.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image006.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image008.gif create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image010.gif create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image011.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image012.gif create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image013.gif create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image014.gif create mode 100755 common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image015.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual.html create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/header.htm create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image001.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image002.gif create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image003.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image004.gif create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image005.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image006.gif create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image007.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image008.gif create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image009.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image010.jpg create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image011.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image012.jpg create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image013.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image014.jpg create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image015.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image016.jpg create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image017.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image018.jpg create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image019.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image020.jpg create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image021.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image022.jpg create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image023.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image024.jpg create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image025.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image026.gif create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image027.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image028.gif create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image029.jpg create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image030.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image031.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image032.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image033.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image034.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image035.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual.html create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual.odt create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual.pdf create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/header.htm create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image002.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image004.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image006.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image008.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image010.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image012.png create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image013.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image014.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image015.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image016.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image017.emz create mode 100755 common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image018.emz create mode 100755 common/idmobilelib/ios/AnimatedImage.h create mode 100755 common/idmobilelib/ios/AnimatedImage.mm create mode 100755 common/idmobilelib/ios/Carousel.h create mode 100755 common/idmobilelib/ios/Carousel.mm create mode 100755 common/idmobilelib/ios/GameCenter.h create mode 100755 common/idmobilelib/ios/GameCenter.mm create mode 100755 common/idmobilelib/ios/InAppStore.h create mode 100755 common/idmobilelib/ios/InAppStore.mm create mode 100755 common/idmobilelib/ios/Label.h create mode 100755 common/idmobilelib/ios/Label.mm create mode 100755 common/idmobilelib/ios/LabelButton.h create mode 100755 common/idmobilelib/ios/LabelButton.mm create mode 100755 common/idmobilelib/ios/Localization.h create mode 100755 common/idmobilelib/ios/Localization.mm create mode 100755 common/idmobilelib/ios/LocalizationObjectiveC.h create mode 100755 common/idmobilelib/ios/RenderContext.h create mode 100755 common/idmobilelib/ios/RenderContext.mm create mode 100755 common/idmobilelib/ios/Slider.h create mode 100755 common/idmobilelib/ios/Slider.mm create mode 100755 common/idmobilelib/ios/Switch.h create mode 100755 common/idmobilelib/ios/Switch.mm create mode 100755 common/idmobilelib/ios/View.h create mode 100755 common/idmobilelib/ios/View.mm create mode 100755 common/idmobilelib/ios/idmobilelib.xcodeproj/project.pbxproj create mode 100755 common/idmobilelib/ios/idmobilelib.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100755 common/idmobilelib/ios/idmobilelib.xcodeproj/xcshareddata/xcschemes/idmobilelib.xcscheme create mode 100644 common/idmobilelib/ios/idmobilelib.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/idmobilelib/ios/idmobilelib.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/idmobilelib/ios/ios_interface.h create mode 100755 common/idmobilelib/ios/ios_interface.mm create mode 100755 common/idmobilelib/ios/objectivec_utilities.h create mode 100755 common/idmobilelib/ios/objectivec_utilities.mm create mode 100755 common/idmobilelib/sys/sys_defines.h create mode 100755 common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/project.pbxproj create mode 100644 common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/EmbeddedAudioSynthesis.xcscheme create mode 100644 common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/EmbeddedAudioSynthesis.xcscheme create mode 100755 common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/EmbeddedAudioSynthesis.xcscheme create mode 100755 common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/ios/doomengine.xcodeproj/project.pbxproj create mode 100755 common/ios/doomengine.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100755 common/ios/doomengine.xcodeproj/project.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/UserInterfaceState.xcuserstate create mode 100755 common/ios/doomengine.xcodeproj/xcshareddata/xcschemes/doomengine.xcscheme create mode 100644 common/ios/doomengine.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/ios/doomengine.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/ios/doomengine.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/ios/doomengine/BackgroundMusic.cpp create mode 100755 common/ios/doomengine/DoomGameCenterMatch.cpp create mode 100755 common/ios/doomengine/DoomGameCenterMatch.h create mode 100755 common/ios/doomengine/EAGLView.h create mode 100755 common/ios/doomengine/EAGLView.m create mode 100755 common/ios/doomengine/SoundEngine.cpp create mode 100755 common/ios/doomengine/SoundEngine.h create mode 100755 common/ios/doomengine/arialGlyphRects.h create mode 100755 common/ios/doomengine/cmd.c create mode 100755 common/ios/doomengine/cvar.c create mode 100755 common/ios/doomengine/cvar.h create mode 100755 common/ios/doomengine/doomiphone.h create mode 100755 common/ios/doomengine/gles_glue.c create mode 100755 common/ios/doomengine/gles_glue.h create mode 100755 common/ios/doomengine/hud.c create mode 100755 common/ios/doomengine/ipak.c create mode 100755 common/ios/doomengine/ipak.h create mode 100755 common/ios/doomengine/iphone_async.cpp create mode 100755 common/ios/doomengine/iphone_common.h create mode 100755 common/ios/doomengine/iphone_common.mm create mode 100755 common/ios/doomengine/iphone_delegate.h create mode 100755 common/ios/doomengine/iphone_delegate.mm create mode 100755 common/ios/doomengine/iphone_doom.h create mode 100755 common/ios/doomengine/iphone_email.h create mode 100755 common/ios/doomengine/iphone_email.m create mode 100755 common/ios/doomengine/iphone_glViewController.h create mode 100755 common/ios/doomengine/iphone_glViewController.mm create mode 100755 common/ios/doomengine/iphone_loop.c create mode 100755 common/ios/doomengine/iphone_main.c create mode 100755 common/ios/doomengine/iphone_mapSelect.c create mode 100755 common/ios/doomengine/iphone_net.c create mode 100755 common/ios/doomengine/iphone_qgl.h create mode 100755 common/ios/doomengine/iphone_qgl_enumerants.h create mode 100755 common/ios/doomengine/iphone_render.c create mode 100755 common/ios/doomengine/iphone_sound.c create mode 100755 common/ios/doomengine/iphone_start.cpp create mode 100755 common/ios/doomengine/iphone_sys.mm create mode 100755 common/ios/doomengine/misc.c create mode 100755 common/ios/doomengine/misc.h create mode 100755 common/ios/doomengine/prboomInterface.c create mode 100755 common/ios/prboom/prboom.xcodeproj/project.pbxproj create mode 100644 common/ios/prboom/prboom.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/prboom.xcscheme create mode 100644 common/ios/prboom/prboom.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/ios/prboom/prboom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/prboom.xcscheme create mode 100755 common/ios/prboom/prboom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/ios/prboom/prboom.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/prboom.xcscheme create mode 100755 common/ios/prboom/prboom.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/ios/tess/tess.xcodeproj/project.pbxproj create mode 100644 common/ios/tess/tess.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/tess.xcscheme create mode 100644 common/ios/tess/tess.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/ios/tess/tess.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/tess.xcscheme create mode 100755 common/ios/tess/tess.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/ios/tess/tess.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/tess.xcscheme create mode 100755 common/ios/tess/tess.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 common/libtess/README create mode 100755 common/libtess/alg-outline create mode 100755 common/libtess/dict-list.h create mode 100755 common/libtess/dict.c create mode 100755 common/libtess/dict.h create mode 100755 common/libtess/geom.c create mode 100755 common/libtess/geom.h create mode 100755 common/libtess/memalloc.c create mode 100755 common/libtess/memalloc.h create mode 100755 common/libtess/mesh.c create mode 100755 common/libtess/mesh.h create mode 100755 common/libtess/normal.c create mode 100755 common/libtess/normal.h create mode 100755 common/libtess/priorityq-heap.c create mode 100755 common/libtess/priorityq-heap.h create mode 100755 common/libtess/priorityq-sort.h create mode 100755 common/libtess/priorityq.c create mode 100755 common/libtess/priorityq.h create mode 100755 common/libtess/render.c create mode 100755 common/libtess/render.h create mode 100755 common/libtess/sweep.c create mode 100755 common/libtess/sweep.h create mode 100755 common/libtess/tess.c create mode 100755 common/libtess/tess.h create mode 100755 common/libtess/tessmono.c create mode 100755 common/libtess/tessmono.h create mode 100755 common/prboom/Makefile.am create mode 100755 common/prboom/SDL/i_sound.c create mode 100755 common/prboom/SDL_opengl.h create mode 100755 common/prboom/am_map.c create mode 100755 common/prboom/am_map.h create mode 100755 common/prboom/config.h create mode 100755 common/prboom/d_client.c create mode 100755 common/prboom/d_deh.c create mode 100755 common/prboom/d_deh.h create mode 100755 common/prboom/d_englsh.h create mode 100755 common/prboom/d_event.h create mode 100755 common/prboom/d_ipxgate.c create mode 100755 common/prboom/d_items.c create mode 100755 common/prboom/d_items.h create mode 100755 common/prboom/d_main.c create mode 100755 common/prboom/d_main.h create mode 100755 common/prboom/d_net.h create mode 100755 common/prboom/d_player.h create mode 100755 common/prboom/d_server.c create mode 100755 common/prboom/d_think.h create mode 100755 common/prboom/d_ticcmd.h create mode 100755 common/prboom/doomdata.h create mode 100755 common/prboom/doomdef.c create mode 100755 common/prboom/doomdef.h create mode 100755 common/prboom/doomstat.c create mode 100755 common/prboom/doomstat.h create mode 100755 common/prboom/doomtype.h create mode 100755 common/prboom/dstrings.c create mode 100755 common/prboom/dstrings.h create mode 100755 common/prboom/f_finale.c create mode 100755 common/prboom/f_finale.h create mode 100755 common/prboom/f_wipe.c create mode 100755 common/prboom/f_wipe.h create mode 100755 common/prboom/g_game.c create mode 100755 common/prboom/g_game.h create mode 100755 common/prboom/gl_intern.h create mode 100755 common/prboom/gl_main.c create mode 100755 common/prboom/gl_struct.h create mode 100755 common/prboom/gl_texture.c create mode 100755 common/prboom/hu_lib.c create mode 100755 common/prboom/hu_lib.h create mode 100755 common/prboom/hu_stuff.c create mode 100755 common/prboom/hu_stuff.h create mode 100755 common/prboom/i_joy.h create mode 100755 common/prboom/i_main.h create mode 100755 common/prboom/i_network.h create mode 100755 common/prboom/i_sound.h create mode 100755 common/prboom/i_system.h create mode 100755 common/prboom/i_video.h create mode 100755 common/prboom/info.c create mode 100755 common/prboom/info.h create mode 100755 common/prboom/lprintf.c create mode 100755 common/prboom/lprintf.h create mode 100755 common/prboom/m_argv.c create mode 100755 common/prboom/m_argv.h create mode 100755 common/prboom/m_bbox.c create mode 100755 common/prboom/m_bbox.h create mode 100755 common/prboom/m_cheat.c create mode 100755 common/prboom/m_cheat.h create mode 100755 common/prboom/m_fixed.h create mode 100755 common/prboom/m_menu.c create mode 100755 common/prboom/m_menu.h create mode 100755 common/prboom/m_misc.c create mode 100755 common/prboom/m_misc.h create mode 100755 common/prboom/m_random.c create mode 100755 common/prboom/m_random.h create mode 100755 common/prboom/m_swap.h create mode 100755 common/prboom/md5.c create mode 100755 common/prboom/md5.h create mode 100755 common/prboom/mmus2mid.c create mode 100755 common/prboom/mmus2mid.h create mode 100755 common/prboom/p_ceilng.c create mode 100755 common/prboom/p_checksum.c create mode 100755 common/prboom/p_checksum.h create mode 100755 common/prboom/p_doors.c create mode 100755 common/prboom/p_enemy.c create mode 100755 common/prboom/p_enemy.h create mode 100755 common/prboom/p_floor.c create mode 100755 common/prboom/p_genlin.c create mode 100755 common/prboom/p_inter.c create mode 100755 common/prboom/p_inter.h create mode 100755 common/prboom/p_lights.c create mode 100755 common/prboom/p_map.c create mode 100755 common/prboom/p_map.h create mode 100755 common/prboom/p_maputl.c create mode 100755 common/prboom/p_maputl.h create mode 100755 common/prboom/p_mobj.c create mode 100755 common/prboom/p_mobj.h create mode 100755 common/prboom/p_plats.c create mode 100755 common/prboom/p_pspr.c create mode 100755 common/prboom/p_pspr.h create mode 100755 common/prboom/p_saveg.c create mode 100755 common/prboom/p_saveg.h create mode 100755 common/prboom/p_setup.c create mode 100755 common/prboom/p_setup.h create mode 100755 common/prboom/p_sight.c create mode 100755 common/prboom/p_spec.c create mode 100755 common/prboom/p_spec.h create mode 100755 common/prboom/p_switch.c create mode 100755 common/prboom/p_telept.c create mode 100755 common/prboom/p_tick.c create mode 100755 common/prboom/p_tick.h create mode 100755 common/prboom/p_user.c create mode 100755 common/prboom/p_user.h create mode 100755 common/prboom/protocol.h create mode 100755 common/prboom/r_bsp.c create mode 100755 common/prboom/r_bsp.h create mode 100755 common/prboom/r_data.c create mode 100755 common/prboom/r_data.h create mode 100755 common/prboom/r_defs.h create mode 100755 common/prboom/r_demo.c create mode 100755 common/prboom/r_demo.h create mode 100755 common/prboom/r_draw.c create mode 100755 common/prboom/r_draw.h create mode 100755 common/prboom/r_drawcolpipeline.inl create mode 100755 common/prboom/r_drawcolumn.inl create mode 100755 common/prboom/r_drawflush.inl create mode 100755 common/prboom/r_drawspan.inl create mode 100755 common/prboom/r_filter.c create mode 100755 common/prboom/r_filter.h create mode 100755 common/prboom/r_fps.c create mode 100755 common/prboom/r_fps.h create mode 100755 common/prboom/r_main.c create mode 100755 common/prboom/r_main.h create mode 100755 common/prboom/r_patch.c create mode 100755 common/prboom/r_patch.h create mode 100755 common/prboom/r_plane.c create mode 100755 common/prboom/r_plane.h create mode 100755 common/prboom/r_segs.c create mode 100755 common/prboom/r_segs.h create mode 100755 common/prboom/r_sky.c create mode 100755 common/prboom/r_sky.h create mode 100755 common/prboom/r_state.h create mode 100755 common/prboom/r_things.c create mode 100755 common/prboom/r_things.h create mode 100755 common/prboom/s_sound.c create mode 100755 common/prboom/s_sound.h create mode 100755 common/prboom/sounds.c create mode 100755 common/prboom/sounds.h create mode 100755 common/prboom/st_lib.c create mode 100755 common/prboom/st_lib.h create mode 100755 common/prboom/st_stuff.c create mode 100755 common/prboom/st_stuff.h create mode 100755 common/prboom/tables.c create mode 100755 common/prboom/tables.h create mode 100755 common/prboom/v_video.c create mode 100755 common/prboom/v_video.h create mode 100755 common/prboom/version.c create mode 100755 common/prboom/version.h create mode 100755 common/prboom/w_memcache.c create mode 100755 common/prboom/w_mmap.c create mode 100755 common/prboom/w_wad.c create mode 100755 common/prboom/w_wad.h create mode 100755 common/prboom/wi_stuff.c create mode 100755 common/prboom/wi_stuff.h create mode 100755 common/prboom/z_bmalloc.c create mode 100755 common/prboom/z_bmalloc.h create mode 100755 common/prboom/z_zone.c create mode 100755 common/prboom/z_zone.h create mode 100755 gpl.txt create mode 100755 readme_iDoom.txt 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 0000000000000000000000000000000000000000..851698613cfe8b4e493c7491d0e9d6e0054059fd GIT binary patch literal 281020 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 UlKz!=tEVjiv`(^!rT=HnVN zk7N8XAJ>p+JYUCrTt&bHejami1%7|<_?V50a8Bg;F$3pdo5Vc96r6$)$~6-c5eW}! z{mHchhw&9vCbOH^3&}_*KZR=|wj&NDrgH7X2E?M^G>$t~;4X4Z=Q@LhxCXx&Y!jyA zG>n-XKa9r_e8o4j$oIf5yhF*^JO{$@7I3~O)?*%xzsFdJuKEMcuVMq?j7 zpwv><6k;vzBl|Lb2D5Pn8nu=)pRot;P%MnsCal11WLm-gVG1H4`2>|$avZQ3vBou;1@i4+9%435Asv-=^8NynD{v2iyI6CLNjL<_ z6ezx%`HUsF408|13%_G4o+4KS=Ow1$1d>o@FLMQ9xDNY1UI#D&JMbL2_cIqT9g#>v znFIVBmg5?12iX@4!&W>+jzg?T#$+79Clo)-7+?`Dz=tYF{>u$m&&Rt6ILg>zEcW0v z@*iVdFcXnTLh0koKP<&%7$-OvFbErP51Ar)ER4k-yhPrA*dI*8F(jb)ziby4;v6zi zDT?EcRk#8BN%j%HV>2Ei@YH`90ps}?fmg_Tn#adf9K}ZzJ;S?M8kTW*I^98dfb64n(f8!*o6BCxIrEf zMqn!*A@C;qfHByKSY*4!yvBI!!3*TP&Fds4Vjo^1&z=9W07ChA0B?{lhB3!v9Ku@^ zxXXJHOvMqzqtHFZ1k-U8?-6vL_1&0(WB7o=54cWYCL{;oBZ@raH5xN<9G_6+5ud|M zoWLg(dCcc96DRNqMV|0E%*1hgM3JX_4l{8aA5l1#=fw;h!v_RCWBV{2NAVtop0gjA zh9ihaffwWyUd6U1Lu3rDGWw9Zo>9~d4*rF2G?PJ zWd5N)R^SSJsPu_>ie7$#vRD| z|5_M?|6TuYN#}Zi|6Tuog+FWj@B06x8UOFC|Nqs>y%+f3_5W3D+)D&m|9=@?RJ3!y z50>B@Wc`0x2lu#O0Z!oyN;p{)gE@#q0*bh}Uk5XA6!9qN=6(`P#zDM69zX6g!9+yh z1#v0RVK<;y@LFbzlX0YT+C zZkUM^NIF73*_f8CK#tYz=r?48+dn=>~s zA7_z)$}Kp)Scez{v}7AF4to)Yf~~km8gp?P>8RA2dkV1*F$nm9a|+|J4{uR8gy+Ko zoP!Tl+i;H_HsT>2og}bGp{pPiJS22!oFbw4&oz9c4Zq8h8uAI z%(!6!4&oz9cH=sY6}Sn%?wk{th{H%gnI2r`sMF&QWD6%~7NjPN%eA!l#q zFJ|Kme5lcf*B$J{YXtRWK4S^4LDttd!XG${M3n2#>kZc95poV-u3-+&!5GME7e-+( z-lOC%oQGJ0d&u@H*DB1y8BlzqY7gRPuov%9YB2kVb$EcBLwFv{!$nws<8>1ga0Fja zaVX~ow%`Q{{m#Ae2*Ygz4&z#aSvU)0ICBK!a2QDl9>ILTHoQjBksJ@K#(m@*#kB_u zaTV^-oHLk)Q=qg*)g8lQ;s}yac`WBYb|W68$1#T3i023z&v}m3c!1m!Sl5LmxCL3; z{sZRW3fvPp-k5=NuukGQVKPoaqh2V-4JVL+T7UBTgCj^q^~sDk4k8&V3uA56trIOZ|Nn2jq4n9q3NFWf?o1-w7O3Oq!Cg`8*DfR`xo7v}G+x2Uj+pT%K#@a<~uHO6HGu3-*f6=G3hEpr=t@fCH}@jSSIfNMzmxIATD(D}U3?9v5wM$mMmXN#n?1~7oJW=j z-j84t5>RU|^8?qBXCLoDum|aAyr0((JV1#9tna}II1VySSc`Y4c8J#yTt%M4yl!JJ zd}w}z_s@8NibuK5-~w_S<64G2@ZkI7d>>?OaHSK>BV0k=NX8BaA?tqIU>#(gZ=HXc z%eaq{QJjZ3i)<%(Z0vXDPC8}QJ+JSp0bBWhqTt%VFj1^8J#}%$oI0pZ#oKM&b>ov|bY=;*i*O|{q zLGx(F7KvzbgZYRLkoBd@@DBBFu^os*-P_DHyhiOi{28xNJBB~w4eH$G{6QS*-Q${w zczk=Ga}po%-2<+jNJ8_6yfz^fA&+=1fJVp195XncurD}_z^5D|oJ5{j&P7~Cv1iOX z+(qznjul>@?hD>u;4@mhWbQ+~VqW4P0$+2E;v5RU;W2OzRpOYBh)2`6ye31|<#m0> z^$|CRT3_=J!YjxVyNa@|G@s;6-b;X$|b|JM4*I-Y5WLkkaMimYC) zA-IpaKDHS)%{3QSQCS&k88XnrFw|L;H4U{8U(wZKs8c9qHPn23K^GgJLuotThZJ;k z80s9#I}NoIUi5Pr>KdxM4YdwVKSTYF2WaeXs9nevV5mP4j}Dm(6@@aHc?_sPL;Z>v zG|a;HBTrUCO~Yq&%Vwxcs7_$vMr6rhsELTjPdN>B9#wN0>ThJpZKzOu#LsyQbp>_u z8fpjf8QhI)vW1q>C53I*AA1Qs&XWF(<)kfH9Od0|7HK*b`4+JGEI4K)iM z3@v7;m*`a7P*?G72}2!1*^-6|M~+fFCydgD8jTO=Q--lYo3e(wfCl9Zbr==P8)^#* zRWQ_Y1XkpEU zZA00{hT4tF-x=y4YBph9@oiJ)3tBWYR5Ut#&$y#Ub3?tx;1=u`#Q(r^9 z$DjQSm9szNi*E-Q>MjNkG?e8Rwh5JgHPl7)9Av0;EE>#s4dF4+?Kk!Ti-vMe{mwB& z?_q|bh*7N?&YT}%sN48`B>OnZP&?6lw4vT&#u!7D9LxBk-#A0r$1{J>Yyw}$oIiNX ziHtjjPhuNG4RsVh|H)WSW*(sB6wWa$pK7SO)7V$cna(!PV2)z)Oty6v+klC)dA>Q! zH%yqzpXV9s7ADQ-dlqo6VA?`{_Ai56Ag&{ec+AC&5mqnZxt4Ohz^-M6>b{)g9A>D~ z7`cLZxzbRNuy7S~c(tL@uzL;X%34F^U1z8pm>JHwvYzom#0EnR{M%4PH*y|e`6iCl zW9*aF+0S3#fHO%8gPVTf0XMWqK+|FkMo=-IA_D6F}ZZH-% z8P8i>OK%%05m)bU?!~aLcex(iV{Gp891j>{JbuW2KjNHy%=PdIUw_K^6U#V1V~#)P znB(pXzUL+9@hcwxHFM+*uLE%gYuee*cbxn2hH|{;T8P*WJl{vg>J#%kfw}papGjnY zlMMCS7xpEYbNeg%o?@tasq9x8*Y|YJ;S8?j9)s5>L;3j(UX!@qD^q!pYM8wCnCgqg zR7qA-CEECC=kE?a?=)4Ki|=!r%J4UpJ-}4{nM{?9fZBY4rYf4nROPdps(Ln4HOy|R z);UboC8wzd<}%gj+@_k5$5hMnnrdr4Qyt51s;dP|^{gO|TZqRgY^owfOjWC>soEAZ z)vv`(HNAwX)|WI@WGPcUD9yH&F;%W|JbrnT|Cck>xQeD)6KtxeN~U^M+2sGuOjWt6 zsXA9P)#U1?+F8R?cWau;QrlF)bxhT*uBqnMGu4UuruxvpR6z|*)vgiS)tJwH$9^_3 zRhed{>ixZ`RyXHoTd;4fOcm1FRP%pedqYeW(AHExv@_MB_NKbi!BlxWnyP0f_UR{+ ztUQ?z_tuD)xlr*{2){HA8e}A zLrhg@sHy(=-Bgc;nX1kRQ>`7zIFB|}-!Z1TJeGYMZ>p6OOl6&Ds^2E@eW9jmKG{@9 zr?B1A*yib`3Y^LF&oWiUY*P)N%YM!?)qn*i|K2lIuSKSMzL@=6%6Ki~xP+PN(+X3K zT4gG|+ElaFnkq-Qss3KibN$UWZ8TMf&8B+0#Z;5FnJVWFQ|;NwbM7|P>pdp_&M;N6 z{iZs5fX6z-z8o>tfupAS`M9YZk?iX~j7^lOvYay2sna~qSyPog&o*2z)v8OT`tb_m zd(BiguQQ%Ec&=Nf%5%q5u`!J2J+}XWsp>!Cai5s#$x~D9ea4)4!Q;O&Rn<4_>s$8k z9mnOpsdj(lF%p<(iKgoQg>C$5s%ojGDxS`Edra2+n#!k{YlcN7SS;#;&7$5r_~_#A zgeiXwuqd6`qTE?6Dpz)kDw)%wYUZ}6)_EKHR*xpqZHEb>WxZa{H8!hVQW{cXm&7#Kdw5SeyEUL;r#^E5(d6;cFW>F6! zE$Uj7MV&v*ex0+ZvllJu@)h>!x<$RbX;G!wae0{6(G_X9KP3-C(Oq|J|yxjN&=RSyhLLJkDe*If7P|INPeK zF0iW5#a4A|xs@C_t6CUtRT&$tYVbCzirZyXzwWcDltWfE`?yt=jI#3YO}6QxRRv$O zs!unq>d0NT|B+Sod1h7LzqYDs@m5tnfyYX=k|khOt!WG&WVNZKE}OcL$);@CZK_os z8}D^(ynnT+KBaByZUvkAkzd?Bt!Yyu>f2QI?`$fnxlN4;v8g&g+LV7+n~LjcQ#bnC z)cL_Sb#b^&-5YCDUnbd9f$28Yey&Z0EwZV1{L-(*I-5GW$)>9A zQGablaxtKjiDrZL0QLn`)b2Q{z%>tXH?G44Ym37+~l3V0P6Yzg1!`CGhuc-kc)J=o)vjFg?CQW${=C+% zT5YkbIuUl&=%`)wI%QWYF56YyZM$mo#IA0?v8$n`>(zI@GzA4mGi(Lv`roP%Q^LRPQkkwQ7n(eIdB~x0MbRu-T!m?&bR<9qQOc zhl;!7P_>^s)WMGq^<#!Z6?8gPU=F7$Q^cu$tLRiu>NwT7=1%o(C#S03|(aH?IC zohtY*r+T%{sV?v4BftEteATHAKH_KIJ5>*lQ_b>ssSo*GYEF5V>Q~RDCjQ`3cY3(g z;9)M+WU7n*4|9>7=Tg5Ocd0JdTx!WPm&%>&QgKeVau#r_F_qk^RuebpyIcJ`)UBpX zcdN~--Kyw*Hw)g~s{S*#dY4~E=Am2Hu~TDjL>{d>b-%}n%HY1sl)o@xPHV*=F32>~iH zJV0GK8=%(52dL&*GpS28GpW+OGO6F@WKw@0%%rZxW>RVXnN`_ZnbnX1nbpHqRP8%lOf|buTorp;LY>W5N< z?zO$T`}QYgF7Bap%K<92+wZD+*$Jv|-C62QuN7)X%r5oY(hKTSzz1dJAFETRjxajS zaG7Ij^|kbPUXg>$|2O2~JmrtQn`TxOx@T8uqw=Uz^9!mun~SP;|CCaBV#=#0A1bT$ zwi>E;fx4<_)rKmzWmC1fPfOKdLL23`f8R2jKHGG~k zM(eDXjD;ny8)xd=HsadcH+=n`7}g0d49~(i5Qmo`k$#{dU$jBD88P#RW~yGWc%I> zEZN%JTC1H|u5~9fyeDr0NA@yX&g^eaT{Xzux%+qX#K}?SiQD7Nt#3lj(DZ3$`r%vsQKB6m^CnNp=J2WphJ%xzZL(yUW;%lrOyEF(sLYl)lQ#8PKj3(J^I zA(qt#I#@QI?rd3jv%96wvp$ym2?H%hc=J&wV1y++-&o80(i1KDYfP~OH<@WE)qb9Z zH<*^F-@TH@J%}`(fcASFaJGgd35EN<-q-aErVX4vG^xlw9M4k zEbskpTgv6WZ)sobiKSEU3rmAKaTaH@50(S%5-oMQr&zZB;<2QTG^{~?+O5HJ{j9l{ z2U_FS=dgzD%xeugT*$icWHIZ#%e*m&sbCF^{l=R5wuUt-sjhW^x1lx8-pm>j*vh&v zPg`q5k&f1gvR$n+tMs%ssN2ta@4H{E%~}t&hW$9wdZF7m>%D%HtWiUzT0=+8vIb3@ zZw;Te*qS;w%o@C8jkUq54c1Z{wpbIk?zD#O*=x;x=#X{jiR0F-r=qM!E}XT7U%O-- zaQnK|`QWxS^yz(T^vfr_$#`LPeu}fkC4I1lrzTo!cvGxf4X-uMX4;%?hfQVjx82K< z#TJ?)r;VFDY@PB4*=80hZVM|?#x|ySMO$#GDz>OHHEpHJ*Ru_%*vJ-IshMr)H?3^J zRomJwRO@JKP@}6Yv}R9Rc&&c6u-d=cdej+eQ*}q$hSnWti>f=x7F&0!ExPV3TX^01 zwgz<<+al_O*-~q-vE{D4!RD;B#TH#-r)@y>y|#N*57}~8Ic_UeIm#9oeAX6S{*tXn z+3U8bQnziX#qZlx(I>WhgUl+B<#g?)=AC|YL-mYvva;>^OL#K~{%vB#R&0En4-M{S4D$DGtrB~S_3WeKiE3SNs(0JNzU;S$ygg#S_c+pC>gFkXvvcR| zHI7}eC+xamAG$uq9<}75{oagNd(^mB_A!Is*%P{dve#()#U9c)%^qCMXTMj{;%Jt~ z>6qyba4gKo;^^@{r$ar?=NND`$PpG<+_7+18Aqoz6&-PNt2k;*sOjkRYduGU&W#+Y z&6+ueR&V8qDBji)m93*=q0!Y5{Hcc{>``Aw)Wu&MM-Khw82a}JN9uyHjs_DZIzk3a zaRj%Y>4>gB&rzf7BFBK7%N?DJ)sEcn!yREUn;fxG+Z_qp_c$&rIpF9q@u(xJ|38kn zkkgKPH7_`37P;zBem5O8l42Y+9zJxa)3J`3+g~~E{q@d~Fy@ovLiaC@9!=657s~k@ z30W=9=v0R@^ohSS;dB;f(6*e;p!xZn(ZhnAAsvf57uGK03@=pC*~3!Bnee)XGx$U#xbgB+*oPpJUbSC8P;tWmi?u>od$EhL*I%C%iafVJD?u_j=#;NN6 z;fyUfnWd)Foe7WUI0GXWIulkcb%u{y=~O?ha|Tu4=nTxU%^8un%NZEGkH${?wH+BUDeeY_J+{zVrsjVwwZAX_H-qod=_H;$(?dJ;l_=_v_+zs-Sb%#8w z=nmdi#T_-Yrd!ph=T7i7bcdg9>Q-}Gx`W!baVO;Z(H;7@vpZr#cXxRIK0MAqcSOQq zchrGl?$9x#-Kx$6cd!n12c4Scj+i>zt(q=yE7uZt)TJp)1{f5$!Ykg=fm{*Wf~KztBGm_=VOg;uoA$ z!f)Y@vVP&cgZ+l)tLhhfv!oKLf zA2(+B^>{zPZ)o^nzo7QR{1!S!`$ZfZ?>BUCs9!>%X?}q>XZa;eneR8W>SDj}*USAD zE??~z)NH+9kJL?mAzQcmC3M{5*T8YWufd@sehGad{X(*x@(Ve6&M)w{%YH-iNBf0d zyzSRu)P28*B2WCHuRZq*ANR&Du*7@61~(G?0w*NCS?wR%WW9g%%T4}Klehc#2-?H*?)Q)Ae8fK_ z<%Ivj#V7qkE1vTYx_rrhXus?JJ&fD_39Ih;2UmOS9~Aw}KVsl({{%DMKYG^oW2 zsc`?x#mjN^RYa|6}S@;u+)^6%U}O>)mU@BW^1-}gNygrQ}7@j@Q+`sU!1UO2YU zOL$|6*V4k}UgSSldyO@0@WLOB^l~5B;&tu$ZC=8+wtHPG-09{1h3_RaXL^l==X#Mt z0xxWBiI?zVxfjkCc~Kury?n(=uW#MV)T*BIEaaG2ZF% zV&o5ajeR}j#gLDBG5$2+Mb=MwQNbs?+})?V66T-tvW{Ky!dJiQMV)-zixGX(>)O>@ zUQ2g=;Fa*s9WMs{xfg!tD=)nGdoRYxWH`Zvm(%DUrCz51EA5c|q|Z0tL4g7=d*!}?Ee z9vls)_Wa2QyY-;Y(igmZt{wC9@qHrL=NntNkMK8+kG1%5pM*D`@)_H-$Y<=(QXf2I zg%7D&<3oJ0!H1C?>BF1Z;zK>T%?E4T?t}f5GH<_z?T@eaK&md=j$D ze8$dH`iwoj*C(Mt;X{0<_Q6wXe6CHKe7<4T`;cmz5Bx}g&o@!+K7_N&XY9{?K19I* zpKs0|^kK{&^BFTv_%J@1@}ZtT;Unxntt0;$ODL;+smptP-C@$(U)q2#QFW}zV3N%`Z9{&@nwwO_9egn(AT}{6JJ8{g)cSpwJ&wg55C0apMBki zUww%S3_r$S?)PJCd&rNh^YWuE`}vU%2mA51h5PZ$96##9V}85`p7LWnzt9iYF7YEy zF7xC4y2=k&3@G9F@EF|aeh?x4nMae*$;btmmmH}mLKo=Tt8eX@WUpH z{irX?{2249{K&Muehiz!k2wb*4-ty!9 z>6Rb0l=97u}@ui>p{crq;zx?RuUjB=pJL_M5nCTvW{P6w$jCUUL$M5y_ z#}@eeyLSZpQ_^sMqMPGSoqf#T{l%01Jimqh*vcjTjPzyxn0l2zuWy|{aW2B2{4B~J zdnCr6SRCt*CnWe&6+8W@CcZy$B*WkRI_^(?pXbjADDr1Kx5uAMsPL!C#QvlOiWWmk zf5v%@Klzc~pZa&LKgn$HXRK=SXC$`x6Q%9`q@l|nCwu+f(*yqQ*M|JDFGl?F`;PeY zn8*C_=U(*3wx0BNXTR)EiO>5Jb(j4q@>PHL*tOKftSXKMhjI4%IM+!4T& zCkK$4T>+#iGl18a6M!}62k<(I0&sFq0Pd^^pa#VOa2PMZeOMX5nA8MN$MgaC@!A0V zrTPHgj4c2^*&M)gI|4}ee)!)LfVrK}HW+}-3 z*#O?q#Q@TIHNZ_?55PO#2yi#Q9Y8d`7r?0fAb_F06F|y83!p0h7C;t%8^Fl@F@Uk_ zmjGh>zXIIP-xG+hyFbvq^r1lV39mq2xL+XV9TZ626Bda5$O>e9$_pgknHNZ0nIFiT zSrmwmE)C?7%L57P>Og{69|#AF19{n-1F5)}Kx}<%Aa6lJAQ`eV(ETTVApUK7Ao*T) zAaQYbAT?1CNOhM466W$ix2P(R$l4o7MJocSrRqRDOczMpV+_PTGY1ma8UpcSO@Y+@ zmOw^LdmvfV6-dSR29nDL0(qfBfxKUb1IhOf2U4de14-v}Aj5PbkSaPAh;KU^NG!S- zhr|S5WjjO(0%A;AXRrOkSL}C-7$X+B%b^)#LD=T-Ae_YsqP~ALhuGrqm!jFFgobksU<+@oz96FLKoIY_gF(bUMuPCu<3UvI(I6_}cn}dX6XbsHR1n#BHi%Jl zF^IAFY7qI|wIKJ=8$pEpW)QXER*;)P1z|6L6ol(P3F1Y65rjYZbr5#(yC8S%--Fy+ z{}F^g^ji>l;htdJcz>|_`Gw;jaYjLof|6DN7e`PT5@|s|`ZbL9*{ia~|_nU)x2V;VHxv{}yXhN|2m84*zCN6bJKW_5?F3DuVIH#liR+(qM+MI+(Yb2&O*O1!E3lFt)WW z*!^=uFm<3Qm`rI2rvB6(>>l4AjNv`On3pq{aoiQm6C4U=_>TqSCyoT;g~x&!0WSt) zCuV{f1*d~?-*ds(^u=Iz&edS*q3glq;Type|7I}t?{|Z-f%k*)*pGr4-+dg6wSFGV zTmMxsL46Cn{us=g|4T4_`PX1x86$-7{Zj}&{y+$0=ffeqAH74UX8#c0%HR;jn_(e@ zm>og}J{p1@nHNIrm>+_Fy)cBbED52WUKT=}TN&ccT^mCDwjqRaYzm>4KOaK88WTbm z#fISbC4{&;lS0T9sUf^q(n2snRtV#_oDf(uLU@acLdeslA#T1f1plfkgw*W~Awm@) z)FD*}g=s^G8~PA;L2U@}4-3$;hEN=P2r5^!C&hFn!O?9cg_%=b}$6<8xCQR zVcbHCex85~Y1+5KoJ#d{*u-7`NFdu&lC*1H4>&dWlv9{ANx z-r7*2YeOi(+7!xb-yDjE#Drq@ZK0&^_E6H27>YfZ5{m0~g<`*DgpyJ`l>BaYD6h02 z6u(m(%F8MXCElzECE~@QjC0aZ-iGQ>>WDfNTc8WYNJFSQ$Q(+U>qE(ZTSKWTdnolu zYbc)H5lXz$6^d=@4JD2^L-8jDL#dWSp^OK|Lfz6Mp^VRthEn|Fq4IehP$2(qaIojMis9PBQCECqZUSlk#&(_yf2;)!(P}L zM!90ccn`ogo$`~yh|?)yBsVP#tIiA~ZsKA1^1Lvru^^1`MR6GUd|4QStO%oi5ryGN z(lFwXB8+#xI*iEFhT)U?FzS)oFh-sw%zeBujN!L0j8V`MM!e(*BmMS=;Q|uc`@%@? z17TS15R4xV<2`sdj7XaZ!w($`WBhhJjJJIT@Sh69zc~|zV;6w#M(hhfBTcfyDlJ`2NIz6>Ki_&N+<^nI9H^7k;x{Yx0}mw$y( zN$|5Xo%e-fcm5oXKl7Jxp4clKf5|r-zb`PH+8Pqhu!e`b-(ZLHn2(0@@Ok0x{-?sJ zPZxx{7cCCw37-w;9a$dk{&7_}WA(alO13c^dvQ}Z{_Ey&#)g=1Ot~!_I}so5{&h#V zdtGukA?JrvQ|aOEzh{Nx%X7ntiu`bFq%fTPyd<1_vOFBitqdpji^H*-(r~wbb+|iL z9gZ8c;qH_AaPntUIPY0YIIpNNoFbcGOmjHT#}V#+zB8Osbcd6Nd&3!@IKz3Y!EiF+ zP&idH8t$GN568Zo49B?B;c%EH9IH7Q&O3TK-2KVfa4Pg-IJxyoI79wwI5qfMIPvxy z;qC|D4kuUL3TFu34`H~7A7&EYcr)Fh{!9`JVq%4%OuUiF7CU!x#9VG>UsX7bieFtP2&n2g=WnS|s7lc;qwd7Upa@sV>(+hW7lY}xxvUgU>NGT{!>o%Jb`Ed7GXkblL5A4Oog_x-?RkUuf0ga2R> z$Nt46PcvBf)%#e~TYqLzA3Ve&zj%a2{ouo*{^ifY{~XLBy~9{|FpEX8xh!hlV=Qvv z6D-Da^I6oYg)CyjVwOAdSr!?+oW+P;#o{HbWl>2RSXe5?g1RP)%GkoMge)qxibd{}uoydJ zEJj>4i;PjTs3yM_pphF{=~+A_%oaF{zGiu#YfoGxDOla^k?JxAU3Zo zlue{C+4x2doA>0SY}{)e8~fo&w)>r@*^E<**wnxhHfDK_jaRH-^HNr`$+hd)BxfTV zzjqUxyc5MHFKl6B2e-0``dBtzzMV}aB(izWC9^4iJ{$i&jZM6s$;OW0Y_e%L+g%}G z;|WD<_u^8v`;l@s{&@wPJTGDs{d?Iwjhu~TD%rd>1e*-hvE5(m*~BFio8hcu!y!Pn zn{NZWb~f+fRyOsKgUx%Xlg+btv)v`VY(|umO@+DG_%}mr^4u^R?;K-O6-U^N=%Z|k zInBntd6A8unPKzVPO*uSGi+kxc{b1Q5}Www3Y(aGmCZB0#>V+?u(79avZ-I*Ve>A% z$7ZxsY@+BRHo5v^Hu1n`Y{r{kuzCGo0p4%fSi}!({E?s7ytjX06V6}RM8&_^*oJ#K zU|oOV5QSbG;yGUq?^k~gem01MHH31g6efqk<#4Evc^qQoaSkbdl0&S2 zn!~tn5r=niF^6h+mV@tH&LP59aj@HKIArg7j$07HAr?e(sK0IIP-D>?vg!p6V`UtN z@$+^LIi1L1D3Uph^?VNbYZ`}oDU(B07bMT;Ej{8bKhteJ3kZWO+`rAVs-hojLl`+o2{3kj1`C}Yj^>Gfd^aO|a>q!pQ zcA7(OJIf(|JI}!nU*foTU*))iu5pO-uW=~p8yxECn;hbucQ};!Jr1>&;*g(z$YHeK z;V`y-${~OHoWmIS8;7y;8xDET_Z-IPj~qtE&m8xI|Kz|ACU6)z46gf;`?!p$`?-wW z4|3gJ4|91_UR++TFW3EW0GBrz#N}m$a@~Jsa(Sa{E-#hGrG9&i%Nuxti^a|7Qr|D& zV(rgxF>EQ9@$qw9ylw>-U%Hyhcw;RWmu=t@Y>dl070D&@p68Me#BlMU7r5@&I45FNiJ?U&85Q5a;Zb-x$cNdT;6L}xLDq+T;AWWb4lY3t~>NCE;;x%m$&v77r%6y zi=}{zP z>9fx*TfSoDs?}@Ou3NuhV+6J-GHUblTcTsOzOXGeE`EE$j>M#$$tkJ)U1{kVnOWI* zPVVl!d_h5BQE^G>p0aXbMP-#pEZHlS$raT~m6{+lT3wCaU^La5>n!yRjaFOJK6`UZ zYn!9JqjP^(H`&wM*Y6xS;2In{cxZTJbnNi>k%`Hp$EK!_zxdLLnUn5Qr(ZsE_T2dk z7cX7Da`ly0uU&ub^&4-z`PR+1-+A}ed$-@GKKSsXzux)ylTSbU{EILD_SM(leEZ$^ zKm7RjpML)3AOHLn{x0IZf4cvH2SIia9Z60L?vZ;|?7LF`SE2v^$gKI_Wd83${}-wM zDE1%Z{$23jCBG~BUD@Y^zbpNm_(=XgJ@C-OUOs*SLBXNnOg4x2=;QOi+6xvUTZ5^Q z(6pgFcD`%o|6%3-X5{~7Wm@1rTKRV~&)Ip_(6g4FHMPgq9%Fl~O`Dsxx5wbL#gWNr zo6|-|R;SI5>`ogVSss}l*&Z36wmvdH{C(F)d;@|*nQZQ3^PZgl^ulMBJp0`86|2^) zUB3Z*J8Cm{Hgas_*R)&DdiDRssb}qb*Qw{c+T+$9zxK#Wdp7Ob$hT?dM&6AiMs`LH zjyxP(9LWq$j=UU22TfjBVPw+2f4xB!Qa8*J(7dZgXpyE;P)QkY3afFL3|{? zZwQMw@2LgPEPW27UcV8G-28m>)@`xz2|JQ@rljslgGmf?7+Kddga6wE{vY%Ae-V|Q z!^oYHZIP_VxZu%fCWEjrm(gVQNDK3s78g8wPTo0zX^Ck=(<0L{&k8*&H4+<~{nO7r z`y2_5B>(#BZ;;u)`yLto$G;=tfBxl{e<1N`^TP>HzlF&U!rw9YUoVXTF0DqRfnK#5 zR;#<0O0M#J)QIM-tjOKovA06xv#w-C9dy zQ%U!#wQy-P29rq(8>oBtN)a9nkVC9^KnxZDXt0^ zHEQWz!eDB!HPnJMCg?`XE+H4~C2B1ul~gK~%i#r(6C#n6XlQS?TY-pb?_N=*8hBP! zRzfEsEibK{Re?rpvbF)`T9b*WEHAHA0|$g0#tVhz<-$rS5LTwIG1p z(q2~lfnAPRGH%Z23yxw#@>-DK^ZnVBL@ z@L3}lmS{*PX;T;CSva1XTUcHx2L$IXoSkY1k<`+1T;(90E=y&6OiWTbE+{OlB$~&s zUA=Ik*F>n~g;^7EDUFVZh>YPEl$Y<-^iE&7bZW#V7Z&2_e7a|ldBQ~ox5kUCbc2{q0dCb}fEIM6K(mw6J_V$faBO^mjRZ?_Ryv8+M zi>JpdT^qy41to^VS8m<9a$>|uHmkR3OS5S0a4*pek!N_wfrIdkF4g=v?K zK)y$S3rYEFpIW+dEnlP^zJB%6si9`%nc#m`t2#G&_44KGVuj7qmjK<2y;4|SN|*>j zl(=@m^0g6(1uF8&l}ncnw;`Jo8jIbk#@8)cz7oro8m6vZx^!;J0p2P#)#9;HOBbz^ z_6|A8!{fcAy)Y$FWN7GeIh!@=0&K}sDbgI&tsB?OW4UTwr%J zYs(A3*jG-u92Qe~RCIJ?bWC)XVfyX2Z{I%GCB)-bu8fx3$eHU`iRBAcZjX+NiHxv{%ZeG87b-0<-@>7zM`24j?mq%^SYCd=21~t_TbHzdk9fuFMt0R}MTgSIf zTsn7lW@z{<5gWCLIX^NzS7;e_mq$jdiz!tR+O7*%rc_z6F}O*X60>rCr2Oiwx6fXE zdun*R7GJv(i&0%VH$vpbE?pXxg7c#>`-R)oEjLNTFJHD6i>&M&Id$vCNIHfUmZktU z*PB=D>y~4=4MW1D*iu8gYpBZ#i&BF|#9zyc$t~1$^$t%@&0KX!Bj-Q17F)C~HdZuo z?%ZK#mz5|j7pWanXYHWCL_R-0CYrCBy87mgnXY!bi4bm&SZ8z37*Zk=MH&)}-P_(i zJ!MVev6iQ##3NN1PMtk>VaSl4B~mpUb~;G1O_joXYSE&2b@O5Hj&n0ZxvQ5hT^SR( zY*_?fOM;sUDr*T*p^zXCPffTQq*)P5maJU68gFQyy7T7Qsl&s=+K83Q7Odl|o!76P zXe(S7v2JxVztDN-?d#VrOjy+Ak!!anCi1s$CtTOB-?%lQ*}igl6u;7W^TzcXPH7Al zu{;VlIY&-izkc?x%U+s@VNo%K8d8;%RcYyUHIs)goSU-93CH2CTD2%QX4!)6Sy}Nh zv6ibh-+uGjDVMXYAZih|oiDE~O^S$!6{zh~7p}o%(v%bJ(?h0|*qH6nYg6!)6h2-~ z2nBp%$n?VsVR$ zv=Gj7)L(B-4ZGUgou?Ir0*UpG5ht8BfnFv?3!&Y=@m&$^`Ldm9Xu@vB$I zWEGYa3RShuGB4G`#BrGQT(A0!hR4z4{R;d)0K7+l@DlaG~ zEGd8)M_BA#z0O`6dQ6oR3Q8)WNzIt|XB1zczsdEVNa8<{#D5}*|3ni1i6s6LN&F|0 z_)jG9|1y$LtN$OxR1N(D-OY`Sous8KJ~p|aNRW}1QK%-N_R?+=mPnQQw&r?UQzNk_ zDPiZ%9EG{fdBExH>6E0Wrtoue_^IiI>U}y{RfVKRBNs_j4eec>t!AYVPfq5irxhC; z+7FL9yF1$2%)8V0JJSjjR@YFURhp5RnT8iu)=!Qd8XD-XQ_FI9s_h|OD^&C7n(9zN$Ey~J*f&kH=DJT`!*xDMbZT$zj z>lCWGP8)=$mHE38cJJ9E$jQ^VhDS#ZI@|0vNp5mRezB}pTAY=cQ(kRq9~e5&(`pc@ zEnRKqvb^2-yVDEGi;If(h}E*n5@pMQ;UT-aN>Qs-%BsrCi+1nM6I3Zx4ZR~H{rw=n zLs2f2O7iwp6Lp=c!u;KNqP@b#{(je?!%mCYWHRaUQ&ThZg(bW5iz^gbt=`<;=j!hv z?Iwdx1yzTPjJ*7u?A$%N)_t|rw!X26!(>~Fwb5>r?9LVxmkD>L6<3IiW?8MHrRT_@ z9$T$WXSSE|QxkV&;hEWm3R9!GuAzOu-O=6M-PLH&D62A(k}`G+@XTUOM`v4ogSFmL zS6f@x*tE}PsmR=skeHH@uWGP&cDFXx*6-WjYLQk|Rcj5^qKYD5COao@kG!_2#conc zwEJ4S2AvM|-n|Bcyf7^-x3p4JB~jGW+1fff8?*{bZ|{D)t+BDLrZ{6)W_EUNp@c9R zYMb|yMwvvewb~jQ8XIesf*f>-w1#?nQ`^8mZ<|S8U9G4rt28(qR*kf(vO>70tV(S( zHMVp#sa4eqnWSt_InmVL-P+nfNWmg`5E1KbP0cMWR-*ypaIs2TQ){v48)? z2)(VXz2`u`Ra8+{Tn6Q=DwWA*QmGU&nOvzRbb3>BXJ<>JQCU@4mS0f1SD{qb)Z3by zTiTjx_7sAP*y`R zPf@J`%4mSWXw=u#0AgsBN+c2)P^hV?t#33#p--*Rf?gEWM70#kBS?J!sMYFV^Fv>w zgEt+j_NnCJy&$hb0hPIWtF_Un)vA?BIp9)ibjoT(3hq%=55ehmP=Zk^6iT|V2t`E| z$N-&CS*(Hm6pPuQ1`t&>Tq?vOkkKd+cXD|(x|yv%YUzriTBQV@Ko3X_9`t&H0nq@1 zR)ZRp#-R(5g%9YX2NJP7%MW~*H6e`^I%t7t7!NalV8p{T5)~nv>!2B= z@zXDN@%>R$4=)HSjh|)*;X$m?*DNx0H^;Jv8XE8iyq-pSk??FxqP{swH0yI<00{n5 zL$3vM3IlhZ9gT(}e}LKM(I>Lv93hY9;T90nps2ya$DHHCgh8lKH|m>}!XwM9M00wj zMWSa1Ek6vUS^VP-f|!%SLyEqqhs-gB_@e>mgr~{O5&`b+G7B6brO>vYvk{UGE*b<- zqsa#2;hK|=mJXCblb|K?K+L_u^hM&{y*!xyAmUw&G*-_zg#Rv4&&?kY(59GG2I9wKl4V%*~r~?*Tj{?wV zWOAT4M+`X`EV{4WV&1t%kC1?cc25sBL-&8poNwV z-shTre@C6LRM1oKE<|Y0RV%-RJxuu9_jDMmgMiwg*Qg|Ac^T=&a#?Xk_G-uTx-q5n@&unZP+sW#`&(M zGv~(T#j^TlI0XZ=IdX+KGi=m)UjjnYH>$t%rl84 zl8m?_(}2Bo^1_v&juzKIlflr{s#+elctvD(L2>KU6-7jH_m6K(_lzCuE?cp9;WNuO zrDW$T`rd6x+ajJmfARFpWM8Yb4)=Lq-F$R+8MuW2$;N6sJV?wTI6t$utXUa%<|w_EeX zCQ=krKJdx)lgE0R4w9;l_tjzU8qmn+%YxWZfkATEt$8)P`4pUFw`8ECK=RZ zHyt@YbHp{&Qy#Z^Q*OU-L#pkq^2nUQ_fL0J4U7^yp4+Av=dViccnOae=o$?pugpx2 z4mp%@&#VjVn$qN&CYmB5LZew{@-{y@ut+v?IGGov20zr7B!zgH+^JyK$^NOKBuFvzI%Yg7erS% z2M3+~JsqX<*KCPPNXjst8Lv-_OA)l*JUKGZVJ_aWesf~JQlFPsQLG$3Hg&|DoF<#H z7pE(S4SAd6Gm9jqm#$79>DS^$~Z|aycIa<{}qR7qe=}u2bt|BzJ z==kKwu!E>bU%w?O-+peQL!P)X+5X0Km!_nsp2*L{i}NxwB=$Pdj(p>pmq&-&m4f7L zu}OJ`={~#NX2?#?={h+!NNUv<{+g(5sf5j@D9Wy|j2|C031S2mYsDG~Ib5|SK2JJ& z@z}7lN0%J4Wk+&quClA$T%hPUa-=UKBEvS_W2(}qa^s_t^2Ms=lgCF7_O%wrZH`GZ zIhyT`L3Q%Bq>_PCV?8!ac}8aH)@_Lb^F)7>CNDlkcY0#TX_6R9Hf~GJZ#|+Z&CAZ0 z9eicF&y51`?p`N0r zHzlMsjafP-4;o^kV-tj}2gin7{iIQ_d2N)y&@JE5)U8TQZtZK=mnB>KOOultO>qgC z%DQ@qs?%yTb{;v{=V&))Y>kW;4d-pxp&;AIv7ruCUW!hWS!x({RBVkcEfb`Oni`ck zT_?sm>iY(|)Oh5U#N52}s=5J7d6oU#WWP!Y}U_7_fIw4zNl~7{LNiDALkfq%&QRBd5k5O+Q>9OnU9Tssizd)xhi`f{PDY9zHO+Ck(WYX4S z9qL?DyRjg?KqSe*we}93uE`?Wv^m4nYSWqy4m6eKR}e&r)Z*-`t174vi;GGma!FB1 zmDZ>?*0(h3}K^+t@hzfzAR4P*_btWSrk!#FGz24H& z+z5p{SevS3T4S9>Cr(ey5F2$mQ&+#kM3_yQ5Ij9n ztRSaIVlXL1RT{lkp{}w3w9&wSiE` zmGGR>=(I|y2>2m%CUYG;hqS2vf(k$yMOA5Og&c}C3bh`}CWbmoogQk11|*6Kib$v| zq(TK4H6bt0DUs^6DwV-*(TF4pg``YEnDuHUp(m7bs0z_fN~peQ0YIis(%EjeE5tNNI8ojAbr$+oMMHMBeB#DLPB83L{)f(Z<8AwhjR9e6dPk5C~Bu3RO zc$gCqm(wbM!jGh)Tnwxt?LZ|9^iHUCCW}!AEJ1?`>R12;fjsC3)x#h#hFAhhIBKP| zLRg_dVgRd9Rn=+17?2hL5P$(bPjLZ07~xDxp}RGu0WPPzU8W1qc9zCpsho zy=ee3QUTmUw^AyRf{nCr^i2!-E1{Gs)H*^g7E8fgpb!(-(Fhzu7>6W5BvAoNr>CP8 znw$*kZ#2JP2sqv5315_`I0!eO&$-YB=@01+!9yrShg)z%XfzmC)(bP-2A!0a4{BBbHE=KRL8Jswna+TwI8p-A zA2_Us1<*c_L~cOq6y_UpEhXXz&L|>J45}qS zRiIGd4w7_G4x#|g2cm#F0538pxCD|x0!3=Q4(PymCD?{`M4bjU6pSz-XuAW0$e)2% znVc|K>P#RMy?iKD3W*5d30O-Mr~r-D5?HZ7m0(e$K`jUF)H1PLV?q-MOh6maXfm6@ z>%mqqWvZ%VF!x~o>(nw~m6XteSuAzvxG1QB(86ja7kickq$PSKGofWu4(B>WbS)fq zhBS3`W)t`fEIeQ=I(Ape=n1AX))|3aI73sVGMLmNSkIOEI)hrRHR%cP1BDvRC5@@E zsoA0~&BFy{67VdL-ckp08qL-^jj*Uxs)0Qfp+wu<-``9~MKD*5CcQ)m8wTJ@@CY!P z)shOG)zPR^YYfWLq_|{xQ=dhxfaRvKyU8FkG&QP=vNLkZl@@DbYqwLIxgkm2<2070 zCS?li9gSL|*8T-%8LxG-OBt_dHe7{v$iZH zdRvLENm^2(v)fx8HdStk!eLY9lsU#HTO}!xv1Ls?rivV)wxz4XEEY&i=y~1Z?2tzB zn30O%0lQ44H8nQdbw#*9)7WBb9T@3XMFuU-8yf16mzNWc$&oHFqf`)AY;cMlISx@o6IV>1B!b!PffvuCDf>kwLx4(9&73K79U~=uG*+6GtjGM=DQU=ueY$UVM4T zqN__?zC4{s-?pvFtkqj5kJ$2)#dc>!>JHRhmo1uXDSl>Ia*LxPA-Q#8q98gt({ST}@Lc4!6pdnQn(F15)*b7U z?I*@ZpvT#+Sg|55ReiF2ZBpZf5&4oW1@^%sW5a{}?WT;SkvlTAro;^8&}a+3Ij!Z| z^g(B6A_bG;!tH6x<^X4rZ>)vx}5#pO@a+u;&upBodhm6cPfiZ?b9RB-q{Fv z;*ta<5FidUXJ?E0N5_VTT%Fp~ZCev^#09xU5>;6Rapc0WkwKS}6emZ!f-$4*a=54$=o z{1wp&so4UdLaXUMGdb8Th$Xtm9IBjhadzUilPq6GfTiqW`H^#@4rO9O zPR9hC*lzFaA@GPT@vx7qbW9&PIAFk2Q_@VNwlvRmygxr8CAVty)WLzi9!Fhqa%_BJ zYPnHfe|*$Qn#&Vn5{vXB4tbr;mc2Pu+S1da=osnmFvV`%k&=$*my|W0pB(HHZb~iF z!Bn(sZO!)dh{W_?HDHwk2oh z;8oU_j)C5-No(VB6a)1sj${25Ta);i#-2fE582hOFW49rpQ0X<=Bqj&yRDbv(Mjb_ zlE^9U(g~6i(+YGWqeBCIWTzo>N9>Lwou~kB90$EM3OB`-4UKlyH}*71qaqSTazRdc z{}2gRyEZy9AvsrW>2&rq6(z=}SjHC$ zvU8d`O&MGGb<^GI)TSd&va`c(D%uepo0O&)m8a*`jdXXp`Z`;U3ZrmiOopO7BQ3Xr z95Kq3WPfvKce~A~F|{ajqM{N?i<8r(W5exQX_dXd%WkZKX^a2QkPD(;bzTBwKRl^h<=qEe01w~SO*^V8> z+MJXOL6xz6a0s@~o5@y9+~#b;EPyhUG$tue>^Od~zYor<8Y|+r#Age2I@njX$OTEb zv}dTp-rU#Is?1NwS2T6BiujRn0-Gc;jhG&8ha(Lg=JEnjS6z9&tP_&TJYia5a;|3D zRc~%~^;q(S8iR0Kp1NC`%NGz5k+OZHS(YiUx2ww4rbea0(rhiuNEND-Dy_X5wgN=fclCE0s&dj& zQc58~lj>VsEz(>8Ar}^Coz7NOMVYihP$DrJOt$W!4l`_F%ktt9a&@f^g;?R}su$)~ zXzC3ndq*o#RVo%03rbJ`+1Tl@qWyGf5kEOcZf(>{^!6@uMTyu zQ`D*DYHN3kMGK*oOjssJ&nVVgZG=)=Z;@Atj244jW@@x3B{Gc$w!F1!iIixvSzue= zte3+Ike6Advl)~`ox>zA0kcU3(z>1&qe@e!k(SAHdZkdVt=B2lhI*5Z&>6K7K~8>^ zTCb8x^!4>>iP~7N6idv_76Q^DjZ6%AM_CEPpuQx&H2k}ouc}YQ0IrPK%6MM5( zDk6+pmD~v5laXok25CiwLIq)n3L-qUv92C!l66K%B_v`|X;HD5&=C@aw%!Q-*xaa> zsf=bF1Zz5_NF>uL#6r-57A0elZ@|eBnHWN2nOss)B7`^yB4_AmVtDh*bPkuWvZsf98vP_B?boLD7O zLSh9G6N>my-exdCOb>A>`t}f95U0sCfDFQA6C|=4i0NcXNcNO+rB17oNEDDlN+1J7 z(K{rxCNq3>2&D;1umuW4;Y&jhC_@N{0$4}~ph*e=rXIp;$RxoZAo_#UX};3KT2qi9A< z5pr!MN-fa_6-rehmqayhR2o1z2#`iPM99$53{(LD-$nX_OdN7Q#1)XF>kKdsI0J>i z7*E=X_@%>l00aI!JrIwB;vnZhr2!xUStdF)f^rfB4{3>(PD%g?x{w$^2)G7`(LG3o zl6#caT2GKy2{h+K1atf3$%aB6!=&TK> zNP+TETF)9tSs;Uj1OPG^#F88+fr5Zh8kXj5mOon8phl1e35jxIq%ism#NcjdHqzyS z>RFMHj%bt9od_KW1>{j(fmQ)nfNtC?7RjoS!x_Leks`qwNF&H3=y(fCZRuhHt#UZ; zL#MUqTm+p)daQw1g0nNTphY7ePrjomrxTJ#bzJ;Q;4GW`*N90EET^+rR)i(F3pG zwKY&E0RkEo`qnkH(4xWV8DJXCD$pw+Lifl`;X*1vSZRI1J1~pRNWr8;s)pgnLE!KW ztVz|?aC!uZh%WR>f25Jo6A3At<_0LEEg*tEk%SIF(IdeWKpOa_L1$G@vjnG?sv)CB z-M|lRY)~d54$RUQ%`DO$615s^1Kv&>9vL6Juo{t4qmvr+#6~x00wD1aQlwKFAy7q5 zj6_D1wQ6*-3ywSiU61)awnem&crcju4?u&|iRL2G6fHj@bXWC&4;TT5K!ARw zA^~Z8K=bd!(HPJKttFZ{8VGTQ1|j*-vPi2OIn3<$TK>Hge(Mtsfc<~@S7U(VWbhA_ zf@;w7sn%=;|JCbF1~^s&&Sq$6wd&N>HAZty4WWTrW{rJ+Qw=-?z>$d>Wm#US&faN5 zAj`~8uTjIG^nWSY_BCWMq^ElxlXowM~=d`vdX>H2BW4lP0%oTX50>i zjJzz0{*jfvYCeBFA6x-k|s};Tj z%UcegI)7+v_Q4OZhxc`{R-!Jt%CtM#?!dRuF^!)jFKY>(l~ zJ6}BU;(>h%IGkH3l+`vl2lm%j6&H(jP2HVs8evXGq1@Qe(lvO%p%H9P$QJ6G+k46V zR$^~SVF^TQ5Cy^WtgXiddparcF>mBKPv`LGCGw8JPOU5>A*-Tx@U_>ciM%yWEQ=HOym{wZpE_~zs?8;~%deemt4!FC znyYO+Iy`KaWyR){n7haOEd?nFSvBovUv{?&H!fKcr8@NSH*fTpt$AuOCUw2{!PWi3 zsArdLk&k@($;Hl$HBT-; zh_J^u%17S2bE6es6!v85zN_DUc)WZAcV3KU=7TRU)a_WnS|>R0_GfQ)CHF(dZ({s1A9@D{qmQ$j*GWE z`pon7r#^XOTDWQ6{1p4^pWJpL`Sa_qes*)eaMPok_${Yzooz^5!HzFGdi`(irf6>1 zYN6}>FJ7_pne#TP`#*U1v@Vl5FH%18;pZ1^iBAM6&jJ*EY$&TbF z!&euMy!GKLj_ifJg%v~Zefavm-3u2yTRCw1_WQQ-6;G`!?7R8lEAW?Hp4e1)=(Vpe zI&&k#R%H*q^6QnM(v^>|%IUrF!|P<>!bOXUTi^NYGnaVfWAl=g7e4rUO1EX+6PWDS z`_#GGr1`wXr3c^t_NFEOvG6AfY&SoAvs=3Ov3YT|*FSn^v#Q^4p zZK;Yb_u)y6Fm_9v*fupWZPjJOCJGw*&K(+5?0$Y%#y-dSp=m<)Li{#mj>)_KlkNRaGVA?{2alcO0!&#}#iQ6w_T7Yz;f}Hc2X7eXn$MC+>Q-xcKnF3vJFq z!Pbman`yAWzrj?%-zKOYIx^`r2wqsXvcP`w%;kN?Tz*th>F|M>MthbpzKGx4aO%Ke zY4zq^>k3K^9K77UkDs4hTHM!m%B9K6O)V2?T3SYW29#2MezaVA?8sG9eM<2bg>ala zS=W}KND}5X8m7C)EHyiKM&LD*H{3(A-LWskscNSBUaa4rFWw~18E=2BX)Lqwx!m~v z{kLB{O{k+%HWz3IN6!x!E8<|^w(TY7VVyEguti-xVm{M8uv-~bm1(Ux(l{z5GAeMf z(%FBg+bG_MY`=OZ91P z-8(HqsYRTk4Hnb&Gv^zmn_;ai28hzAtQc|2*r9VZ=50C86y#0}e>(VjiGG7( z8!0%h8Id<_v?R0`N1EU7-Iu>NUYOT&_{C!#vdr|2`I&ml)$g~!& zpLoIH6~}50=q8JsOKQ_6d*8Wzr|)7}!ZOB&Y5hx$FDNZ9MDc?1tJ<9Pl6v*A8-JVm zY+^bp;IUTD|6%VvqvJZRbWx78Eqgr9k|ir!iIONLF%u+6kRUhJyJozJem6nJ;?lA>=b zw(9C<|Ba&8A*x-Wl=s^Luc?|kQL96Q(>gU;8b zgSm~rO8eP?4a_Gte@oloO|IL{%dv{(HRVT=pTB2My3F2#H(l?1{MkUKZY6Tn+`=36 zfAq?qKKuOjzlJY|e>3&(Z~fbuS1Hb&qRe*Xsxz9G@Q)APbAU0?o-QWMg_n+Kf zbujzu_x|AfcRl{3pV^mQ{jJ^K6IHy@@vqU73|rc{-p@b(BXYp}>6N$7{r=|rzxng) z=h_7U{rrXZmS1soWJ!0}YF4#Z()#bM`ex=g`MY%S>YpF_@gqNb_L1bI^vtchfBDQk z@xK-y9!d*upng~Sv+>+F^*8dSpLA?*7QH<2$>MptsJ!0Z^oOh0Lo*rX{o{^XH$VUM ze>!iboa2A~>Yv}e73kZ<-5Tz?`qG)k>K%{leX>>jvF_BK!gWX18M0myT;5Cl_SSVN z32la1lQVV0(~q+ZL!OJNTfTYkT|?DPCAS3E;``UnD*tlnPk+8u-^_1P&R&22!`EN+ z1+)17c<^VY&4#DVPdfIs6-*0%GxmG)$Wh9DKe+3`dmr4i;nBz0ss+aiV?0Uslk#<` z>x%Aa-rBaFc0X@tnCEDI{o*TA=8@KG$A7c*myQo=XR=Q--k^rP)NtM?uH#!tWZ$m5&t78(84c{ROM?0@C$e|v5E)j&beM(5U#U7P6g zQLBG&&rdVx-EE5>P3IZL-<^|;ZB>~@8g3q& zY*NXKj+BLaPWJm0yEg6FyoY6R4YtWkDcNNLYu{8?mz7qM!gY==z247TpZM(0lNX0> z{{B{;hqqT`?3L*1YWbu&15fRiKwBnY(<8N^7!JN`?hX<`tH&sYig&y8PfpGuzqr6xz*HFrYQ@Tg*-};B3jkLF-QW7 z<_Xnt?NYGy{6KHfV7{k_VQyIx4%RaE7!6cYfj4EK!p*I(r}oiaX8B5sN^@H?#wCl2 zF@2_PyFS~0xIvIFOBX!n@&Oe1Soo}`6}b()ISQeT=QS61(t3ak3=W1{y~y<8az?P27xr%O?xcqmxZr2bx+VIwygYYYGW^p!+N^;8}@bSPn7CYM}K_!u8zBP zhf11KPi>xfba0=rI<5V|k#*xp07-3l*!bPKb(2qcYBEFg*AIR8{CwHUkoqOYryD-Y zzEsrWO`kaQ;l9@%>dFYH5?2$?9DKXty42g0doupj%D+@xDl}l+Df(o`TNTX`gDZLQ z*$+!@RbA0b^undAzwTd63h*RT)IW)D(f^b`=GC;b{*ZC2@`b|2+(hSw6FcACJ(4K1 z<&5Wku=B>QvAyiv&F$6aGtWNg+n2#gnap|PnTvaM57%=NBMBE0I-jy7Q)Tp}oDZ`4 z519Ajy~_w?I!?1_vdE^=N>s&@Bk!Bsg{-=y zaOWEhH+qMf+B!u&2SyFo>m#amseZKd1zMYRmhIO`KjFTlI45q~o48ToOzO%kJCt^y zoR!vH+g&|S!EKH1@>wltr2YV?kc8MXuHRCsxI}BifxiyHT7`owkLP>Q|wL#r6lig zS%F|`BpQmAR^=HpOALXgLm zic`&&KwCv_R{7?1>gu4u*T`6(@c3}y;yjEHYZql-y)pIYh^wl{Yxb$BbF(u*d2 zA+x%eVUW&@Obo2bJOZwC;aX(L~GxYUGYAf!`dV)nCoape=iteq- zc67gSW7c1vwW*|P;^nu`H`z<6+j)j7*WSDoaplw`H#$E2=*E;!dpP+}W8X)gzC9x3 zJV`GZS^fC!5l?mPK7R4^@hhi#lv`3ZQUq7uIycE=KNYvtVmUoGuglE&Y3>nQ^R>AM zEkEt9^sL6kvttI{{hROQmY*BC*y&^JPg<{aO`kq7Cd%7XcQo4c=4(^l%JQEUWDazH zc(q%SkogpgI<)%cidnMr=yyt4W0x*Waz#Jhct2Nk^39Xc@|u54jZ-$xf3VP&R`zI0 zUhm@hw}%>!mH&*99X|QeR~+UClb$Izo__b8i#+Z>rasDdtb8;u zQqK7Lp*VHlTW=2bW{B>8{&~motDkgu)A#)}qd4&XZ-3wBKa~GaDzo?Pw{N)u}#H}?Ma)e{ua!_RHxM8^Jlc`U!=*YRlus}sLp7%s|ua&ub4)a*Y; z8+Yd%c(_ElF!K3CbJBshEo|W{Cr>*px#_hVID*BAQ=xEfQu$$1>B8iziw4<&s-0@t z%EaW7hZ)y!KuDQfy|P48rYo{Da>HlNu8O-4@ed!W)4efrf#rC%I{q+|KYQr~?#S+x zEzeg-u3Wq%ap%*Lw)0i1$1k}}MFrXS*Ogs9aiyb`x4Zm_^18V*?<_lQrHqYx5BhJu z__`x{EOW!QgT^y2{?V;CR+;-`ruydDe{ZwUi+0_eSozMYZ@n-PF~iFRqVYFeqVWf?4wpa-JrU1Jx|kPt=%nmY3tj6t;k~F`1_VpvnyP65=~gDJuzj^U@*f~Qm3xLy3%9h zYlNBAYOBD}eIv*g=*sq%ivnfg<*RL>C?olZ#uC(eRxhlKg^Ks2NyIvnZEEG6rLO!P z&)36CDhy0s8JgiIZr@vyRLSh>J$K@GwEXCOiHB1QG%bTKo;s%}dSuhKq{NEg@atz6 zr#$%wcO2Qd-rD-o>D5=xyV5sp-n1dxI&kv(XCJ=Rn6+W!#sdd5L)UM9`j-!#>DwOP zn^dkHxcbhY{^dPM;$sg#wv@J*L?be zKmGodCC#>H9(m$miF)PcU;g;+slLqhzj{0_N7MDz8-MxdmwM@Y?tW-vE+e{h^W#5! zIM!CV^B2E>Gc6@2yEo$%cD>_FQ>r=69d}`Qy{!+MN&l=m+icfa>=x?=3|Z{B~o)mHudKi>7-`*YPD6BjSOxzr)ec<{U5yL&$+*mdHK_ioO% z)b9WJ4<0|#3bMVT`=Z+s=ZL?);`&C?>xp!&0w{Q6Dg$uom zjrVS+NYzR%Qx!V>(I>OUZNK-v``Mms`IjYumlsa5c$Jj&sn8M>}hgO^vP zgNS+Nh^ckuwbHPaSz`$fdYij@2F(U-RlUHe6P3xD>_UpXqfHc^ih3Fcn^@1~illip z0%_-1uiqupaw#eSwGf#f%uQ3xP6;Dr^A5gFE4R6HrjCVvW+fuP2Xx6B68Sw|snO+{ zzqZsRqvRDmfA{?dWz8$^{{BqY!n>b$?)}a$A4`?GEmp0*XLY#SVKH-A5`!W?smwm? zWY(A4=FTrli?fps>`FfH&>m6K#kb#mdpRVnKCt=OM<3l@-89-UI5ajhDiU;G|M;^% zzBuHUF^+7?t;;{UCqv>GKJ~&}i$}=daFX(K#d@tVpx66Gdpv%>r1;?-*=0&Wtu5N! z8ECT^oZeP@MZweeZb?5@WuCkK;X9{}k91GUQx80RKa|Gd4NbiL#>#SUsPc*R&+Ww$ z0E@l3t$StpM6W}UzwOXdo8$35e(>eDUK)t>cC~tn3zP17=J`~n#5Xv7?fUA8W}A)Q zke42}{i$Q(o`Fl(F2DK4N|!Ws(@%HC9py#OT|Iu{<<)+lvhMjkd(!GDbe(7L+{$v# zK!<^rvTyg!w8A2mxp#VOzJF}0$1hEI{@MEz<1;z7=&6&ZrlVaht)Mji{%5uyDiDWH zU3ua9D=#lNs&+iLdE-%95zp0q^3v4&)YNPvKY7DLKYspDrEzHd`0AyXr>EL&wTBZn z-M{5fkv=kb{_N>9r{;WhaZhjFv@fSz5FA}to>>?hp9)Aa_H9|ed0&cg`qF!^zHokd z#9Fcc@r}=H$*zjSVSNM615r$7D0^M#z|lgn3EPR@6QE%YPLJn+c9`%8sw zlh@vR=jv)WC@$Ue%WZoO<H8jh;J!GHqsuq*!av`<5H(Bc3U@tv&$G`|n|fylRxiD9>UeLr zi&J*^*#{nZyv{$^H+1608&?*a9kR-tt;kBh+t@fTHhuBN%V$TuW?p61_UE2`^pMgL zXz9Q5;cKs-A9M-x4nOwGUp)+^^`Jc8n+_-&iE?AW95+kEcHOYi^g zwH6&#NhUt@llvbn<{JFHXWsevqt^%3)!D~(-FMHE&lK64+ehYKym{kltASBlo4@tp z`ybd!*Xx`u$KU_x{j>cJUR~yMKl#}`&lT94M;0&L{O2310Y+|WO5D?rKNC;)4)=|Y zoqqeq3lsK+dTMdp;}1Tvt61yw53Jt!mk&-wd6d%3Z4dq8seSdX=*Yy`7v6tuxrv>X zmRFdzXTzq1`p|f5^Weole)7@~T&3CZ>z~^gx2II&@0-8)(jRV~>QJ*-)#=-xdU|(8 zIk(9d=)3&MXYbGX1$Ai$wr|;t(ShH(GaiH(?xpAjaZ;{oem2j*c4KgU#6eVR)1t!

#v{1!Z~#VGq0?)w3=DZ;7KKXCbgcYGj|NmtSl@qwHgJLnekiVlIwLQEC|r(`PKC* zXVcK!(&}`Jpth7vW#kn%aAYbSV#2J5l#y{n(qPo$5vW|wuw7hVFH%a8A*TULJ!%ED z3OIC~c9#-)oF#0xGdeIj)2LC?ljC+DPATQc!`-U`^X&t29-ESREVGzlpIBX*>Hjl+%P^fqcxy5KTnhb6o z!cwflx;n1ZVDvUeLMEdG@op-aRHW3Hu>{Iuvq$WP`br9g#uDkw&Op#-wOh?jlb+A2 zsiKKgQlls0beIsvArwjZ5-gHLy6mXet5CAB0*xs#=&dHJLaagrjm6|JA)}9k$DuKq za;eE?3j~^71`e~Lrn*692}Rl?VH12!bQ-gc#nihRgMN?O=Wr?I{CX;1t~Dd%OsBJ1 z5bfvjgp4|5+oI4LgaVby>Gn4@HF-Q5Ij5nzmd=!ltd8bLB<#@hSXCSx+ zL7x*TxauiYREAJ#a)+D4A+uQ_6=tW`izgjeyN6_F9C`y^11$_R1_DmfDmH~e=SWo+ zPbk>b9I#<=43|!$gDnUmL}Dqw*JssB__P{IJ&UKYyF-y^Bw)}A*_7HkDhun$?cR{z z>oS=Pav^B}M<7v~&31>!<8zqw3JI4^MV>4CEOLfIJ|y6hNd+uM1Dhitp&4eUF9cdi zB?2B2?(?yn#_qv<$7j+jg-jZUO;UJy&`iWD#-hOxxg(N`q*{x`Za0~<7Q}gx%t&JF zoM>=6ZALAE62($z0@lWF5W*!^Aqd8z)#G`kj3?%Z6A%^Zk?e0GaQR8>QvOZZBa z-QC(4F(Bkrs*upQkPzgv(#TA9pWTe5UFeQjCF1a4lQa%%v(c?|>Je1Fa>(9TBOie3|ax7rr}{- zoYLqC`aB+&0-?BUdJUsNC`JP2ZL!D%4J;~E z4B;~&zhNk##P1D-SU{~RW=V_&vp3MwCRvIHUo5?6vA{a`dw-^yZWiY~qskAnY23~dq zeUar}2nR!!f1OFDL~tNDYStPIb|gXLOVu`uL5ApRrOAoZYq3}>66^(0ztRZ8tNK2kQRg8WkP*UzgI_s+t>|E9v@*# zeveIWak{l4tR#cUKprz4WZsVDZ92Q#qC`L~he_iis1~PzV8G+lA^21#LM$Y)REP{j zbe6?zvcY27brP5}HlvQt)oWcYyUk=ZXr)5z9)nIVPGzu~&;t~VIKo)a8VOS~Ao^P^<+8C0fre~egA!xHs#M9bNX;CJu0znD z1m@TTGovG6bW%R{I?(A&7DQpm#Y%-lfQ4-crzPQ&2slO{90@)|P+u(65{-=oZNhXb zl~OUnwxGaBPiG zAqj&FMm(sIi3NNCmP6_c*dD`TP)P-Ro*3(6^?Flm6pRHPLS)cv^cvB42D8=e1d9>x z&L`DbkZ}=SD?~DrmBg42X;okdEDfTY9aw=39zoI&CU3IYy)KIiR2R$FmV6_t;o1si zrPgc@gkXFjseB>PcIc!FSxMwd*i5Lc*?=|KGNyo!=vliPrq62SFd0-)rA+8Fd3|1o z-7Hd3RV*n}A<`?%QlrSG&twU~6 zyWrsnT9JyarJICihE{4*`JGOcfhQHI8YEcG$nHQT`S zFdVf`j*DRw_>^9OfuZB+*>=8`E8rU3nxMidZj#y=X10!|_^hRczyjMJ-wv-@>;r6=I`MWzqzsVPU(ZQR<)> z>$FrW%K|5>TN+ThMFt7%Du*pqVREQ8Xe?Hj)MK$zjXbSTSF2|mL@tR}VwZW9ICI}F!Y1?zj6$Ul^Ekdnq83{X9*YaFzO)9ZglpicSvsDTuv25#+O1gx{UBwpR(aCqz*tQ=-* zgc`n>Bjn1Y8im>JciPM*i$W<9b0m1zrjYA2CM~$;Fq;e-XeWs#$DBxr*63}nkk_X- z$}u`nIcymh(>bHXYP92}lm$OiU<##d*k>tH2p~$=ZgE+yYQ0h;l45fi0UD+;>r5J( z!2s1Ylek}`+s4mImt zVj-<6Gdr)ef+toxnn$M=7W)G(Esvg^v?K0FAw{h3={tGxW z;5E6&j-(cpRrBS+&heSCsmcD3M@q{-cJydQP6mZ;i44xoPfpEuM$GKe!@Cb2%ulXn zn_5TD96vET+3B~`XU1*YpIBa2CG~eso}E0gFxKu>*A?u2c2{C%eWlDjuyAR4X|Xfp zG}dJ8-Laic+n%w~w4SzBJt#GRaGm_w7AgnARXLHBKKtcVcCx+pA_* z9NrthuPmpSYYL9dFTZpOyE~}rviI!V6Q5RFrVn&4onAb7Z75e`HL8@BJtEiTr(yO&Qcy?A-5%g!%9x?y{KaxRx)XzUrkIJtUlBoyFe zAKtWSPf>cgMB6gDI{xCy@=UXoRfw%;cBIjBG#)>SJb!a)uvJ~1viZ@i3GwAjNw8<^ z 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ℑ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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 0000000000000000000000000000000000000000..0ccb56ffe4b1f4c6e6f6e1bedbc6b25435c5360f GIT binary patch literal 72861 zcmdS?1z;OT^FI#X9!hto(v!9)v-JP9NZXh>vm# z=i#>Ew&wbCyKuX5yK$qq(cBnrEH{qJYPedij+@2J=H_rMTr1bc z9l*779b6~Z#jW60a))zAa7S`SaYu8xF@(Lx#zhTxVN~sxp%mCxevLYxnH|k~xJBgjlPGP6A)7a^JBfpg2k6+HW@g4jMel@?AKbSv+Kb${`KbAj% zKbb#`Ka)R)KcByd-^g#~FXOM|ui>xfZ{ly|@8Iv|@8cijAK@S8pW>h8U*KQnU*q58 z-{IfqKjJ^-zu>>-zvF-8f8qbf|0!^SAjpDO&;`HHPv|cU61EYx7lsPMg^|Lp!f0Wf zkS|OSCJR%Ay@Wy`B+L+I3KhaWLai`cm?tb0_7xh0B|?+XEVK&kLYJ^gSR))HfN+>_ zq;QOIyl|3ms&IyIws4+sp|C-?Sh!TULbzJEPPkFHMYvtKOSo5fKzLYqOn6dwMtEL$ zNqALwLwH+wPxw&yMEG3zO88dzLHJqtP549jTjWJa^oW{hhyihHaiBOv+)m69hlx9h zyNIL2v0|P$UYsOO5%&~>VzD?~+*>RctHc^{mN-{jAcn=oVnkdf?k~282Z){GO7TE( zooI=Nibse?i^qv4il>ODi)V@FiWi9M#ZBTR;^pF1;;{D=7;-lgd z;Y6G;;-Ug5-&-TEGd#EnbOwMAZc4^J877-vouc1mGY$B zr76->saOh0CDL@MQmT^nk>*Paq=nKVX|dEPbxA9vmC`C{wRE7gMp`Q!A{{LqCmk=H zB%LgsEuABsE1f5uFKv`INf%3(Nmoj@O1DY3OLs_jN_R*QJTYea;w}XA0W5O9df7KC9jg#%9ebXe7JnPe6oCoe5QQ9e1W`4 zzF6KYUm@Qm-!0!G-z(oI-!DHPKPW#WKOsLOKPx{kzaqaUzb}6ve<*(>e=L75{~-S; z|0Mq`|0e&bFojnHWw0_t*+$t`*-qJB*+I!shAKNM!<3zrU6s*Ft};>COPQtwl|rRR znW>a1pfoBGWr?y>S*A2AtCTg0rGRpna=3DYaArRPA;K_2iN?m5bHoaaQ(sh%@D z=XlQdtoLm4TPbB*VE&&{6OJa>8S^*rc##PfvbY0vYXmprd|-t@fd`M~pu=X1~3 zp6@(Ad4Bc$;rZJucx7)t?^fQez5TrdyaT<1yo0?XygPYEdh@*n-tpcE-a>DYx7Zu< z?&GcY)_B9-eZBSG<=z%=t9Olet#_UGAn!5WW4*_DkN2MKJ;!^l_dM_U-V3}Jdav+a z>AlK(wfA=K9o{>=k9r^TKJILN9)?yJ_Ti`8XnliH%LP*LKc(>S5|p>hbCc>WS*v>N)DU>Urw<>ILcs^?LON^+xq3^=9=J^;Y!`4Yb3wBei3+ zb=r;EE!yqcUE00c1KPvdW7?D2GurdoOWLd2 z8`|62d)kNEC)(%QSK7DQ58BV#Z`vQ)-#V{Lx<}V^Ll5X%>jU*6`gVGbK1|<9-$fs# zkJa<^@%kivioT~F)Qk1$`rdlEUZvOQv-G+80zIrR)+72deSf`0KS1x)SLz4q>vT&$ zR6jyLT0c%dQ9ngLT|Y}dSHD1CuW!;X(J$Ap(y!HT&~Mgn)9=*p(eKwE(jV2I(4W?y z(_hqI(O=i!(%;oT&_C8c)4$Ze(ZAP!(tp)|*Z=Y{pXgJ3s?X;$eOvhk_y+s7_3hx> z(Ko`kvu`)w7+Jo^Hut)eRaM$zWKgIzItDyZ>euT-*R7@ zufw;(x7xSXcd+je-{HQae8>7u@SW^C&3C5n9N+oAi+me>n|+u0uJm2wyWV$`?^fR( zzPo+*`5yE=;(OfpwC_#dTfVn_@B2RSed_z(_k-_8-%q~Z46pI3@rLoX@t*Oa@rm)d z@s;td@q_WR@tg67@wcD%OMZ`E^Bewve{26h{}BIn{v7`>|4#m0{G7yBdrW&ZvBE&c=io&J^n1O4m#mj6)y5&on7 z$N5k6pW;8=f0qAT{{{Z_{!RW%{FnQ$@?Yz}!GE*=HvgUed;ItNAM!uyf5QK?|2hAQ z{#X33``_}v>;J(2vHvswm;P`3-}`^^|LXtU|Ch;3(Ns*;^qHo)l{vs1Y;J4rVD4y+ zFn2b0Gsl>@W`Q};+}+&6oMsl8C1$BvW>%WjW}P|5oNq2N>&-@UskxuI+-x&D%oXNp zbFF!>d5C$qd6apqd4hSed762qd5(F$d6Bu%+-zQEUTI!qUT@xH-fG@q-fiAzK4?B- zK5jl`K5M>UzHGi`zG=Q=zHfeHerkSUerIoP#LHS>=URC)C3j=76rnAeFIAa z2L##!9f8h3S71e8WdH()1P%=x7C0erV&J5}sez4wO@WI8n*)~wE)856xF&FI;JUy~ zf%^gv1s)4L9(X$NOyGsUi-A`IuLa%;yd8MIZg@*qbMp(Fms2^7(>Wh!&Klm(T;I_# zyP{^y{*l!k^YH(pMx8Zj17~o4i?@UgT!8CmiNNm~HisAH6_!k%oSQp3Z&D~Yx}YR9 zVRWz{6dD~WEGj4}Djc658dn@Pw=OLX&2DYqzoV_bAyVAh(6v0$(&^SbfE&o=SfeiG z262PAA>20Hw%m5y_S_DZWXYCdc`UD`TAHO_$_?dqk&z+XNN%L%vkc1wb{cY} z01M;aMO0B!OJnQGlJ@%Lk+3-wKd5YPjI>7@V+_>RFD`0r>1=OpZbs8JZ0?!JUDB7~ z{KCA+p@|bGjLs`6m^iv1zc4g<(zsB`Xl&f1yrNJjSTHFsYz~gqTG~>AGVN$+k3?F^ zTN{yqQHkIVYw^nKTAB{%ij+2@G@6z)McTvW4oDts=tS!|HM@zG)wZ@aFRpJd?U>cn z(X_Z3D;pGJ1e;Nq^wp3xYx43YjmpW-Em$`yXHD*;yz!%Qa>q@Wv~Jz=I0Q5$xG8@;o<@o5W4#cAw`AhZdCN9OuUfjg4S?d;RJSNHAqiMNOq`^vC;hPi{K(+S=-G4X_4UgD&M}U=Qxi&E(3sa{Q^%8jQVXjRkf+uv>xO zp1PCYWg)gF)Y#P7+8%6=)Q3$If3I2Ay0W5vMbpxH{5Wh52zGSf&ZNGj(;@6At6$yP z)fqNNlPugZm(;6uolVV6ovR752Ddexvzj6+9qbscQ(aQuB|#KNI+~WYq(C6<9Q>w8 z$9!Y~iP8K0B#=FXpOpzo6jxa7IKTYFt;yP&n@N}tRdDm*0$Dm*7nv8R*p5) z+VL_j!Y$#J+LGFj+n;O3F+a@O16WN|So;E72JAZgEo^Rul@&*p)OR&^7DpC$Ep?hO z06%pEV-Lp~6jWn*8f!GY#KuaU-31XtDoIo=@($dt0b0{ZT zbro#}J34VdS4Y~~BOUldeJAb?k;J50Ttwn7K4?~R2V0{q<__f6aBI1B+(FiGYlO9v zHPYJoV$R}#I|Tnd%-Y4;)f$cejtiT9rq;R&@mflS4V4eWS&Fe zOhS@ETqv>Dm@Ll1@!W~lsP)_l)^6)L%i1Mu4v9h1_^63A1CxCy6iYfF9m>W$o~-09qu1r;^%&*BxG#hpVHoo$U-&+ToE4V!@|$0be8 zoso88*u;&hqm>767jYYie7%*sp4(`lvI!K=s*Savv@^22!On|9c~ z9R1H}`{~>*8>o%(YHsK5N~-2=?jCD*Ys&m+Q~9w4paf)3yw z;U1&LKWgo{o_pNdD{PK%hF)}z_cqw#08ewz62LRowDsI`Rt3AeVY7cSZFInN z|9pC+b$O(-eYLA}-zTN}fmPyiHGun=``Q|H3HJ&2Dfb!oIrjzkCHIvz-I`&QT6mR}xZj0V;e@9%p!k5A?|xTTT^2S6Hnc7uQ{UFs z92v8!0SEY)w)R#!D|(6hn{kYBUdA(liA-WLQ&3a5h09tSZ0)fq4qR2=xy+_mj$Il5 znAXLX#>lG5C2raHch)RxAFIlmXVrzxv2*PDQ6D5VsJNBj#>Cc(n$GsFhR&{boa*-4 z$TaLGrd!qcJ2RM{ne!6xYpt5v;?~yX_S|4wv8}`Awpc@4>IjEp#%8dpzNvi!>(5Q; zgJ!FP|91ZO0vm*N4rW8xHf-CuolVOl9i8>d+vYb$%_tPG#aVN$*~HrRYzLMz7tOW~ zyGCnH*o-W}v9SBtvCSyU=4GuNonxt$W7}8Pw~Rs6-W*vG8QauY-ny8EOr))~b1XHb zi0r_ohK|Hv#**m9HnlBlZHd^QJDo{=Io4_Vj%*m}=Gdfmn!S$D<@5O8ao5&`y$!vG4-db!mS^EK-i6)0Vxbmx}qOmtci4X;sEY&nuK$$*Y8~M4PZqqkQixk_N&9oY=r7p3~ zD%d`Ws|TxQHCDu0QZ;N^WSYI~#7XC{`Q1ntBI&YW(@wtArcB43JDV5NY;Lgjf6<;> z5u9C1*iyEPHO=j?)i$a!YdNsJtrn~K|7r#e3*LBK?xs6C&vctQfVHr8Yt%;8%G%fg zR;$%!9k7vguuj%xwObul=j`a1n&o!Oj=gq^JGnY+J(Y=w){%$~vby5j06WSWwV55l z4rPb2!`Tt+NNa_)(pqJ$whpw`Y-UHZV{q-HKbEx?u%pM?f6$Z~R)kxv`nHZpV~#zX za**-1NPFk%oFZIMm$tUs>*rv1fF={!-wp4zWyMW6OX^oUcHXcAGPjOd_03&qoF!0g zmq3*~vK^E}F}f(U8YY0aqxnp0>NVz*>@0RRJBOXi&SU4Z3)qG1BDS7wU>n&cb}`$` zE@79l%h=`Y3U(#Cie1gFVb`+j*!AoNb|brq-OO%bx3b&V?d%SAC%cQ?&F*3MvisQm z>;d*5dx$;E9$}BN$JpcS3HBs=iapJqVb8MX*z@cK_9A(J>+B8oCVPv$ z&E8?}viI2g>;v{8`-pwaK4G7-&)Dbe3-%@Ziha$#Vc)Xv*!S!Q_9Od={mg!0zp~%h z|Jd*B5B4Yfi~Y@WJmYy@;6+~IWnSSuyq8ybjn{b}Z}5KJLKaS7k^Z0ze zfFI9K;3x8v_{se4{1kpFzX!i3zZXA^5Aub45ns%Q_!53PKZ7sj_vUBvWqdhb!B_HC z{62g&U&Gh(b^I)THa~}-%g^KI^9%Te{31Tg@5|Toi}?m?opq3Puw_|b9bz479cCSF z9bp}59c3MD9b+A99cLYHonW14on)PConoD8oo1bGonf76on@VEonxJAooAhIU0_{k zU1Y7dHdq_2P1eQMX6q8`QtLA7a_b7~O6w}?YU>*7TI)LNdg})3M(ZZ)X6qK~R_iwF zcIyu7PU|k~ZtEWFUh6*Ve(M42LF*ywVe1j=QR^}5aq9`|N$V-=Y3mv5S?f9LdFuu1 zMe8N&W$P8|RqHkDb?Xi5P3tY|ZR;KDUF$vTed`13L+c~!W9t*^Q|mM9bL$K1OY1A^ zYwH{9TkAXPd+P`5N9!l+XX_X1SL-+Hf7b8TAJ(7NU)JBiIA9DI4@>|i0+WEr!0^Px z1I!Cd1*QShf%$+L!2H1QOeFxUAF!=}Z4InHumQjZ0viMjx9LNGZ3ApuVA}!1efkc- za)1p5wj;1%z=i`G0c8dji`F*fd~4V1>YnfE5D^0V@GE9oUSh$-^%pLuUtO+W?(t zSEAw8v36~+xVW^ow6Y>t7Op9tS>qBn5pn+>#MMPJVkFH(GO#-df>c*l*19;YL^P}i zQC(G4Wp!<+I9yd0tSzamE{~zMQ-N)|7nl_+D=iKO6RYnc!okeZl`+-5c5Thv@|wF-!Ko9?vJi;BXtLe(`WepgdNvk38a?ritCDMlLUAYq3zNgt-7uvTvQgs znrmvYtwrG=j?KCALNU3YO2zWJ7po}>R)m9PIEpLls*6Hl0aI*VbPWor*4zaChAeF2(9{@8a&QI3vcaOl1aFxbb3X&Iuxz1x{m6r3f9Kv+j&%S zc(;<3wKGE1woIM!C1t_sG0rZe5(61-Fq&Ie)9Ejc=GyAgswAQfM6_)ZQLwBwR9!*L zPp_`5t8!VtI2~o>Z0u>5@=~JQrWefegaL2`5$@azVO6NQytIZ!GYX!>@4{bArE-!= z6^E+ID(9AmDr&=Jl|}ZLcB!u;>YaL{uBxo5#lch*!ip-UyJc>qGDDKelvd#Q!SRqJ zl3RMGOA^TKM7MoPJQ7Ekdc>{!E~4E!iMANKEkOz1OB92XC|vFm2h0ORHX@0vJXlm& zGbfxNt=eGq^iXVcKHL+zW@c#>j(NNBE{l&5*>*|DMU_=^!&NhaH8_xIjJc#w66x?H zQu})s(pHA{Ty{%5LnQ{KC{a^8w=AYQo+qkdNmNc#5U@BjtCXf}u)MTvt_%AT6-XYF zHKD4Yt(}rMew7GECLxzr&8VyhRid_u53^*!z2TtGjI_5znsd;k?P`v!U5kB-(>Poa zERXU1HW6;iQWK((t7CofUOLE{+RB)SKP1BKdx7k>9(+Qy16f&9%l@|JDXgm~Mh?p= zNyECL`kaVH#EFXMmX#Kwk}1d0Ra%H@ymoH)b>=H7vO|v|b=B20CA%^4EfH^*K#cl5 zs>5jLR3%KrABc2hoD`RknW*rJOKWhYpIZ|yN5x)-T}~p7>4%@G&{heB@cYVeRcWjf zej|cWaROX%YC_esLfF49C#4moxVi)@io>W2iD-6;(~va6vrB7d(Ari}9IP%5V^3A1 zu@Do6;Gr`8<7H3<%m`P8Yv)$QU^OBc94Em>MHl(Rl|nFxZ0k5#Wi^f&TQj?D2oOcW z=yF!4vf?C|t%)dMbj56h@?Z_hI*gW7sHipxcOVr>kPY^i-E?fM+v&m(qS-#q-ONy^ z3eAMlS+tIY=Fo~3quq{ZhsJ5K!DuFs?hMz2$SSlK-WYjKH|V(Du=_C_LX+1O!7!pt z5P{2Tk_dJpq6C50V1uL5Ojy5#UAnPZSCMuEjp~LvJ6K&o7FRd`A1%C6bb{TUAzCQ;TDvil((=Sl5JV zae~E6CLu@#hb9(`$);-NbOK3|PjL^HN~%#4&91DT*-hyQ(}{FQB66H15{k?E-b6Ph zHJvk`u&Ggt1+CGfaaB%bhxJmnuC}TUrzeS45?qplwL!Pc0xB~yv5cz#Vq1vH zGE!OzW|9!5LW7bE*#=4Cx-Bdws^Ljg_GqH63!|3qDceYo22|A*mf;2@4KK^6%+86m zkZFSB(;jthJ)sKRFyNn~ODzam@B2L5IdZ-U#gJ~tv59>zntYvdk7C4X!?9i=1 zb!c8n;&ntkwHtA0j=hgV)sHF%H_f>GC$t3jw}rSlw-s~3YHFoIitY%rLpqd@y7z=F z`!r%Y!f7==Vd>1N#XBimB|BQ7HiWt@NgEuUir6L#me4|LYe07l9Y@52STeFrJOg(~ zF4c)dH82%bb!lukohBeT5?5YF4yN$k(}O(INHjkzMv24n!1vNm1cdftdpv$nTsY(xr@AsXovRBhutAD zGhDcY$b&(;!ObZvn^m5J7rJeDVc4FNKW1Fc=p6eD0pEf|+U@(=wQK48rv!~CGNFoW z8#!282EZJhng4`6C*ZxDyycC!>5N7Qb@`>kM zWg$9Qpd(F^1DX2Oc%+lK7~V`Z?3rZ^q}$Qb#k0s@!r_B(8)21Zi4`+b?6We57dJGxX4(6vA{Xi&f|{8nRE$Ggs}xn@3=d9^9;~^*_istlODk|Q zfF@?Jn$8&$4SpB)p)KLp>1O*#3DwqgwChm4R?enVazRFBK<6NH+d1uAKWa9M4o3-B}nOw9s-G)Hv^S0DTECcz$lj*#}s5(x(j9u}12 zv2r0E#>FlHgck`cTZL9xRa;tKI?p+#E+b*Nt$c;xCS}Q+tsn8wJEj(2-x8*3XH?@! zK~1oP1V*RIu@UhW!DXvu-SdFdqxW5coRVcb>nf@%@wBq6va%}1+Xn=cMgx@9w=C_d zUy27;G#-lZsv=xk6RyKe*z^iKW1$aR*?&w>yZ6phGE{WL2W!g1GedK6cU0`+eAY+X zl5vW{bdX<1YQsJ7aDl!gpfm$D4&+=06wR5_JJ>e_Ha?TqC4kunFYa-p@O{P*wyaUD zpm1vD;wlr{#QsDO6Efj~AWAFjEeLK$5|4I%C5()_Jlao1RaLl%7KL!;CG7WpC#Z>; zvXcN+jazKDoBkq@qD(>J=UeVN)ctr%WCWOI;f?n@2`S2zZ6Eb$p(qko8ikS)3)gU5 z8>(Vk8BrmWG>c!W##7`ig2+vLj_)TH$PA!X%8qmzD>9}n|EsAWS{Y{6YDftSKNw#CucHjoC%rO z&$wPkN1r%=U^1Rji6GNs7=sC8TqdkU@8%NsWa73|I-?;LEnQVshezFYHAyHt5X!Vn zc%VTa7cc#Ydza*M8F5EK%ShWr(RxCR$cmw;VC|b+JQsAwQf#2_Ola9Et*Rhi*`kH+ zoR_#gzFSsMcsPdlMnzS1wEHJDN;kkR)EI(FW0fV(>zWz(AOZDFUF_~a%q4&{yQO3R z#~6#A>bp1L&H+Wj#3&%ldA*MWe6HBm-r5ksccpaE9PPmP@nOQb9@_Y|VXUM8EMp4s*7bd`;VNmK=$Jfpb~Dw-Lt!RrY;PbVwM-bBR^cPGR&hEfW|617XK9obcKs_9{Z$gCNuNPzp%YGsTteD_(IL0aRqtN=MDu?X(w@(sDdpF2Wm| zU~MJsmr%lZ{#F}5ITDMqm*9kgaBXEcKQCN}z}VX4Qxma-5T|F!ZH!U-xj|3RQUXmg zNK?oV=Ll|#aEPJ~N9)6W>`_};R2iE&WrUf=?oWYPS}_A}8fkA_W{)Nu^0ARqNpNME zv^zEy?Xzp#XXCREdzhEhmEp|<-jo&1M21~!RIDcCG{!^3GPL1#A+lc8~} z*H%)~V~~povhW{pTM?Q~dwN&())QV$R(R!gWwoU^9C3f`-dxz-DFLQg!s3A4GzpsCXt0EXg|5jg?nh90 znKa(L@GD9(7M4@_?D}^`X)*e0#G2P*fo>znZ1p6*oj^MemjS$8rt?YCM9#Td;xagzQxXnwvBI85zdAe&y->#dNo0&F+fvr6;-hKXrekc zkk=ASb`v9dNa&7OeDM%J(-jXUyo}UB!Z52rixStW$~wH2b(gK43&9}-oyM|AZgDMI z^0m=5fF6n9#B+sd+fmV>iHCGG;ZSvTWpzxlhf_VXG8x{~-_d$pw%w6wANSK+9{aIa zk2;Q`Ix^P9P942-d@P}5w?vW*9DB&#(b2MwXFV0QC9VQGAuA4Ty8~bD;2j4Ju425m zN>*nlZwXp_ZNQhYb+whT9y*QC(wrtHkAx_1Gb```95ymI9iMf$tvqu}kZhCG?PwS2 z974)&KGs#(NM*so*b$<5KEY(9ren$`3PUf)%F%X+Y5a?}m?L~DS{Kt08@E_Q_8VcG zc&>;x6H=NJv3R#7=mtC%8#kxt4T^Xffn{WC#suZ4)C8^X_F-%|TuGp5E;`~Ib^|S~ za2{}1mXzQFj>-~Libd7#>9=?d!R}t#f{wjQF!X`r*@Cxbb4m;G&MbO`HaaKvuDP@j zug&n?I6gNCSHxcwiPsa(AQ325yBW$*AZzSjlT9xEs@5xYtf1+q=Pm4{RPHw*epJ7O})r=lN6s6pTd_Ij;j-T zF_F7%chA3#;?v?YE$;uyAwr$S z8^m|HDbA1BB@{42`~ZFA#1Da0gu&upmIR*)EL_wiIBC9$p@CiOXW>{(mQ%LbmzxLMFPRHrJ7DF}=Ij~xc zjKCHFoBy)-jrgtjo%lW0^n>^#cfR-)cZ~Qm8-gzl8lzsqy}8HEC+E9pjD}fl_3ilc z{03sGrIUQe=U^be=0^M!SRK{`Y@vl-^D(Dw@i*~*$C6j4mEXJ`#uW zkDEcx+kZ1X~33*0LDQ5SrU!mxWw z>Msqzmn`TT9P{K(3fqw^!VS_u8vL1(J2ecJP^`l;s9}S&4WVa3>W$4MX$NVj>oqH( zLsh-g&dt&YbeolSlF+GYF|deBuS>g1qZ7Shr7;rvS2X}@oQo_vBWc*QV{T3Mp_K}x ziAkjgK7QqUT;LE1|~zpN%;`)!a4CG^bNA6WB3 zJ2FL8Yey6L4B_J#hlM`kHSD+-H+WmOO#`G-sf_UVmSzG&FWi<5Qn^$CtQFX~bAuEk zqXoT2lS4U3HPUPhZf_mNt2XY9T{aWnELeUTy;TAgvMz%2{Z2cDJclO`T($a5_=1=+$G&Z8j4kKuDL8h6HvT2?0Izq$|iOSo+_Dc<3Q{w@tcqwRD3u zX_It~bgguqgdv+w0CpmMzbnfR^MKaA$QuV@hL!L;S3a7u(`Rkqoa$0t&Hea$n_mhE`>hzM_=^h=C7Wd zzb1eD1dMkzDR1&R&n#!D#wWdwsS=gFqpDm6$2cR39=2h#9m_;|fSg~^3OS3ckpC;G zJ2Pgp^eCy8$AF!Ko)2+rW5W2{sId|6ou{PdQYpjdQ5n7n>^xG2*Ep#8(krw^zY6Sp zxA*|*4e5hS71oE+N7BdAC-|pb!d3VJU>5?r9N0$tFDk67a7Br!2q&~fqKf!R`da$N zQ4yB{TMz6a(h*x6rbYV6@^6%WmVS|b1%^{?6R^#$y7+|D#m0qB_>!<4?xn%~?r-|; z;;6D|Zdx1?)6P4I&vG$Zv2kH_PMDAd+)sbRxeI*v&4zE{~Td zC7L#@THf74WBI0G(~hvs7%on_ryT4?T12F`44c+=QL@P+PnRn&_Juq{E|vF|XUb)A zIk4M+-45&yV0Qw$3)tP87I}*_@mXDH;mXDE-m5&4VG_YrYJqPRsU@yC6 zPjt(=ADl{4=1>_8q9=hpn`}6_G-q2=Hxi9}oWdue4KnI` z#C#FhOSm|Z-4JO(AFXJ#FTC~NZ(jUExA3J7JE*3qXndSqCErBj>}vTM`C9op`Fi;V z8K*cdQLh1e9oQSd-URj*u(vP4P&31Eg5M_JF5e;FNz2-4G=bj%_AapZfqmd?zhaXo zHgswlDEMc5n?g}SQ&3^N!j9O1g{IL9p{3t5qW4L4F$K=N` zbY~fMQs*)ZQ)pXQMXg;eofz@ejW=N`z}~a>yz-OsQ}~6=m_2Tv=B6b4ZgS7dk09{* zG7i8Gof0p|FH$@?H#VYMbff%|{4(u|dw!Jw7#|9+$!}o*B>8pu4H^6VV_=^E`*frH zHg!C(&+HyY+Y$wV6S!f2I#I>Q9~6nsj{1XR5x=TkhOq}5E8F+!igZOB(UE8=8f9fm z^J;r+JN_&7X-rF}$@i{^W4b!dKe`c2vEw(U`1DD8}H-$ZE7syOFtLB&vrZa zCQ>D6Uzf<8nZMeHh_rTZmVYNL@&~Z*-7o*f4-^jA4|rhZL?|i7`JS_T&V=2^73@B~ zAg8K4$w18;KRK!lV6SWP{scAL3C+wx)Rr@XweuPk>Y0*AULsC64x|ZVq)~p zq)nEey_k$Eh%P3|aAgGW%vns7k;=|Ef1?pdac*wJPj*RKRgiv^LvQz|GM2h;9Pnba zKb3sc;YxurUYP*A1iT8o&+RB(nXF7j6G_=!nF72FJOjS#D^aTK4ZH@t9yT#5Wb5*OC;p)AY}C|H9%<>Ku%%;`@3SP%cBN9?jfoni z7I*{rZCs)O%4}sJ2Ax&rD07v0%6w%3@P6P;-~+(-1AeQEl|@Qe*;lDoFcR_Bzz+g` zFz`e02OJ)a(PLFtS$51{f^nbAQTO1R^|>8gi<|60Q`?FCzo26oo_$BZbEKZH?1wA8 zvOnQfgga4 zpxusQJ3jtL+u$DkYcDLyT4f#T9Sj>;i^t}!S?Bh`M&%&oU|L>!BS?LdflKX3GEbbX z;h1G3bC#eM$Z2Wq%vpkqVxv1#4n?(yv}KW1O&Cfur?nm9*tt&{@fX`(-lxf?##wh% zY}Vl~$I>tHp?89ElDnxhXX$%Imq^~X{R-ID|xkYT~f*Gl^cK` z3H;7Z#j$YLNfj@msUF`)yUiG&+@?Hejk;X9UAaTKQ@KmITe(NMSGiBQUwHud-GE1B zH5&Laz>ftU)l@FnLe$$4eg6)dQW=Z=5Yo zwD!WtGCUJ(ZC~JoWv^*i7Fmv$HCsEsR(G{vEO4A#w%;SZ#xASx=p;L&If7Ni0~9;O z3h^4N(JqMb$I)~|y@2NqizgN2jxNXzO&ncVkdH|MCQl6J z1;>w{Fkw9*NYTV`qYK8D6pt>PJPv^;7nDpW8do@O+$0JV z?X=D#M3I6ikV;A>78d7YHiij#!Q#;c#fAB!3nxx2939Hd&(9AQ7fl#n7(ygRz#flB zMSbK!^@5L*FXvfk4l`01HI48~Q^ zgG=g+m)IcBww~>9UBN)d(%qgM&rszzR4);Gk6+tf--0<6n%X+&;_fH1ied#=92y~| zz?TER2R6hr+%v+nlV_y-p&fwO-f$2Z1;NIZGP--APn=y3@MXa7jZN|F;@Q=+8{IKC zA}R1Q3!`_5p3$B$3uCqw;cUc@#&T0;VO)3o&0dc@xt=_{tBzH-!IRHTN&LW}8t<8a zmky|;6K0Sr&yAjmo=LQ5_40k{H7nkCQ#^ab1y6k!|0?Jy>g}uP9yETgG5dRFcuGBc zduDpdJmsDWPo<~IvyZ3RQ{$=i)OlukW_#v%=6dFN=6ldQ+6VX=;Ol^&4g6f-=L5eG zcr=bsY7M|gfL{uH6Y%>3za02h;12-41NbiBR|3D9>RRLpd-nCzdlq{dJdK`+XNhO2 zXPKwTv!7>wPqSyar^VCiY4aT5X$O7{@P`6_1n|cIe**9)1CRDSu8QXZkE`Bh;4cUM zD&VgL{s!Q02L5*7?*{&U;2#G5F_b`bigZP%NVUabUo$jXJofX+dRpPPJSet%MBCai zmJA2yu%pL`ZIp+#Q6BKV-sQm#-O%vQc%b#wj`rNtkQA6Z>3};fi9@4Y%!+eyBpp`Q z{xdG3l4xsRjO>hUj2~A=8-Gl++BxxR?e~TM!D(~6ttUq-ofoh4bZYCOf7aICBwkuL z9YYL{SsrKLtSAEu;tZTe3@rF>7-(2g-#(@xUj2p9>KDbUx8L&pN1@=OBMx7Q;016Z zADg3m>>KC9j{NXn&OVxtW0u8baaELu#c>|4qptW@2VnO~Z;V#j7_ZcR85hpF|DAU` zk+2h=-;TPUn`+kE_gM)e@Qx@4OX3{ZkrMu+5!k)@`=iz4GVSWThe_(ovKBzXr0YEy zK}_ehIVUoSgYdB^EBnP+d5T!6{Aa906<;Vgz05v;NEmX@Mr&-2*Jy_uX#8h2CP*Ts z!pD=4j>Lw)5@n+$&c++m@O}RqHd0CA?I;UvaTeYu7XGi!4B~3wqbMisaZYT1|Np2@ z$}yWr{Aeo9#+OkxI^%47`yUL(1V!*ew8j zYD}00UKXwWz*y~Gi3G6EKdU`D|4H*Z+Q(jWoc)y7*Ut_227tGK$2U)C)*kZz@OjK}xu^c}e8a*ux#RP4@gYfWLBWJ|^VZ;<^o zTj8|-MBwoa6rMfV?LYUz`-VR^hu&S}=jJBxSm&MBE7W}N0tf08;G>VHh{tn}zxMSP z98u;^o}7Ty;9b@$R+D!>2kUg;@hMJ>tq<C#x+Qn~ggk6?BDCc_yjM1l@E(cKM+1Kz@aNmm z7f_Se?@@f+Y8sgN1(d09QvUdL^Vj4~95;d9aV27(=sk_tKFNEs_Z07`z+VLXdf+zz zzj2fIbnh9C2sQzKu_J>2hm-B-bBbmzoSjPa>%E(MmCq&KOHn?!-@OEQd?bZ4;xdxY z1y_0IZH!~hU6VU*JPzQ*F?+2SZ_;}ivp0KhaU^pE@K-vLu?O0V4a1@wj-Qw~Xz%tu z&@0x1-iI8ltAW2Jj&;G$hp+oS%Hf0w34``Y?{mFkJ&%u}>GdFg9q{Pr!QJi|3lXwDDcr*eCGp3#ZUwiQ;*ZUpt z$l9%h#ouO6fQyb^ca4LUSCF@E&YHYQI6f0Q;TP{8y)yWx_b+a^iuady0Dq?qdKY!V zd86Q6p94B>(s%^Tot&(VRaw<~166g^hoE?ubr10PItMwuk3cVa^0|Y@&0CX)^AsoO zWJH}jAuowlwZA%~SJZ9PZ4q^Q;PIILK^yfULcL(kXc)L)O@4trEhmr5MdevAemv^v z1R1Eq)m?f8-c{Yr>7+-1cb*8@%JaOzgHP0>orEemwh*a#>cn2LCaIH=$tl1;4*U}~ zlTX_6d||`$!xy0Pn2Zh1Etr^xOy=k2cav#QEyfqaYN1*L{L{ccyFm@9CBQ!i!fi1F zPA!dE6VJq~3ALQ8iN*hlHPIA3P{JpO_Q6upQ^Xh(%z3wG&9-8X*#@Y!>Rc3yTBpuZ zXRC97e;)W3fPWGAmo};M)cNWH6%XrP2L4^(-vi;+|G!N>79R+W>JmKNRPo&LmGvqf zJ-&+Pym&Eadmzx3EHO8xx<5WPQkzvgn0yWRw_OljZBsk&Zc9Bt#WTm(fq!Fz+Nt7+ z<(t62)n|sx6xqqtwd%n=@W94hS<+1@YbHLW}~^)aJNiPCe1rVGWBS-R6SNb4)_l-Ga2w70gvyS{^22Fw}Z@-<8G`y&yV={u?4Q!2B;^i zr{issdWw3giu&ba;6DNW(~asG>X|AU2%iD}Iq+XZ^ODVS^3&l9s$N^|o`us>iC&3j zldX*$x+1!WM1(8-mvOc>saN1LP4!}RvwDeosd|};tL9h0e+~RMz<&!os_*YNbC!CQ zou+JW^*U=8;D2xul>v`Wa}rtXCG}Ury~h9RL}i)eRdb}ZS-m~}rboStvX(ud-mTuF z-mBiH-mgBOKBzvVKCC{XKB_*ZKCV8YKB+#XKCM2ZKC3>bKCix@zNo&WzO25YzN)^a zzOKHZzNx;YzOBBazN@~czOR0ueyDz=eyo0?eyV<^ey)C@eyM(?eyx6^eye_`ey{$Z z{;2+>{;d9@{;K|_{!jf~{X_jz{Y(8@<20u6nxKiAq{*71c{H!4YMQ2NKF!elnyCe} ze%e;r)>?mUfHqJYqz%@FXxnJpYTIesYddH;+E8srZJ0J(8=>u_jnsD5cF}g#cGE^_ zqqQ;GSZ$n^tL16=T7foRo1jh9CTWwk-L)y&RBaD!Pi-%4nikXwwIZ!p3uz_VbZv%K zs_m`K)XKDStwO8Rs)K+P$wF9*^+FEU$c93?khMT~j zfd3izUx5D=_}_s4AMn2e{|E4Y0{<8Ae}lk*z(C+Z5I_(?kU)?@P(bj2-~~YiK?6Yt z!3Tl?f*%AEga8QrK-da|twHDy!T=Bkf-ne#!5|C)VH*&(1z|f7wg+Jc5OP2m3c`*c z3TVKfM1Ko|?cI1q9{$O9oCgaQ!8gD?Svi6Be@ zVKNB2gD?ezsUYkD!k!@P1;R8Cf*=%vPy|9T2q6$kK$s4~3=m2|*c*hIAe4bn4nhS8 zl^|4sun!2;Ak=_R3ql)!W2ZFE$ zgtZ{71K}VL4hF#j0YEqeghN3%41~i$I0A$tK{yJ8qd_`*tSF%xT(HRL{SaIZd-;ZfBi2O}l}Z*z(M2njJKI1nVsq8pgmXt#v{K zxla9>9UFUSuSMud78W9BXomOBnjQ0cOR}wL_Qg#$+14~Wc6A@w*0hI6WSL}J)9ldF zy-_A67t@{~%;d~g@eFPW+14~WEOfTn)-*c=bf($XH2cyeyKHOPE7X9#v#n`%sOHpk zNdmEBFlUx+O|ye5r^~jceL&pxnQcw`n8>oqwx-#aA<4)ovaM-$Xya^BsA+cm;=WR- zX?BR>EK;axKlL1F@l;3{chk*Cru|BUS*B3aes|DQXGTj%tEJiZ7@4F{)9v8E+w_td zEg^-PZb$yjEQOk`5T6Mdo>HYy)9qNj2}!Q{PNAmz2sa_MShPsW6l%I1X*Z)3YWh}A zXT(yzQBY-!ah5iPnr=tRO_M@Rx5MCWNeVUH4uPA{P7F)fYYH`ehi*bimjFw*1KB2| z38RQs-BPIOBM30N6l%I1k2Y-zHGMaNO~~kljY^S1O}Asnrc0rw+d*OzMwb&%C^?0f zZbyAh7+tZ{3caRK(J(~vDUl_xnLdS@ZbvFj=*DO~pl&JDbUOlRLTl2b zP}A+0qT45?bfP$^DO0HFb;NB}Db(~iR3s^>R+2|Qrp@|KS4bK!Q)O0)aW)e%WC|BK5sOd|IrM^?B>2}1-ElZ)MFQ+=PNTH_Nu`qk7 z3?-T})N<53)jQHu=JZB#sBYbkY?;*CX;P@^_N&Y6QmE;6gvu;asObk&JNinYrrQxE zvq_<*A5OSQ4d^q4nr_E>%r=FZek|3LGzxo5p{CnUDZ3}`>LZ1kZbxLyDutSEhh5A( zg_?e*GnkT7ySa%3oWS8pY29=?hGK>()O0&i;=hqXO}7Ijc1PNh6l%KtzOs8yV35b^ zSQdev$vpMVB&Hp@r7&|=*&Zp>^vhBa_mVO}~ja z%`AnQZa<66DutSU2f=5WLQTKB59*{8YPuckFD2^~|1c?qnr;X6%Q%Ia{s=LWCh~Z8 zDb)1G2`)`2<&<#I!=KbC)bytaGEFeqJ|I)2P}86NhnOi+sOc{d=6{(&O@EncNE3WL zr6f|PP}5%{tTd5DQ)0!;l-^RP>2DHjnsBixVcpa6_>g6JXMZYk9CuL&Sc(BmEe(=j@AsuXJa zcZ8HC4sS}NUQ(#(KN47){4puPy5~I8?Z>Fus>NP&p6UN1rm|IwX>*?Ge-h-skn_yP z5m1^bo1AndUCuL~Kv4fY=b2CLqix+->NQQ7&r3jQMphiiiSV2*=b29@urzV^Q-USs zJoEW8hM>t(lp^PuuOC5VoS`XY&NE+s!pOMGqsw#3oM*m41oaPdp82*RkTl69;*uq? z^qup}w><%-St*kN-ODG+xzHo$nQtgzrBNs;vAX9x^9?7IG^<%klnip7`9@|XJGA{V z2SK`=XTDvt227vx%r`o#re~h>%r}mJ(}cK>%hZ|OiTxbUdFIO}n2cvsB1kOfnQsDN zY-!Fj-()JC(GW|M^UODuP}1aZh>L?}5uTnzQ_9hgJrb7r_9C>5v|SXfCq!XZ3`GUo zTh23Ih|scCS}Aj$`DSDVl`iL*Zze&dF{6@&-ZST!uYv&5Y;TeQX#Tp1Jt>(;SzR%H zU~l4`aO-rb>)VGg(_|)z2MEC@ep{aN%vVeG{F^z?e6tBLjiHnx;Xxlc&wTR;GEEPq zfK1AH=37Vr+2-*GzE#Mb0x{Dl!WcKKp^UT*ySZQ>03M@B2SO%y(+`Ep~>Vo2IKr&NJT`1ewMFO~F-)oM*nX2`0OV zkuK+%?>xfGNG&7`vy5_{`7R{rG?qnji?=xEnQsHt^WWw?^Ic4JWUPz($a&_wl+dzU zBKyjD=DQ**4sHG3d(Jc8)mwtrTh24zb%d7Y_%C@RM0rb<^UQbSmLQ=ajM<)|NxP%B z#lBkzDZBZYBIlX!c7n-BO~;f?FFDVAcWp68i8;@F_inL>y5&6cJwQllPQ>EfmY^GY z$$92`n7}f!HDiKuRBD3Ocl*$N!0LO9K+_!0$2sfnje+A*eI1j%YJi0Nl zL)fA0Fm^aQf*onCuvS{Dtku?m)|$|o>=LyaAcVa9M{gt3z`(%9M9 z#n{!@%@}2jHpUoZjd4bMa4m8#nYmIfr zLB_#`Wq@&raj0>aakz1WainpSakO!aajbEialCPYaiVdOak6oWajJ2eak_Daai(#W zakg=eajtQmalUbZaiMXMvEJBVY&13*7aN<6ON>j6%Z$s7D~v0RtBk9SYm94+>x}D- z8;l!`n~a-{TZ~(c+lcpQW$KzI^_r$Bfbgl9l_7KG^mq2(K1T6I`2(N+gItXuo@Foavf$%m6?||?w2sqH+2jK${J_O+-5IzRs z6A(TH;WH3E2jL44z69Yb5WWWC8xXz)0SEK8xXezaXS#V2XO}wb3hyl;*KB=193QrBS72<#E~HG4B{>z z?h4{=AdUiYG>BtB#898(K+FX(55#;B3qTwX;sg*Uf;b7p$sq0y;uH|4g185WdxE$Z zh|@p}f>;P*5s1YghCnO;IOJ|I?uSOa1$h;<;& z0&zBob3mL6;ye)NgSY_1g&-~hF%06qAl8Gp7{mq;8$pbKxCF$dAT9&33B>(C+#ked z5SN440%9wOZ6F>1VmpW(Aa;V-1>y=2SAw_-#MK}k2;v$L*MhhX#DhRQ7(@$10PzqI z4+Zfs5Dy3O2oR41@hA|F2JsjWj|K5K5RV7(1Q1UI@gxvWjxN;3>!jl|^ae8CBI2~( zK*qa7(uX&Y@c|KK;ooC?Oa(IV?=e0j!W51>c!QVVxMO_T3t6&%kMRwWW#!*vd{0F( z^Y1Z!BH9f6dyHR+FkAl~xSI6%o>Milr@tagK8($s&R#c)7UmgDdBI?Zp zXL@yIo$K%5ADoUd(KW@tEm3CRtK;8+2($Io@$X2bGWFH*k09#oe0BUgQ<>C0I7uSe zt#`U4fs7%#%zSnHxkQ`JSI1vK6v-Yn^ace_Ywf3x?ogXZWLf#@_;>G#oWfVfzXy?R z$BHpSN$YBiQQEn7ZBb>_+;G*5pnbOycarf>BhqZ#di+IHqA#}|e+f}#;nw3Xr2@%g zGX6Y2!L7$%Mub_q_4q3t^gi8s{MAI5iCd4qE*)foTaSMZ5oYGr+WP$@m25vq6{iskHw;um;BG?kQ9)BB^ zOlW61w;q2-H{x_|J^mF$oZz~W!mY=@nrO0f>+!FpGHKm<{09?Bfek~wmWm|E1~0q2yY=`_Aesbkl{9WW{*#F|!CwX& zTwPaD6|9|+Dp$Dwv~JLGz0t$1$A2c#CWydgHPNlde-05P2t2i0kN^B`Y^HbX@n6&p zmCozvZE><&m473VB?u~wTaSOULtBLzkm@n(7Tz=W>el1GjA*lR>+xSnMUosn5*&3x zb1+qXO=)F?yPjP`)Jfh83DnN}2bc7EBHaSF9{){LFk`nK|E)b(>dmdke+QBF?bhSJ zo9KG+v~lJWHZ|^VlQgdGqq14J_4pr5Q(00q#rV1e{S2`;+%rD^BWWsgdL!Ab$NxAL zNb2o0Zaw~|h&stDhD;0^&j^m*53@ow;Ta`0;o@Lz(CzkTsZ5q`J^mM{P+x96{+Ed= z8@C?+Ydsp!r(2KzO)8VETaW)8DwQ-bdUNaXzfYvyok{v|>+yd?g|c$%@qbE1GI#6o ze?j!aSjKKW{;#P(hHgFn?})g&GY-BIq?b3S`a?x^)io4Jq$ci36RxQ%be`B%R+oli zgZ{@d!J<J?377n&!1* z5Ak+$>oE%nAkDpg4*S#dS*Fx_b$k6AZx@1_Dd-QY|G|l9!OVBx4Agd#SvH z%qD`!*ry?-myp>^7#VkYbhS_EC1kb|)IanRGTR9x&2!ASWJxT2dkL9c1ej*wO$LlM z(6*0ycnO)S2rG?3Nr~0nOUPV9C}|eQlqeZ^37H3FCA+@8giOd9Fuj+Md019W&)iGM zJd%LZJPM1;)S2Ch{T%laGLIpcjAv9LNX$#fJf1MN)Jw=biArZQ#L{>PnWqv;npcl; zanLNn^OAI4LgpESmXWrLqV@0+GSAM6p{QVc^Aa-8BeZOlR!T1+^TMp4(s>D)8we_m zRhBIDo?b%c#RQOMx0DQ!k(ZEpDPg90%lj{R37J<=J^!Ycka;yBrZJRKJQ3`}OUS&A zAk*|v3dkfcA@fE8$oBPn?8$ptFCp`m>?N4qOUS&P5HotYneYs>4=*9}E&@$6NK?qL zFE1hUUcyXc_ou*2<0WK1Kyd$smyr1|A*V4WQZVYgh3)AjWIje%X>@c7EZ3u_rdA!n;xU!k(@V(w zgs{_CBXP;aMtV0dA@lR>TkH(KUcH3OuLv@Y0h)rV6kbB+w*-^j#7O5QWd1;S8L5SY zVV04Xkohw~r?D)OTfD_yLgsH&&wuMBWd1>QWUPz(@DeirCbaC9$iBRU0(@2+_TeQI zkhTP^H!q=phtSfTCMJ)BG+sghZA*|+c?ks!LdtGFrtlI91PCT0H62qny?6-)w%%fn z61{{11GiX2-MoYXLkKC&iCDbb5_Cf^UP6KG2rMI8GbSiUr6y?o?p{KH90E;q(Glmc z8)#}Tq3F4AU>L#fUfR+bX__$VW=3>62{S8HU0qsizji3An~qlz;a~;&%2fx; zL$fQZXX3Mm(rUN8qo{&lb`|`8wS9M7Q`x$9P{u+r2_+yqAV^0#f;8!hNDZMwXh{fx z5IRT#DHM~?dq+BoR1pzO0wTR*L$Fuulo8Y!otZD{%sJ<~=X~e>?!DjrYb9&H>n&@o zckTVlexE!p-?jeZ3-7;$t@TZv{(nc^-&E*+Q*rperh*r+v+Lh9=>IpIaB_CDv;Nzw zdZ^(y6$bw`C;lv%`kNaj-*ia2$6{kNY0yX0i zApH$u1+|1)^T@-XJWxn+J(LFuDM5YXYY2+KBI9CsB~;(hTYs0fgYw8f8=xnlJfuh& zoxi*R>ImgwMJnk0l|0fh-bfp40v?V13;e|^<@;OTcLMJ?EIKYe1{(m0!z9FEzRPO- zV2zE%N5m6?;v!>=wRk$PgvcmtjFtrH8uDlQ z^6CQr>5>~hj)47Zae`^4O;9ux1I0pl*qJ&y|5-YJ8=b%F?_T4f5#PKHgN8$SSekk| ze*>Mru@OpyMnZXbnkG7bGo8PMSBvydcK$CXU1IQ&F}#3yb!Y!x(27?~hr~t&#e7>E z9$?|$OaHLp5k!c`%3FNrcmshDvhLr}27eDB37Yb+LZCpYP#(nR9G$`8(+Ro$}@zKgOd$vWh!Evb-7Iqq;{8%Hxx@cZTlp z4UQt9KS zk0i$NB&{O}kukRfq-74s${m#F^?yrJUW3Gwuskav#|c5WSlS-iZg~r(AAv)KA-tq? zh)3fwLAEhLL=0BLDw2S?p`@&$>hr@rB2S0ckB>Z;f7ohJQRC@z{yqga1=KY(wX}JW zeK(Jc;@zR#osh1!Rx|+!-*FvTZCPy)Pob{fUmiB-s`0+-8}NqM;CWdSN#x~6gZ{Tp zL!$tQ$Un>x=Eux57_0ru{s0Kr32Bc_!eYK39lTYze$>n@CNeUP#s}I1f`X(#@*oY6 zF6ap87|0&v3JL&)fFeQBpjc2mC>fLn$^w;w%0X428c;2$0n`L)0d;^bfd)Zipjpsu z&>heU=qcz0=oirMe0%vs`1bSIBo+D8`Hc9?`7HUY`A+gV^Lg_5@CEP@cp%s~J{Dg# zUp?PNzCJ$okLlgP_oD@w|JnZ8@NxgX(@UV$JOC>%S<9g1Py)0PTJ=3;yXpKFcv(y5 z@1gTwY=PE*XwX_{9f-z*vGVuwsQCCV(fKdaRB5Wbs|ta5!?G@pkT-uFf){C~^`L#U9e;hlOfzkT z_Cp7tSD-={rp6{Nua@;J?Ga%)i2i z|4vg%BYbBF{m}=V_})k7=h8p{5ZwQauhfP|#c2I4(eY?4bR-6=_2X`)Ws4U0wf0`fqW zzTdko020_Cuv>t4;}U=fi0}xHO$Cqwfdat-u>$b|i2_LiWPua`ssLReO`w>^W?C*# zDNrL&D^M@c#3K~#6S&J`o;}OmH>08GIJp z4(-FuUKH;Ei4IMJWIzQ=pIq1C|p!VR8~|`R8!PZ z)KxTElqAX!EfB2{tre{oZ4_-6?Gx=6lND1HGZC{Avlnv{3lobJ%Mi;I8xR{5doA`+ z?6dez@t?$Zi|-W|6c-kk6qgc*i_3`1ipz^5#VO();`d=fFcp|S>AEYyoy1b_=!y zdkNcweSm$0eTMxi5iAidaY}+DL6=CA$dF)2k>WS1dsTWc& zrCv+Dm3l9=F10E3L26s-lhiL#U!;DM`UBttb^<>EyMeucARr8Y0Vp5}hyxP9egFWZ zfdhaXAP*=4%77|x2+#nu03ARN&_01aRP9DoPHfe0WHhz4STcpwo-0?0rLKn3VP8jt}n02Yu1fKR}$z;AF6d?$Ptd@o!G4u*@s#o>~004@WUgDb$5;c9RV zxHeo5ZU8reo5IcER`6r+6L5RD6C43|gL}e#;3#+?91RbFNl4?hJb!zpk& zJRQz}XTo#f`S2omDZCb54G*+4@9VMMDT_Rm3 zeNmbtJt(~@y)L~eBO(LHNXwYW*vK50iIySBB+E3(bjWnctjIi-d453ofc6311O5ka z2k-~Z95{QR^}y_b+XwE*?ve$|LS+qQEoH4`QL-Vjp|T9weAzVuqvV+SV=t{wbz@E3V8d1?6r^2g+z_E@{RKC@}2Ut^0(#h z$bXdoLxE4>fP#vGnu5K8n}UZzltPjMS)oy(U7=H9QDH^lp28PJe#Kpi+KNVsCW;6} zA4NaKEX88QQpJA7VZ{-}7m90&8%leXM3lsojw&5jI-wM(gjWhzVkqS+6)LqV^(gf! z%`4qeT2bax7El&aR#eth)>cL+`zZS<)0A1tS<3Comy|CnUst}Xd|&yq3ZKeO6=fA| z6>>b=F1b7U)*$R_nge{h+(8XQ_8m z&q1$JuTigAZ$s}Fy)TD#4jUgfJxo5Fe)#m^$-~zV-_)1Tm(@S0kJ1m(57lqizodUz z{||#b1_A~r3=jrLgCc`!gEI#A44xaT9#J@=aYXA#^byjLG1|D*xW~BH zWQU2MiLi;CiK~g5NsdXWNx8|4$t{y5Q>dwwDcm%`G}JWAw86B^w8M16^cT}FM@^2} z96f&Y^wGSd1xF{2E*`yM2ACkFanOQb5pR)ban)kVV#X3|DQPKXiMNcgjI+FCIcRy+YNwTu)jlhKE1VVH>Vnl3 zD~>gvwScvdb+C1~b%garYmW7x_3t*jZT8xj+1T3H*%a7R+Em-TxA|!E`Iz=Gqhlt= z(vD>x%RM%I?B=oC$EA+TA6Gmcf1GlhcKpHd)#I;hEp1QQI@spfmfKd^KC^viyLLk7 zgz*W}6VwyT6PYKbPTV+g%TCk|ZYN{sV~4iG+BMsC+I8E#v)i`&bkg9Y`AN%@X(zK! z=AK+W`Q+p?do6oIdt>`VdzyW!{h49e#H- za5Q(cbR;>ZIc7N4Ikq~sIkr1qa=h($-|?%Hh|>WlIj4h8@=hvF!A_A*WT!Nz(@rd> zET<1nU!8Y2?{*e;hB-?*1I{we2F|w5!OqFf1~u zvdd+!i=d0Fi@b}Hi;9byi-wDVi=m5&i3|!QH7{M zG$5J~Er>QmC*lHvjTl8-N8Cg#Bkm&ZBc33hBVHnYaoynxc7?jaT=%=eUFBRAT$Nq* zT~V&Vu92?Mt_iM5uF0-+*K}8gYk_O2YolwkYrAWgYme(CSB~qD>#*yn>jrWUQWmL- zJcQIl>LAUK7D#8LEAL&P7t$B$j|@U$kg>=FWD+tNNkyh2GmuPV39=i>K`tWSxe2(z z+*I6-x>>kcyB%}0<&n?2y1BWb+ydRuZXs@Xw-~oLw?wxrw_>+aw+gqjZoO`OZfv(f zw_&$&w<)(-w-;`|x~seExSP3KxLdm)ceitQaQAdic4xU~x#zg&yH~hZdHm!d;vwcC z?IG(S@1f+O>Y?kQ?_ua+;$i0D?LqU%_2}~$@|f|M^|kSEv^>PhxY_dM;% z^33*Z^z8QR@f`5vcn*19^PKXW^_=&-?s?bqzUL#)r=IJcn_eKVonE`V_Ie3{)AzpZ|aIXljTCa0n=e;g?^?F_Qy5cqBHRd(x zwdD24>xtKMug~6m-aEZ_c?)_=dP{l3y$^V+c&m9+y|cY@z015Sy=%Pdyc@mSy}P`7 zyf1n8dk=fhcrSb3^M2_4*hk;T%*VpV+UK~BzfZVNgb&dt(kI!6;zRdI^EvIq@+tHw z_Nnlx_Nn!0_v!Sx=yS>EvJb~+&}Z0Z+UJhXiqAuz$39PeUi!TDdFQk3yTg~?7wRkK zE8#2UEA1=mEAOlAtLJOrYvgO{Ywm01i}hvtp7mw>uK51qx65yjpM;;3pR}K>pS+)v zpQ@j_pNXHDpQWFTpRM0XKSw_ozW~2J*BENW>E{M8>q*q*QmFs zpHbVW&!{i{`}`&R_xsEG%lj+&tNL5`+xxrud-(hM`}+s^6aAz7ss5?{8U9TFEdN~p z0{>$FM*n92bN=W3JN&!-FZ%cS-wyxQT7$PCO1EDS6OEDNj*yc9Sa_%3iQ2pS|4 zBpaj}q#mRdq#L9kWENx@WD{f?bTTM9s50nk(2Jn8ppBr-pkIT&2K^DdBUmt4I2aNv z8mtj)6O0H(28RUWg9*Wr!7;({!KZ@B!IWTnaB*;1aAj~!a9wa?a7%D&aC>l9@O1D> z@Ov~L8iH0qo1(qY5$JSu4muxQfUZQJMR%fm(OmRZ^e}oFJ&RsI-$36(KR`c6zeK-5 zzeoRy{)*wl@MCskgfL)?2u2(uiIK(}z^G$1F?tvSj1k5RV~MfBG+>%A7cdtw{TMc8 z5Ho@q$4p_CFw2-{m{rVc%sb3F=4Z@rSP*t6b{BRpRtPJLRmU1&O|U1h2rLrof%V2x zu!YzbEE{_R`x5(W$j*?TLUxA;gb0VgLL@^{L$X4eL)t^eL+*!s#r=fajoX7$!KvZ& za0a*|I18LL&IX6TA#ol!FPtyVABV%?aZ$KfTmmi$cN)jU<>2yg1-MdN1+E&`h3m(S z;U;jixOvp_ouyXjo`O zXjEuyXhLXGXmThuG&Qs=v@*0Nv^KOMv^n%#Xj^D!=!MYU(3#Lz_#JpKUJ37w567Rz z*WoYYNActMIs792CVmP30RI^O48Ix%2{Q_d4WosnhGm82h82Vrhn0oZg*Aq?gtdmX zhYf^r!iK_z!#;-Z4Br*LH(W5>BHS_DB^(*<9-bLq7G4=%6J8sBEBs0Lv+&jM*WvHN z*9n3IF#?PrK~Nwl5mX841TBIt!HM8W@Fw^X0tj&g2BCmZL?|Yd5h@8ag!2RrVUci? zuta!7cu9Cecu)8k!5<+QArb*ZC`YJA7)Dq|_(TLnkRtLUY9eYQ8X}q_&PB9E^haEY z;6_}H7>O8ddMovUdN6tpxj=U448D$b>7G)V_9pw<^6xA5j9d$9P zFRDLkIBFzXAzCN;aP*OAqiCyWo9M>q?&yorebN2V!_gx#hhhw4Ok&JpEMn|p>|?rO zI59&p*J4Iv=3*9N6=HQ_562#fHHx*0wTW$sy%^gUI}po`9gQ82Q;gG%(~mQZGmf*4 zI~La+$BnxhHxf4%Hy^hce=uGvUN>Gp{z$w5?vF06H$p>iJZit#A}J8iF1hyr*u!5 zpRzi2?3C>(ms75%x=(RWT|G5&YV6efsl_CPB%LI^B-14GB&(!jNhgvJNp4A=Nj^!a zq*F!Z*l6*=2q#zQ8 zgd;_fVo3?4BvLXdgH%L1Luw;+korgiBo1kabd5AankQW+-6Gu~Jtn;;eIoOdcagzl z5wbX0k_?a)$jW3jvIbe3Y(%yqJChM)A2Ny@NJf)G$dTk2ay?Cw59Z?TuB*88Bdu? znN3+pSx&i^@-XE|%JY=>DW53(lwA}sMT8t`C_|nAE#M5Nb4y9?N>89zY8Kxagvq-Z}b4UwKi%yG8OGryf%S_8j z%TFsxD^2^F{!_Y0x>!1pE|V^ou8@8xT{B%L{cyTTx>Y(ZJuN*ey*Rxzy&}Cjy*0fp zy+56uKA1k7KAJv}KAnCieI@;V`or|c=}*&NWC&y^WjJQUW)x)%WL(P_%^1s=&sb!5 zGyE65E;>oI7T9a#7JS#7-@{t3>G7sk;f=xlrYK}Rg5!?dPWoDEaN<* zgVD{n$mnAXFgT1M#x=$mW0En$m}gvP++y5e++{pqJZ3y&tTJ9R-Z9o0KQp!&pBY~m zzccxm{LI}<0j4k$!W3n~nERP<<^kqGrXo{?d5EdW)L|ZG9$^|Yk1{Qo*39EfJEjBE znd!=OXL>Pxnf}ZmCWeV)hA|_UQOsCo0yBx3%%n0?nHfwbGmDwaEMOKh%b1nS8fG1{ zk=ep*WwtZBm_5u(%zh@DImjGljxr~h)66;MBJ(D5iMhhO&wRvu%6!3m#eBnu3GMi zTtqH1my*lKW#zW#Udp|k`#AS??%TXQdC)x3JncNAJd-@XJZv5=kCMm8W92pHb>?;F zE$2PSdzSY{{+@h+e4TvbeA9f-{J{L+d}e+@eo_8~{44pK{MG#R{LKPzfn zc&Bis@JkVY(XJwuBAp_=B8MXPBF`dP5vwSxsIjQMsIzFg=w{LFqIX5xMW2eH#Ztxa zVw+;eV&~$};^^Yo;^N|(;@aYo;@RT);`QRs#lMz_l}MKyC^0FqDLGyeRuWqhUs6y~ zSyElXEg3JFEO}k>bIDdIyi~DNx%6ZyvedmazLZi*EA1@3TslztpmeqLRoR|0Xqjl4 zc9~I`Ng1ImzAUkp;2K_VOW8#AXE@5ax2OzDk?@QW-I0^K34ou$ycdVsa2^{=~)?A8C;oO znNyipIbV6Fa-~YLO0G)2%CX9$%BzZ0l~$Eeb+)Rzs;6qMYN=|u>gTF2Rlij$RBKdg zRl8JsSNm3{RcBY{R$r*TQq8G;RQ;;@O^slUSPiVkxW>BXSPiSDu%@`?e$9)TmuIxk z7@aXWlYS=WOx~H*GwWwIYjtZ)YLC{kY71+NYj4#)sC`tYQD;zRSeIUxQ<04;tk*cMz%LrYsrN6VM9{AYKabvWyO*7I!5*_N~C&VD@m$2q=pN6#HUcj6rV zT;{p#b3^AQ&rP@f)Vi+~(u!>LYxQp}ZLMvsZ++hSzIFY))_KG8#^*`r)6Qp{XP+NE zKi&pzlWdb}OKhXHrM6AA-Dtbj4sTa%S8hkOhqQ;b542xvAMFtA5bJ<-1a{y%!aI69 zxE({CJ3ECs_jRH=Lpnn{TRVF?dpkdMfx32dxpw(>p}Ly8I=i~Nw!41s26cOM2XqH@ zpY87M?&t=_j~nw&3Y|*(|WUeb9?XfKJI;bN%4~ACGAVGmy$10E^#l7 zUz+UO-3RFt>2vDy?DOuc=xgX}>U-Sxy6^2}waa>!^)Dx0rd>|GJbU@}%MW`e*v*`>*%k z>R;-A)c>x3t$(}!Q~xjhUk7#$>>AiRAT*#eU@+i1;5&dC2pm8UL=D6YPzUG(X#*Jp zi~-g_)>*dI(8$wh26?-XLqrC*q7M-Y&Lt4JU-P4*Idg?*p>i2aoPg8hp9mc7Q_WN)!Qv43U%#sP75a&~d{a)dZwjtEDbBgp|c zG8{RM0!Nvn#?jztbM!a{93ze?$DCuuImS7`vFA8(5F9s-C&!0_;skQgoDdG4L*PVm zVmR@fQyemf!l850ISfuFCx?^IDdLoJDmc}gT22F}nRAZQ#_8l-;Pi4XbFOf>oU5D> z&Nyd^Gs{`v+~C~iEOYL09&(;=o^xJu-f-S?HaH(RA348pzHJ-3N_mV2Jt!R_V_aM|1k z+*R(YLD1mdLBT=ALCrz!L65K|kp9q- zA@?Ewp}?W6q2i&^p~0bvp{bz{Ltlq}ziN5)@ekrd{p7I(&8H>gv_?tDD2J z!>YrFhFyn!hf%|c!?fYl;rik8!|lT}!?%W)hPQ@)8~)>(+BLmv`q#X!1zkg5%f41} zt?XLwHSV>cYxl3cxb|{n&j@rxbVO}LZ$y6tG2%1gHAzi=&0uCkx`@3fYH#=uu#!AMxW8-6!V{gVjjBSsLkIRh9j-MPyj=PVCkH?KCj5m*Wj(3mW7{53EVEm7X zJre>G@)PP4niHNAffKG>P!<>qtc9k9j)ks;sf8O0w-&xE@-OaMR9@6x)LryhL@#0& znTrLBMT>olLyN*?aT%;rA8qE8j=oC)_9AKYPFX ze$V|E_t)-kJUH~=@B@PfNe@yVq(9(17<(}BP~f5HL-B|15B(noKCFA#`mpWclZS5} zzI&wq$n25Dqnbx8kIp?>fAsm$uaB)B+dp=Eoc1{Taqi)FzC;JLzc zrRT}dGoCY^&plsyzWhS+h1?7I7hW%dUZ7vJz36?>x4L^3vMREAauvDizFM=|vU+ay z`Re=C^_PcV9(`&4GVf*i%gUFZUV&cic;)*F^D5+3>#Lquy{~?Iz3cU!*Y>a7UVFT* zc-`>2>GiYM?_RIH(RgF<#_&zto0K=yH$!hG-%P*V^%ndV`qt&G_gmk$HE&zqo_qWA z+b?f_duR8~^_|vz{5tUq3Vx&CJT{rbj+{D#?v=SJX0@J9FsaU*&oZXfkWKt%%x3&1 zX_K+Z+RWc9+AQ6y*sR-Z+-%uw-R#*M*u1tmwxzJ8v!%CXv1Pq=e9LajVas{Tbt_;i zcnh8Hj|EuUIHwS9(umia9AS>dzN=lstNpU-~o_)%@QW5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 0000000000000000000000000000000000000000..34da77006582a725d9f4c4522a556e403a3fadf3 GIT binary patch literal 178919 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 + + + + 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 0000000000000000000000000000000000000000..d09f61bc078fd7716f6d4b472a8185cbcf4c4f73 GIT binary patch literal 103888 zcmd442VfLM`#-+3v$uQw_L564geFKyxpY7wBmp9Ugfu#5NRA|sW-b9jC_AEJK|oMM z1*IuP1VIF>fFhs*B4EJ+idYcr1r^Z$GrPI$9prokhP+S%vwGz-SqN#>NCN*E8Li?o1D+Clk%YFtJP=V`q|>KFkfwFeZ=5X9}1? zridBNj9^AGqnOc54O7e9!qhP?rk-hFCNoo*8O%)PHs*F_KC^(ik6FkpX4W$6nDxw) z%m(HuW+StSd762id4bukIYZZ@5~>} zUr0b&q(gdSKxPz(f>0=mK#`~e>WZ#M-H;u{qXd+Ql2C8d7xhDFXdoJdve6JU4CSGl zQ85~iN>C|sq6w%HRUsFuN7K+OGzZ;@?n3vWg=i6a5G_M1(R%bG+JLsAXVEtFGTM(0 zp(E%W^e%c2eTY6mr_opF9QqNRM}M<7Ua;1RKe=W24yiYzMX@+llSWCbKDQD%*?g z&Gun$U~gp8*#2xLJDeTCj$}u%quDX+SauxiV4Z9QJBh7jZ(--Kcd~b}ceD4fbJ=^@ zdF*_40ec^NKf8o|gng7fvN@5S@*V*DUpf}h5l@fQ3H-in{a z+wgY013!nK$8X>_@d11gAHr|p!}wSH2foB1j^nhPfwORaTp$<1MQ~AEC$0D)l>CT=Jv3Rax=MEoW$ME-NVi07H|)6 zi@686W!wtx32qIymfOf};kI)-xaYW?+^gJv?se`B?l57p^U`>Q3QqxY;S#!N6S`(v*)g)DH2XELYu?Zt*1V&6SM#3cL(NB;Pc)xu&S<{T{Gj=nXL-zX zyp}idW6haAI-<}z4<=;4g8J#0Dd4ph|lJS@p*hcKb9ZIJNTRV zVtzb7fuGDz;ivMA{4~CapU%(X7xEAAOZZ3lNBI@}YJLsBo_~sentz7h#y`iu$nWG| z;r9xAg*SwQ!rQ_z;eFvl;iPa%_(C`%d?S1>{4AUoE(m{WS*=E^(;Bs+)?XW>4b?_! z+iN>(yJ~xAW3=(wByBJ44catqhIWv4ur^1Vr!CTs)Q;8OtS!}+X(wr`wRPGCZKHO& zR?^Pa&e7hjou|D|`+#IA)Q92)fsgboxd(n7pjZUwbymhb=7s(#pvw1 zBwecR23PgkfLsT-vmrz_Sub>+HBU6t+@U7c>SZi=o+H(e*`i0*dX zow~WY`MO2A`*lln59yZamg`pQ9@nkYt=DbTZPGoX+opS7_mXb6ZjWxi?oHiWx+A)G zb;ord>psz))_tivtNT{>qwW{o@4Ab6MvwJ^UavRnt@;3cus&ShPTx^~oxYpCr#?=f zpij~F*7w!-*ALKV>4)fZ^#%Ij`qBDv`tf?FzCvHAuhqNsQ}omHGxbD&yZ%o7T>X6g zBK>0h!}?|V75dfswfZOZoAg`s+w{-rU()Z=@6qqmzo|c@Kcas}e_a2O{uBLY`Y-ig z>%Z0ip#MexoBpEyF9SC42ED;#uo`TJU_+RpouPvv+7M%iHN+Y0hIm7QA<>X#=x<0j zWEe6H0}KNVgA4_RLPL>ZxM750q+yg{w4uyUZm2L!G)yv78mbJ{hG~W-!*s(8!(E2E z4fh!48kQIyGCXW}#IVM&*09d7-muNE-LS*(oZ&UYUc)}ae#0@tJBD`+?-@QboHl%J z_`>j|;VZ)#!!L$k4d)HN89AfI$QuQtztLt4Ft#^#Fm^O{GR7L?jCNzZv9Gb8G0oWD zIMkS9%r%ZNjx~-mI*gNymBuP#wQ-uU$vE9O!+4kRZsR@1xyB{Nhl~#!A2F^mt~IVR zt~YKoZa3~QK4*N*xYxMPxZilp_>S>i<0<23#?!{{jXxNFH2!4#%fy(Fi8Yx`7L#bQ znj%b*rgo+%Qx8*5Q?x0@)Z5g@bc5+e(@mzqrfky?(@4`O(`eHeQ@N?aG|@E4G{rR4 z)M%P!y2CWbbf@Vq(*vf(rUy++Osh?go1QSOF+F42YI@eR&Gd@tRns2RVbj~DBc`LK zlcrBhpPEjYzBPSk`rdTWbjkFm=`XXvY&4t9W^<@H%p7ixFkf%(X6|n8VNNlpntPdh zn+KW)nX}9{nTyQB%_Gbs%}(d7*ic`F`_q^9u7y z^D6Tu^V8T|&4(pRhHG3r!AW;TP)95c3O5>c3WPt9J0J+Ic#~`^0DQF<)q~k%Q?$8 zmTxWJSuR*ES}s}s6!oG(G>XAuh!`q{iCx65;`L%TF-c4oQ^Zs;Qyd@;6bFd~Vxd?h z4i`(rQqd_+5bH#jST8n+M7&j;E#4+B5bqNgii^a@#O2}&aizFQTrEB>J|S)qpAol; z&x*UnSHxGvx5UHZ+v3OK3Gt-(iFi)@M*LR%PP`yq6fcQ?TJ=_g)o3+YL#(0JFl)HA ztMz(oH*0rmvNgq;YVBnmU>#^3WX-Y`T8pg1ts|_ZR;P7>wan_W)>|8_ldZQ}XIpQx z-fq3my3o4FdcSqKb%k}Mb(M9K^=a#7>lW+F)}7W}*4@^F)qVirhzZHHf{hsh! z?&-~8#o%8$A?>E0c{fqoZ`H%H4 z_Am7>_n+in<6q}L*}u_$hQH*0oBtgDd;I75FZ6%F{~`aS{>%MW`LFR`@4wN1v;VXH zJN#et-|7FV|6cz${15uS?SIVweg6;rPx_zo|HA)_|2O{M`~U2J-v5ICpElN}vFU6^ zn`ra51=&Jvk+$}>&bF?$9<~@;ye-Mr%XWh;&6Z&sWE*VDvE|u{Y$I)BZ8zIWZDqDe zwrX3Qt-;o4n{K<)c9-pL+da0qw#BvwZA)wq*_PQ>*jCz}wr#d;u{~qkYJ1kU&9>e4 zf^Da5mu-*juL0aF7S1EvKu1xyc^5im1gR>16l zIRW}U za4z7FfC~W^11<&p8Sqyi6Nmyefx19_pgAx!Ffy=fV2{Aqz_`G^f&Bv00y6`%0*3^S z3@iyO3!D^K88|JlDR6qA6nIe@K^KB923-n9!J1%Qa6oWKaL3>- z!QF#<1osN=9o#3lUvNh7px}bw5y7Rw)xmYalY^%O-yVEN@SNa#g69V>3VtkjRq#{6 zn}eSX-WI$k__g4@!EXc~3O*8iBKTDBx!~`Ee-8d71cz`Tnh;%xDa0BQ5z-~3dq_-3 zY{-oveM9<%WP}U~$qpG2GB#vfh$EyTq$=c=kh%~lgoNB0a!1JBA@f2W4tX@>v5<8k zPlap_*%GoVWOv9bA$vpK2ssq;LCA@auR_j+d>`^d$X}sMC<@ht>OxJSA)yhWT|&Eu z#)QU(-Wb|9v|ngO=%CQ-&=H|yLd!#|LaRe-LK{P8gp$x(Ll=bJ7rHQXap=RLkA|)f z-59zf^u^F!p}Rxh3OyY9cIZ2y$3s63Jrnv%=wD$tObFA41%?HM1&4))MTK<=iw#Q% zyD_YP*nqHsVTEBuVZ*~lhdIJZ!fL{r!e)g@VRwhk3tJerC~QU8%CJ>oYr>uk+Z6Uf z*lS_0haC(%6!uZr$6+VJPKA9D_I22=;Y>Iet_|0P2ZaZRhlEFjw-4_e9v7Y%o)q3M zJR^KicvkrE@Dbr7!^egfhdaY>32z9W6+SzBPWYYSi^CrbUlP7Fe0lil@TbGKhQA#C zO8DOJec|tfzZ?Eu_=n*q!#@lEF8ufKOA#o7jSwTO5q=SY5up*05#1u9BT^#zMD&YD zi^z${jTjbD7%?(pY(zywRm7BtrifV)QpCK7`4I~u?vGd!u{2_B#MX!%5zj@u8nG|p z&4>dLA4Gf@@lnJl5vL=*iug9-yNK^2ev9}$;*W?65f>x*NFh=isf!dNLnFf?!y_Xi zBO}{IMn!gu>>k-8vS(y+WJ+Xe*%a%*b0KXGhM7yfboc2axvDgBciqAe>Ub9hbNBv);5i8G_7q@l`LUGJ70 z$OJJ_Qqfu_msy((xR9u`rZpMrw(EA1^o=K1_ zE0{1zdxS}5QkYbx*C@pjszHww zM?*`X4cW!xos|wzgun93Yo-h>o?KB@TwhZ+7Cy)YT+6u_tY~+q%5Esj$AH zvZB6`UX~B#r23)?=M)971x$hP>L@RW45zE2thyBhN=d=5aDp8Lrny{DuPUytSE#wN ziyLbi>OopYO-)r+R`k>ou&LU*nu$79VPlyIRAJ*72Xix1%#3GBm{P_mMM#lSJ1I(P zFLjVQN}bk%lFF%~m`O|}Q^iz+jyh94Nt2|R(ky8X2%&5;oZ}nH%ACzw32f1lY|QyU zt+cqVlq!#2tgsxV{7}r@AHK?PPAG1ute2q_)kHOaluL_lu6nT6JZOf~1-}&6Llq9% zZgop;QSzutx%CAwmekfZGEGv^3TB#g-3n&9)WsooR-`v;%9j8YKw@sC07UA#f|)H{ zUofP&qT2nfk(tBXBjv4P?qu#_?v}bq-K8F@n7N>|c~VbMRfR*m-b)-Pq~4hiHdS3F z|C&(&Bd?~qxK8fQ0Pky^l~8ANmO4c5&j&hds+{$8jqYJ|KOII7NYQRmfy@$Sxm2`< zd5C$Kd4yTYEMp#J9+P6ESSe1jOYu^Il(>dj!K`FfF{|OfPcUnwBq>=+mrCHjrIK^Z zfQm|IMsa;{L1Qf);%Rc7vlzy^cPETi=*kU&{!pwNuF9%+Rt=SXVTjx9w(?z=`@77k z(7&{_s(Pi-?(YiovK?YjNljIBacym-Q?ci0YS5sXcbLu07Umi7CR>?jnQhE=W(V_} zZ2O9@&#ozvjb)q)oLgL9E?-dvy{LXneOz^^b85~6w_x=<=|(A4N|E|YH#o$Y5p+C7 zgUNa|D5HkLMYp(v{QA0vlKO@^r@M<@qFwZ|)QkSTi`mV*GRgzLkJP(J8Lo;We2v-b z5W_)+s&@bci;*ej7FX1*WcD$=|Hn1{v;I>4bCh`lq`t`SKy(Dj}A-VrY9~ zDoTgcjHmYEtgWe!q3uYg(Y&I>CI69?6+=}PQ&C%9Q|)a2NOemwN|TQI!u(EK3{ z_0-Ii=B{FnG4IMgU-?_P^nK>IL-fxmDscCdyO&ooA5f*V_LXwyN6g0#vFqi1rz+Xo zxK}bKDBM53-aYz^%%{wkQr_dtDdscgH1j$0g_I#>N&}>U(xAtgub4B;*UVYwoRlTq zBn_8FNaG=t$W|4ft5~%%sB-I^lPhW(TwWi_ngvd+Tp#VKX{al4W`nbgcG0LaS&lkA zTDjB>T~J(C=4=ie&B(1?p5N?-F4s4>;OkmJcPO8Eg2M>*x-hGHLXFZ&x6%TcUzqdM z%l;}2Ucvk(!JxN77q@tJ>QP+EV7kCulnPfemzY1LAyU2@z=#myAYDW(!qQMFXC=}g zUdok*jRhEWtkI!gR6qmrkm9oHiu#69XKu%S&VCI2k8CB#h)iRK=C}Ce#+As(^j5`) z$p11i0U)NJW54?rcz^_>kZ~>6ET=E4P%uqk6d7SC91OMP0#(>56h_54M87Mw*z8MC z6!;Rv>o zV?Y&>YXv0j5WGWMAn7=Ed#C)8np!pMLpA6YdRMK~(0rG*Sv;gR_0BpfT@^7IO?CSo z)F@49_A_WY_!%?<&6K7}P40`0h@jiN9Kh}94yjR^Hr9(($A0&GCA$OlzI)I-ulwes z1=4hB#^`2VH0|x!uTj1UR&bT+aUgmCEvD9~e((@_q=oBJNpf?2jB;I$R!Bs;&3&;E ztww9SWUfW)q+6xgBSGtmDR=C5@12+N+=w=N-LnNfBi%0D0bT3vtL9|CW51CK+hb@u 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

-_q_BeJkN`0Om`2`zhN_7 zL0HB>PQ)e|&MreohK`IIxdnGB!@Fnr85uM2&Kcf0!yU?)$NRW189!sIj3q233wvec zv5K{9U=IZpQp^GBagQ=ug0M_?A=9%n?Ut!8(>r83k4)cMrk|VX=VmSo!g^)kTzVae z-FpqfJN0sgy%z8Z&a!tRz3Gb$dmoB3=>0Zx(a>8%?@$od$Di%v&h~L<`}E{lH22Zm oM{^%PzfV^X);9%rx^Ex<n1Im4{IRF3v literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..453efb52866b5a7f828619eeaae95817bae629ea GIT binary patch literal 342960 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

&UpCRr3Z^vuge)Gi}$ZJ{lA>rq3tU zJD}oBa&lL+KB&uyu4rdE88?#gO$Ob>pbI)QKC5QvXqQwAK)g}ctaYc?$;Wn`KBwOq za7tu+n~c?D+)T!Is+=Jwj_o?JmDobYtql6^d0dg3_b|C&gB7XORI&3KM%IgI z&TE~0fQ;;OCmDA!@@^onUC{TvzaLbrLw}3t9N@eWkh*&==Md*mKn^402V`WP-S`n8 zcmLet;{9FWmICZApajkqB}t0SiJYUH#sb`^1FSv3JjA}X4kDXjh#^Idd zoYkO=k2q(mGJZ|QIm}}5FB8HH}(Diw#t2R#F4WRZO-6)(YdO@0lnf} zjRCDCCYZ)7||Ex5mV1I(6vMeRsNYu@}=j6sS-5}-M?L^}l=iW!j_-ifN^!EKGd!AM2 z(5pQK;QY+_b%RiQo!_WXzmxG;6l(B7dRPzYfb$TKQSZE?^RV*>v+61e(n;gs_&y^!dGH4|>gYrjMt3>t*6|B3kPX+7U{HEUh3 zG04@`Rfw^4CsT7WwcxQ_3&!9cN<|=h@x0!AZ;Ogr_ zx0&lYGPNWVQ{N`0zE>>}9_W5ZT_#}DmFcY48|WJ38p@!07h||8T*H*LXKG6(=DwA1 zG5zZK7xhk8HQ?1AQFV=Wai5v4D|X%NQv1wIu(*U;sO<-S+BUnBvfEKyB3ilY{EO>$ z7q^<}vgfY5U1&9fe=*s}lvIm0V|4QuhS!W1#X1et3>SwR*G$)gu7_L?lgUmd2bogH zRN_re}+uyWXgc_ zrc6xx9^0dvwyG5mgc&B&l^#g#dVA5uK}NTi#Px~`L57u^MJ7+Jav#om<`GX#X#x>O zqulkbO@Pwf*16tty$$g;lgURWX3tH`p3gjT{})gG&D(u$fAa;<8wQu4uwI%DHrIPD zrLkFWyYJfVQsav$NG7Jx6~o--j34x67gc$vokcC_GZ%*!*XOP;Twl7rB9ly}2$?P? zQ~N5{UKhfP>pL=CK_+fUH=WOh^lb?V;~z~?*J}{n0jw4-U1+1lA=j@MjJ{9*&GoxF za~;W)U8|Ng!u;aL0fmGNG_@wbbN%f)%TRh6PK`@#6z527LZ)0Y<*{D!F>~8Gn7-~b zg=dbBp!h;qWGMOJ$VhC3GS!$WHVAA@Z3bYtzs_Xp!ob{($LI&;z;OU*WeqS(Ibyk5e8=BIw247fb9;vR>On~Yd zaH=~sOVwx*nYhzkF|?WcehTINtr%JawT~!LF!gdE=_Vhk?NhIScvq3Bm`o)sUMa-e zy?v_v@F4d53IVK^l5u%qY`UD9ms-HX*4t60UY*(%xZTLqn@oH=kLg|ZEEMZl+-?{Xi-b;Po}

c@cn0k|h|TJqB>`7I%YgZ1;rGLxwT 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 Z|NiIg(Et12s+IoV|Nj5~4&N#9e*j};(Xs#l literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..50ba4bae40b124bdb20f82f08942f2fbe8ca2d55 GIT binary patch literal 417659 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 {*QC@IY*;6BgrCR-%< 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 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 0000000000000000000000000000000000000000..303b6b3bd494f6791d7678c59b493c1db083dae6 GIT binary patch literal 114668 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 twBSw1L%~~+yMisqYhstaticMemoryModel) + 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 0000000000000000000000000000000000000000..ea80a08858428e3d4efb154f60753b575a01373a GIT binary patch literal 485468 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 zµ-6!f}zqhx3>)vIxU$b_Rk?nX2w$7fmnhV`rbOq}q{*=fGmc>Uub-sD$T8tfe zf<#l|N0pnhb#e4A>ZM%mC_am^XYYjW*<)AGIIlQV0S+4;(KoJj*C8Bb$Hq?o@24-a zyOh&*H1+?4_a6UsUJK8mt08g*HOBhrh;P+z;ovtsJLinI($GKiEct`RvwxQVvH5*E z_P^x)-!6z{t4bsYkvR4i1#TS z@8Nw4Z%V(rDEIl(K3BW?oR8E#bncwmVq$Lc#%F@>)a-S}rZ0exVi^B5_|`Z&P2Lxd z*N>=E|G%&QoMDpo?T?XZ(r?Yae5)ac|7rwm={VdoqMj7CJ4cjL-M8~!dfeN|jMEtF zt9Y04+5ZqoG#?qMd`EBTl;ao>hXC7%qgDd&|VLE)$2_e2ag!uAQ{&y>DZ+_ zk-~HK2pH2bJcIHN949B!y52LQ-L#HV-cmlzMKjH@QTh07>O4T% zq2~7~52p1zGorl|pTtX<{S3B0U*~+-XQSKO#5MO4Kg1eBJQ121j}9YyMQbBb-W%^3>lb2bCd)!u^Ibo=jPXY#)mzgA5Nr=Gi~-K^^6O9 zSg-C?j#s|zA%3Jc!#(W|tn&wk0;f?=ju?%G9u?MetVy`o7K*`d!A_7L$Mt4KYES+M zyXr@?HRpL(&lY~(qx)bO-KsQO{>oFEIKn6WCXTR4nMVzd@Ld=jIlXV3w+SzOg!uuH1;T{x9H7b)O0D(mI8|g6IyoQ~YiG9r%+iF5FpFa0X1mA@qQMllUa7 zz2C7cOE@%iGJ>WUyJ^SM6uOOh=3-xA18z;}Dy6BEo>E%kz33p$_zUjEPI=HJZr!qi zP88C-gH4G(vX%Dp$Lc}WzTN#u+^X;Ph`tNoj_udz26}gIO?GOzfbXd&y>oi(T2pPi zy0+b|-rBxv?~(T1TuW&4yB`VT`>(hmvWlPH02~Lh_@&*TCvtp0vb~9sW%VBWe>Qtz z@WC&2Y_D#$0OOvp?zb!lR^j%Gv>nwPyMy_awf$3@&x1d$S$?f17#69IobBmHf5v}n zYv&WJb9Swwjj-17?p4u(>~I7Ohkf)YAOE)eHXW2YT{;FRry>leGD(YZ-7ouF9F~#FBaw@C`uMJUcuN zKcrv1=4p@rQ`^c)yS<|rxduw)!?|?4{pF)RX0HKpubfUeH zDGed`AlvD62V9^N*s9C10(go&fL_?i|MB15I}E*9-TjP#Wie)Ud7{eM=dY!W@-*&e zXdG|OEUsf0$k!^mI;8ffx1D-LpEh`Iw*!1@7p#h%OV`-6V>_*7wQ)$}qOpMPZPB{@ z(Xc)Z99Tv4Y4`_t>a15C{$1sq`5v@Wnw^$a%wpLej(6B$TmnbVyNQXK-qCS1b7tol z*YBVmWW}_){-v`R&j&v}^T2yK(Ip%%W4; zR4z9EC&P-}$h*u}4{ZmJ#O5CR?HP#t;F?5NV(U_a*LKE)@gHEl+RCrmxe{5x znT_@PBWG$$ZB_05h_fv?43v94W|vC?S;FIxOhU0AU;i#qby=Y0c z65pRM$BWrR^n>pHcx4jC|5jaCYi+x-g0EniV_#KY7rn`UeWIVMTNn%SW_bOvWBJiT z(0g0)hAK3_o%fFkK5RgEav^J<*50$N8#KnxIJWgP?_aP)2~*u^W*i zK^=AYuu%qEn)mo2rpLWkw6QjD7P-Eye7UqL9w@D8PmFHj!)F$B71q@sy%T?mPgO>K z8hsD_bz7fVC0`TgC7osX)cMRBmBsuF+mR*cIgPq*&XkYwr|Q)Ib6d-%{@+JyR~lNI z8#xj6T)HOKT=7xbcbFIK1tI#v;&|eefmrcw{({AE&y|Z~dy#NB270;#m@c*dt?=EN zdm*{kps#!3%WDH{kkX}*Q`{Y;|Lqguzelm1Bc4akMQ-T=pMBsxoIlu;mO1|2L%-+U zl=k2A9q(F*Cq?GwvkSub)T<9=SZMxWe7ezf2hA&1*~}p+Pr&QToa!Z!TfNj8IWGy{PCTaOx2%jGDy;pT{2&{xC0ZQM;I}~= z)1i~I>^0Dq##?YmeroMr<9!Rij5U159wolfGv=LcjnjXV+-bh6@GhmVkMT{puqwWh z-+|(q_*#Cy%6qFCF%KZ)kU3WKH&ZE&@*(*^Mlu zjsSRy^IdDcy<=?Hvtw*TfpQ&L8mDy`y4|zNz}l=gR!qIKXN`RH_)SkTaYzOz^h>7%$GV;lpTB)x)rvm+Z^`?HS z`6i|vg9GbC>}Tgul;Rd{ftrELw|Yxe~0^w@eQvr zc)D^D-Q}HCAWonQ-&gb9Ox8KH?m0FJ+dG)^WSh0WbuyzXYPid}=s7+`tKY_i%v=eul{xBwmXyZ2a zDwbJ?^C=&AiftlK0cAP&tOk9=gTXy)$63>LNXJ;y$AFmRxy^E_b5XM&k?c#}&*i;- zw*|Wu7y63&Bi@otejWdxg)XEAF}c4o629l5EqM8`N8KvBkNQ%0#N#pVghTD$1dsG} zO+xIBd1mlbD%Pd|Pqhh;Xs&@H;rHVDMBcs5I=y1yH1B#v;qDTXv$qk)%ATFVrlVMMERf}aV^s?(ZKLcwl$acQ}E3f_~qQ~ z*ynx*@f|bx5C3rvZ8aWWEhm%wax$5B7WWyh9GAy6j%$KdHgq`tF57yR>jthVT%zrf zmvA{F0%!hJHM_(*YLjOF`cvha=pFdS&$C$9rrnvuUcJ0yFo|k|iO%dhv|uoqQ5w|V zb8^baU&Q%Qe1i{N`_J*yH2$-OT6cVKL0=yQ51YPbBhH$<*ZkEu=e!0^{-TMGnH4dbwuaU*VlZ+oDbGcFpeWq79i zFQ)&R21Fw063!YUy!qpM_ zW#SI|kdxry1Rq|b&Pmb@A(ktc^m1^jTn4`17vVRzAWTE(|0?4 z(LMuWm-@nunZBhDE6tlkCGkD@w+RW1Cd-+f>e7V_nD{U#?Q;v5FO{{9M-fCppby{b|f4nHlcy}eQ zk~2!NS(0Ho^A3F&d3rmzx;+_JxIOVgVBi`z)TnC~b!7tH_le$$oQ=f0!qTKlU)bXi zjT*W(`roGhKQ{FrXx9Hz>et@d2ly491nY&sDjW${jt@Ldm^1#;WM?{-(D2KB&`^PI z!2Jro$&r6PaMw~PPM z@)p(fPUHR+;SAn60^fX&axK9krocY){q>^XYNf8S*dq81?Lwgg#3Y}VD0&LmP<)x#R>feFYQ3-~oxjPb9DEWd(`?@x3_L20sUy%4z8 z^~7>$?b|A#Gn83dU;N|TMe2J*|E#-{>%RnCUbRlH<*0#=I}^_Ci{0XmdTSWQ?A^@U zC9lRAh|o~jY5Wk1Pp4g-A=;|an2{c)t_7wZDBC zV@te+M_I~e{99W-=8UJh=rk+F6GUP9)&eGQ(PAsGSPF9Cns*ylX^JhwJ`?8Wt4_&<3_bKEEDC*c=F zuX2%7S@D*Qto;nX#ONEnRkBy};ECYFKFyv@A(J?hdP(Xr>a>`lM8elP#kPy2LyEg!7ZFZ2gZZd~dXszw~0qq54bg80na(SKeQ@gCvr=ynA)t+#r^MKXQtWTcsfPJAw z<`C=J=ppjc*ulgaDv4~DjdtJy!o~GDf$&}u#?McLxDfPH!0CEk0oHFyX+ zius0fw}?*_es7v4{Y43MSTk0otD_d;nlyJXAJ&JcPiKvcq>nGdD{A9)_H5q3d*Mc~ z&!!%=sk&9)7TzhBLYC+0d8f3|1&%zow8Ufly49v+iq0R^9wWDuk0w~qjQR>~kB!1u z=YUGq|0Q!)AUIVP*fj3KmFjQcYJR+MYQuiIog9flQRBJj{3 zmOkniYuB0ns1KLMi||(%Sc{)Axz!!Ysf`btzJ#&pO*HnQCXHRLK0sq`_>JgKD5H9{ zMmm@K6c?&b{S<9vp^X-3100(77x1gN8|et@_sIU9-|VmYIkJy^O&jr3Bl;*@dEiF< z6wHmj4jy_J^{ZaViIH`mM%{vM9`E0-ZFo06rCFwrGSca!w`t$C6A-)NGe1_L??^Pc z+MKg7#z#IzcfAaK8XZqM`;>yw|Ikw@Yaw?uuI$5bn13~<=)vPt+JGmzq!(AGB5tJb z!|Qe-l~uBpIe(q8o~-fb{v`IvH)PY|EZ^mX`^%t7!{gnZhIcimD(^C~q+5AhRL=7C z{en7l)a3-%dahMQ{b$X9dSy$f?wP!^tZU%OYt6g0)cbbrVket(D@WpZ@)6l1rf)gH zBKu&Z9W5Ko=)gKlrVL)fFusxc&-mKywbr4~CgwA54Ke?fZlfOMN4YIw-u{Sa{&ngT ze9GS?`KVmdw)Lm78_|6lxY9T)pS3mg^_Upo_)7FH&HYv%`VO*=9BAEtM0=wsuh`Fq z4g(zJFuv5lv9^YOVq-_;t?;dIunzU_;6Qf23C9Q+ln2`immPya`ZVOo zKe=ZQzhONaZ=LuYXO*9Ff>yRVK7CLg0meh{X3&p+%Umj$ zwckwk#VN8ctjcO&UWMPQVP9AS=0AIQjD2y6?2BfZzvY?ii~D6?G@tF#vk~^iDY7qk z_ci?9vM*HkU(;R|cxyW?KV)-&Pt(o^HY@yVY<6iZZcVAwig8VC zDe?%vtu4hF?eJ(@fqoU1Gsg1ITqWJL#y+QYb66`9KXpu$99ba0$1=<6i2szjSFTzb zje)N4QN}5qiN>H2Xza@RS4Pm-7gM?seOE;{S2k#j@zB^b{F^#2eiL|JevIC=XI$f? zF>0$09Gur2r_X|S=?Le7_Z+%)%1iGxFhpuq;Y#PWv2e4Sdwnn}iGP_j(pw zXiTi&bDmX2PY5cWZB;sNA`g|?W$ttxtL#YDDvxu%z;}V@e_4_X2c)Cr$6^P8yEU0$ z*{!RPGnwGq;BH>6m9fMAs{x;Utn4cwcEtmfG$CB~WSn@nRfx2(3zI7}l%ZN-mX3yWww{rz!up|k%(??V3Uzdv{Tq@^qeUxKoxS%I*Okz@mB%;E+U~31;vda3#*Z~^a(_n` znOygVhgdJQv}V}EKi_p{c+dIc^$hC^%DMY%;f{7+2KF{|OXXkC_zEW3NDgobCh{R0 zn2e87-ygXv!*|fdQ!lp#I}S2u6K}V`=#r{KZ5sOWnUA4&jT>tt*pe5KXJ-}kc9qsq zSj+0KdBpIu*J_#I!cTmMV1&0`HgE>ZUq(M=e6P}(;@zrSI6KN-d%0XZ#QkMx3wR~ zTCA&pf93Kv`jvE}>WW$pTQ!GIy-jt&^Xpmrl|Cf9)#Fz%NQWEK{9fPcJM=Wt z#98RQ3(feac9QJ2nN2?(dBbu!a3Q-xYs$(aCRl|l8$4Ma^nxBwoiS^1Z`qf(@Ha;f z%hxHNw)kE4fp9C^;zH(o&1aHdR*ASSZ_UBf=U|}=W@&S-)(E_XHQ6~Avd*n@AZDVw zD~1r+8mr6)DKoFVv8F9ry7*5xhnjgUt9qOD5Lk*lzf|jEg0XvHb8VaN+fV<^(RaPHH2WJCVeg{%9+o}2$O9i1 zbb!5!eS}_34hHVgr#V-=qYlksCllu?JOl&A=6bAI?kG9=1t&7b*j36mC0K>S@!%oH zB^ylRqV>(fcWgtSlf}#8U1(1HEEunB&bPtu@BzuTYS^Z0l9?woY%3=quM6{vC;BZ2 zXUr{r!!P&VaSfROzQD_~?e;l4UHcqk7aBYjt-&r2d>ERkJ{j9>6Y58(hdS$X`>-)f z)JL6$mypXrANmC2Xj!)b$Fp%e^~-0L{8 zXK>BrVjLXuDMBA6_ATQN|A)%sH_z)E$I_TQY3P}8XWi+DxqqE;wydj7oPHoVQ=lAi zj4p827!i2e;{x;5c5xq*brE?&CFms@I44Q46=b*K}fVNmWhE}=*Xkh(# zY#I7*2Rg?Aex{Cx#y7?soy)A_>wB{&aF}=KcjmmQvh3~^$SU#+_A!nn(c=D>v%w1o zb3v!{ukQCX)+h3(^UJ$Tjy>Ge}0W|>y}JYypGNix{URq z_d^F+|5|k7%g_s~1IlaNpog%s?quR4*`L_Tcg^R9X7b>YGS3K}Z~MN*dLwb!`(I}5 z^|0hE^>0n#wX9NyVj46q4Sr;fqc8UG1s&EfdPdWqp+4t^$lE#;c8=-`ZLaq1)Terp z5!e)epcq-zVM><(TuRGgf}E zK6KFkh%bCGWhHMWAq&LInwu>7IOM}Y-;=IoqeqTIriwPCM|k+Z!FwY%4jHazlI8l< zmA+H^vwnT_74m*jXBqrN(kWk-eAYYZmmheW_j4ux(H~Vt_$RK3VXY90(4Relv2%UF z*?+68cxJ|5b-sssEI&fuY_yd=w}5pQm*l7gZcd_HXMr*$!xQMp&=38-bb7}>ScRso zRalZ7f&Oi5E&8LqM~5XRMQf5TGZ`zGztfZ_Vw{JN4-f;Fk~B8}W_CFGC;OxN=;Q zgVGBX2dTJ>Tlm%ZQ6E0lsI%Ntd4~fIPAE3`NxtZ`|H6m##(?%T&KiTmd@ucTEA6Uo z$pYcQ;d|!nSEl0c&i4M}i zX_suAM4!hYLvCr;8r3z?5p*!w=gd#oV*O^!G{>0yn9Y*qR1%j8UyUzE1N=i-Psro+lDmoE&~^h|BP zWqc^Jzu7;H&2He-*j&uBadGpto$p&iN=C@UE-ATP9e)4hpswj%5~bK z8^1Y=-(Z*VQRNEgn&3%!z^Q|BW>0n^e2>JJ#sPlXI?0nv3F}LG@Tnk2m(1!v=;OCF zvKiV`-~JgmG(Mu8WA+uc7{1+Ce#<-IIklyPYw>{O05*nM_t(8-gX&UTp4z<-y;U-z zpWKS6d=QNIKTM38%e~P%>YrU=UMR0f46ibmwora#|E>?|S7BL_ zVT@H?Wrd65%guw<<{{%1t7#P~Tm#@Es)v4={5s{A9ptLfrSR2+exatmgn@;hcp&MJ ze^PT8>tNqSXC5hQgsVP{DdXq~2H;iyJg5lmzX-JJ5#s?Tbm2KC?|wv(N3_W%i=-~7+uG?JglF}y5o4hS9>Gn zy8a8#zpsquF8MIT%N~7l{f4|pwq%)W%>Gl4I>vbDO1u*+4)w~mlJ8OPq%(c~CFElW zJ}mO$7VrxUfsb}_2S7`fiThDpKqF`FjAna3rSIFS2V%t|=-y)-1jjz^yE%_C&;9#= z;SF-!>-lNWmQzK)U%sL?yzeo51z~;P?iI-=zqX?G2=z=T-jPfy-I0_cd-bFo>6HQd_!l!&my|uI?vZ_lHVlf+STq>Sf`t(T|Yp?p%N?e)x zl(zQ|E!bC#^AFE{JedT%j5~Vxvx$5n>eE7>XQimF`fY3k<@s{^!q^W!#9paJ9_!m} z>u~jlw)MdJ#`VI8`}A4*dxUr6*q&wnbN}q-#{F`BzxyA!(t3X1?@iP{?)$d&8o%jv zeEA!i?dthMlpXng-=@a@MI-t#Ifc2|$C2fazgPSIaqSQBot~v-t!DcHzgu{|lr}dt z+fCc=8`1tvytARt1<>adWO$zYZ<6O;^ozs2TfC*`*S&iMyd+;)f6Z;u_Y1a_pKEA( zzVxxYctrny$oXT?v!QF^h_OSXy3cqkCS_r8mwboyh0w&p0{5K9#JAlGi{yJ`o*I|I zCicFaWH>XUI0TJgGrUhRR^-KDAM^%(H$qbnYke7=<3YuP54u+VlVes)!*4rnyTg83 zo_#H2<@b%{oC)TUT|bqcc&TLTI^^?uYnYfE=xrwSI-|5AnS#x_&<7UQRz;TvM!&Q6 zUFv-cEYPswMcNi!qjPLkS-}FFZW&u${rVX^C7b4xXRPR8A9lwCe?=F*)NYlPZS~2E zRyd!$ig)Z;4Y0A?;^K}8g%#P2XFc9Ep}3;!{Hs>flzU8Phh&56qs#uLf<4=SpO~Wc zDcnCi`xl0fUj+9vy}JxPZN_J?Fs`OD;|eR1muPnqxSdIT*~0a#M=h-X3|mg;%noL( z1LAY>`(t{Y$^86(xFx-!Htr*%lCY^3dx^mbjd&TFYNtw(kKca0nU#!p^f zNPo>3HvL<|wdCsOS)9@sLO1o4rdB|QR`vSYBxt}HLQV>IjK3xSLX!qwU|lN3?UuD|9TC5d}}I$)y_`JoZgg)>GMZ; zHu+=sBn8Gwb$alC;RnX6z?^nz6aEzT2EEBnmj3J-{TbN1$S>Im?edF#MgQiY?~5l5 ze(>r11%2rL82)bLujos93b{PYd@njX!WqArpfS&B{67N^-#VP7WPSTk zj{4>?ZWr>sczvGL$muZ;f1Fh))^>^is6TzKIi&s727O5;NDiFOe4*S#54hGcm$K1E z;q@ZA4lvIQfD63N0Jby1iN;VcXdDaG<@JTt70Fc^H(;DY|IR;`bp-tPq7~)mPx~g= z)VIrTcsy~aSM{q-(ToGV%?$49k}MZ&OfEj6d&SW;m>aCs9$TdJ_k-F1a~E)n{pwSTY4zPL$12?X<{q( zik36b@>J+*65oRN#3@{BaDfarGHngGkUV?s+y7B~5Tie|{7rd=E|Rt@c{Z;J``nTE zc;ffTGuDlXok;5--svs4nBJ@}XyU>zVB=eB56vu#H!g{@g~5<>(}p#t@GkKwH@6DS zLUWQWHz8-ios$6v@{MZFeFneYTbvneWS!lI%q5g0{9xd|YMpkZ-iKpW9FGd^b~ZZkZ`nQ0csh*2Y= zW-!R@?lcKmNGIte-P!v8J-53_WWe`6zt86%z4X1e&aJ9*>YP)jPMxai2c2Tt2F#f15mRgm!khtZFrji@||Nu+TJ>72JGVosjo^nhcw$UY%`Btou8 z54}ARF}L;uRfH?e|QkI3#uA8I&**f36=%YQ+!ppU09jQ|^)gPg?se=V`^0Q>QJV;~2FYqWB3RKUTcKynv}Y*xJTsS8^(9&&59(7^LqCDnHP8`> z@JVZ6X9y;Y&vAa8209z>_asgQjY+rDUal7)4`F+VnP10P?R5=k7>A1oy%TY1um@@) z>~0OUcd`9sEHiD@@W_Mgd(uU8#x(fIg}mKE=)JW^_sOAlO`>)ME>uqeeuzS8hr;E5 zTWN+)r8ze`U(amLqIvLxWW)Cj<Blu5e=A3l4?vYsR z5o6AE(;P4H6$cxG&Oltz1^QCE*=@08hjQlCiQwPF`_axTA6Q*B-=V!nt@ zD!wYMD2B7(N?!pT>(JW^&O8SA4A6$oq0~#cSa-4=b6vCtO2}pgjVNv;Oyf+{skgoS z+YlbFhVaM(4r9R&84|Vq0vGIxb84M&78&LJ$Dv>0Y+jp-bl;yKYb0Y-M>@ZL6lB|o z^@ZWG^p>4xots;t4jNJ3TJuhY%f-B=v>P}eUJCgdvF;+AUoP^3 zo&ui+;jw;1F$4Eiu#X5<1OC->J@9(_wlkewfpaI&CcSaKKZJ8GaHf9n-yPVS4r51* zwe|^?ZTnycz6{-T5aUGWspAxXBs&i!Z&i*WW+SNkG8HrMB|RpX;J=b`Y0hvLhqzag z6{45fT!1;jQ|?!wqf~y(Cw{!k^$qL<%+I;fATQhYhIlc5Ci;=PToT?99sZLSx54h% z)?;^o24R|z-7zwR&(PkyI5)_Pq~9&(1k?q6gXwh*Vhm!#{X=R$>_a5kxNtwQ0Cn{g zf$vZU^5GCosa!FC+ZFzK1LgImWn`#q-Bo43d=<^P5L{PBFL^;7X$?$R&+LVcfxiIp zQz3g_qO-7qb_4ZS655w+>)>ANXWUPr-GG-HI625}06u67n~Us>B;Zm3KWYiCPjUSo z*H@*brBk&$^Wol(>j17!T=7YWAH#JD_YXbz;Df#M%toG+U)43rqWABh9D=9v=~)83 zsh=hP?+AQDv?SR?jI&Bl-qcGzpzmHKeI*h6GSxP{9XvpN$wd5;-m?`Yp?~WcYmd7w zkNmp6I-;)cwYm=XrvKML9-;bAC%XzbaK*53Q0FBXU#a%mi-aF+FAj13uZQk;aO{&o zENE-doJ9rVr%2zmV$4D31+(I13i%*b1CDGf*hNRsAACq-EE)^_1iBDzoA)NEyw)?m z|D`=l`dkNmd-L165FU?)@F0B^_LXqpAIi5bJ(zE}pHcbvDn0o3ZtSHE``rtiNX|*d zEmo`(L_a7<-&ZBap&x`?Q+yK1^xL62oA>>Coqrd~_h;lAuGgPnGpKw3+Fa4;(4klB z$`bTd!@&OsP)0Gn7c4k8YeABm{LUim)Tx%>*m<&jk9!yD)0-|MLUb9@i!P&}$HTh! z+e<;6OR=}%aqwUc<6z{S5TE2WQvS%7?DWYfXZ=Xm;Q@(_v0JF zGk1K_|Ju*jg<}7~+c;kcJcGVwZ)dRmIM9ajq5ge1>H1I~LvfH{y{DIUpP2{QVU}Fz z)kUtOA-Q=Gzh_aG-ZHc6x-wG;y;|6#SE19x`IBBf3qJ?(by<5aoi!#XGg{O!Cnw3> z+jk(K&4~Y&97u9+qxQEPc0UNc&dmwh));GW(6@qy+5qoiH^t*!EbP;Gt{6TLq`_a0 zJ-+r=)BFS4{pc*y;g4}v#mA%Vwhu?y_q>Da<5l2!F*KF{j~wAM3qCM{mmj&j2kTg% z3(<}^L&Nz9;Anh8V<`>fG<+5T_Em6i!Wad<78iUj@xn%Q))h)2>P7aHh;iKC(T>nXj)(GXN1<5o z|6&LEo4UYD;kt9ha-0|6sCp;lcOswDC_C}kQrE-bw4i_YL-KuQKqrw*eT?`>(<@iY zH{!A}j~C_(#A}?n+GlZFh)-r*#V2ILs&X#}=S4`*G5Mj<2C9sOHxd7co; z6PvwWvDJwVr0)u^f*l!x9eOqF;62VquYyeq!43?;hV#4+vTS@c$$bfYOZr|5zJiVU zA^20(JEXVQfIhwJXbk10zbY?1bQtvy^Frfi@bM8`A5vS9j-kBnL0*sr*XBu(ReFy$ zB0n1Go`pywUW4DxrM3;ysNc8ZJ&iS1p}ncz0kh6YHW$h0%ScBV4)XQEZ+ev3b3b?m zK0jRV;H)IXE$u$@+R(4Q$Jph&Rb%#?Ii%g=es$tk-$$T5!7S$?*xJ$t@~2 zN70~@O6gdeBRhGS!p9aW1*SQQ8T=XnJ;kFO&a~FuLjGxnIX~FFZWM+ZwlJts+_B31$_|ki`S~Y56~9&XyV&5_9UKy?pEhoFsFjK zLx;`(%l3Rt^|M%A2mDv@9Pq#xH^>(uxl#GTg!W>vjgXH#k>qP3`P)>V$7c9#cH%wh z542TcJo?c?e<7HAUAG41Seza;xE!+yXt~Eo@0;3fhQ7)udrrTA^&@CUY{SL z%|g(I)-Q187o0*dNDyUJvoelm`B|GRMPN zYy#R@gFc=+3qJ;5{9KR+LUKbg^ELAA-F9O@+ur#y%#Z#Bc~iU!^#Q-OHhT=?<45)i+@?AUh%@AZhm1dXtc*5*hF!Bad2v(HC7#~n`i7#)HIXGK8gW8GGe z*G%9&6ZSF%f9^tGhIVlv##h6n?V50W68Y(P(;g>exRzps|1b4b07vyz_p!h@jn)J+ z@E*lUlI{?45f5B+*nJb~qV}8ezTmwDZE2-Gi_U)B<7C*whJ1s}275jKb@yq^O_GdI zJd&37Ux2>>IFAQSQnip*+^3RVf^nIFp>L%5McQwS`Z>}$WSas8=Pnh(&-5+U2A-&* z^&1rDLH!!DY(qTVZ{4(q2{XR{9tiHWLFaT(yav7>DZ*z@u|~AV&o1yI<%bwN(EfR< zyF&vSs%w+gy@c@2_B`37H4HdXnZ@Mev-*iuk4vqsb(F9pl$Fqhlu+0$rdrmgzI0r{9bS($YNw6-r0M--S2fZaDWAJPK|Tcg0Ai8DIFX;0aQYBw{LMMeTO${`=3xygH#x_dq*vo$M(QS^ zjc`u6aI4~&HWF=igXq-RvAzq>S=i?^Gv4NyhI}cun%b{mkm8Vy!8SaCdmHWv7s8Ea zrEbnt>V6gFC7b7}bo~SBnT+}qjsFYxVOpW?v~TzTq7`(JYanPu`=xQx@yb-tYM9#3 zfnHLOUYcIG(wahkBJk0w?KV=#01i`eeje(qQ*4f-gv&7CG5}W;)&1+rtP#MakIi8b zfR9;p_QqxFR0Z<#qLcVCjMGuPQ_BQioat-mTi^!#a#8j~(2@r&*Q1}0nS!#h|I1eJ z^|aBT9r*Gn?z6BacAAOGwqK!JIDa8TFYFoRo`d|h2pe4wU@XF=Bd=*_i)leTQt?Z5 zpOywZ&`x1|rrAYj)+pF5XtyvbOM}0OS<~a?%l2N!aa81QU{lc%U)4Cfm9;9ax8+OfgS`^z>mka%Lo%K2B zL)G;;ddwAJ4Gpc22YbwSLC>h`YdFMTXuvPD&q0FufCl|qEMxFvn1gFz@D6zs4=smo zM&F3{dc+XtQ>+@E->41LUIcDr8@vzSB;pR#H82cul7P|EIv|v*i9vbcwLqAwyRsID zSL^eNyA!qqt%0GnKxyU^>Y5l@^Fww9y*I#@iT$3`_g|w7(yeEqm(?|6mP77Y#{mml zb>TPLc+#~Z`rui|w`r2peh0cz4)%3WIHzfkBEp&GLO7fYr{bHBb$9Uf(wZ=mn|O!K zv6I11cZP9ZG343? z9sSbZ^$Xs_o`u+hjl&v>o$?On2&|3cum%})atgUSuouWq_{~_&X6RAcD~ae%d&gln zO_zwiPRyMFpDXdhJ+v--0B6pGJ-*N(+WWW>&!|B?<3+O;EVLB%*sB_h>kTSxu%9(c z#(s72!h>erg)`=Vv)}@NXx`1x~%Rze+H@ zTt%`$V{`#y6T~{e?%8vx>>_ZoS)GX87@)2ffo=6$U9c}iKlur>K;L7XupV?Hc@m|U zD|z^5Q*kl-8*afYE2%hdHbpNh%;`zD&s+UZ`j= zclv?!wR%SFN2afptXVb(`r?r~@Ck2zt%~T*W9|U7A0SHEkntsCmyQ(8@oJk0XcO=a z#sRRI0E=h9WvOr+eD9cJoI-0!OpqS~>a51$hW0KaJTw->mf8uI16Od_e>z#MXEJcu zH)Ry$?+v$lJ}T;tbDbT81L4F=c?#jKl?oMU@^U3>GGfsQAM@9aQ6)CVN7C0y_QSz5 z7-?@6s^9OyE3`gUlrnqa5*x1j|BegnKvRC9`xWpH@qh(;-z_1V88VK!_g05-Ive^9XYryv&_4D#A27xC;c)YwchcZH9Iov7SZ97v;c!kz8hDIJ%d(&g z7GfMVKSA0v9lAL?f$dqW>Ndnt!XIHXoA$hevF1B9Jof*=H#Apu^ zN|X3EHMEYE#z0nSk8>N&8O*+Q2krIaa)1xJ0_BcGUDR_f@$N11Z{aM!h>$#m^NXOe0gvejC&|QVk|)%wx6ClY1>fpI z-v-=)TAcmqWC;hWX-^B)UPApfsDIQ-i*pXO0d)TFcAS}(m%VQJ@Lm6!_F+lx3v`BK z$CGbbUq-)5^M6)JU^%!B;98nYL4-EPyC`3e^2t}=#C`8_v2d!E&P=8@qB5y0tYJ2! zpQ+_qm4ebH9a(BD&C!tbHq z)VlmP@(I&B{H;Co%}#v7!M1`Np2pl`jg9JxdJ}E_2QU_iXko=({DlhU`acn{{&P6m zoM;x#E8N~Mg=iUm4&xf;+Z~h+IuJfJR6g*Y*$eM5+!oYgfCQ0ae{BTVa`$zDYnBvWQ; zZ%eQa;rv9Tk?$ubR44dWKDjz=S}5&H^wS*cO))J5$EJ$w$buKLvoMo;E5ER|o0et3Rajf1qhMxjomr_uq(nLn?j_&H{$`>jqxG1?pQ zNIq_i{c3h6Cb=byL+MQ5uuU@vydGl_olFML7Qv>p*<91$5AUsGG@*WBQ)Q1{4a4st zSpg1O3uMu1b6^hqG@p#PB{R_oy3AyAJQsq&ddzo$gG+0(IY{OqGcL}gIMPh$qk#j> zQ&F7>cfuJH3ds9j7mZ7&N<_B>u1K~ZHVgWIB zm|{%?<;7xw$;C$NGFv~`duF!hW9U@$(en|je)wbX(8rLccli9}#c1CnsLzK9$dBqL z*mq;T7JWYWDgkYhOl=BUB$KU!^8bo;3PkrXy~8@9U$1^4Jw(g*pl`#pe3rhK6yk9g zt?wCxYZTg@Y@oiF4eoI>u47@r}A#Wcf7>&^z{?)eP9+SAcgZm&G> z-n}1rK)1U_p?;fD4z(xh`x&2WJB~VkhW$}aQ#x-6_EUt%W?Y2RHu@H{8-+5UZ`HXu zx`#g*w7c7d*rox!?b86_LiqF&7wvyddyELX(_&k&= zhUAIPzovZ~c~Sw(9%dx+CY?!m7|^!FLytl?lHQz(cafOSnL+Xmm~cA5E(46(7Xyyo(>wZhDe2W> zn}hb9xI2_j82{ISKb5cIA1c#WbgGK#L+c$yc0ZlJuGRs*s?*Q`ZU&yBI0exvE2Mj< zuEc{>-Y(E8nD-v{O`r?$0rhJdv`e@j{(<^oz(S7)=cV#-h7#(j>SD?ZvPJss3(~28 zi*Te={GP$gQ=j6>XQdNrPKM> z$B@USFO%H6j_=0UbkB9UVb=at9<6_;rnn}mosSps&+5hH*5#1 z_MmKwrx+H}Rbd-QgK~&g^~j6M4a%=Il>Z-lJ0ELh0CG+ zk8pN^!sTbH=cDtXaT0J){R=OEqed#Tr5nF>83>)|XvEBlMeF7Q<$B?g7zeTj7F=Xhw&#V|jA|8vzkb(?2?`F!aD^p9AYk~pl|3)yb9fw5;UCh4G?hp&@#A?+7qH0=WK$j*zHw;-ITy{McWB#*_2twNn{LY|!YdF=W8SpxEm zJ%gD4n^c+qtg?ZSg(QZ^SRHBj@ps z?m;&L{664QoWB8B5#PcG>*Dae)@XACk@18Vn-97L#1l}ydh;$f_NRic2Ka}3mduK?hHz#Nt=FS@ zCr*lWvV2>-t_bs1`Fj#|#kN@FgSNTLHH3c6#ET1EvvHqbe+7FN(mr;tz_0&`TOIpY zZRwFX6Oyyw%od7UQ1{`2e~#kgLU#L&(CbD#gU>#pd48%t*}X9e>~9b9!x~Dm)5YR@ z6;u}cgAxuauHbe{f)4%7r}qHl#?|Z+f??VdW)fB2MFzoC6b zir~{@>`nDP7x&>b#Du7@ivUY=&&;yG8Sc}m{uqOh&&IHoY#88VHqjaoq8(zDE!(k= z#&(SVX>WOT@677pxl}=4DB>y%m`|#)!M9k1wFc13|8f2q#vW?<|J%Iz1;p2KzcO#m z+fi4V*MuHsD2MiICH@q!=P_(R=#QnY2>OM;oMLZ5jRB-jXOzio(U_cIP*sXuV8u`2fZ9`g02gQCKnTJ9OiKO7#{b$je{=b1)Rmou=hXaLwMqI{PPKi zcao|fx5g2FQ@+&h7=u72;$Z)x4G|9kUZFF>V`)wMTV`8q3ihn$@DA-GU@itawLnAP zUYYwvoiHcLnUEg9Hz{eT5BAZHq5BlnhxXK_dz>Z47z{5sL0F3H0!2B_9mlaVOgnlCyJhcEZ0do**kV$-{?n8+7o)We( zn4*m56kBTendj^-$pBj7iW*{Z2In`HIkQiL*O=`%=y4MDI35rANiffG@{?@eEi~G` z#ryB@{@cO8H%VHq&KaSv`7VAO(qIFSZVA`l1O83O1)sx47W3oX)He_>i`H!C3y8rZ zd)a_?A=v?+(OlSRI?F{gCr*g8=Q_vN+0rK=wuzzMiLeX%#=YpEIZOfbmLBjX!BU#2 zOqdXfGmZ%FfM$o99*uesjJj`>IdQvWU*;S?$5zl6^S*%zTgeXEFHGF(y4ASVF*t6U z3hT*+O+~g8)e-Zqq%#qtruzK2eA17>eY2qdVY41^b48Fz6ZQ#){lb}+DHNYb=b#jf zLq9GD`BZr1IlHiHR+$#x(tJnQr=R42ZAZMKJ-50hA^cmm~i)O;5L0UfY9gT5=YG2rqm(}K&gS~s<^BI7?pe7Dy z9E!x3XrI&&9L-4*oR~{zC&+G!H}c>dAfl^EU(|(1x?qEEwkWta8lQa1705WH&TXbV zMdLX5%_m}iHnLx+zPS{;Av;r0N6hg%MXTgCQQLraX1p`9!_|^0*GcEZC7_Qbn{vDv z^+i6UFHp9?lkH3P9o9$d%(5x_*6cXJoEm58|1M2xEkWZ!CWipe__ z9=>S2NBD?(~*pO0p~_itOw%x6>0b~B^&W7WGj9kl{&JP!1gqk(m9^Hq7l0U z`8_C_->4J-uYMyHDp|-QwO@fk=^vO%9hvlvR7&R=?-I>})V9%(zLLmhj0?6E=AbEl zg~o5>3o+&Hbkn|ZgrC-g^CN&4bdHPgz`<2+=orCh4g&Tt z$9V>{-eG{q$%+Z_Q3<9U&Lm48r*OPLq1Zi1Spj`cW468S_>4m6HS7T_?X84O;utpu zV`+*BMIX*2*^PBHu-m6Y9}-UBPn2^r+L`btyl9_$`i}Ad?Lg6>rIoKe;eOE&Mb56~C%+C~Wb85&wx5Bqo@Paa#zOmsO z&_zJ}&rn?Cqo#3mq!nWq)JLVMozB{MxzY%pVc-?w8(!L~5bsHPn;Jv3cjy?U=wGP{ z;WP&EMIT@3|n^gV7|Cq3uXrlW1GTQL^jq4wVtdr5J9 z#Fr#9%TP}f&I{$y2N=Qs40Td{IFOsiF`ugTd4S!Cy0(R7#=H}zi(bVnRs4V{V3qYoA(#M_}w z4v~I99yDegHW+;@=s@|uNbgBc;M-Yj2ViA4jcMOY7FY$v!9t%4_zrfe^HBEJ%1O+{ ze{El`sAH6Tl$VP(rE+0of&S;H{c-QwY9?M>gOo{ny74lK{CLtd@eNTSKM^In#p`afhpuxE@diZ&XCKO)? zol~y2E>l3e>wbR^zSlqx()XmJZh8^hEQ5!CEmrzBHNQUQBOS(U!8JHM=s~(@4|pOS zycB7E&PivE>6DXOO$yGRQTDuyYdgsv=)V6?ID3rNwLm|Q*IRFc9)l0A=w){q_(-sP z0YBU#(t$_7hez~SdxZTP-ntEZeryQNa4E)lNNl@8b0L6nl%PxzaZFgV0R0`@Uzcq5 z2k@TRLw-K^5+6a{6xXjYF9(0@2T$T$V%QvXj?q@YQht~RH}FNc zGk{e8c=!xs+6P=jJgyOW=weW484!Q>--6-wE`6)Y{BKmfW^UzlyMpjKf1Rb^8N%;|He(5X`JL<*?R38_`$LScIC9TfGpbv-6QP2F@fqIaR+=0Du_u(C#304St z9Cn|?e5sg=z8iH7>$;xr3LKmy7{1&ins=YV)JOPi=D(+MIAP!8QrC zx!T^QeeQ^S@R>zTb0aPh^S#*Tfpk(XF2p15!aHgw;t9ci5`4D}b`avJLBC1BkB99@ zZOECnqdjSVm(W-VYkknigMQoHQ*llg(TC25x(PJGp1#hF$d~K`oKIFsJQK8=h_`WG zJ#1-F!I?z%ZBDd3cpLTu^d9^LpdZq~-=gV7r-<{caYm0*R0^E?$wq@b1?zAK{0tbR z(;D*Kgo6}}iP4}e8|E(wXXpn<_El*#w;84hrQeKn=w1i4^**E(5Ik@R%R2gQ(Bdvf zA+J8S*ZW{6HqdGU&w| z4ADgdeW(p@1AX8N2kd_M7HNN~Lv9KBhuUHgbP>i@*G*e=<+~uB5^xKCSKx*Xrk)4R zq&z3qCOY_ZyK9SRbGaLN$Q|M_AR9Cf$l%)|8nw1-x&CnWEy^W#CQBk`JwY!2%o{g$7nx8 z_S^u`PUo~>olft1r=5hXzVF^L{Df=Es1q)-Z?>S%B)g5uruD?3I>R=@KANF@n#tCJ zpV~lYoY5ErV<_O1tDfBwd>6jAxl}(C?2&yOr<}o@EzJRuk5)7%sQgNCW(<9K8t5RP zOj-|s{s4U}+C0R&8a!hh<$x?zigxU6V8{9*@Bz_Ev=>wkBv^@L4f_Zwg--ZM4^n@3dgJvdH5(;Yys%UQ1`u{gNx&-ZRV$Q zakg~Kwcu!}z!aVfzAG?ct}gUWkQO*G&-e-Q0dHHRBltan-(=3}Napa2-y`@%x+^)3 zk%_});-Zy55N4k=cs?f{22V|!=W2QjCbg) zLXs!qGtq+e2TJfPFVUQ#rV-B({p=~2vp^o?vyZZ4JbVFXP882^KK(|Zc6izCPS3i- z)zKcD^$2=Ak@q-z0>2wqZrC_x&8ii+WsBFYU%7nULu*$(wQ_~Da{c;s>!(NyS3bUS z{i=;m-ZEsx&C;yA4G(9pTe0$%A*+9LGm_S?%3D46H*1gvbQxQjx8Z?RYx43|f&4`PJW!n|#f0 z=d4?okIDtV93`#&&6=#$>y|%Cd0ffQN=2>9@BM1_+Bta}Hmab#U#lhmXT8T?yWUw( zZd@s$w7iY0)~%IRt(EeAvtrdc=@yC5zqCMfIbyeFmAE7v}>@!=`JX3P-t_!ZLd4J((osD#4>nQX3v;$SLU75A6&Ch zT9LOgZ#~{EisYF`&odF6o)&>$Jcs`*xZmCDIsE?r^>@*0_>!*B-_-q#dG;|@j?0eg z_qd91DSH_+6)`po*K6}<`|tk(&?}5x-p-g2N@2*OpeX{`7gH^7XRIv?zf*B)+62%S%HzLB z;JYD6N2kotG0h)8a`z7s1EZd6Yre*b>^U%)8>qy-?F&yo*(aTT=va_YaaPxjWhq_ z4VjN`+qC(q5u2ZX=FqcwTgtZtaOG_|^z8G`jM%*SscoAwAOCoRGyjVxLcx~j?b8=H^$i;Y2D;En3h35#MlcF4#v1!<>n>9aWYS`O$olVhFP z9P{9L_Y97u;ePTQoP)3sXAfZ0t}@)4u(4zYE-$WA->vzv`!bzdzwAW?qavGTUiDh#fGpX7;Sx695b;f7Ri+6FLDY*C z!Uw`GVTDl9mDGKA_nz)gx*gqOAT@AnU~%A)z~;d2z`?-p0v`na7C0IBGVpES$3R6u z2~-BKm?uylXb3b0ngcC?1B*Gf`7U_3?&Mfti)IsJnoR+4N??o1mh7*p#02jHTN)l_ ztl{D7rzb$tOP{!Y`pkzIoB7c7(;4dUrCR#6%O~xzc;WTG-?f>s6PvG}{wngOi~hS7 zepEhPYvCTgR{DL8uv^kCIyyy5PhR``X-H27{bQ~}|DV_$w^955?mGGZgzvpb zm#%{!rBmBqk3Wn^+XVbJ0l#a}r|N(Cp75KE@`qffe)N4<{vHUkALP#yx+ng)i1s=6 zEAb1Wo{ElyA?D)oOrxX8%>36OAO#}b(b77gx{j1PBT^&ZD3RR%bE!m9S zlKsncZ>X-sKf&~Cmrwi?#;PhB(&#w{B* z>{NZvJ0rPN*zn=MghTzZo-5gYDV4E z1BZbEn>g`#;6`83UnJ`XxJi@VuIc?PGG>z}|H0MMM*U!kaqOm>5`Iy}K)jnWWkY3< z_B50kzy{&n%{LcU_paX!csF(GmlqG;gQKq446sxj1}_}D<(8Y>LoL62ck8YH?K)}g zd6xvZY13x9dVee7oyF3i^nRC&(laxkarV?%WGQ%;l~u3w@TvNa&(4mj?BT0^EENr( zlk>6Ts&{Pq^p71q`6aS6e5ht&=gU=%$dW>u$6hslE;vrVsK<`w^DwM^B=R8^WZGhPey+3-~N?V z0`PO`tMsO|nEH-&nxQJXkD;C{{KSH@(0j~V{3eQ1^>R-cI#uz1Bq%rnC4MX z&-Po=JY_tj0rj)8K;Zj-{*{$tblh^V0OhnrcfPrTmGFNQTkri#s9du(k^NU>;Kp2b zN)TAv%tE{$9Mv^^Sy36^9cZ0Vh;pfZX6pdf&*-1Ef|c>l>-`TFqTDG_ZCNXd&H}DY zeI~f2*=l|R_puV>*P62raD$`TU*3rPKu>xm$=t%SVdZKXroPH5Q2(|$1b2T#&7oJ> zSvrlJBMZre>9$4bk~^@Ox*H;5`MtEK3r7UjAe8Tm07XkLuc!B;=n$ z`K5mWxQelYw}N@f%cgNYk1$Rf7%O~Qj_*!SldRRj{9d|&SvxLRSZ6ufJ$FQ^&x7BW zMp!x(ez5V#h+JQY|6WP~-1d1~=UMPU{+JXWwn$?e=Vf-5@T+x4#w^1#mCIiG8~Z@C z-o_!nWf5Vx<#Y3nm7{+1$1JO>R_W4bPYT0=(0O8K8SgL@jZQ)RM?@{WW5u!eK%WOk zuXyilu-#tT!B*??=Lww^pqC7|YSeGT9m|eY@cBBpmqPimz+v#cccPe3f_k+qCB8Zr z-IkMxb^t%#xE_3|^0SQLD)WvPOUO~wwz`1%nA6alG^3;fwr1<7$Bdr_^?`f~(p$&p z%^^7N)I9J}yEc$yVIQHKwyAl>(h%J1tUJ&=VR>!|;F?vqmtxwct>{;Z{=I3!@{F?~ zxUT@`9h;X>2Dr}KkE2}1x~DDMrl9wU&MwRr$Zlz ztb1e@=<*MK$)qgMqcboQzn&mn0*jfKYj|J*^dIbpmV5x1m~Ezq6A}*fcO3&oPW!b{7+T5#TjKG zxKDw{zm|SD=q%Cip1sI#jqb+>rVly=n`F`IQ&I?SCzLgFE>Ba+fuC<~GV6p~HMA$A zJjO0|C9^QxNj$eKPkXHl^b5na0A}o{XFXD%}%vepq$qGlR@V|pk+p? zwGQ&!IxRV*huHQCe7Aml%C<7V{cvlt+HQ*{ri@Ym_k#*YbTPm9H+-MmC%J^$cmAs6 z3J=<~C4O9)9p$tnE&zY2aL+yjxZ{12D+ynM^Wqn9<&~&!OZKGq@oCkRUsJ!diXdN^Hp2nR3i_p&5&vaBIA8H%Ow!sn&2|d;dHbc}y;^Qj z8R+~i>Q{>PoPRg!$8V}D(ww0^ekRq0&T;GsP@Kv4B z_nQ5cCfjAQnozOtQX{!sn=f%&tEE;>f_EyHi#>|`a_Z&~EOLyo?kC@JOq8Al$` z8G7>Di7Dk}kT=j%sZ-n6TJ$yW{cvcqtpafKr>9hSf#>m|$)2;=k|}d~ic%*KU2@?( z?h51$P5y}ZgWx>CcQ4>h@lTZk&Ql@~z7}~k;EoSTtt(^qMC9F*rc|Rp%^aRuSIU1V z68$_Xon;yB2zER%rS4PkOWtj1ijQBf>*y!t+J#~cyQ|o8hz5{S4`loIpeU*26 z8os|LvU`wOmA~@at)-|3$}O`5*iW3_Bz1Zqx4xMY=$tQB50uJDfB5^F(LRI++ja@h zCm*nQi2oe-TYMh;c5h+gDRHf?@&V2lY+uvv%XokEp6p73`}U4Zz`d{gHV@zvq? zgQq7ht%Q7@ePC!&NRL19CE6$Rj;u=3i$`v=csyvw#Z$9BDo20*)@>Hho#<>jSdZ^N z9BDy&qJFnnP_DJZIVsay0seaH){N4SeelG2i0iHdf zesBlDy))19S~-3lA-HYxEVC5AHLkUE2JM{KE&rhMre=FdZ|uDv_<|2U8!O6o=$qf& zuPq7U8~aiij`YypTS31N+$qd`5M0py>wzn~3ND;qx!P{A&rp8r*JOJY!2Q>Kc_pMb z-gzLyR)YNgICr8aC~v0SBW<$>?S^sxSkYU~OwoURKx?a3`O5SxwOeyq z)_WzujNdNwptequlemQD>pN-`!%K`V-2Y6dh zj!c`s0Nlw*IVxX$J0}x#UaQ+bHXd|m?633s9I90LURqlNy-`0khuJYJa)j!~4~aTB z)@1%jTP(h_G$Uj`OD~e1IzBZA{K&Ba@Kp#d=NRDr0JzeiJ+vc@{aJixUe;@N=-It! zH?liFpO-bNj(<0D=i2NQLHkPj$4s_DIKA7{?^C1~6F>9+75#@TrnE|JZp6u{vDNRX zbXH7Hvv}@wG(U>$xOeW(oJ@9Az{p$5wI_u?M2o{u@fbyHvCAu9C!U^{Gp7{%kvG5s zdm}@8`oeUP`iW1U%rG&W}zpzbAUik35=O;uQ|*pC3KMatw0v-J{9qze#VH zwp@l>_(n^mWvucXzAy0zBceVTJ+xn$3MYm7878ac!Y(NXKZNa)64)iwADw_*Qlj#o zEU%+y=(SS5=HJI3O;fx=R!m^fIOC_-=A`^l(rbi=^c?Z&$&6rs`Tjk?7y3NAyV*>oQGFPNSJ z`C@GEgK##1PJr{4p?o|mo?y9H!I2wrAUmbFgvwoB3H3{lPlkR)e>8*ah>GZ@xN*=wABqcL z9~1}qYF8BW#K!ED(qoXv_0yB>)hPFa>B*l~^A*wE3sT;$RLeE*xC}f}7N;Cj&@PY7 zNUp2{9`TD)4k;K16wE+>sq(!i|2*XW`{|NuPaU6;oKN=sUKQW+ioFD<(l7U^--GX# zkEeDk{dxXEw43k`emS)xUwJMQ(eoY^E;!!$_oP=76!eo-Gxja1;4>pO9C%eag?c`o zw$Bpk&;LOEZ{_rq0~M^=**u;25ABgd?eW3SnK{X)g85mV_#5yA{fh0N^Mg72PSJSb zgO@iJ)A*|@hv-M`<|%3bzUk9b>dN@?ipS7ybwX~$%hOYg*da-6w;;Za#ai%jTe_vQ zlS9R-r*!A!qJf5C= zO63>Rr!-FaaO^m*0{d+5{prwu0y{H?2j9C5+wT)U3XXrxJ1StOztuk#b|qtvt;z(S zj)=OnWc()T7u@|8fj@{Y`4aVS6QKXjV%#?2cFRsL@8w>enq?ySEtzY9J+0QSs1SaY zK+Xh=OL8OHwwqDENv39utIwjI%~_MfnUFY57L6qpUd*HMf|gZTxB50=@0M&94&du%bU%!@UjQte&E zbSL`34lPR~yL08knUkqs^=MgVnYLOusb{_tl@A#EAC#M#6+252Cx10RJGPR>jd??3 z&z{m+znGsH3%ySLr6<3h$roSWVq%@JZ&$4`0newZKYSsU`Ghjv!}CxN^3HAXcuedm zoyTJHl!0EJ*+)HOPtx-Nv~%z|h2SRFvb8mNQY_>ikw>@3e&mCG$s8K1oYm%fj?9i# zI=Kl1=Np0m$z}$+=*o2IISl&gehxNKXF2yNPrqk{9=I0xP`$cMb#3tPcLw3u+w4r94{xxiE1EXm1oikvE^$wTC!@-W0!jF3mlH_D^r(efC1tZbIk<#FyF5p}L!K+oldbZ6 zd4ar8UL-G;@09P7m&kX^_sI9kOXd6I`{f7ZTsco(CNGy)$SdUs<%i^l^oO*-_fyVj#QQIes7UyCrakLio35#~OB+*PKH={z-m1PW-Z5pv>JplgPS333eI0F_ zZeVQFjgEnl7ZSQJj6N6J*3wW@pHL;tmG#kHO>ePT`D%f_1Kx)xpE*7(b@KZ+h-Vq~XbaJAGJ(>$nSXe+B}_V&9x z*e`kpR(1vAnv$x!n(HgN9TDB$SmW1YzPYh6s!vQ6suA7YFD4?kSrgr;OAy64kMM2M znfPi=ec*@avvK}FOvHKV?65O^J!w^=f0ld(%^+rs6cR3JeI{LOy>wRa)%rSk7vELi zB&(3h&#^Hqz!a7>b=nsH6vU5 zwxl&i4d%wyB{zAwy0*5KX5CNyzm0Ady%9=WS>SxYpISGeGsPbjA2C=v8fdo%1ZQ+( z#J>#}nyU@b(XIT?oprTM!&_sU1~m-1IK6QwpI9~IWK^4`A@0XMp9k8S`?U`3(0jT$ zV^w!E&wJ`6XP<;lV`M{oLs!CuOt;je_eIr5bnBAK<1Sy;UTSHn6k8gbd>tw6@myC# zK%rLB*?U~1@a2(Etq_SCwLl)C<1hW`5KX2!){7=LcGGOVi` zCQ3AVpsL31OG0;dLX*C=GcmGR>eR=3y1Tohy8{C+CPX$Hy8OoGE~m$Ev8%PaEvA9% z_DB1ST>*aV#Xj{WKB_CRwU2URwTWrEjc2{wMXo}_M>Hh-6y4UL?P~5@-~WO()({`l zY1FhO*9~Zk?2fGUH+N!W+uEkT5OGnj^%-?Ort|do4K%WdHnAbv6X}cV7Wul%eLNjP zbyTajmG>k!V)w)P8*1YC1Y=x{-=nLK<{FY~hWdoA#D?+T$JAVE_cldGXhnzMY3fs> ziK>e2zO3UkX`a4f;|+BNu3xOF)ALgccVS>fYz=<_8)EqTd8563JTZ0g5z)p#byRym zs_$pKC_2u?d76c$KxAVK>mCfAFr3#k#nvW>I(s!;mKCXXTbge(Kx{uedjkpk5$G7o9v$3&nt;y4^kMhQ~n!E{@ z;{u7b3C?yycT{_$mWNi1XzXfX9h`>i^l_fP>=LhUAKJ-BH6(TV`ZO_Pjm{q_c6!@t z_=biST|<0zgs=UEPJ<}+4Meni`XvHXs_~ng_LL8=GqUnkLTU?a;J|fu_XP4%Xo3TeXqgkOpmH^$5N%Gh8-Z zjIOPZYikO$HFf!0b^iF4n5wRJUf(JjyCS>0HA!v5YNId3c>-PStWR4 zzA3t!i|uMkZHRAb=i1^LI-9$j46W@<(0H4>+S?NV+hlBF9hc$)G4UM8ML5$%vZOqrNJ5kfw8QsVNLTpD=eQRfXr$5fE=e)JeTw5fLzwJ{Sq3ufOj@5ZN zQEZE->!)k$^0ymwLPU30Csz;OkC#=6HHJ3U6%)`$HX5S1J{>V!KP{BB#-I-8eZs(7et-Tm()Ih>*l*!J3Au;qsP=1(1`x12G-JC!?lTiU8^S0-c_q> zjqBq4Es;KBf)Hg22vJ>qOUDg@( z5jw8R-xPbkwfnNKwGR5PiwlSyk#&*n19frw053$gX*B*D+7oK~HpbWUHIWzntxm8| zOpVFk*6r_zjBV!i9om8I#&$7Ai0<-6c55|ayO$|^O&@QEzs0W&bai=n3@QBR5jr&q zoT)oH5U;<%r)%mKn)T&P?>BN0o!y3rfT1(O7t5Oc-7P|QV`mFY1%0a?U4CNyfcij- zK{U3ST4VK5fmluxi1bC68ib1tP1**rjs@B~`NpWO0PFUF|9qP0z@Yl5PCXZ?)B3ub zTWhqDfj~!doX{H4;EQPE8ah33?J=#f8rH#Dj9^<$C+illJ3(Z-pTE$zJpd;439jy+ zO%B=K0Bg1=rN$tZ*4>|%4x=*9C zB7WxH?|#=No9ND*_cfihJ;&i@YBq?%a9Z=#OgR=8q{U}QT^fX-A{m<_9LCkTIWN+j zIU^Xg7)ma0vMec6QWVp6;DysnyqJ3+O^IfurWA@9iTsS@C{Bs^N|0F)J`o2Atd2AB zW-RS7dLWufKnK;B4q2L)SdOdCAk>lMd5%0K=8zD6u^>j8o0t>{$3M!ltf)X5*j`#s zd*YDPjDYf8b;ixfVB!0EEIQNFMB$;yDNc$+uQV%+dBPEFlA&nF(f!ffM*_xmSf5}u zo>T-rP=qkYc+he;Ay__ehwdnLq_OG?GsmY`fr}(3PWgFWmZH$D^s;8g&kvKC&Dx^j z_);&31Ch!amy<;^v<-zN?S<}o4jo7|6d;OdO3e6`C~|Xj-3Cer zc2sZ`E-(zoNe1dHHMFL}B2O{_O|vpdt&o!E#xb8{g0jcjW1kI!WEw1zG0A&M7>ATV z@FW*!1COC&l_98zvVGF$yl51gY~t{d%Cauu<^omqkN_jxysM4_k7mJa!i79As6h@l@bQY@SC zLKp;SrHHM_5h;oZco~^go~y82NHa9$0wt}`iFC;fo+v!+V3wnex&OHa&1V!Qv7bdO$I$s1W37vyecf$H^4< z86;e6&2)p{ru>xmIDllDN@$DI$W*-QW){>$!T0A5IE$Z53DR}LvEVY2sS;T`3OOdj z$5}_SLyMtHGe5?`*d!G$Jl_p@DxwM14jn%$hiNw?6P~7NNsk>7p$9}(Z>zo)@dMvNmnsv%Ht<@IBDeq-$Vg1=Nr~hyQlT1#3pQpP zdO^{4;t;g2%+Vv%;{r;cWB4gNmH3iO#S1PXBF82ZU2KUqAAtmF=(!*jCadSj6iL#y zknq>SBn}*#NVw1>rxFyLS7ahgI4R?jCL5Dp!q8DN6&xZKOob2PxhDp)6VjxU#6GV; z$ZQ&dE^7>J(h&tUh{aLR_HB;$qdsp*grG{C7YBSIW@9DfyQ-h#xM1$P)0nhq_)T_1 zMJ$U-wFN!6@;QU?F&{2aZSQ zVMQ5Mi&$C`I6ubE_)+919Sbf8PkN5QT7;dV*f=0L&JVB&TAIs3mR2pE_55)vkrHEO zMMk)YVxMb^u0$xXYb5QnnR1q9oRD(E*dkriv01`%_$g;&)Q(DKsfeNJh?Yd2bv=Ui zcu+l?3ZjG|W1DdTa|#1Wqv?T*1wu&2nNXlhuz?aZ$%vDfattH3;&DLGRAQ3?4RRi- zH2TkE0e=m1HcA#?{~-4alJJeQ;i-laYGo1qKVI-w#rG8uSE zq(O;EWF7y0XL24n@UO?8Gq% zZZ@|Sf(1%ISa@C}c`lJ;HWEMsbsv941&-;3i;zfI4?YW(j-Zw@02xAWVBNG0Wn0>0Sg{@Io*h%6?GhA+AD1+Nr`aG6 zD^HMd45tR{G>RdJIujF&M=v>z50hudY@|TbNQRWn6q}deEzkxxXUV{g7JeMKGl%x$ zC?YjqI(}V=KTHxdsjs?mT_%<707gQ!rBKVLJ#dB;BMKMp2(;$ulA|?dK z*73~=h!5CmNQDe9azQMBk3i@NaSRR-k)Z`C7De)*H=z>_{}3EcC$vB_U>$6@pjQC>g1e)H*f(r~p_#}bgTMz_w|$)qa4?7}FqA+3CI|!W|9g# zgg0=xzC*ewjU)vM?2`a@<^^aEqAV&6rcFkK88ac{T1iYMlu7$=TEP5Jh|l5ABqfM& zGgvO68SHRLVJaT|_!27_V7?NV(JiX8Zs3774k`s`!7=wiK zBqB7+6@+M1MR+A5Todc$z|C-_F`moe?3dTg;4qUUWHhWQOnldkU~2=Y!HOIthln@^zv!{4)$ z42UO5X-h!jvAV<&g9OIQ!y_mx6-u2%jLU-m1d+%HkaO6M*i#Y~he=S_HDJ_pLhuhi z_7f0%nv)29EIzJFcH3iQ*+?C;(SRFGMLcNJ~&t$u9zVycx4a+CnN(F z@26pIunU|nK#_zX2?7oYHXqxKXd4m;o99Ef0ybhf+)c>E97ica3=_#RQ5=MxPX>^9 z(j&s9NP?F}h#O(cxJCHS49&qDdkhJMNhrVpkwgI6I0A|woQzy1&>3r!usfVE0l8V~ zuLCqja3aPjB7_9Lk79gSGc-$sK0$sUT-YLb5k=UrR7uRz9F8WU81fG`D*+e5i}A4- zeqsa~8YNI#JPogb5+Iovix4tcKLXGQ1A+@%t_xli1Q3X*x}{z;%NzNC!U!Q@KGop3kDj1 zkHN%{F3tmr5zrtu5fSs?Lp06LPO^i2$%TEQ^GHwjNawN`yW&v8uI4=$r z*NmS8^13A6>qAd)W`uwMAN&H6X5kLPcq~C0hZ#fFV19uz49FUd^#X}-r}z}?bb@QZ zA0f{mZOh9FaUkH4%Znp%^@#Ps1Sa?emNzDrh#SL=3YPYmPDl!jlOaQhA_gWfFrAPL z8oG%4#>1iSP!b3dqznDb7@t7UI2R6#j{smp;=siM2PWV50?2=WBZRCh9|giIa53~5 zJUgJ4Xpg_gx#1~39kUQj913K9`AVE700iccg(`!bhfBDE<3xd?17X2#0V}ZTFtT9F zP)R3D7y?p_cfv3r4;*191o#X78lhQ80S!qd;II8bR4Ed>0QSc=-ifFmZUX1MG)*J} zEnebbgq2YtC={R|z_Os8Kr(PH2J{FB46+Od97Jj0o)aQfi;kI>XyClS&1^swKo9B;Wde#o<3Pq@2p^BHx`UsFQvylA5&{4|5d|)E4&o1Y zfu;a#3@E?2G|WIZA3zD~;X~VSPLLdk90$(`Dn(;12wW|kJ(<960FQ7h0V2^j_<(^J zEhTm7sNi`a0X1d7$+3=TiIo6EyaCt;;aTnljtImRkA(;>U7Mw71Bakk0COMs1w%py zAz%g$0I&z-m=f_R08p|tNCa4_ztp)Us5x+g5O#rC!-WHf0w3NufoIVX1R53t9AKI4 zfLuW~un$NRv@`i{B9MMyWU6CZ$JLiG?uS+dax2o9YCj{0!U@y8`FfP3=5XY74R^?|_vwx#pEOgVsu z{=qOq@^M%^GA)48C7>Xk2-5^ChSDve0ZIw@Ujj0WBC%9-{0R0K1WV7x2i8E~aByIN z9vp2EkO_PT4&m-0`v6;rgzrN95&D5_EKMMbo#Uv95R?L8dE6{604B~3y`?TgU$H45 z3vO$va|okghq$ukC6Gb9fTS$t2Nx1zb$A#kH2!5d_|phFLQoSIo?!&iOT)3mzu=UR zb0#4P9>D8E*PvNTAa`+5kf^0)4dE-3i4Vwx0ih{~HsU*Abl{H(L<k8>;%gv@Du>H;krS@LjnLcaRf&TYywz_8(FS}SUNkfx1kMpfeK(5U{^>G zhs1}c0u&7o!#9K($5l8~0HWXnYYD7;X&N{d6qy12gH?fNXkeL;y#T@C zi1`C05McFz8HjD-LY7X{{|%x(tvA4gwkJHu5h{A zhz|Ha>;)1N@uUO<`NK{?=)gJPqq*TSv_pbLL3QwyrANghI}QoN$p!d5gyq1QENvV} zCV}h0vB9h&WE0`6c@SEH#qwd5a33z@$Hx3gkrCCGtja`{0!zNCg2*AYD)> zEEi0D$*;hGMaYPcE#nNANE9)k0nii#RYNQui9|R+OGgDaNWlTZ-z<%5vW$&@up=S^ zSHMFKjRwc^mk!Vp3qa%~c$yIhjs&qIfr1R64+=ndR)Cmef@ya!aX3l{%^w^fSO6ee z#3=vG0fOsEI?IR_i6epo1epccaNv&6TM?uc4iGQ{7vy^j&`Yp?EG~rWAOf`z%7%l= z@=FH@&`ltCX)i!5VU3rr6&xTmmy#4>Cj#7%5TP6aCee-|)(9McV&f$dVoo^95OHJ( zEvQWrd-Bo&TGB8a4&33TFBL3p>CyqhivgW*fOuAtp_s^xf>JIWprzvqea3bE!2yEx zUphe4Qa^Dnh!^}f2PkCme%e_&Knzp{-ssW+;{SUG$XO~2>=YMz&}`9I5u#AmQwcrbbywm^8eET0%QH}9UwTh|8EBfZpZ&m2S}FN_Ir=0 z!!zRWIWJFhSL=!A=SHPd;=N}?D&HQz+kXDX{ud9}2DxTml{Y>s-2Y|rVS7|fJr_3` zQORaQyZm<5AgX%z_U!alR{)$xsZP9i*89;_FJ12TZc9JCzwwiu^(Sg|6cE{~~DXLEv{Pu%uPvVBrPNV;w`4``{FH#xZO*YQ#_g@DG7fwEy zs<{redFd58E4?avz5Z%9Ix1J1tSFwTYv+7^+WX+CnwjN}Z%6;<-z5L?Jv*GLY)9ig zd*?*fPPay^+_`n;Z=RIWPaat9oUgQ$>Zo`3!Y@1Mz?;1I)2lcC?n@=rE_OHKmbUrZ zTKafxm=%VVCRhDtBlqZoo>M;Aoa$TC`QcG?=Noau=*I`$i$8rvu3zTc#b92_etw7j z>VX~*jAH4lZKnGAaI)AsE9us)Z!$N2nZ5J-OyxrJ<>>97J~hApS0kf&M&+OWqItF#o4lP)u0DP~|Kne%yKgW|toZ9c zYk%>dfA6mQq{U=jW^VuZd*Uy?Kf2y%+_)s~|8$?dEbxQELQ1YadLDiEAGHU+Ubl(z z?|<0&=083(Z_TC!q&}3~KmR59lmF1Wy8HCjwf;vxzFmB%ZC_Ani|HS9Chxut@BMO{ z>h8S!=(zh=Klk3h9&aZNndgu8vY&m|I@!OhkIg^+FYm7WbYE)9`3dJM6X*7M^WXnk zSbu)w)xAOE2Vb&#&7?GTGoGHLE5Ci9{pyabv&r_)-Yfq2)2OM+uBoLixz&E}+s~YP z4{tTI%-M%W*6t}^9!o}k=4Qj|E$z1-c#rP~;Uu&Dw-2<(b%xM2;mtZdrgGN!)?1AZ z#OC4n`ayqk=WStD>5tzzLnd@oiLdI8UNWlBR*V1iL-TBf;g9OltD0(z){?6gL^I2N zcf&sWlP}7okvf0pbyjPZsJSbZUgR?NOj`ZL2f^u`wl?C{zur(z%B#&@+>qKh%ZF5Ng}B^7;EBw5k~>Bztk!nmJ|i zY}c8mV=GbRufN}%>~upVeJK})$b=E2ow>DomWncG>h3r7cp_W*af%tLlxyUf_J(u0 zYxs-XR}QXLa8TVt&Pwx$$#$*x9$D9dN~?fBF}Dh%{(>8sDm&| z>iP!r>~;@<5{p-_RH?6U2Q<|&9M9vSK-KWJ& zKgjTXqBLEs=q%?TzTQturc<3P>Qf_UOD;!twv2H#u(RhgZ^ zU3RE)Z?R?!Yd-9|di3CA{PA`B?xI_<`B|FnsZvAUdYO^fhE#Z+tDmI!DXJX|GPf}6 zz3JgVujB9z-#YJ~&kjeHVx-$8>2xLYqL_bK_c+_HUZ#pCsluD8PcD>v*F0#oK0KyY zhJr2Gc74&hGwW9@dRC7bHU9OM@^TLhB`P(;d(XMOuh(6N5O_UW?amKhtJP~H@|bpA zeE8|)>agc(!otnUuS=Pee6F7;d?&v1gue52jT~eclXbGrsNUxkE7pw2uG+7D)NDTJ zE^;mv(xo@~R8!5LXT@1W6dKC<(}L1X`z$#x1f7~?<>GN|2JR_#51ZDVw`6Y4x{7#o z;5CYsCnaslkJg59xzA-!Dh|!gYQ}73WL8Xbed5dg)sY;}wp&hl9`k;tvof|yNwbn_ zC~jfsR_FSiSAt?{?G0N`SsXQEOXDCnQe1cKbZxd+>m<2x&PL`3ZWyO@6v6g{B+~CZ zN>z@_C}_2c-cUm-R%Km>;ZaeRcIK-Mp>(eC5!)#zW0>er9C4)%pOmhnwUg>Bs`o|D zsP|FsGe@(Id@ z=ZklrrP*P%oi+GulgpR}UA;(W&kJVl*-G&gb!hFNKBOvd*C*LQQWzJT6}l(-E3Ih# zBImiXS-T+ju6(L~ksQ3uI;cdezATrIWH~mSyI-!^oEdDs*)TnB`D=jXA3c*UIe1DOXjcDLU2?j7mxy-k$zbK&M!8I`|OH@>bh3&vT0o2vbOA0?Nr&|h_0y93cxy+!$K z-J@sZ-plb{ewNDkp}zAXm7ke4@o{DCn=+GF!GoV}i=B)wm^3%n2wkH2=H@WYj77;a zf?JP;`c=w;iMjbUywPi|YUfIBEG#zOrc2M)sRfm2Bj?78GU~2Ulcdm8Qv+#{_d53* zLDo*(%DJ-nidz}amD~_Bq6~NKD3fkwnh(je(m7YcC5!V*OMs^r+G`p9by=3nhJ2)~-1!H}orRzm&Ar#Ygv-DMK{i&XF{a&iv$>~h>TzE2CI!bVk5HTx zJEaKoBZ3YXpv<7>(#^(-1IQ6bTq<2 zXtGzFE5g+}b&+F;S&H;UJ$+pfUhc~$f=rDhd6q&DH0uvmW6u!F&r6x>m7xgPVVpQ; zngz5b#QBr;U@o(|TMy1R1B0ZCXBy`czC0`W(;UiIUN$6~kMr?L~CK?o8d-qGIp z>OsdZPX$|v1{KspRjA9=!11!?v>tZzPO-sP+nkddvy@ZSjqD^9bvLOiZu{KaZmjkt z^`!346w#U0{7!+E5S6*NY|WR5vI8O$bt?2w;-bm=K#U@} zxuU!+so1KGvRoq5Q{tFGHMcM;#}f^;xMtCu<%!V91=IROnB^Q_Aj$K)&hc&X>CIpf zNz6=6T-wYiIm1Iyk$ri;!z7aA(c{?g945)WmL87k?ERQ0W@1mkiz z&3l%}E@M8@RFr2iAJm>JYv)L>E>Ojg$g{AJbaJ#o2&t1?=FKM4NDH=GuuV=3ZCW%0 z2EvG0a+Ln=d6{F zyCnxTl(w%%vx!t|E0Zj6c26pqTkKzBrUf%oNcsBFTz~ zPG#z%Z0h9hd{9I%G~073WIHXw*9to;Q&g-3ZrYJXoU%YI6x~EyRHiJoKnUbm5Fz9e71#`}6iV#r86#*8Kj3lVgTd zd165`=(Bip`^ZkzA4kKaXGTE<=$pBWYV>cPCB ztahvl-(eKAA>xH{;Yn)eC0};N)QUA@ipSOTIknY@6>Tu9N?kfXc4~7c7miZOOh-Qy z8%rZbajd%8*rl&zndmb&&!*dMuK-GuWQTG6)II2l`t^iz+vzNJ$jZkXN zg?=WmD8)q!{!S_Nd%AJ64(Ldc)qDnrTT77!}_ytxZLxyMiw?L^?scdgobk`)MIi91qz6 zTZ?UVQtD>o;pVlFKh?5R)CBoPIcY2MA}O4$%~`IyK41`eKi)@c1R>6obYw@lA;&wR zy?4s4v3SSS({$jbU5Jc}i)ATg|BE znr?N3?5qMG+;_Brxc${?;pu8@@TlKRLO@+Ksg31Xuyd00NPebh=UizZDidS~xsH}O z(Kd(8P42vww9DkQJQicU5DrRqh~itHlG-(2*A@~v)!0c2;4<@8-`vuVzug&>r1AK` z1H~H(tT-Zy)^sJjtkVvH>IRqY$(BG`T8L05@|Um8$ zy5^JJTWx()H#vcH=2i0PcQ4I~!z>E3*q1Ube}6DuA&zf$(x{prr&5ii23kARM(M!M zT!644H<4}-cYc>%J1e-HNBe?ft{UTwIWf9@LS-V$&r%nwnKR65iKZ*82Q zL&r2_rnfQFkUx+{YsWd&PP8fN?t&QQV{4O|8t(xVQ1;PU=F=4@s{$ zM8)=WnbJ{1V%M%=TfhBLnq9%YMssAc#nO2PdC^|i^rMB z%z6$f@y(ptQiktbxA*xkK9~eSv8$47yKd66N;f^v2aD?D>iaLK{Gm`;ohofLKWR?N>{T(+E{alHDD`79J9VqNS#74Ies;3eNK*Xq_99H1!w26SG&N?% zs{PfbQn`%l=Y@GOJilT2=Gwfq$+g0rLGQt(Xq9@J3m<35Y4fQ3?7_>ma8xx29$!=| zjEbYxmQ+02>3b=JPFh;}H+N?q?>{*HbEuC`+398uRcS%O96=Pj@^g(T0+CzB6?z&HTL3m3UpG z7r9O6dLdH)^gMWu#V)oD>ayE(x`Gq*HIC9CE4;)7DzZbDARr9E*o2(Ny^zr+kBTOcZh1A zjD7vmb+ zN@`=;&b#xip^>qpRIiMJ)o8Wh)#qZXEOnfF$BfqAX-$9dOXb#cdTlfp^U?8c=GO;; z?!>pBc%MFLemFwM*cJ%-Sev8Yty`T&tme+vdt{~s59$8I6ca1cy4gGbPGh?2iKpw@ z)56YI>dtKL)ci00+_+pN1Mz4pe*R7n%`~)VmdAW3QHB&x^VHSO)TxZnU+2SMl@RhOWnSRmjXPhjxbWdpCPNQ8um)$(P$Sak*k<>yP{vr=-9Bq&42r6R}&Qd&Jr_G54+CeA^n(2!ZF=^OQW|vU4_lp~bmJ zx7Pk{?e>$!O=Dnv|MTenpj%E~#`MY+xqG1!{rg|aYhz!^xAooli^KKL%E&a)rI+&d z!_9cCl+Q&z`%1p`)V{&|_S^Q*sS1w|v~La^SLtr_IC_z9$M*+MK9zs`Vdf;r9sK>q z;cuw@k>~H8xrZlgntt~E)A8O|>L2PaJ~SSEYc6!Q!ttUX@(-vuAu_CKpn4(PxFVr zUH8>~`0f9CTj?w+>g!6m<*M0-x49?pqrW#pKmIs+c7UpqDC0O})|#R5caXaAw+|9D zK7RPOchfJWvfEfsJ*(#W!~OhEKDGLqm6>LP(XDfmyrj^D&Wne2Y2NR>yy>}EwiwS^w`*qA0MW#Cp+YmJJcX4 z+Wk!7^9S;2PKcgT(N`Ps&Kq&-T%Fh2NU%mqss)Cd8}ZpO*}pS;^`7*G*ol7o z5%cw7>^JXU*gNKoT)hm|CiZG~{dFbi9KPC6TK?|zvXmW}nU%-c^=CIG{r#>-teda@ zX!^2HJqqsi-6AoVt^033JqMjKj`GMldv|x=z__5NB`E@tVWH^TK==!RG;S3 z?Tj!YxlwBKv%`bGTa$t|`QU8y>G9xZ&rIIeiFw! z`A6E`%C&#%39~&K)|g(F3$AvYi6#W7h%<=v%X>ku4ligHmb)4T zXdI{S{6pcpkH+Qd*WCLr{H?I9k&~2@ALjh#I)AR^r=BQwin<``R4h(pRzBSgFG`u` zo2e%Uv30$b|MkY^+2C&cypS_5ZwSveq)tWmMT=h)v2A8*){nKc1y07~C%r=EWYwHpKOE#xUu74NjwWqRm({bw#Y~or_MzU}l3(R3 zm!k*sw_Djkd1cYP zVP7$y{EYwTcvvfco?9CZ4vaY~8)0e0@a}kHVplzb%8u;XSby)l`@wbNMld4xyOUM^ z%S~hoY300BdY*jptOuVar(!IP*vbW->LBQ}kb@bu)v|AOMr+PYVQsTYoWWPh3h~>$ z^oz>QSLA~))tqh1vfH>ZIsaCd^fC+7eXs#TV5mdAt#2Eka>t=S+_eEx9QV- z<#{gKMQ7p6xZUc!bDZ_XgRbO(c>ggi z=ibKef2EeJxsrZW5r^^4pmnd`xjn!n46b|Yt#hE8vf4`|@$C*A1?{Mkd3kxsz!v-s`=(KcC53e0_7?*qhF)!LZ_y(-n7ABCgXb-`r06PEGjyF4t5uz05p8 zy|b=h#UDP5?^wr$-G{>;c8}hnTUz3cSEI{=$!pN!8NBPaii$6O#ewVo5R`v6n#L2d9RU8*pRtOr;l>B9exmZQd;1=;}Gy9LX zipY&=Pghfy$(_gaN8gzHUR&B2KK(cS(~1;aucY6mw291JZBZ}pjXi`oO^tr~k^6c- zGd%j(cwV{xdGy1t%@RFM)cn)Coxz810-=66e=vQ!l{+pG7kdMu(1#nUJpx;K5Krhz z!zw42l^Z`@y>WE;LDcB}hl`*6k0%COZpH}o7m2e&>Zs&9qF0`{<*PO8?8Dx0D{fKM zizVOQok)CxVYH9#uN=WKC4a-G0)TY z%+uT2&+q0w+o^PVt9yU9a{rNeGkjTEY4pE;dH&t2<~zedLCF5@w)SOp?O9pw)LVj= zAEVEIS(uJ8UesB|BoddjZ7H-JRhA6{Cc4Vn777uw&RCHp6tn3J-$7V$x2f~$<&Hn` z^9Rjw&8UaOAR&wb-N@A+XZxMC1w+m?WxTE(?f3z?a(P3fF7rJ(WiKXu7Vax`+tAkr z^FqZxm&oeWBnxh4-a5&kT;88B@s0v7x>8BMes_FtP-&3Ay}$F=KvbyskT1RT_I{yPYX$K)@0Tubcb)Af!|wdP zcCVLD%$~1^gG(aT=+LN?Eb@{Q>*o`BuKoG{x>0#5R4(#krt_VDsca4TE0scn8<`=` z_d}`eXmd8-c=av2+Omzt&7c0eC+7F8tIV$Q;R(AZqBOnov^+_!N9C8}i=0iq@>boS zKM0@P$QKHI{*TCvBnoNwdkv#szyD)>bMUas7hjc*?*AW?`vf&^-ZNe0JLAEJXMg=w z>)%^?tMYo|$&Vg>=YRQ=)bUa42fw|(md=(|bohWl* zt+U@I!hH7Xf1v*H)<)~%*4KB<)HmtqDLFbpiPUNCmAF~e3m-T5xLl}BO#b82fPekX zd$YH@{Xtf2GUaY(<58-5Dyt{u^_-UO^fgQ~dhWU(pOB3Qm&C^W%KrE`q1W!u8^^aU z-S>V%m=>fZ9) z)Qip!&1m*b>(8DD9cB7)>uvEt13CV?m-Xr-ugxj`{Eru-lfQcUY@;pC^d~Go`>1tA zt!gjn8dV$eQH|RFSE^Lb$)A4!@7V6vpJk8Vd2%~yclYH$cv-PGdpBnuvVD_!mpfH& zy(yQU8990-a8c>F$CIbU{5aQtddKRmf0==Wb& z`keMFk%z}bzU_B^6bxP~vhv{<6F%OjyNjEvC_ii5P_O6P4n4~JvL2QuLW5lkyV*Vm zqKhi^2w~^6uCtTbZfEN`KV}s2s@9KdwpEJR0^0uyN`L!!do`Y*URtz_W;G~vugUr( z)={7x(QkIs*I6YA^Dktwpp(R#V5coVDNy--@#SX1ubBPX9>OgGx6`G}#&*V9bdyZx z5gtG9N>}73!D!LGuO4O0-AQ@-pVQ<=`sC_^l`@a8#*uGjg zbt^!e*@SX*vqC>Dk%SfTEOKt? zt!<{|Y^Bdf6;m2j*qN(rJ!JGdNS~uy7xmZu634$h`%@(zZ@yX|q>e8YMm?cRnZBOR zT|3IVzadNemauVt`DBNE!wMRc7j?3$$ zEsWRC(oxwCuD4DUt{eaUyT4M=PhIPrJZPuwkDt^Z^kv7>_O6&k#c;QdlNA&(8Eo#% zERk_@$2;0e`)yYo6y23s$CeZyw>oJd@Vrh}_+DvignAp)I-qkylGsx(eHtsmH<&{* zEoC0x{|A|2bNou5rMJeLy3G{Q3&o9ZTn}r`rBym7Qnq&HP3qIsY_WJSc2$$#5>4YS z88_5`Ozr=inP<6bK19T~U(Ro|BugqXY#(|L@k2g>*IL%A1v(%I}g5I33H-yVvP--jS$Yh)v&u_+?&22;lRr`D| zAm${BPP(o+uf%3MJ>&apy1O>?2rWGm^m2r8V&Slevhq>Zl`(VAq*FRc8T24ZS%G-% z+bgkSN(?bi+non!c?j9vsg)ryr^3UC2+_1;azQp#x~-J2c}(9yW>=de>qBRgbDSW> zfk_8ifBuSj&#ko(!Lz%T6R+CtC;U)S_po7hGJlz4;7EfEXDRSGhNJ^ zj;z>Y7dx11RgC#7Gpa|nGNGJwsI%*aQACMS z7Q`f-I*%n&Y-!4X-5Z~%nnBGEdx@EoJ4B6+^h9bN`mD`N%RUAyq6K$cU?)XPL&)3t zW%-cK(Pi}fhU1&2j$S#mH(|z5ObxRxQYy&vh#1Bopb6B^G~}eRRcUi-O4KuB3v zPk6l+MUG2w*#;k3T>b63;i9`(raiy2YF*%G<08WQYXLLLbsV90qFRCUJ^0K)|CA5jO z)&jJMf+&nqKqt(v@wr1 zrOXUNQP7t^l`!N*n@%zVEC()=QPnXG7-PK9rG@TvN?epeJH?~ij3zXbU~JMdd@O<* zGoBbx3sjGb7!*ZDMGQMZz5xBi=+MS_Nz@z-Yl+2kge`foo??0^PcR9LGvYYZgn1bh z3NXH(3oO)BqRw9K5(H)x$pNlNu`!;^r9;`7tJx_P@GODD0q zj0AZ`3$8SY1eEE~n0LVu%tWNU45rw16n4S-K8H$EGZqE%|KjSsqufXnJ2B*nKp|&z z&Vk(|o8&N)lQ?N-X2Wa_x662eu{X*)_RF z(PmA89!`@2+ZD|aI(Z_*h`^L1f?c}0k%8)=%7dm2imQ=>96PHv=!S+oHfCrJY8w!5 zFj9QAZ9U0_X5y+P{ zi&+A;8;rv?U4>ezrR}Jq_O)$w!Z~ak6b-CilhlTY23U0}TW!}l(E@%o0@Zk#HHc;o z5JXnXSK2H%xo9><%|^J%K=SE8&n4O&^}30wXrQm4?$jIL z9}?{*NG_md0cd8Cpz(+uNl@@0ktBl=iBZqog7T69!X`$L5-reu(1RXFOETnH4G>UL zq1;3G^w3&1p_8!GnpG>9%7~i93=*Y*mQ0kSSPAzVRTec}GC>=`s9;;Fj_w7tQ;eU4 zHwiMa2^?jrEwSL5>P=N>v)~Y)t^@d^qm9__YeT#cih-6Itw><&w$(QD(JYjVHV(3O z9q2SvCNODK6e4*1Dy6H^koX5h6vBH@-UDpY(2^+zZ4v}kklDcGYgQ;TKui?&2BED& zHNb19EcLntgCEHJ$V33Tko!Q{SRfn)oiE7HpwTc;zJYiYIQ__Z(0(BR0_ z7@(H{mY%Um#6@a)j;M_S+Xr1N?26Si5D~#21W^&xe%w;Uj1tlx=$K`?iN!XWoF4LC z5ITXtETK3sB8Gs!C$C;|vc};@O5A?0T{Z<$>Oo$^w z9|i3cvpW-b$^hOfr8FrNZ%wM^*7 zP(vcbYv{PNR0@rw4jn^;iO#PrH8`mA5dQ(xc95STBdCyEh5Q%9kU)5Dp^OM~9X$af zW9b2Old*2mE0_wgkW)YtG(vA3WOJe&fnm#F!Wl8j6EbNHATmH+<#j-S0U}9=#OMmp zY%xPIL(37Fp)p85`UtRAStA4rYN#DJPOO66PqZ^I#i3Pf>O-3nf-lf%13(q5b7;1q zH6owUWHCyEXp3xBz=vmKs6K)p3e5-$$_M;VL>-b0ZOH6F7!)%#uxEiK1LqaB2b@#F z(TCs$q6ddJ$T?s#22QdH;xO8B4f2_QpP<%Zss}A89g++&2_m}y>OO=CfX4*GS&!}v zjT!hPNG$+&MQHOVt&YYN(QLux=-1HqgBad0qQ+y+1Ud(P*s>@T^jASk1`ig3sOSn> zI^z=<77-H9$CkAu=Nn3qUN<)`(sah9QV|H6`do5FI(>2g=_7Z6#92 zF#Mv_3<~BkNH)q7|5}h^#rzZ1m-KBd^o1n5pw^>9Jps?ThAs=lcnn_9ARwb4BpFeW z^kgp7G=M0Nm}A^&3gt0t0dbsEW{GfYJcTdFX&3 z?nFf!l0YZ~Og5k>2)aLHEQI6sWO%$cV=iEnAZ~!>48kxGA|n-@R1iHh zqd{TEAY`l&eJO~bpj$vZQ1waXLHGwb44yiAY4jvSl?bg1qd6ue$T`eGiE0J<0f^*) z50A(bg+f$BbbXi(Hd{1NmVr7V80o0&K;_}ygg=f60E9`<-8I0tt~Gf`_&~uyYXOOd zgroLA3BzcqLL#hLhxjr|0M!l61g)rM#7qYX#f-QOH3|qI;96u4>Ji|wkQjn$6Q&F( zaZssiMZ^u2zl!@q%LKAZ$Tgx026i#p5Q-S9P$(2&_JHCrYUmdl5b46W z&631p0E3ED9prtPh3*MDV$>K^O%U?i48$ASP(i|;44M;kZ;?>+T-eh<2L#v&bO0JO z1UAqqH6exsolj_K)~gmGVgt=~#2D)h*$81Hq#x}?B}{ARnKRHBfJg>PiFCTi6HLI+ z+aW>t4Kz?}P;|ps2dM^Bhz5E^lZG%GW^iIK)o2=64QiZV{uA*57EKX#6xc(lWrZ|Q zokf1=BqPRgEJPpyz~Dn8=5jpb-OvMrS&!Zxtp{5OX3+aFE1=MEp~*o>rICZ=o*7*m z2vNY7L3{!uH-sgK0E~`8lWlVllz_H6jXF}tq#K((6&5MSyab9F=v2^7p=#J{U`YsU zH?$EE?#OfWYb`iLSC!i5f_hHhE~Vio$^oG9CsmcH8NP+2kk z;Yub7`nV;IQLH9K!oGw;AquF^5J5x#=g&iU5?Uk8Hs%(lh6bAkHjh{`8W{!|aNMBX z+SJf<}5L=n$g=Nm;1`G~3uT?+I=5P2Zbe_(;l6bLKO z)Ih=P6)4^I+{)bj3T2v4*DNM}PtfEa>2*6C+78<)n%A_IoeJ0p zwWtWyT8llDsha&ENbuEL0?!-3(oC50sm*K*TPkj0#87p3rdkrGdh^D3R9RVD0BD1S z1b)UJq6NxcVS4FC@8h0CLCn0{64tR`Z{D@QcSeMAJk=OBdHa&V_BNJ{-ekVjx)&|7 zwMdnBs}>nK-uM)tZV}LP-e0%%T-6hSHalaZFft`o_Mj6 z0IdGdQqFF#oIUOYEPk>-N(~2 zrI4-STC5Ig%%&auUAfQ!3?rMQ>Ql_cWu-Aw46w@`s^}mYO+jG_M-F7be@= zH5V||t&DNKf0=ezC>Y3%Y_)6;s_C;YCB z$f9>a76*0Pf{Am+e9fD^?W${eqFL&uibMB~Wp!F5z|Uf)aA!O!HJhs$UG2yxA%?eV zyT%~}S$BY^y}Z(UPvO)(p9V8*uCG$`Y_!MH8bc<;1EM)Qawj0W{ds%El5Dw()LOWT z^VYyMYIvzB-E7;I6{ivxRfBfN=UCzgQ(nd#Di@1Bd%@L{ zSFHSIcY`l_o7GMG-C`x>b7f}E`GU0EHL@PAb4tm%o~<#uO-4)!>3o+pH|U?6@@((T zjHITnb!V>#TFe}f7IxjwS^zxc_Qoxq_?QF!5hCYE=q#Lb)f6t5cgAOn2WIVCd)F(C z{TbifUISQ2iZB;|4lVH9U1@t$l08?9Y*UvXSlFZ6IUw>%_)er`S#8&hcl&qfhSW2b zHk!Lu1pC^N_Kk2-namk7{#t(9X}Kyw+k-c2kE`15?P+9Ey8o7GYl+H+tHdl^rwYz61rl^kEqxTH0k0|$VI(t6trcK!8f8Peyk z`AjQWL)&4P-tk8m*S%d{^VYB~7PoJ0Q$>j2+cpdR%QH*eye&1e&gp|}!A)t{O%Xw( zRT7?3*%}Ysvp6kML*}7XXmr;(fl&rmn_QY%cWnW6I=V0pw}+Bjv4B(!!=r^jv~ODh zDY0Rtv=(9K+1qMu-%S<@_<9qQVzWn=j7EN?yQ$F?S~P7=M9t>GoAye8+Hhz#*}vsY zkC}HouB<_}6-pbUJCq^qUJVwVt0#1}yqT|7ylTSlfC5vw?AWmdPY~X@p3CU; zL-!5BwxJ#=#649Zw=3ngYyNX1Ri=tv{g{cR6IO1$J+fAB4rytl$$^6QpAH&4*Sl;R ze4qqRpQ%)uayIhag|h4s&D$e4JdLicrmfxu`V`%$%Mz{G*=+wM^eNcEEj2>-`%C2k z-7RZ3(8PILGaga;=DVaKx8X~(fDV)crGCi^OBU?cD1r}4(P)7skc z)}TOYZu4b5w!1CHicq$-v0K(CP|z@CM9LALym>^FRJj}~s2*%ar5kkGwaq(uO)nTj zE83W<*D{y^#>_l6oJFUr9G|MSvpw50i^k=?sGY9$+S7`iF>H=NExn+(Zu!A8%YlyX z)9;vu(wvTQuCZCHhkPj}R52|dDav3vtOd1ZI3ARMQ(L0aLz_0bogT;w)-{u3t2^!1 z`I_dU%%?ojzC;_W2&Uckkk%j0c~g~2jm`AlcBJ%Pc|0BtZw^4h+8eW{N~TX9z9YGc zZU5G;wdS6LKf?^)(Dk&lkwhbMmsdE+otE8f8w@<&V6qj9?gbc_VRB$lpp6(>=XiK` z=SOO#34_wJs!vyam$*8t8>;3)upCmDF5h-nyIrpIzdQEUcoZ5uHFKAc^95FiL4(r_ z?iKg8)RKUzQ+0Bv#I`2poxLT@j)VlAaW!T0T(=!mX9xB=m;ivh)jBIDf}&$v7TP5} zYto!G16+|3jX*q4MWR;481KF|RB@<1afh?1IPM;jfS6zEzrZ#PV!1chLM@C2Xt~*= zPw;^Sb4YJ+BwH4y$jA(n<%DZ}sajigRP=IpN*v0DcDmNX!p=iW#bH%56)0=c2xayV zK)se`Fc(S(l0%RUgBBeitnr#}v)Yd848bKFAcwac!6K_KJM=b4f%DBg2p0LWsa3U> zylR+IGrMEher=f(!&1~GQ=6eJK~+KKBmyA5oYBB#Z6-8j#$1C!cnB)|p^VNKIr0A`6Z49e(Q&YGRYJz&ZQ|I_*Bh|mko6N-?U14-_yyab^>RghFGT7}h zw}frkZxn+ZuoBhQ{c*$nT)@;Ema)w#d9xO;R;)W4WusFrU<0nMXMx|WN>G9Te2SC% zvhXV?>X{gXY^pR}abiyk9!OjZ=eK5%d-Vxx(qLJJRgg7P?#s086|P6=t~;}RcY0Ko z-Zq<5^G$o%UFRnFe$O2 zvRc18l8triROekcpBqlv^o~YE3Rbgu*0>FBgt-i=r)Cw?BXPkb`*JM`qNWW!l^I+0 z>s9+U#GaEQi#mhm)BzP)jI4&hrRC}{H$f>X>u$`z6-p?xO*U!OyDL`LinHNTn7C`b zstlJ6wt-T$3KJcZeqnEs6*nVEY{zoO++fVomobMM4)dL`zL}+K8Y^0MEO~vSD-(gN z7}pj-4GLg>*J@ItKjAT0a%^IB6UQ7N;u*7aU1P2A)KG$0v2jg(J-WJ8BC*F zkkP194%5A$qcL!KJVzVTg`(YL+!Pv$E9bM;8Ue|pVzuwnM5Ab|q?=nNbPQa1Y&DqM zQ*d%7XPwS;nRE7B%wSR!B|fxbE9Uy-dYv@~a;?T62w%TlOlLCA+v znix?eE7RB*zCE-ZNf-)~#!@R{iW?jjsmV*_3#U#xayYp2h z9NzFW0{((yT~Eb&q87@O_7uzZsONslaA@;L&L4HABIO#J7lu~)McK_XjUDHbyqjMAA5u~MQrb0EdsF874Kb^1{$}Ac(y1XPF(5@uR4}TO3|<_ zUv~P6B|&CNlgT({HhNdP+|)p zog-IJB6r8vkD6|GEBh|GI3d%_1&tREFD4vbz9w~*tD1fPMj?pB9&A3RZ#Y+AI5H@4 zj7=NK;}|Nk0e+pD+HuTw!=nHibB=&r7{5NO7?#pO;{~`cUES5Pzd1gm?uCgKeg&-&p7mobwyCecU+>QO3^D1Ut^io!7X{J%ndGX^2WYP{WfebWT$WLuHMse zIM!M}v9f-G+7blUvU59Ni3J=R2~R-~xBZR8XseKVI;*d>>=0R^%M{gEojg6f$hfQ* zCo(?6x~)G+d6otJ@cm$+JfM`2S@w3tue*Psuni9F_~stvzBhhk#|B^vo8vaL$1f!U zX(~!{m8#KN>96)}GF^2@&^@$Lx6P)8WjUVNRe=EW;MHl_U+$^Eo@4Npfp$%@E*Tl2 zk~WG*XQfEF6~NT3yF0EhUePFflk^hy`qYv0W_wM`c1L2(sqMWRhqtN|8o;k7Ze4Eb zmV+7FGVR{MSTKm}sT(*P&aOUmNv6v?(PpH*Id*T~U z>yNBBO4i9$k5gOe$<`X~vRVR(pyF*TAKEZFls(Nm1Ce-T7}qc5^tzO9X~+coRkjfZ ze$bWOqm(LCj8lu&o8D&j_R|Y}AWp*k%j%WacSR?bw+A!vu`44RCZ35}EdXLsMPr~a zk!ZVDT>kY!t?b(p{k7R+%dqwN+Py)w@yG|eCbvMz&(t#zEwcpI3jz#Ju#OY`)~rh? zx;0&vDw!o5SoeJT*fqbQ>A4eji_w2d zVN2PudRnITw)E1@@%wpTMA$;hCp0(oU@1q#;jNYrv--e#S@6yAl=o)9VZRfx=K0en zYdbxZWXp$cwuF&S>b-*H)_|v#5}InGYXg!AX`^ItinXS9=Rh{NJ`oROO}1Q{UEqOb zShebnn|^pwv*lVpY;~+bZEHX^i#BnMHi#K5+(nDC30}mTBHyitN~uT?M}rszCyjQSQZIS6s`K(!L7?9m(XtYw*yl!~ zwR*;5%nh$a>IS1=uz2Kf#jxqu$M{XyTP}@e93M!NovYsBqZk zg?krkscKGI&NGfyh0b=DQbvjORe9Q{VS}t*-ZW9NEM$gSpmhz|YE;=-F;vUeJlt*5 zKn+NCy}_x^G4--t#_^V_iEVmGkmXSMVd%_D8kO23zjg}G#c&#kZ}S*}?#+v5wnH{A|vW+L0LF}={Xz+o2W z^ZEmBk1*0sE!6XJ)il3d-dwsj_nUKfHseao8wiF6IbrX_{)Znv_2*xC{P@(ccPjSQ zk6--tU%&D4?fH5t=%0%Cy1J}by*c`ib?-a;#EDRlVJ_Tz>HRle`}aRveS7Zerx&S- z;r(Cu(VzXvH-7koKRV%UPmJWF>!tY8JFoxMPkwpj!>dh5+wLCj>h`hS9EJV8@Ud?{ z-P@PDbK%v$`{jT5>+2t%-fEjn?#Qvn_aA%qUw!+9XJ> z?{NlP{*#A~oj88r$V|6ON;HUVVg^E%ro_t9)eC1XoxPQdjO?8`c649RZJ~jhEsHHV zy|!}kolh>_x_U3pwrs4|K6+%h|H!fN$>TE)UcmnP%G_2)Gg?`kpGe8M`J1=bii{&T zeel3zM|yDjoJ*G#c#d1|CFV!)> zkdm=%ES)JN>i)@HQ^UOjV-Z*tW~0l?+o|aCt^4szA(_ZAE~lyG>KY38!@Z+JeLX{d z8n!cHayyyJh_Wgbb2+gl17#R-IULS#cfjd$vU;tMNbM}H+}qmTUQa?wMTYkmEx026 zgTv!vBmJR(Q(#apW3fc6ASTn2TvlKWfGfNKyWL@?tWGOqf&EB!JGQ#KfixB2*qMjY zA>0dStFM1(e5^a*bHF7^)09dsAKTnX7b-=`X!CW4d>*fhhdcz1xHyQ^fWueZS-H0m z%cirU*q}L+CTeEZ6AXv?1_#0}7XD*}Vm_ZqWmAP>C0}XtF0aSs>gw|YQ;G9d$UUPW zh}mK`hV*R3Q{wriD6lev)WjWVPGEu>j9cY^QfwdES1Hg2+{i*d>Cm945iGt7H5-+R4x^Y zGNJMGu#=hu5qbER;25)snx{yzgwz9_0xubyyOF36rzgmqR|@$; zsgTR#CPWOMVi=aU;$auijDcCeNi31s$4MYEwE^*ToIu0v1_1#X2Gjvy8Le8irm3=s zkkANmV2`Xv+1Lb!!;WA$fUXcnY#I=^2#DkpR2?}uBmW_Tb;vgy_o1mG*CeG}%w*6$ zV8lfsF=)lGU=-4AmBuRl&k*QNfD4M1qQx6e;KvFbCsmf)vPL&AS%V_yP!y|ib zPN&=FbK3xCf*BYdC}h-1qzebrVCbW>fLAi|1Q-CcCG>8c(nHfgg@KV=4X#^y+KSkC zyj~~Ipf0EgT|x=M&WwbD8qablLGXouJRr_JHKe8@iXtx4fd3&C0V3t-z))EnZm-Km z6W106)fJl>$Yp5d<1E{PHX#VedK@Pb*A$XiRHQ;)gt#q2K)ofVEuFM;ohw-j{2)-j z#fq$|D)JW@OL2nThB}3sKny8rq_yKAB3X(C{w<0SRRCrN7Ltby2PPOw6N2g$(sRhD z`XnkeQe?BCsk3mDAg&WA;X)yg{nFU6r+N!CzCCdDnJ&Z6~PDsRe`1u3aQ+r+QaVvbrTqmDl!I5)<9|kiil@X?ck?C zU{snS7Vy9j0)ri7iiJWbXzlRHBn_~J;w9Cd91)}P!Nm$tBxD$A^9(8;v5dfBJ8Y{f zWt4Rp6%PeKg6RZ8IuGOBG zSw`-LNTVq5K;t5bBE>|qx09!x@5y~SQ6(inB7&ZdJWxiY01*cg1_=UT5OV|ATXZfY z7Ia86iR6R(kb4jl8+1; zxyPUT?hDU+<$GWL(t-W^M@K_$i<~W$H#cuyzjXeiw_bYb?YBSt=odfz<%@5>{C9u< z*7=X#K6l~F?X)7Na*Yf_hsOJc_I~-~p{JgH{K-=%fAEd(p8U%0-ADJ2?>)4ye`H{& z&u5bqV8*5V=9!xdtJfA{ThaB!SaSZ=&(2@F{pqzEH}Bj}Y%OlAFC}3AheH6`NL#Ri z829(OyZpmLBay*@;iHE}_a5GR;Lvo>+JJ# zLBHD*hXR|vUZh;g0R?bB^Y!(N)S8RmCjTGQ( z83v}Rs5MH(N~Ktqq*x`N+)fpXB~6s7Vzs0I%Z}L*F%)Dm;@GT$*KTuS_F!inw8Lh! zQ7nt#0HM&51%(FSMa{$-Fz}en zoWQY82Gczc=X6ipENNpYIRYO3)NDtfF)x#Tgg_j-Y9ACPlY$G zTDJg>Nr18#`~@Bkm^3TcF#ER&EHW2HgBS)WOz{Az1yqvEMinw7!#q>XiE^Q=NV#%Z zld@%EObSy!nDhYWhLtr1jb2Q1I1A(87^;OSpwnz;OqkL`!v=6aAb$0jGl8=PW|oTl zk}5KMoiSp`jj9HBPORLq;s8P$LY7D~5ZNuWV8u{}2^>6{Io`lha0Tp;4*9)b=Osy6)9iE9=h-9ThxiU2SgAfq$}Q7moRn9yQm!|V)W zEe)$4%x;MrGyH;pkb@Bul$`az z8Yl|Mq{+~#$DADyRrnVfF*gP}6bqCFyzv@{OA~Xqnu5dNqgBc4JR9}Km#eRDoL;*5U1;V;YXjo(gikTJBb0E_npk}df0)q*t zQv`;g72_)~$i#pUuwpXoVps*76bND9Br)v*m>g3has%WwhJLuHA-CWNNk(uojuMwG z!hFCS5C~eJa^bFrR{(7>91}4K4A20pl8}LrCBr;%D8lc7kp&KzK&|Bb3;5P(!j6iS)@{W8&Vu)Lk+Jm<+Cc;hw_AJN@5g)*j z2rmeZETIU|jD$gM)4_iu^$4qD0Ej@zgOoGCx_BY~At>AtA>mFiHzJc4@vF&{G;1>@r!&eVN{rsxV zFGvP-enEaqe)YS%kbuZP^7ZFG`20Sdcb$)M!Gl|Nu6=MJ`Bf)zzYFTWeN6JY6XNHw zd=M~sgD)OD{kPycA9n)l+^-WFe*NGRALpMOdsLLQ&LbpGU;Q_p@dNvz9ut7?WQ zwZRqhFOFcQ6Aib$r7e4A(skEyJrM5A?_`r-&I!%;`Cik$#1&OH&`Y0g6+;J#@^;$q zwYaW@<_=VC)P-QOuP4FHnr-bz-kW+WBG6;E4I9n9>6y(ftvq9id|*~vCzfl0i(O`W zW#j_oo_%_al^O)`*u9eNU4006?)&3czjJz|IDh2ou@sahnbL&o#-V@z#X?W;emXX$ zKN7!STOB*G)w;hOIIOkvAMEuxsnpqsvvu%J+|;sJi@rqafU!=9=w1sz6Hy4m(sEzy<-B=hZ&_31dZYzj*UJ_XHqZ#GvDd)>m7 z(YK#yY1WIJb$6b`7<==K7)wcjSEmE4G{pv%W*%Js;{`-(1rkz0d{L)3*wPWN*X zw=s0#8<*Jd#hE;Wp2rp@Kkawjeg2JL$<(E*&49etE!wyY6CYi8XjWijT?HehQ6+0UVor{IG*R%-T2}O^1Fidxgl%%uwWMzj z0wX>@q@$dh5-0Z>N@7#*3~n{b#r^Geah>HyBxPrNuXJ*KL)tpxb!{%^3{M-Fg%A6! zC(W^oqHknkb7P}E-D}9+5d*zEbxopNVP+#{rh0@$dW#)s*p}>f9}*q9O@of|N$mvY z#{MnOY_BRn6JLV3h$4f{>qrOUfI8A8XR136+L9AOdlJhFMQX!Io0vkmDKM07)l;!M zxA?Tj$d}6i@0ha8R?ybwmvl8hXOuS_)v$AoS+NE=Dp%Rqof@sKfi*iN*HfZ80eJld zht1{_@9W#)kbVj7Lz5X(Zey4?GTUjvp$)9%yLJZjrK-8?W-B_&&S1u9i~Dgl>&loM z+mW&oN_fk3k!i`ju#bp#XFXc0+;EG7ag|E>X_Ze?5JC-2HmS}xx_hM)f+~)4tfd#Kn@Nby;?9A1f%aLkz z_}26tzp3PnS*XnPwY~Scl{&pPy4|mq*rLT#VH4)!FnBfhdA&o>QmR>S&?|;yK;SDS z+2~?aRRr_|r_Yk0aquK!Rc8^T56nyJP)sye%;v1O#5G_sVodj!A)9G()GS&pJ{}7& zcf)BqP}Yf!X2>WyFZCIlL(8&B4Kb}1&$eso#`qmM(sF6)nv1XQyR0{CK9UaHGbh76 z(VmOCfHqu?N(RpDyY5WtCl#d;rNWfV%-cDd){;$ovnQ$LcwJYyA=WH@)mTdTnxUL< zb*$*I#;Yv=r?Qf%EclnZS6nT7$ym#FmF=b-PNVp`qB6xnP`(p9_#{BTIx2!`HBg|f zP@qe)RJ+ECnkNwf8eUh56rcl?_BM>3``*0CQ#HvzQoC~9cQ}JO5d$c&?e?$Owi;7A zLyK*R50xTU__lEQx7pz93JFA1?mdG_FY6&js@|5XK z;K>Y9ZMCoA)o+3s<2L3>hVl@o%BhAIOhqy85rI+DOHIa;aU@z6Th*0PXvG1#3>}XU z>&iqxwZiocq+?gq3Xd76o~88AZid*hU351};LkCZJY_5dEAUS;Fm+8RSm=VaB?%H! zYn1|Jr#{LxYzAY(($u?}A|G|Mc%16Q`m)_xu~~6L(H_XR-j>|h>6N;Q#YQ6lk#h*- zj^SXj$w+GXxSk$!uZ_1y(e>6TTQ$s(gaYyQ#8c)v0g$ zVocJlw^-7Q$g{G!E(zd8gGwnIVT}run=KK7Lq|bSVCBmc!wXJhadL%`G#5>6(*?`E zTYZa_o`yrI#R9sPZ%gyU2DCDzG^|aHs@H6a;*COQ)SnapyjIQWUL2p#byq2f^usU6 zZrpNbtoh8=PnL|odRC(5&G^ceT#S@1_3JgMH2CC&L z*RY{suy2BF!D7Xx({b&JS#1a6uAC7*LokC0Hfq)wYn2`Ow&HEHt@k5Uqcdp+q>|S~ z;q~B%`qH4wo2p#WTdjrHUA1CBWPnU%&1G*&=S=%l1=LH= z)s{z14QZXXy7)}8MtdF2H7e`r$g#%aGnPkAcha`khwAYKEAwm1dsHTU+0|?${7mBfm`n8lUHv?PeNxS|4uG^=+mR)HMsDs}+#4`clwj$+gQIytuY> zHr1uHDmK;RSnJBQyjd#<=|W8mMBT=MqewM5up>76l)86=YtU`3T=K`ejZs(H5R~=J zaw7!&n3Z5#bBmI#3g`%Ydvx{~rEl4=!Gz;EV+QoZP(iOMR-8b$vjSHYvQ-}FMyU>U z5%4Jq(-IGOCKP=;`o0Z|S#;@>7I!NqfPSU1R9&sXKg8&6u9=OrZGuwu~0tYbRbtiiUzLY%_>+BSa1V^fR@%0lMtC9YJgK*tp1Gv$|8;=Ca@&OIu$1iBqg7xppy)|Lp-t4B5OMG6}hJK zKUr#izTD{iK~}0r4q0!KK*$?%#e+rSgXJID0WvO~`rwiHr~md%>`pk!`kj5v1;M2j z+g5wgv^6e#>fFDgwK=L;FbAMe;;KnicUx@hA@k4k6DU_pYZ)nmyFH02DMHw969fc4MKtlY zvvwi|&)~!&-JMdxwb;5MYgs&z%pg~Ft|cDPc!yOj`4kr;BxDoWBq0k_T!k+?pW+K# zg=gc^p=EyT|NImE8LtCU63b(zv=laOFb<>2My>naGM-4J?5fRB6}#0PE+T5EoDH?+ z)x$riioFzCLO#Hj34%a4FUEdZ+XB687(v6q89U9bst(dFIF-X`BNR?>u8DMjWeHPi zl6C}ujKE1B$q>W`IYIV$$nF8+M?S&M#e<|GS5S{pm5>7R4ayfs$`4XOvW27wPk13I zCmR_^Ha-I{mpn)NrP4z$4Ig{U9MMFl8c3#T*Em4yT zXrm@&kyXxGXjpN$2e+7-8D8|Drpnk+1iAqGfn~~!4N)A9!xFjyWeU_ryy>KbG(_xA z0n3J>h14l27ZQ&LyhLO;-%+bM;`MVxwx{&~nDI z=GGM;!Bf}JOj|A5EEA6}3+_!$T2*K{qal)}i34niJHg|^fH@YTihKv-wNrPo8Po#( z9%rm18Q8=DTNY75D<&yL%#ef!l@HG(F(fk(U?)vT55nqfn300&T-QlfGdFp4q`ndI zFSH}&hC%b^+RkJk%6JksQ;rHPn7dOg*N%sli*7yK=rl`RgZ)_nBoAykB92WHe92f9 zU5|=Aa%fz%n0ggL7^ryIZ$yuSy+ddwU=xqT4muFfYXB7+RD0A;r~x1qB$e3dLrp~` zd(a*`WkUK$R4i=bc5M`J>M5|4VsvD0^uYJ{3aDiA3FQpq~i>v!FY))dlis94&i zDhIkQtt;3~d3%usVTY+VSa`D(41AH*wW?GDmPQzP)E28jx}w&}fHtgNp{#+ru7_?3 z&>Gm4MztXo0DU#&6reZ&g#*+E)GA~v@(WQTO$0TV^mL^7acL)NhTgG5r=EM^>)-nB zbKm>Yzx?VSP1$SKiEeRa&Hec3^dbM1|Mfro!~gcb{P^wHUwZlCnSc7pPyhL+Kl#U( zUjFrk_{Q~XcT?DFH}@U?;dh^%**o*p7r$_LmxCJKH#PR~m!F&odpVlZiD|K1v+p`~ z>X~o;=nwwjhd=n{)5jm#Js9TA7D1pjsiDMD#pLW~Z~Xm#{EvV2^AE2t-Z^`Ab~B}M zP%Vqydhf+wzxd+IFTM8L*WY;K-LoIP`rEf&d*huCKR$cr%-J)aUbuQ|tpPF2Th5) zSFX?By?*-iTuJDkn4Fm0HRLmh8#gb0{LY(iz5mW{UwQMxPd|L~oYCJu++zp4rdFxIIyOAAXWyO! zC!YG|AN|Q+{L4T5)4%wi{%z;+Z~nVK{U=DnS~3cN{bbA5Yfed*p^+-r9B&cf`q>sPN{ zzkYjeaVu7Ut(LQQ_mNZ2e*Jsj|IXLH^_}nk-uJ)ztrx!d#N!ViJ#ymVr@s8{AN|Rn z{_&5#|GjU0?fIu3Id=5W(W3|VjRTBBdF^NXMV z!;k;-kAM6(fBTbv{HI^O_{u9J)$e}r@rQ4}@zz@(UcA4ZjBl(iEi5jtZ6qN(#oK{} zgFXdp)PUFE?Jk!$90^Cd`bKsiJoW4g-~Jch`^F1j{m$?I;g5ds-50*_koO<%f$4`(%pL`fE$4;Jj z_>o5*efY$~k3RX#Q%^j6XlB>g(9r1A%*^!U*vL>{Boyq#vODbexEwZ|qcv19pV(Zw zeeL4ek3abE!;e1x=)Je!c>#4wjl#kMv!H`iB}?%%n2`P?V(zw_oBufOr;JMVvT{`%b9t?O5= zT)BGf+EqMV$K&ShyNfFu+tGL`SH#(y&dl1qq3*t+v5Cp)Ju?T7o;Y#x*o11IP_vdGC zT)lkh;)V0)&Yn5_>Bk>_`0?p;7cO4BeD(T`n>TOXn!SDJ?)|0J^^L7)GFvFCfZYKG z<@8|xcW`uK*VNRmU6bQuW8=G~ckh`waQN8ChaY+LvBw^N;;E;eeB#t&Cs70U>>3|J z4)}nn1po`;)4)|pH0A_areK?ON*@G$b^*wG`09@@Wu-`+h_6T^Lx0AQ~Kf7V7}pj9Sz zHc=KN8u#zb-jrAyrHkj!kyxC+h{gz<$<150X6F!#`=mG6jwVvs66O}FS~FYP z3hgIapD;JG@enH4t31z|^D>aqIQeZd&{wlGi%=rie{%t zPnQ}xXq1S$jO6NrW3>j6G9Lt-nzEI`f}T@gi%Z3$4Y!-6ONpA-LkaZktk&95xQ^x2^JtL(AqTW=%}9Pju1 zr|Um_a`C^M+4IMf)&IJ}|H$aL+gcmmCB@=JN8wBLX0l!um}apC$?=NClg`--##T^g zO}Fx~g1~zlzG6l#G&rlSuapb=ghrC0ReD0dAthfdk=|GS%4a|LPdvyaaAEJb5) zB%dBTw4#r0bgz}!6N85B4~v^!H?IfAAOE8If$6M({h+XGZ^EKm6*IX~ea}OW1nle4 z^0F&+v$CZO_a3$k9^lk<@ygY;4VTN}cF5+S%TDDI*UqmMT!T}AT3HWkHecV+Xm7W2 z_2%vEr7RRMd9T;g%^RwXf(F7N$2%QN3jl^T4UCt$jwTNz117Q*OK~;|+Auf`t|?IS zfe)Kn!;Y5GLa|V_skZ@Ez>E|sIyjp*v1Yn0i?RssY6)v$3%skmK~`ytP2jU6ty;)I zMluwHoVmrQifYbi_Sh_3HdD){3!KI5VSM)Hjuvm2onE^E@|Q|kDJo*g$agv0H4z%G zg%<6B!O4!M;{)I|=W6jqS@Kn_erHIoN-c-an#;Db8}sS#G^5awkQw`U_13!H=(jow zJ6T)XQk|aEHg0d#67I+|UD-2h;z&JWWS5gIzsuFA8Z+sF)zM7)9u5}b8#_A#fpDg% zWjxL?8eNAXIDsO!OI9miT~)1h=qFZ9{?h$IFes}oMq~tOJ5EQ;lw-4O^R)|w#(Ht; zR4FHyl9oYRL0>JiHbYM5R+6?JYI&vE7qA*r8|EP=71?=zabQFW9w=T)gj?JGz`bS9 zM4Rp1n3bFWtJk)bTASi+mQu>Xlu8h0v_hT~Xw+sVgFQq?OS0H0xt)WXy}b#Qc|%va z9xmoROspJeoBXicL=0`?!j+ncvVg z{o{IRB`N#*`4}X&y-<9lo0e3r!gTW`Dr%-v#%_>8hEjQyPm+gldC<_^ga&F?Q^YM(CBIF}D@X0Kh$z1wpm|Kn|LUfG`kb zI{_SE04MkW0;=qs)Elud!vw#9eZ_W5*7OW!ud<{zoPtfCiI$CB5nF5hzHA*B6H2%5 zDdDLhE_r6zG;pZ5dGBo0HM8GWxpY?Sd2Bbm^ZqU4_^FZl+&kO$gOB*d(;rF$4<9yf zzj@2J`{}{fr8i>kM;`X3-#x30K09q%d-aax@blf(PhQVNo;>c@e&bww>bWW7)fbms zPd^z>zVf~@{lY_*Tfdy+9{Fmo{PxSyfp0u)UHSDz!=5is>#n}IXg~FASMkmFa@}7# zCTzWWMw|Z19@CAN@6pGe?XRAFZO8ZcDSz(W_oSXDj|n@ko^OplvzJ+Z<)(h}xn1<_ z-^?5LKR-@gdu>*?@0tDF&DXB!Mjkoj-FoY^96mlXsD6Ad#*XdYN6&w@sP_)-9WI@l zPn&y(rfmyXqIK`!NH~3CS+RAEbhqc03Y@DuXv@te>s)u2O}D<>XuCoVMp@2Q8Gq1P z&+kZW@N13vM5X5N!gO#e-}Z%krk%}nyT9MxTD+TOCP%%}?0g}7V3Li$y`bCoa8LWf z`?1i86aLtnXT*J9nKobg#iHZs=Y!c_za>q7?EriEXY>R}>N^wF3qRlXfAwj0 z{by&|M}IIOz4LdQJ>UPf{oapXte^ZJPd4BD-!D0S@6UH7|N6gfj{U_qyRQAG-xeSK zqf^!o{_2A63;*IF)0=-YOF#RaDdS83v_zeJW}ow;7w_qY503ZcKe?WF_H_4AOKaIS z&j&*4R=EtlHMgr(kqc7G>E~PJd|q<;y)AJoXY>XgmF;-N(c5E=-icxr*HgQ3Gv(bo z8rpjQu5R*hZ~Oe2?ckHU9Sd(RRF6LqR^IzC-ShP+>(yVbu+Kae%>C?)GX2dd-6ww^ z4SelM=lV}RZ5{p2RQ^I*0**t&hn~}nAUQP^r^@-r>-@YSF{{Exh`M>!<8UNa2uK2Isl0wH122D5KTjzTR zyMyYD<&wqi^IEIu$eK*RWvb?iipB1*RyVRWN3YMabt}yc?CO^1&u$Bc4}^0ce3lq{ zcCYQmt8;6HxIck{dCrL>gj>(FFsE1{rW!U(|=yFfBDJC=Kp=6a_DQL zy7%8$_kZnxd-0{qy2qaEtH1JIZs@t)*0~p#4W}OMF8%hjIP}~YKl|#c;n=CZ`fKl{ zLSNb&+Ii`^IPv5j`|UUG)P@f232lFJvmy*k_SP5gr46=FFPqF2AWP`*8Y@b%QnUI6 zy`0aNct5C_(L~!Bay7PNd9JIU&(5#c!eayG`77J(p7Gw&N7vN;V?*q%kCwQ{4*3&r z%oe7f8`PhFW6S=P!|v6e&9;s|+uL~c&0O!-53{rX*B#r_FNE?xe@&eF?h*RT-^~kO z{$eow>vs#&-=5N6`o)^_*@s>6UtetQd%nMV{*_qhIke+noYz0}y|LPRKU?-b|NKDi zpMRC=`p$Db@qc(Z)BVNgBIP%Jope2PyqjBo=Z>*^us39!o6qT--v5Wa_kfG)==#U! z-t8ck>vm@BUMyK@}8U$*`mvTkAN4~MFz|`bT>zBHK-`e7e%;Y9D#X*m(-G1wq zqj7uOOo?N%?*sBR);P#nt0)vXrAvu44|lYebbDGB{M)>*1H4Z5d}>1q+TAjBNVQX0 zmsI-YDP^X*_u@9!1wBt$EAm}mSvo#&GfVMS3Tt$(1;x#3pS8{Ocu_Uxl(cDjg9$5A z)=Nb1z3X$FR7#^pVVQ-h+OEvHEUROFc3@?;tx#8nTPjMeq}9ZvjGj9&s;X)F)K*qx zTT;~ZWzOKs#!c?JI-c&KeBCkQ)x`UcC%=6fQ11F7XUd(&ql%t4Ra@j#cm3VmNKjet z^{&w&x4}eGL>!f+VuzQemYS+s@2UcOY}XWczSg*^3(bU$`A(8_4_uLz?q5_M_|VSg zN}%Lfi_(m~7Xma7d*!DGR+r;wqO_K=$rO6z;fB#tGmV)#yJb;&>(aCqs#ISl7uzL? z#za%>VESC{^T@~{$GlqS`cm%kQ10=<$hoxGu~utTB^RXo2_AaeTn?%!ZF$?g*@c!3 zFFRfIliz8hes8PR*k$69@J`R`dL4E5|D~m-S^?cwuPmW^LsD*EQsei;LR^9FuF8p#W7a5udsr+GTDfA3nG7x0R8 zPqmZ2XkL@=onPmiE3!+qYs|NWUd%?*0;!3TRGXXK^)pU4Raw@SI_Yw48>$@BjXWo&=!20~nbi;zRfSuwz&1Ik{C(G}_FiW?E1wL!uj>7? zoAb2*Oe*wHqKYAnhdZ1NfFQml1iQXLwuaXWxktF+S;+L0<8aED4)rWU&W z9F!GKMPgyOORgs1zM1n&`}#_UY`IwuZs(Skm@<`etlHF?VeJ$e^M#ery(-hznba`Q zsZ90Q%2f>}HBefu#AaC`G!9oo-MOt6*UYP+P!-xKaW{iX3`Lfr8YBGR{`hL^>Ux}+ zXG?6Vp@Q5P)mNi2slt*Tf|U@B6qDR_IH${+R0xbJC5D|M>|z%Dp2FXdLu!NlvPR_pbHW@dK)F!*sPW| zsEu@5cw^K?P}B;wrPzjwy`gk=9132cnnpl0SXzU|b1|k%FyyPF|Co3bVa*9^Wjd(5 zm0%MxSPe9Ea&wX3LmFwLNMlkY)krtw*tPLuJ3VXP?1i=OWjm#1*_&%`U6k(jE|&5# zt>~!_Q(ac_-rC4nQ|6Oh-mFwyFIF4nK|Oo9m{>JR>8JookabdxP%bpBHZQHm;VT@T z6w09x6BD78Vijh^k$UXtW-(*RU@9A0B!zTiDXtvHnhCUhvQSfr*Jlcn}uCi^XMP|ko%>Gk9{K9_82dKopXC7y-kR;5N)$dq_HvMvo4P(7QQ zZLY)h@LF}P#7!ouHy5ePE1ul9l zc4p;Ia^F@c1h%Fv)mHWrRnE0E^0G~NFP#gtJ6Fo`D;sk2o2aYZ?Tp_v#pPGeo3M^p zt#3j{4Xi;8f z#MU~h?Fy?HVp59RiOlOutTR~FPNB;yC@V8Eva@7m1?E*qWtCLxqLf!x)<}fa)g~AO z%7|&LD!rlD7{|Ni^`xvoUdza_yT+(cAyWyA>jYSkZy=>Aky2yC=wz045W%alzM!_K zS6M<~rc#T0AvMP4xaB~pg`QxY4hrT4;tC=50MxTMOxqx=(NxuGWI{;;rXWy^5)HKT z>m=yZOzP_@=@kQFk+e=tptKxXt3@XDDpY1vhZ=DerxpPh8{l38T}@q;q`^dNBqj~D zH8|Y~J)uxiOB$hqidd_$_NRlYQ=IgxRYN^8c5mY}x1a$^KQ%a*XVi#=ESyBpsu<|J zg_dfpQQ>9~4aOTR^!Z}6(STFSST;jT)ETLn8UeJTN`yiJ-Sb+iOId`=3Uo$Lxr^=X zSiq>qZGBK>uVrxfM1(fRwQ>nT>%~@Xx*muMj*ZV64JtLZq~p{X;=>gJjan=l;KUT_ z4hBSMBiLb#t<}gi7Ge-E(;&ex2=%NH`NKgu?CMAB#$qwn+O!0_XXr+CtcmdJp9lmC z;SdjWI1GyGOi)bRUT(U#9AAlrE_SR>(F+YQLc;cY>@CNTom;g+O@?c_M2*#vdhklb zg-(F z=rXF56{K2{S6v~#QckR-*Q|ETA+qG%ZvO`NBr#4M}o7lKn>#Q0zb#pY}Er3TU%c#U)uq<)!MHs=BH=CFD(+6jPZvtLTEoK0godR?V8X z?AbA>O`u<}f3q$vntFTLIho)t2we45_AWR3^~*O;)3AP%{^tFgcduW+OL_hz`ToP_ z57M5%BDb`(vH~1kV&ZJ$=GL@@uTR@R-{$T8yju7*^LBG{boX+xwYRsiw6QjqijAQc z9$Ifz8Z|r>78hq?-61y{XDzc{=e&ABSEX`t@^cGvb90Ld%T<`3g@Oa<5EmNBB_?uH z+!Si#=!L}*|K=?MgM+YA9oVu(U^5?QcRL$n?1s{+ii`70b8@mWUcY?#^y#ygFP=Pk zo0;|QeNlFH7F3%Q=j9fcRzPDO6y#&a1WpJ-xrQ|~bvQV?xHx;bd$_x}xjVT#d%C&0 zxVqRo+9{w;#KKsN?GAMsB~%cop(~*r_u*pEGczkA?RDzQ*RNiuzDiF|PkWn@m7iZ) zQGxS>5a_UPTV`fqX<=ez33Ui|c8-qDE)Gskj!q8tP+4SUVQFS;0<|1C0f^lZ=vZ-? z7|w6wGWgbxJ{HdNJ$3_UdZavYYY>J@P49tskw)k-L!s6iO?s6X@uK>tP+ z6iJjr(*V}tXv84nP(03~K{};p-t~v{ag?7byr8-_3=dQUV4j*kc#o6lbUGEiIXxYY z6MHHeIE|62N}y-{@jzh(eygBefjhg8({soM&fW8B0B8(+6kHq@+ynI*W;hv2W5L0F zh%)r#K7yud1Zb*1dT_9`0;fR@fn&=Q4V<2orw8((!-Q)6fSv~A!SGP64ZMm1P8|Zx z0+i*KxY#R9g=Q%k@(XRW#cEyuhu!ZD%lTbbtw?T=dv(0&k)z0e)<#51YpmNmDzx#s zRU&m#-A{bpJ4w`Az01G1^=@0uf}b0TgMY6oNWAI)O=9-`!Wr7)>)yW3XRl4QyY;+_ zU(QoWKdTE*nzg=E?cMRs&89sZle`9-ovj?$Bw6{|T%G0V+t^@nDQtJAWVh$pBl4Q2 z8#O5@J}|Pt#5Kdl|9ye1AhTJyha^|rS@lk8%IaPh2`$B@_SWSk7Lpfl$}H^aT$+pD zmPqWFi}@|g>OHN>ifXKzzD<@nRmeQNiY`_(mE`E$%QTj)?b2@4Hem~t#umh>rS{ex z8`DayjjY7V-8JKSb%Q@{e6*6PeWVr7OU(tgnKmMo$U%`?_Do<#pe4e@vR0tY%F@YP zEo!ZtGD=)cf6q0sc4ivvba^#yn)l@*8+n~rf(uA$ipmRYS}?4UC|hg7WaVgW?ZqNS z0tH_gX?0fC4vm!xSyeSr7N}&l4C5xxFT)*8s#?}kXpFsmxXXww(puP?X&VdFwOV6I zeXUSxBX6vEUoJM5i*$`P7=@RW>!7?E$52(47Dc7%I)%Kh!ri1&R|y438mWa+W`*;d zWz}qnk+ZT|BsUl47vm~cTs~oYp2`(WzFMWOSKqVB#1$%pXyX0OIW!p&gR7`Q=x!qw z<-97X#R&sr*Fs6d>zrz-$Q-w$7vw&!6Jg|ARVd1-Wu44e8%JMP*4P#L%FTQ{EFBz- zJ#0N(Y>e`Xz(kGfi?!O4_xS}cpTByQmYtKGT3-C-<(t&E)m7?B4Z>+G$Np$@7e{Ze zCSG1v{{HR`?oM8=7REMmxrL}&Y=rp*nOU8>@VQQzo}XS=Oq9jt@;YUCMny%vMx(-3 zGhFH=EQh8Xs)kBbZy^!LN>ClNLYX-$keZocwxv;IDiKQ6^x8{Y7iVN)LbYv?x*8TY zy5(2mK2LRhO$9D)5fs-8t1w8z{ZP0Y4}(jUs2<4^K%+Zu{?Mq5>#8c)Mst>x)a41V z>Slx)Bq_Qk91NFBC353NZ3PsWK@Xrztv1DWSd3{KYoXA*qDEaIs;yUIo1hM-`Ww_D zoW*CA8WSm0ec|#&A{U#O;btG)UZSfv7s_P>mlJ7mf~yS2sdaVeg=%qhA8OAqA=DtR zQ!%(|MvIf)B3uL3AR)Eb=7`%D>vhn_O6QHx-QngJjLxwK5aUgem`Jco5O+hOtb|bA zj;I^zaW68_*5Cv^wxnWYN*dKr$AX({pudZbkTI&p02QlQc$bLC5SAGKl_*?nA^tn9dV{fY|`NVN{NN ze{>@tv`AwcC_Su=NdP*GZ)99l&rKX2ykZBn@Ok(^Yn)-$rFHJEyqB#8`eo{VtbXg+ zw4J@`iz407Ix!}aQ%lVTcvoeJ?QsgEnK0w%J?Ey1ce#v%sHobg9mz{|X=bY_bW+ID z^5yo@l+sGyhO8W+OHE;pMH4}d+QLDWNsNPZ+2yQnc|p0%rLd^j%AzK{%-EUDm6$eD z7U;};3Jb~=HnoMdwkGvy#LTKDwZX)tqDW_BQ(d9)kZIp(osD#_1s0~&`67jJS&`aR zs?AloFuE+Uqp<3|)ZPdO!0d#|@q;Y2aUQOC5aw!ya91NXV=AhlAv8y0Av1a}052*dVvE|UN`;Z2vIgj0%h!jG*;WYo8%e zT1ZP}We(+HFfc7Cw63);z^+V-ESn1ZN?fX@s5Hs9Qp(gCt4iy47AiARDKEDxFt0Qt zN^!AEnPrh!P-j$PTW(#5+fvO7Eb|;IMGac3V&ftkl}xFXS1WRD%1yM@rd3V_vI=8N z1y|XWm=>GjqC8x%U|Wt^CV8Q0l>@HC)>&4W6Ye=JQiMY%X=L)peYH_Y96y=tf)Y=sZ&>l;e8Yc}YWzDqWeCv9X z(pn>tMJ`io(|}7L9m<3SP@bqRG-u6<8U;q8T$$RlR97ak(&#Eo#adO3tyZ34Rcnio zOrdN6%1o+I8dZXFYptYIAi$l2^Q@Ot5@S%DnW%@L*+Z1j%d_XtEG^r*A#Z&{%r6=oXQ zCU$j~R_AAD<>qESz4p_tjo*Cv)z*{AH46U@-Fo!s9NZjZCU+_r720AFu67bizM zE91uEXTKlb_Wkxl7anDlLC30l)8;{~+IQ^Ou2rC~rxVn@pi@_t<-dFRB;{#pMlLi{ zX1;uM_x9Z<>1C{4V4rc=EgCw0Xzz|e-j1fED*O5E^FJRwa^yI+`(AsLR;)F4_G{g- zbNfIqI}@qY%)Uurn>JWvwUG(#4CHuHJh1BC|vzwsLJ2+@VXiE*)Am z_jIt3FoRj?i(4?v;OS5AD%dli=E_OdTPU#EA<^CW{&l%{(al}!_Q5+hsR9nX!`cl z)=h^V)cK8^Hho-si`>h5H~nz(d4uoZu<26<2N-2vJ-B7d!K>LufkUQ5g^%j!qI-Mg z$o4Hef4rI5=+a@>8a-iZ%&fT!7A#t@ko#LOpZ}Xb z4}Wu`rq3KXe&WEMo!htYakqn((1zNQ_wUn^A78tC@$4@L4Z{6CBTh?#>e%p?1J9qEedEmhQ0|yQrIdtUM;p4}T9zXumk3XF}^~;&Fzx{Uc z(&ekzXMOkX!^clvynLOWfeKt)Q2~XK3^9U^cT8k7@om);M~xmea@5EXBSwxGK4SQ=;loglLx&8-7Uuzdu<5#Os~~?LPd8^fD>Gv$P9acT zh$Z=X*_m`ZE4H$xBtL%q@Zp1p5AHwU_OCupPN928U%o;E!?aCSPHsVA5wsOzd`~A3 zFoVGBki#kg{vfRoMy#~Tw}V1;28*BaGMtyjQ5mAOEVRpU#O;=1VU<;Ovs9ZpohdFC zP?;22hzh*lS=TGAN)#2ibX}yvN_485QX{N4DRfQ^PR6<6CQm$yaYC`$I@|kB#}r$w zMpTDuK4kSZHl zDoR@aI`D=|jS3x%#;jZ>eA?&unBSc(Zw|WPjGLBCZ%_IvamDDj4HmBhZuHr?aCJMg z;|bec{5B^P*kh2cvKm{QIi*D5GiqKp+=H#Q7)`>O!X)eR~ti@ zleEn8ZJT>8`3|p|BnQ5cny0pS=uv~q1ONU6|Jy%7qpCRb#l739YBT31%{z7twuYwg z+bJ(!q*t2xw(Z=dPfvgO`|Br9oxgtnb){v?UPDJt9M|6b{rP=+5B+%lUXCPa@TBmV z8AH5E&hOm1Uuc^R4UdkCoe-?LvSY&*Fyedk1gLjh!2||8)Hg8#FO?`iPFc zmZdlLuHUfh>}zqGu!W1J4Q*+hd2Yx04Vw?$uMY}av~+ezZ@b)cKYX`w>%OZMUSks$ z%nBXkRe59IhE2PU-7Iw;JS`?{OixeElb?2NKX5vw%D(5skdZz7EmdjPPyc-CKIWpa zCB(d{%;J56pj2()U zP8d7br{c=tt%p+^TTGrXx|QtB^*wv97b*G=8Pnaf^3}-$7gHF&?!)>ANegfNdiG|K zMNseVo$MRm-nwujRprvEeOGUbnpZdOJkFB21a)fRBrd@w{g+A;kJc?cEOqIxA0`(P zOWzh=u13WvlB)OT*S&Bl`r&Mo37$pP zVUulMY6H#B?tWxceDadrU_X`hgfO=pwXfy1-S-;G&i*d%-MrCa9Q970#Uc{P7P`|kF28?N~^A&%=hybFdf5tFe=xkg(uFI)Z99e*(5-q zYaP*7TiB({(X?4IJrI9JB2P+6aC zs&$q%;4-U96N%7FDXhk>2D3VujLttOB~XM6mG=z-u?Zuo(qRicvBVSwwpu_l97-Fv z?h0{HC@%Y@69iHm=+j^x1q$Dw#~6#=*lB=mE?DfA7TLRqORtw2jcot>k%wIqn_c_z z!iZS`FTP9n@87ia{wrCKT}73u&gieY`#f=RVq#o>Pvyg1U#&>upOwd+5TCKr6Xq@P z)-3FI=lqeJz(lXC2g@t^P7H4RG0D_#M>S5&Lb^ZbpP%bZ2wCVw$QlQj)&wJ7 zEDHf@jR^6R5YkgjNEx<4JOHc%MC&07o94a-1OeOueW6-yAI54M04wwm0rNA!b3}R= z;G+jOm@WYN(D*wIB;-~EAzhKez%K}CxgKtJ5HfNN2ID;82!G zWWcjumw*zFFM20>tunsyW~Eit zy;)m0sO;zJmYgFe|g(_Qh zZ*`n{xB9+Xsdm#0(8OzYXl`msG*)#T>L%B%sykMfTvuIZtL>=$T$`lbr@g7o)r#wz z*7vQSTK{GJq550(Ik+#{P1i;DnQp%Bd)+DBV_gxHZMrvfY8cxP*YIt_;f8AsX$>`) z%x>D)t#MrA?8Y^XdmGO;K4~n(R9$0YePV55abjBH-NciL8x!Lbha`F>s+Qhb`rXn| zOBG9>E%|0i_a&8!cP;L_xMa~ci+mSdUpRJQ!GgI9$bv8COXq(%kDa%0Zuy+aa~>zO zOV}MRh>wW7G23PK+}H=RoM*+%ybvRb863S~#*67T(?>lD<>Qne{)>+SZ1utn2w{zj*1_-cEqvaH-}{m)eNy3 z5-_;mpeX~F4A|QLRKLf43;T%sc=YbtYf{g}J+^nh*e$KAu8V7zo}H(5`nKcg4r%R$ z?E~74Z@a3^>DF1TtXlOBp5OAvpqxObz|k$%2R!mO_8-)o5J%F6#E`zsTGmB$%&5_< zzvXDfHv2}`W6c`7HYP&zshPFCi>FV^PJM<=2v5{w{yaK6k&p;-j|4Cq7!~swdzJMP ztPzw7MhMRe9Yu+vY*9b)38O3mUk`vtkzmpS&gJ^yo5OO4T!+4nM;+x(F;2-&LCzbUmCj>b&bc_aE^!X(DYpwdoz`ZT`Y1*Qb~7eqXj(XtS%$ zT>X~#z4hzRd|Pu>^U?mN{Vf7!20RRC*5b<+IW4*e?h4cfjtlxV$fD)UmiJpW30@JL z5!|8G=2lg$2Dd)aTG%F}&4o6KwzJyaZ|l`=X}j0$g4=)7KCgYZ4%<3Zbr{s~V8@1z zV>XjqQ7*uT8(GewX^0^$+cTroVW=xB*88Xa@`$xN~6H zz^;SV4ayu8GW>5KLO68QGu-LGl!^*<^!=uBGg%^Z-M}$S}iAaxdh#V8S zF)}&QXlkFS%cfqMs+!tzTJ*F-(=w;oM~#U3I_hSWE~@qPnCSR%1eDrtGH=@_XiN=Qo( z&hei!dd`wL2j@JTQ$5FFZuhxU=YBi)^xV|B4Rbx_^_@3k-r9Mm=e?R&H_v%~*ZEWC zubh8y{+;;+^JNQs7YtZ1eZiUqM;F{(khegz&~st;g&_+UFWk29?82uD%N80fYO<*N zqKS*_doS3*!0$aV8+{P^4in($W@ba!1-^iS`T}`AiM+2t8B9T0v`3kkF43TT9-*9eqr7IL+`6Ou%onRsmbXx*>ru87QN~Rc z87(S9nV&`3FUB|Mj&C7an1}Cj6yIk$zLW0)*@6Omw}be8Q}7*~=hxwzp2oMGfp6?F zuL0ltG`{;(e1C_z)u;;xQ71;DZV2b3p`NTpeQBLwl#q$~^A+k*aJ(cw4fSdn>Q~b^ z4eHuX)VXf6EoNt-4z565^oXrOyhJfc$Nn*D)ama~w>_gv zQO}p5zFWroQ*a+Da0Y<725F7&*h)r zL7VO}NrU!1bE410EVTDApP7Aj5ADC>glh1D@bOOLpMf{@7^eZBm^#*Z>@)C+EA_dbun6TNyTgFkxrN&&C* z?wJC<>DA*gc&K~#`{1X}-EM)m+IGDHK5O3P9C)sz^Us~ebZP(}9@Mc4Jh@wkJn-k> z_OHRKz1rOe-&VA}03I%EbENg))>Yu^9a?38$2SSS4}Nda^4FkoL0a?y-2-#bA2e(6 z5PgG1z-j-{{wnkr9h$#I-{IDL~)j<9!$X zki_edXCKd8^i7@~*U?WA_uXz?+|to^Ik=v48SA1%e-`ANjJ{3obkwo0V=nqTH;2pi zpV@2B2L{`vpg)w`9qS8rASlXieMw{BUTbKN=3C{4Ng zYjsogb=Bw4#=W^VsP>UEN-0wAt?5*gTAfgBUVWmfUsX5G!tC8j0Ei~APm6fG-qDY{rVu25O9p&+o}QU3INN&dmS9(kF$OLHA_ z&*zNIQD$$<4$4l>ipi2^9ev;LeO~6OOwY{g8KD^@WB0o*@6yv3r#q%!cst>(CT&|< zyR_6d^WWILIrn&IenWG8&-H%SE3R$5 z*8N)H)eToWUd_Jp?UgoHGA^&V-173<-@o`h@b|P!t1bmzO1t>Q#h{CCFRZ>0d?Dlf z*XP@w&pEg5T<3E|zis)g*Kd_)cb^?}w(i#>zmEM?^y`^3VP`DQTss|m+U<1msl-z) zPG$bG?w9VrRGr*^a@0xD$=`mC`q}a4M?WS0)bgj?AGiKE@W+M|r%ptius`wm`10dz zj~5@?b8O5p`LSz9=N|Pxntf#3kzq$9M=l?pbJ+iI&Y>NLMjbLabnD>KgKZC19yoR& z{D8}W)cqUw58f}?e|_K5eeL%t_x`dsX0PwwygmE(Oy1+XCvErE-D7quc0b#-Vb}0o z=DU)2uH89wr`gWr9qV=s-(k7q+4fD_$85LTp7z7eA143c`9t2eW7}f31#PR{dSPqg z)?Qm>TOV)Pv}M8;w=Mabf7(1}bEnOM%@4lc`2EE1y}mEqbaqqXrv96(Hl=SoyfJQL z=Z(^h&o=DdFk?g84T23R>vyi7zP{ah(fa4>_N|Lu*L9ugx_4`TT)SlLkhLyr%fGw& z-TLpszH9xR6TfEg8lN@nns=+uul|1Z?A3!;`>qzR&i?Y+m%F}P z{N-m~w*S)ZOVt;zzBv2E<}c=bG4_jgUpRcBU6sD-%BsDqR<4@5YQU<1RhFx2SH4+! zW#xgDYgW!$IeKNsl^!dlD=SvKT5)B?;T3CF%wG|@V!(>v70xRpE2@^iU4Ccz>E*kY zf3Ic)4;}_OhqTt}pv#+1_RAmn~lwzbt&&=w*GEwO{79%w?Iy zGT|~+QgKp7((|NyNtcsOCml`No%DUuH%Tk7C^kDODk(H+Lej{jK}o%nx+b+x3Qh`0 z@=5Yaa!qnfvQ4s1GEXu|k|)WMBuSzqK@y8UhWn#$0@z7Flf#WU+}gsAEByK(j9`S- z6=4oS*b@*(6yjQlIKM&MyOD;|NXtE>DFbO!B?*yE7o@j6(mfjKk4HY%BR{_&Ur&)g zW4fJL*D1140fR`?x0MnmP=4R!6>Itl-F96+ZB{w#R@6PvLniL7RvSj%J|L7 z+Le|l^8qOPmG}l%@GZ2f9PnMn;`?mIcY5`O>I*x3x6knXcHui_e<{W{9gJ`LJ-+d~ z)hxdEV0`y&`2KloOi&j-L!CH|x>5g?H|oiJ)RzZe*M9AW`ZE{x=+QTtZ@f{j5>dZi ze=9*<3qzf|`d#^VE~tY`P#52=HATIQMg4rfPK3HT9d$Nky#V!h2I}#%4N}zUIMnU* zjaI1ViKy?To4io>H-7)%djZ zKcxL&hc>op`?KwqXmjg!B=0ao8(h0Hd8awrruc;lx1jo7^8;g7-Z7$q{_$x1UAeN&8P$o$L-CmHA5x z@T=rgZs1+lPFsSHojD@{PdoB!-LHed<0{Yg0>3NztuuIE&bhYWgBj<8!4uzJ2m*gh zyBG*wnRY1Ir zEeG)DN4J}TSHHc}27J5tZXfXQ`g`NKD1S2e>G7vB^cT0Ed74{al=^CLQ^xu_4NPnk2-Eo!FQ+{oCtsF?|o9o(jbh6CcM zlo2&ElK9M=6CLeKp#JF}9=CsbNKgOKqx$%_gE?|Q|B;x_^zS{o=YU}_IrM{bANqX2 zKD?|p?3~t{+?`t7kKUp?_ux{APafVu5AMOKs81eBccWST-}>~Q85uP*Dq#Ul#E{S- zr2ojF{_WbeZtow2d0AXTv+gf|ep<9~lp7|3NkvyaLtfo@b3AW$Tg#iPZ}8@HHD@NR z4Cqeqq*#V==E_%FI5XnWBhC!j!}b8#ZEnA|)GXNK5JSyYpU`^{TE zp`~-6CVi-4PNysJiKm|K=yYjK>K4!1{_TSgA94ATHz!JdU58cy+4F-4&=Er4n*Mruhzn_mwVBYy8PcbYup*_-fEX|M<{ks(J zgCxAY4DajkUT}7l1B3Uw`ga!Z75aBty4Kjo|GLI2kJighc>nk@Ys&L)YB#8mdmyh1Ggk z2b029J?w!=;fNki!lZCc4_9GQxT}X0m=sd=kO`AQfgUPgQc&xGG(-LYQazZ%q+q89 zH<%QB^biP>LOVTlgGr&E9)`iBFisDXVN#f;hgg^t=IbE|CWX~{SO=5BRz2*2N#Ted zPQs*cP7haMQn;&!6qpoJ^^ggZLV+GCU{X-)f%qZ+0I43#VN$TugBwf=K6(g*Nuiw{ zy1}H-PY=UjQW&R)$uKEQ(?cvw3iI`l1e3yQJ*G#cR1(FJe4u>T*R54RPymJwf7|?B8h_V>zgxlIt>Eug z@PAq>AYSOd_z^EQGtwssyN_YGVLVMu!{dY(7CZHDPX%wa4DJjAPT27DM<3`{!x=K} z6Z#-T#rwC5WXPsZ=y4$O^b=DVLg!Bn4tr^p73z^!tC%=P)EzpA;GZPY*INc-p#vAwHj^Z|ev8)rAb1$i>Y6@ctV=(47`B z1Y2A`JUo4msUiG8(Ct1@4e{sN8tDB%H~)mLb~Dh&f&S_Db8lv#uLk|o^zRKe&`&OA zNaiQuD>@tK>y|Ji`lG2DKK*n18R+$i4D_o1@$mF6BMkJKB!)cvr2INeG|;auXUGnS zl7@%(Up&=7pZEns7Ju@6*2Ej=sb4W%Yxzh2eU}>O)?fcw{kiw0fvyJq)AqG%gMlvm zmLcm5fy3m}cl)4$z6tcJpU`_BHqb|X$BJ>e7jfqVn~F6i?=DWAiY270&cNdG5vXRU#rxq~6?J_&yYl)&=ov)c*J zpZHHR{XpOKXW#c{GXwny=%4bhm$2f)KezkO^1t1}Kv#oa@=5&191ZlGy(r&LzVE0Y z1HI%3Lsq-~kwO0Z_vm4uC*1wB_MbY?KtBL_(jVUS_2bTH1KsQ1pOt^#$p-q4`wVg8 zv&x0S$KPeTfqv=npXL8byn$X1di^KyYru8*K-I~A#(!ea>Unx<3PXB*Qht?a6+GSP z>7RZ7lc-fZeH7^9Z2m|9pMHzO2KtEth8*~VtS_IrCk^yrh2U?W@TV6S4D^1b3_0z!+$7ij-1 z{ws)8?;i@T+I`Z0e}P-4c=}{0VC-ZF93~(BYlOaPq%}%&4(Y+z3|QwU#uSRbn7HujtcxIIg0kFETM7|Iw;}+Fsu{< z<7iYyY67SO77`K_5fRb0b*qp+T=5}LNohEIQ&&;(bmf>nd^V_!5hU~Yr1Bk00A4Gym9a`8X9|MH&+ z1|L8CK_CiH@K-9`-^?i;D;i=V<<1AXFs! z1?3~45yXT>BY7bSaZxb{Y9+OTds^`H;bWyT(k^(I%2DGZB4&Wx9Tt)Fopb1jUzSi| z=`tJ*=N%@5Cj3J?gD{(hG%qeHA%Y{e=7Kt~18oQdHLX-pF|l*vB0^#l;)oFqdTR8n zDWTCHTT`DMIFD5Dq78Z_u#gZmxUdkqmmnlGE-rL|z9Dk9T#eyvsc&b_HxC0fu?NC`49?Yk{IY~fXBUhK`H|*Z|Ec0gE7*h> z(9pRdr0>TT+^0;K78emeZB}$RneY#^S+OCps0=Y5TgFd`n-RioK1ur6Iwo{}2qi^? zhr~q0kd6OLOPG~_vZJI!ACto7#KqxLammA07QXHCABxJ7<|xt?$Q%5H#qd>|CsIMu z2*locV(bF09C#v?B27VD#S`Nrc)rvMC`+ga*$Jh`@g+mC&^CwLo<1rlzGZTO>e=OU zupqdgtSCg^mMEF$MpUpo391;t@6sWIXmI?yzFrUE5<+rLCK*uT9{? z(B8R5{W%RHE+Q;Cl(sj{O$Ds};F5f=N2Suau=k3bD@j|+_g9~YxCM#YCFVAD@aS}#!< zLt`SyZ2BI*AU*;0br<)Js!i6SzYB?s2csel^fi876kl5N(bs`fqYEO3=_?3)X$>+1 z#=rhXUqOiG%5<+eF#ffIzJkCN=~4?I+*>w%gEhyhms$eh-hQWVToRx)54*pj5~4z* zk&}>^S$Lln7cwn$W_WZ&JlP0xNJ3N$UK{BvN`zvwBE!Lu=2*jK2CXG;=^NLzu0h!$ zVDx>IXsH?Ypy4A#!_I(m&V4!ObO^8+--ot@khve~Kdpay>?6l? zJWvjbIdwcQ44*e<3WDASRF83v`JRXl4w6t8^p4{>*YR*}2g`Y3dYtpXw+lL2fJ!FP zK%4BmFn!?E0p9`9(ZVv&xth;?B?Lwv-a8#EbO4!aHux0aBXeRodK3Jzgbo&{9KdrD z^utl8FL7L9#>UMG<6QEx5FIwG{NOSSo#+Qw=mYWa>7k>CK5)jd7=uJZ$;|*PX^X)F zWpmzukdUy11+jeR6iRU(#hXE}qC<^P)Y2{}oRIK@S)uy8@lnx%#s_W&sV6#gDxVU* zL!#r15O}1WBo&J0@^zSoeg(i1I?z~(3PITs`ny@kQ$$GEw9q)pY^5|x-Y#s`%(;lT zBW(V#;5%lx)ccDgJ3#+{6DwNNLQoUXJAgyaC*GU|m6i0-%*6ezq%H64pKSY6+hLGr z2XU^+49-<_7+*p(2l~>cW1$&HKKFUKrl>C=o~6;DP%yYwB0SLUN6(gcrbWj=9YI{j z6QNBff(Fd>IxL~1AbYeqDy)R`;QDJ?%|fO{1x|@dh$p{NBzhK);EXiQEbZRb(APQ9 zu_TSYOlcWTR?x)9g(gJJBF2;r#l)gFfLFS=v_G}z!3ktMj|y)&g@jYS6cQ626&XoB zr>rPCep*yy0`Z~TCuUA`LR4(@0x}FuHzW$qx6>DD9U2}^22qX^J8NERYC&>2{sT8B zDaX;roDem0K|;jLc#`^&<&>zYoE@QT#^8`Tq7PqQblkTPx#n6LWpDbT=4%@r_1&R4 zrR4%DCu8z0k(W>Dux})ayAA>02L5ASl zHy!LTC}}EKh0sO`$(E0`9h_tAg9m*h9x$e;fYA6D(qd|hsWa!azzw?oQ|3fPhtoHL zbse|vBi&jC1hpkh(zkHWa#N#1ra$$(3pBXU^BB4Llh+72&w&1ZA zR7h-ro~K1QOrh9lf%n^g+21DTD#y01&b(8JQnm5@kK%gUBfFW@P;EQjkRv zu@OxN^N#-XD>H)7Hr ze%SAr1vDtel;)LqpdzuP7;i%63he2^1`V4l{;y&2Un%~-Uhw*?3UAO9cAzCLjHRy~ z=@%D0#1F0rVZ<@<^N2viYy(ceNHj&odQ?axG|^IM{gl$FC+M4|%|+TD;Xq;P0lX90 zc#23F8lcf7yfe?~Pk+uO%{I+G9bVF6?M1z>02nVI%m9i|o@#sePadG|02a5lnp&#&>SxS7~8E8zj?3A1I9m&tTZGBon_v<__Yf%UiUlXj&LG ztpDGwB}^dl%gpAQF3mE{`W{%(8WK$l`w9^5i^qLOOJk%7{odTW=|i|p0r1~Co|e`t zxW;oAz>+gSgv=RKRvIb=u0SJT-3IXQa=pLa?1Voe9R@xm;`oq=t41P@4~hPP4~Z%J zU>tA53nLP2#qMFrmv|=-z>ybI>==r>X`$`s3N0IjMi+dkKdu5)gZTe$i*lx= zl}mp@IlfD?O|#FUFleiqNL!UZ5MykbB+L|w9>kkTq#jA9NW2~iLg7)K%sE>{kr8_2 zM~ckTBin&dvE<0v9Gg!e}#oK@rNvIV@TX4D6mm1QLWaU5{{$ zJ)AOkcUYTIei{hGm}Bmd^kWWyJu$JVq^vMQfVz z0YUI2?GcdIm5|H^p0Ni|!a$Bt-oB{w+)fKx^S!_z&d$&aSPhzrtPbYvMvucwIrTD4Pi!bcCsICblrV>ehTa$WRB$QEGw^f?KPrH2H&BK;p}MUxF;OH zEIEiTBxE|Ebm{k}dm4BdlnSui?nElUw!k1QGHNO(aYFnIikveuEdH;GyL>$7xp;0M z9&X=6?Eh3ekGOco;TzKZ7j%!s|4e?~bMd4g9vTPTtMT6*PZ;-oa9bO`k3WP98i&uE z|1ci?a*%&`Bck%N~5GvGm|8d=-oPxgWYwG zeRao(6^)xq;A`r2b=j83tZ~5wuy#CV zCtpupw&yV?c}Gg?z+-O29E$kJQCLYCwx`^Y(t1%V6oC9G_1BwX0?#ByKAIBy(rf@_ zfS(-zec%?1nUGqUJit!_zPXf*kO!kVu#wb;#?gafQ}uBm z7+RBrpVPo+b-}BN0}9$1)qEm*$TTFDu!r>?O))vc9?|E{0en>hL#QM=_FrEv9tZSP~7A#srg$x zhk42O(}Fp_k;8oCcc{w?M>(vyX~>)@g#De5ArKhSe3?&kJ77rk6+XUBa$B0t>pye; zy2+PP^Trhp>uDMijZkj$q4bh3F$V1(?{5$;g8+7)$A-ygn*w{(oTkWglzfII%qI`I zJd86i7t4KzYL{6?w6So%%y0TqE1jbrCjoz%Vg)Uv_%R$@3M+MlsuQE zjZNVBkX3+t5_SRm0L}%TZ$*l|l)jYh0&fD(Op)Rq%|;^oildi^@Cj&Xi*{0P0_H7( zu~`7OkyhZhtb|c;tX0ZTJG4&4X6jDHeL^s5MKwi@7{2tS2#m&KCTxjco2&R)12AVj z7{v;_u$~OHqrtSMsq)gJVue2q#+ymusK!J}Unp=~19!u&!nbE7wzc^5ciGXbBAt34 z!*YERLi?P0AFD4hp~90=$FbBk>nT;_(;SayDJy3^y%dirb%MUM`zi8hoS(5`{kIrF zgPO>$;!-k7af$k!#9pKEdxk5*srBc2G+J?!q9J-TLGhS6p3ItXK`mC;(x5_dy%a6^ zm5ky5B~RfZM%TtDY^m=s&bPpG59ri=xE?>kD7c0gp~p`$3Wnw>&Z*kxHaA0UxZPca@5hA8=b@I~sTe8^bEb(ge(6DNetUhN7`-1c%Ni zQu;#q78krTkZ(9Gn8m1qz%Y{R$kb{8a7Wj`z!dB(v>t?we;1((G_wI^Ce5fk?l^4;7qb z^aY2>kyJ=e!b}*Do-V-nLwceS(ms=yp7`b}2vI!tuZ5_mh?L9Gp9)dDZzAV~C>|5ac_E6&3_=u-8H6YvGYC;U zW)Pxy%pgSZm_dl*v42B|qS^RJh~iO$5S3!c<6jY?_$2%%g(zAjT*+S+qV#c~5zz`I z;DxBRc>NEAD7`;kh~km|yb#6vGYC<%Z2o73C_cXbyb#6vGYC;U_UA&>EiMn^h>#zl z@j?{!U`2Ds3sDqBc~dSY{8Whg!!ajB=^g)TA&Lu^6QcA^{}7@+1clf>2vHyShF*yJ zfd302iUvYi{l6nb@qYi65XDpfl@P^K|Dq7ZJN}D86z}-|4k3z9>;JqEMY#s{9j~Is zr$Q7r&;4%-QG5>mq7X&9u8)K$9{nIh@#tR_qG-e)3sKbf$3hg3{~<*2_#Z+PkN+V= z@%TRoQMA4LVMC~3WrC@E^5C_NkyrK0SJL`hewC_Bo3=?yqt!J_O4uhF@d(i@vE%8o!PTDbvt z9#-tD%Z_{{O72J8G#kvFxhkq2nMMr6Ocr%qvYsozeug8d2l>KkG;*t@eVM7jky# zRTg*yVm;ws3sFJ%R|*v)4J}cCO1DJ;%2x#_zn}o+w_X9tR|P0Pp#bG46`=fr0+b(D zfO1U~pqwf|xwrz9ODI5vNcZkSq=Kpt3IB4fR)BJ<0Ob-2P%fbWy5pj<)$$|V$_ zTtWfLB^01sLIKJp6rfx}0m>y5pj<)$$|V$_TtWfLB^03C|1%0uP8FbBQUS^(6`&%h z3Q!SL1t^zPfO1I%D3?@#a!Ca!msEgqNd+jERDg0x1t^zPfO1I%D3?@#a!Ca!msEgq zO%$M969p*OL;=b*QGjyID?quX3Q#ax69p((ti=_eV7jP6QRQE5TMAGvP=Int1t^zP zfO4%=fO3HXluIf=xugP=ODaIQqym&nDnPlU0+dTCK)Iv>luIf=xugP=ODaIQCJIol zi2{^sq5$QZC_uR;3Q(?z0+jnlDL}bE0m>y6pj=xOpj@B;bu9+tc9>#r|W z;9NRe)t8D`l`5S_uqDo=byeo|dCsM|sxS3<&ZW7kFSSk1rG-^rYMY!(3#-1=zdGmA zv2K6P#ivFSeW@7dit9_Ym2>F~R9|YFoJ*xzs&o#{rBL;yz`5cwFSkw3#f~F=DR3^< zj`XF#xfBQbQs7*Q1AQrQF2#Yq6gZdSuc|NA7S6?!(vrSZ>o^x%_{Yk;0?suB{s0}gMT$V3ugbC{Zb(~7r8Yn+7nVLM!!~}=*v*!-TcO| zwXM=(t)Vw5^RglQFi4_5N%NW^{5VMZloj7Jgr7-L-Tf?d1(UBfOj>n1yhk9d9vbgI zVaHDZcs>7!?^!JRz6je`>QsEpoO+qdyPV61Qj(^kbfsxNk&-NRPORi#STaL(_q_Q7 zyDc$>`BzApyjjmQ{1I=Ev<7;wG|w=7tzpuAlB^wH#36QPbG2qH4$WnT*-uH4MtZh1 zx3J~}`H{xtI&jY&kzS9JGM2Tc5rE^4p-8Z4)%njCYVt)CT6Jzup=Oa_ z7YR0)Pr0A8>I^Q6*rswouumdo`U$_zHasR7djag{RInrE*=LZFT?1Gxb0 z!LS)Eo!-n&|1IiN;4fG|pP+W$$7sTOJ7HVeH~T`nkfCJQj_|lokSRQFC>*ic=LVvB z;8D>JJc-cMG@YSTD(Q_;Oik?qvw%6|v3@4~E&faCK6R>Y29StOQ}xX7vX|j&9X=&I zaA8MoGZ0KoH{oA4rTf&WYIYckPE$RP66AZ9rlzUT_+|Tm z^@^hoU-zl~eoR4IbkyPZ*M?PQ8X}dMhDa%0h(u=U51`8?b=2`bI>{~sd>sce6?FPO zusG`Qb)VWF98Q2Xrv8wySK65RLlvpa)E}luWv2cvid1Im4_BlzQ-6dam6`e@6{*bB zAEgK~(-DxdtD_EI_o@AfOyXib!&RC@6glefCvzH+jj2CXAt~Jyl-m-{5tQyCV7@pm zHoopt`_q}khUuuopP@rgnW;bPdy=P)I{evOpukZF+s$5$uWRs;1yq?SlgggMmpJP1 zb)VW_%oO%PM;$)gO%eIHN!Ia*Hm3g4J#kpph=mqM9lq>S`_}{&>8QiMHmFCLsehdU zm6`fKW5v)>hkv~yb=2YCaHDjtjyn7swVujM{S8}WDC(%gzx6O()KQ0j=LSLQsKdWUdl)E=I{bTe%<8Da->Chm%+!D2PN}DkI{XJ87o?6l{71AE zb=2WMru9^2>OZbXWv2d<;*KS7)Zst|-7&fMyi#qD?b)VWFZgsXQGxf*VZ=(n~1|4-oP-UhO)O~7yx1g@dO#R*MkMYt7 z9d-EQf?SoE`r|F98#?OnCkDAHGxhhd_ex!L)Zy<5@3Jhcjyn9QL1C4d`g;Yr>Zrq? zW*?He>ZrrtHz=$!Q-43pa}ql0@K@L~rLa2c@Q=5=BO^y0{t1>hTjZ$2Kgm9a;*p~c z|8#kvMvglCGwc@07d=6)wm9nWop}?@bU6oWDULe)V4vF08m8gy6h|F?iJZca()sO- zu09=g@WBlqJ^1eO1ir*khac=y`+37OHbX}penSA&QHS4XUY1-q>fixC!3E*g;NpOd zsllKh^@DwCf4b#6iLKF5hd(1&F?H18&$KKZI_mIeSw6}`M;-p`V6|0d>K|e|O5tgh zbkyM=YA=?NsG|;lj^#Tmv@!J$3!utO{kZ{DJwg9)+fABMM;-n=+Xpam)Zx#Ujw6|= zzd&k7GE;wHfCHJSzbL?g%+y~T;6P^TFA4B{aMZy$@LrTv+W~K0{K3YQ1BjAgV>%*^ zVNh{6@K!(Ar}mdxVy@~ZT#99OnLs$|-~pdo(mZ6Qydrr90^E(a(N;g$r}mGqTd;=W zsKZ}w*{7GKI4v3pWTw1%OamArQx66=F)LWoPU8LfJAgW97@o|r){kU^r?A1ESEJ%LaZvL%$8sUF z_kldt%MZn1zJpKQ3V3k7g6TB_S?x*=>lhTNnL_v@!fzAqPPmQ*uVn*RkWa7*4di}) zt>fCkg7!wxQS1Gs6Vl9oc7+ow_^ITy-$Mm+3R(~g+EGC8vP}w@dX6myF4O`F=+xT? znO5LXE_5>@_ZeD=xL@REWCjugHzVJ|;pezt6DMuL{URrA(o^JSQ+Mu5L7f}%U7m0H}o8W#n z!Ts!wS}*i3!rQQ5OdIEZHo^UDg8SJ7_p=G^XA|7dZq)ul8<9BovkC5J6Wq@}ru9M_ z5k;YmNSyoGi2DT|AeH;ELX7(nV!iorj-0d&08s8%C@kDBDBK$E7ZfdUzo;qn)<*7E zaMH#`_=XDni^RDfys`ykBy`fIFmlqSbt4;*IQO&Ttma1kMdI8KPTDj#@-GtSesIzj z=YDX~riCN_BAOdHX^V3|IBCil{bEkq;@l5T+7w1k+FIg%p_4Y@elaI)aqb5v zZMtHSleRebgOj#6_k%I5&LHwH66bz!(iZ1_aMBj%esI#JF!C>=FtQPeb3Zs~OK?9p zX=BF`_k)u*){eLzoU|z}_!m)J@Gqjc;9o>>Gu+Rj;Z}3Mn3J|R_k)wRwsF6hleUQa z!AaYf;eK2wJRw@7%IPfodw&4t$48iu&^H6K$hQX1{TcvW3k^tU)w(%YTZ>(O<+}BI_W_W|Nk^%OBIgC@W^;=s7 zxuJQxlyBL~f$KK0{2v6HgX;5a_K&5!$?ErE&O3VCgX!;;l9PEoXA$houU*?2c1#xf zAR5!oN48_9m7}=zD9NA>Tm2d*ThrmUIM=pf- z_Q~ydf!qmP`wkiK6sg^aIn?dX0qiN|&B3({X=J7f+6TG$`3SgY_L9=8i5IU%XVU~f z4_w=owfC0R>%peI>`_QyFs}y6GU=;kCQD39%VbUCU)cVGX)b^jaWJz zx3XbMXzdK%#`rDOHdo5rCuvTrHDc+3N94eja?l4JOBbSI(Fn zD!5X9SWem3U#qpi(si~GOIK&Ut#qZVbt9JE#FetEM0RWmj1=Al(lfg z(&;DG<|CGV2cFh8AGuQ2!VydVmv*JBV~tq)c5|i7r$!U4))-6QU#{ve=So>;5V7^RQSSv$_s6&F~#;sQ%oTwv*n$d zvPLm=A=@))w|^<*x5tt&ISOS<&Z9$aw-*nu>y8`Q{RE__Ydw_sJ2m1yW9q%x`Bd9b9WKdYn$zJHxTvgE_oet7ZLR(%fpURZXQuT z&c)`tAUR~~7q8&A_A@>nSwv*=d$(_QyofQqpbtW39Xkd=Y3E4rM zF`j^4mZ7|vCF*&`s~U}LGZQt;siKrcj(G#P=D{Ghs^YMkuc2=cQi)+TD?9;I-GQ`q zHQRcdu#9c2=ADs&5mwDa!qYBAnMT502v4U+*$IRm;TeSA2dsqx>zVYiJqc&FZY8Y1 zzHum4%dK5^MokS%p2cP_M`ryx!a1hlJc9`2i1x4_KKZ4d86<;$A4T}9aDUWppcTGh zgm`m2*fr8QEz)RPi9vBL%MB+}57>RgALM3+l1UljEZ}XuHz4d`kv|f>& zN1;rL?EHTz(1~7oMRtz+HfeLV?La47x*|LON7|f`l4lE)JX@gT*#afc7ASePK*_TO zN}erH@~lwuvT-2~Pb&}4R4MaT9-ir;Y*%@Brdrvx^6*TJvU26&nObGn%EL2t%F308 zXX>?0<>8s0%F308XZq6HQ^>AH6ix^M8NnUQ1y$X#3Nb%HNct`i@={p z^B(vR5M-D?SZenMeKp;g3fc1M{3+rc-;M0`F2tPw82zv>VXt#AhN5g4Cn?kb(I;`B z0n$vEzGtwg@@op}2d_gqlnm3SwTlsEwiTw2@{XcxS+#$ghUwF5sK{RBE-OZuN#W_8 z^iuUN7p70I*dlwynJThZKHC2o5oVh45;_6Q#~ehKb)?Ap$a-GKCj&{IvaH2qS-l7; zAzaJ~6M?FiErrj5qbRYQ4+vUC23WI_?d`+%u9o)L7TFZsFtGYhSp6!NuT9DipC%1N zG&C}>b~X6EKGPw=z_w*lUz8u>J}Sx&xxX#H8vpqw^~K$NT1Ni!10@$3 zn9Ub=_dSoh;PSiaUxb0tY0(oTOe*FwG1*r2YfK-$042m;e)Jq3VQ+X0FJ={N=^=a^ z?MfdJj*W9TVk2qs<2j;r5fdhOmQA(PIBlWr(XS`RVlMx8VZ>!gGEvi;uXCAPGmWN?P$ zl(R4@o#o!_>_otN>2PnhaTTC0>;5uJuGPh;`7viXBi{~1@_$EK!+o43eQ#|iT}#p8vmx!I?V4vK;h%QTcin%c6Ww9{d*RUdf;E^=EwAc{x++6P4Z1{wky?Q_>O3 zp!sFX*ly=E5{xP7TS%Y7^vW7dA6H19#`G?`X!@)|y3h2kbfkiImKV~`VS2a4lJ5OR z#FQ6M4rj*ngx9Q#bT+d5_n>6t1~t`YH>jy*+@MAgq$ng6TYJC$TR8ljE3ClZs@sgb z&<$!7K}wmwm-~pn2a|44{el}*Kkf$AHF1L)g^p5BGvWr-CETEfC=4B?ohnxi^F$HS zwb~U{6gn!L09|3ZA&SD#QHsLQQDLuih2;`%P+h_es!O;*bqP19t~ocTQRt|+D=e3E zh2@g2uw1KLVMU(pJqN7 zT*4KWOSnOG2{))N;Re-3uCTuDZcq!J?SuPHTwx(rRNNI-1f$SVaaULf*Qs@*&{1($ zSP0jtxhkea=%~0WEQIUS+$eNZ+!YqWb?PHX-Jl{|rxuPvM`^Aa*&|$M+!YqWb!y=# zbX43G7Q%JLU17nqeZmzM!gVHGVIf>+!W9<6btYV4x#r!VB3x(E6;>=j?OD=dWT zWXF*i4?;(=c4TCa&{2vDp`#QRLPsesgpN{t-&b^l8Vem2cZG#;oo#c46$>2|xxzxY z&M)H%iwgx=T+6Po+!hpo8&oyp*%QFhvOasBTt~F5&t50~4{2GS{kasNWqtN0DL~8m z?9FmW%lhmiayikmKKq2EY8X(uSB+WLcNfe0Ov180ld!DMBrNMQ3CsFS!m>V-u&mD{ zEbB7~%lb^hvOd#K<`P)eXA+k6nE{%omi3v0WqoER%~Q+z%+89`vOY6Vky_Sgl9u(% z65q41tQY5Ew~%@EGGxo-ng0W3ESjMW%W~H-FRCT*Jb0I0rfOA=`&%j_#kt zD!#8;#cwzRXPYMO_58_!*ryr~a)8K2M=u z6PHmjHp^EN#ldvyUkrr$m0U)}*zCb#39U~3n+-nClk%?+2vuB0+2`mos%i&N9&;8L zk9pLP>fDVFY;Qgyk$U7Qlvoe$M!pLMNE-Ng$&Bv9bA(M)3 z^NVitFU0&E6dN*^xK&}U(27(>B#XMQwsZ3%xf9zuKpah=rvfcOyN`VtO(C3GS3KP2uc`L_T! zi0A#hw3oqVeS>)BZxFnMcsXpKr1w7qHS%2amcg2XdpVr4&1l!OYuCFP$Gtn^tB;5M z|GuNgZ$N7mtBEDlb^LEmXio{6u^i5B9Z?=mKxim&%s@|!rY_@UA7yEqt!gTCu< zfWPcetU4E=|7Ae%t~5Xb0E|e>*+{v=`#5iaL;?7T`u$J2BL*NzLIJD~lQs=RlEeeJ zUgH6z+%YWmE*ItJVX3EB>KG>7940->Bncg`K|=?m+zUwZN-&a+!@Qs{xptI5yc}(+Pc|b|$47 zC;I}VEyiFDS3 z#sAWr|9kwidP;IW6>G|vlJj{3=6oOXFXN%tPFBLKB#(`&Ouh9JzV*=?aJ`| z@Jjg7|BnS9bMRz;>&jI)u~ zNXSJ`zFq~j*DK_yTkao+6_YqP-G7( z33s{!1&gMB5Nj7r{fef3MN_}0NMvYR64D_uA^&ZpnryjW574P->Q^-NE1LR+>eIy- zWnZLl5{o4KJjm}3pQONgm)jk)c%Wpj!8ac-LW#S1-5KD|RFJ{oR}?eLeTMPt{)D6l zzqy{4^o{t=QX6D&j8bpmQz~6GgY;-C`Ok3qT}FOH$}_wHO1;982D6XpfYtk9JZ3PT zXsZZ2f{mNO?CBE1J98nt2~b^di9`Qi0S33>H-`3rIsFXZ?|l8kd~f$!epfD6~;i6xygMD$S{lnxYQ5_fz=2 zkq89q5`kb{A`q+_rShUH(y9xd*dPu)Nt^ev>U~_4<{0F3C(waTa#&E8ld0v+OK9 znQXqH@>k5A9jta_qZSVY3mdgHSml_F+MV){Us$=2i=PYx3mY}fjcnB7fnZ^yR*e%E z>7Bqvtx=xCSD4DKY;1wlj@ziQHJ2~gs3|Vks3|Vks42ehD+Yr7T59!v3}R*be}Dxp z^+V77e`nf}q+?anNWM;n9)lSx?k zuV|nfVbxV^h4D#Ylf?wKKtjcLw)#n}A%!~*P#djDHY&zh(r6zx`VF=bT49NV%y@K| zYQ2eIYQAa2cJJ69XcxlQ&PLZF6icBZ_Skh>**^!52S3BT;n019ZpEhz1_Pf0Vkf2B z^6ArA)755P;GIx64M>c!Ts2@Ewc-A?-Haso6u2M%vaUyNBsz4}(qUkX z<$7{Am7d9bHG#bX&_5dEbd5uBh?DXI493dO_cA{G4g&0E`{w@0Ja=~DLYN@HQO>@%b@X&sdS7(0$p~^@^GoifO&j z{}tE9Zr2S(?XT^@m9$ndNfyW2Qlv*WDhDqpkXZJe*!i9xRNHM@t6^EK!R$N8F_ z8WdK(X7>tmm9N=pHqO`VzCq!y$A+S=(f0R$#ixe#>>B?2{Dz|1?y41*one*XDqpin zzGjnr&CU*1Tltzj#K!rWP4YE6$MT&O6N)K}T>C3jzP9bqpj^7hr+{4`ZAW~~E(~zM z*X*JI2Yk&g4sc;Zk-fWog0FGacEGyfFPq7dFp4OO$r%K2kK?XhS6W?dwa41Z8NBnC z+PD>#U1k>{TU?*=fX`ZaPXtz2JOcsl#@lFX>x5z)$u@;zTqrytniGoYWl`0ORBC@x zsWS{I)Y!|7x2`digq_Yu;6}h|5U?}(1INs$hWgew*sz)IRUO9ab6LH?u<8-`yc$)n zXZ6njYnHG`J;lP^d!cI87S=n4i8~wCA-x)b92LOr$a*sXYwt(7i;=$xpE~G=$$Pz? zDYxU(^Axr)noo@Up3&j??7^#l9R)tarvXEs&7p5ZdL7hF1whv{5zDF9-jwZimwBb! zeS<*DR-kX|?YJY}on{KYH(#OSe2;U#6Wxi(E(MgNfa$hSz{nnd8rli$@moy+BYS)f zn^GpV$4^i|KOa#*KTZK%6ABo)m5Nb7m!NIRTQuVk(~}!DPXHbcD!qw zqkt`l?1Dbx6wo!HfT3Hd7zK233g{9P&?P9KOHe?UaDnP>)XtRxx(#s(=x&`NL{d$~ z+->S}s3G?g-1hDcYE;>LpWH8TYq>kAKV|a++Rr_HzUS`wG45lV9|*L}bNA|)M*ywx z+(zwBDWH2G9v$92NPR1tpU|wxPV0q+_==PQx&#Gu|Ibjsg2+y1`{hJ-TDK*Uo#wVA zveVpFitMy-D@Ar%`0F9E)3I)ULwtSLCn#Xd5I;@<+iHlfGiasAPDx%QvQrqjl~UMR zksUjZC?G_3tQ}E6xRp{|5ZNg%i0l*>M0Se5Dg|td$c`taB?=gGD;4dF!mU)3eNndX z)hS@$qSROSPuwuA>Ivra8TnL|;X0F?9g0s74s!=)zeSRz;WMib0yZD8d|xTgvLs9C z-ju(Ae)VRJMxZ8!`89N{>gwDwHel4P>Qo$CZ^KSxUAN-9+Yhy|_fXq(hi9vzHX7b! zq2LYN8mMK#8+RB#w^14i-n4cxs(CT0xlOPxn_yiw!Mci3&5N4+pBKF8ljQ3mc+;_N zf5F>%d^UUj8vgsd;EiT$6u#2^QCkIXI)hdU-nbbV6TB&m1aAskD|lna5$l5BO*cB% znacH?#lip=1aF#O5WFca2;LMYSQl4q2M^691#e7_3*LyojNpy+T5^BXI>8%T*e2`Z zLbV`xV}0wnET~NC`@;c(ZPKc-WI>&f48=6+*^)w${Y>Z`%Eg9KE;b*q+OgPBZmFIL z7^t36cpIplNq{1#ogKq{A#dzJvZ?EL#=x)CHib}W>fEOkO0cuCjxbw|^Q`9tXW zC`6$+OG^ggtb@?1&3DELeII>g7XrSD1DO%F)7}TpVkixfI4hjT|GEYmU7|P9K>I>3 z>6}Kiqv@t9v`KYM|+V@bLOUto*ftPe%5-QHR8Wqau z+Wc>jyk;YDR?Dpf?&bpHi*!G=P}UedK*D9%z8inHi7BHYn*PxB#T^D{mFQy!!` z(d~ukQ&ezv6@;OhKV6eVYW@QNI#Fg9D@+&`<~C(#)+qO9;k(n7_%g5H+-kdW#Bm{? zDifVHFrNvMk5s-*vXA2{dT!u~d?}8xqsh7Gj%GoerL&F1S?Z@d@+%p*?XG;XE7mad zq27`PS`#nn+Hxe$Qiq-pnQt&E_8wZEqpq}{7SafOFEw#1!6_N=a0t3S$s8x#Hy`c(sc%rIO~hO zq(3YjMdB=lkvL0XB+lxFQQG{em0fWaLj$c3;1_A2v36XXrMMu@Qd|&cDK3b!6q8tS z4&qpdt5zUZ96*!|VnvVT5eBiMSM;qhan?4yq_cStD_)U21M+S}uyWo;TVvv^Ejah0 z=Kpyw>1+YSiZ_p`;N6XD<`w`LTH^)Voi6@O_=suFOL}lwY(Yhnb_H+dRU=8PW|1)+ zFOM0LssZ>wo^@XesVn)oyOgww!m1Nk9Gx;KV$Dxjb$?b}AWtw>TZPY0$;qVhTvmRV zumeu5naii!?+D9E2^%?@K0(t9*>vrSMNo5FMCMnE46lZ&W@bM7m?*Zj`p!E;-=!QQP%w z`|+sldOl&^3fit`Bk8_D+r0{-7X`WoWJGFnJYV3O@=EbO9E7)p>4@)Z$v5#4zIijo z(KfFnE`=_zyQ(j!z#ED0ABEJ^9DF66)&!18=yW9WB)-faIPuZuG#qmf91I+jtX#Fi zGb0xwaX4mB(y<(cCK9$2MEHD@Hvww`}58i%sJhIIo{6C-zUqB zX0{9n=i3 zS(MDgQ$ zF(xnb*>0AK(nIhG8t-Vzd?vM@k1rABr`0$qy_hNNV>})h=_NrQI1d9bG%-#}FXiRZ z{$|{^BFazyv>e7s>1%?D!lE;LR`U$3Zr`P})7z4Q$u zrSlHC|HA+DjapAd`RNT@n^2UWzV!)o9|kc<-}aFp)l5y_(Iv$^)l5y_IY7{Wa%!fg z@6jFx0%6Se>X=6WVbB}3KNaPt9~dn4RFt27aJ--i<#UfgE01U^6LY8GmPkLQ^;DFf zeq51?^3zZLJ5E(7%1=N2n#^IQ*NMY7ELp*6Rq%GLAjCp*VLSaXnNJwz{|U#Pd1sgT zPqQdzYmUHzX;X3(H1!$tIsZaesMP}rS2QZ zic3Qbk58UpJcf)?DDUqDz9So)9wA3o6B!b zRX)b6`3y^=T9>3>6WhmHbX^-^o(Gs)B-6z)3S7EF`k}fx5`4Q#dvylu*@p2 zPak5ZOH(le4<46%Ay+CS5^7{0`00&ewy(qweygt1+z=6Czy(GZ*L0->}c@xTV?SSp`IEJ8} z0`({#g8IjSx26Nrqx4cs%;o%qYp~3|B=AIRpW%Q{C21FedR~K5!qWmlJ#UzQ! zygAcHSe`Z!)TftQ_UUDNphVO&1ogaKOa<>}-unP$K5v=sqQ?+ERQ8bcq4>@+>?JRz z;6i9W122O2KsClV4KnJgc9OH}b1@Gxf_Ujj+DF(xr>PUdV)IV<`MNfLavW)xyOn6YhI6BFQNgO zr$I*Dj+)ny`-mgkN%J(wsM}eQ1{rk&6={%Bmkct>ELjTUwZ9lkaWa-7o9dAJGybPK zYDF*iA7EXnPKtc5{T(QHmK3baJ;8!q#>uF?++8f#Rgv#i{S5_I9lO%&;CIN4MwZ|4 zzk`A|qMF}Hk)PYK8&HL!Z0>TF?5wENYnR9TvSwQDd7L$~chFP$vZY|x`-DCD3(%g~ zkNx$Shw?KB7sx}!RUd`+%zPHDnYRKIfBri-to<05p;^dOukPPaWeBUxkSZkboqtR* zef{Di@FRkSCV-{)gv@p(!8}s-`~#?E`m@?oM(VLn52@FHJ&|8a+A0=pG#^)@SZ6Cq zEYcvw8qJ{`TX#)o+5k!KWzJ`_b=D9Ml(hU{Tm$C!Og}`+Gkt{QH7tfZa(xh;$NqXR zXW4_;_R(6F<@Uqpa%A_Z!g8CVa7edEHPgTUfP=Br_}g(2vL-R>ZpmUVALDZjTH5Jnygu&Y={X;8XAWy1dNKFx zyc23q;o*jXQ*k(OcYF;x90`Njt~rQJ*Ik6B-{o0)P?~15{!e%fXu}V%;p@<_*ZWD7 zG~+q$PxZXB+)#Y(Ms^?Z*7b?B@iK4&ee-`}Sm!;~F7x>W+VO9|o7vk5Qj)cA!l!g+ z{1oIhcRai659IYeu|0|n;-uGUcP#iBK6@ftyZe!0@m0Y6zRQAF3ASrj^&QS({#f97 z$R5I_coucv!N*){3hOa6Of9TQ?`zmI4WP_T+B17CU5~3M>iOTL={tbE-eby9GS3TP zxE5#8Dfn!PiVv0Ie*tcg-^0V?#J3v=EP)7ik^DZu!?+3~1oo5Y9-|D~w`-4(IW(Zz zG5ElPM{EvZYGDr9X{f}-37+@8Zv!@i@mex_>mWJ6+ws{0o$6{%m0lNdP%_B9WRPb^ zgPbP$R{{5v<=scHnX$`>p4nH9HzLm)zP1B;xt}NCBS~d1-@n>;&meavxlI1dk^K)~ zy>#>;VHGy_>K7h~-NFAR90}NS#Uk8ue<7St$ffz1=y;$JGKNnGuOyVk`YZeXCE&>U zIN(V?(O?`MVv9BCVx$B&mMrNi4DCDkn0B#JL&MZjyj5OCi}=f4g+|$7@aE{f71;FS zmA9iVDyMlZKA)h1E^0qnf^OK7(?#tsxIeK>c7WjBfW6_TcSK9)v$oOXSWZF-S_e3j{)EG_^KlhLdL?)wrivcm;G2D}@m ztrieqCUq_g>1qBJ%h|OvC(Orx&hQ1!@WR4r z9`rF1mD7rc9@>&#ph+RGsyRL?Ysf8)-(Yq2olyQM>HHOW>z+_5d)3uJjFN~RT8?%S;_BLkDo{NqH>w3YwhD81% zF~<7?o`cpKG7|jNOdXCl@}oMR_b?_?wnIyb&dqB#?~h8McJpc;N7~JkfCBAiW_a22 z@O2?RVr2C>?dCgKqy_EfnaHCw)=@jo&wmfFIqhc3$V2Vs37BhAyO}BYwbvdZ(NKfA z&Dzb)80$ZSPCsWh_RrUDF8bFLe@!m#ugP88s25Um+Rf^rN&Pi_v9Z235^6U;B~5Ao znC)Y%ulHI{_Y?z z1P5Ml0wh&`@r}Hq`mDeTnk_#2>m#DlEj|~c&t$f^MJBF4LxbZ5wUW-tea_=zZ1K5T zeHY-TXi(&Et;*zn;|KGmVBe8WrtJ=h-$54$x(cX2erPEgxB#tOD7Ah# z0n$v%>0M-a{eMO*Kf^DUii0O(y(e)HYo&bueefGva{B#}sh7&}K)GtJkmGr%G3Xb} z`=Q{AiI=m7D+O;PmJ<%aBc}Dn6kNeO^UPf(J-D@7R}A`q^&xpg{;_-FsWTEcVb-iS zL-1RDy)-ifKcChcUR7Sdw^@3dWmytd6CbVhH&1TrX6Apr0apI&2_zgE@5`1WSgG6uWX7gPX zSuzbxFJn`;NYlgi2HuTr{fFR%#1n8*%?81j5-(u>FJ#ht?c;g7$PIp*;T`POu0La! zBbT1wncK}k49%^*`}AGpCcMLp6@1PqyDWti=uX3E$9C5&8O}5135Tn zC4P^mAOpD=&Ax!oF3TXC{G04syS2BU;f>u1ncqZp$+*pNht93N>5PG^dClJL7{>ZK zOwSuT9tE#OLEexbI^MG0xLc9N$J3)o$G-pQYTSyWJMk;cuTPOR`aOPa!Pofb@bw$C zHTrQJjM<7h6Z)dqPxr;RhvC4kJ!sc)_&;H9d_9EJ2@I%w7hX*h7UJMdzN5Txe?^~s z0*>I8&`LM@avYDp5MSj7py{)5Fy?S%P53FxAZfx)IGB!u-S`-DYd?dpyulZ6fgdx! z!R%7b)jDtRUzzet^OB@gAjQk_LWmwLX)ntQfo~&up@1UrN?^V`m=D25EEg-Pz&Fkk zBy{eGDmy-mBeR63`*eLM@qt8%!``^e{rXLclC6DbYB)cB->wBr(t!g`mF!3)%!i0}15|L-*GtorS8ck#$&>(XedDzZEph&^a!6yuN+n;pl zX|ODf0@9xkw$};C!TK}whdmfiv8waf&Z}%EFYT}mQYtz;WK5DeR;)u&saVH~yRl+* z(pun;!phnq#DZ^5#}CSe$Fvz?WpAMQrpBW!#(1;E7;nWGZ*DrY_xUgtwfv?Yc8W3H z@?X_qw6ehB9+dn9hN}Lr@suMO4|aZIF++-bP{kN;fyTa@ZYjDU$D_u6TOCI0Jr{Y{ ziN_2n#(0xerQ-g-{vMQ-Jt)~^vcV=3cb3w!vlMzXJe$0#wmZJs8}1;HQ+}7zF9IeEw+RTCU<3M(nfp8FHXVqwdJ@;qNV+h!@5YE{|l&|(@&u0U9wMik| zsStcx@B7#s@Xf;@eOElLjSAfxj?Rj7k3aTuf51<{P&ujP_#n?%8!tKb zQ|?orqYDLYO&u!6g>Wt@gmbMF!o?ga7U`Z_5_q=0@Bhb;zEnAC72Tu!%d8~JDi@YT zhIJ@N(N&~U(6JG1 z9G-_}b?W=F>sttA>icr)PZ7%0_vM)1BjnWg<Y3qXFUQwa_>}Mht+He@ISWy_RSW)P=PEimw%G)@WsID5yYxT5Idboq3F@h z&>@5y!v9C|)FX(U%>@#VAn@~xjOmu$9P<1c1h3& zZmp{@w3LP`o{Gb=UbtBj;fjNb8m>5~ryIfw!VO_o3_XI_>lKB5>wYest49!fqt**I zgt<1MM-Y4KLDGuGs-pe>T25aRtn)SWInKj)HdAFrRBu z=ohuFMnaZzLtYPX0>h< zuJ|W-z=mEz?6@E|3RleOhF(JK#2`2FTenf_s+SOiE7nJldI>?eV(lo}5Z2r%T=BzF zSG|NFT(K68{MPZDgkD1I3i}NytX@Lw@s@XFoI}f(>DX(T4CVk_#^(Jm4p|Ai`L67K47&2BJqh-7XBS0g4_G zHAPn}3Rle1p|cQ#E9Rrz=G9pU!WHXkM^RHcNnv#sf^fxaWhCk>1mTML&I+A{*uw%C zMNQG%C~687ghS`vcAo7E7&!~E^QGg+SqP%0uy*7u1W{8I7dC_y7ow&pE<{aHOfJef z@LrTvD}*cN0HS2*wvCKq_zal`91mAa%yUH1Bf=Fg7YLsrJm7Onnuq#3uSlMO0C(eU z6c1PYJFKCozuV=OeR^5O_KrpZ^>^Mprh<1jt{G;Q`@BWE^M?}Bk&KjACH)C}Xa9^Z z{@4jFi@gPTB1YQM)~`|%NV2-0gWBHW+w966-tI+C*m$SmpY=W* z4?<@8;`=kqne!If_a~HWO@KT%n54c_Bl>JHq>EMGbGB|jloF#yTYnZu*_x0pR$b89 zYIcEZOX!~Mxj;~0^l0)Rj`!=SC?4>-+yOq|0zz7R8V*&?^%^aPBd^ z7Mhnp3bzkfUooT$p5`F@m3QL5+s*2_MG=bW#wuieZd{OC4C&&P#w3vE$O^V3f&8}Q z(vXWk*NY)ta5)u2x@`B5E>4Xe-@;oV+*v+`T&OQNjM>FZLOKZ$iO>?zDBW2e#0TTK zg!Irgh>wExM6zEzi1i;J6mB+%V!O?N)nbY@oGtzh5LfsL6s)P;8`c*pJp=*UMF`l5 z6G^~oCm_(pueEO>V56%73_@8OH@FKPCtw?; ztW9oSKYsS}`1h-7VUszS=zcE#_f=fgQB zj4z@q76rHvNRPd_d?ApYV#?a6swjJXT(yF%Epj!%}`f3tUaGg>AZ;;2FXbqB-LW*2iVB1^-Oimo1LL)HSGTBfc#Vt zj37>+{0w=D9fq$$B;wC8r)ZaQ8p?^-%C(+3ITc&EYUwFpPAmm zBj#kqNtcZ~>9W@b^>mj~LAXm9XHNEdMd2>xk1<4>4|gfGUbsscXHNFkDe^)KcPTYK zZMaK$spM(g0(&P}g3X7!l-fhMOR19$cPX{MaF;Ufq{}`?R$=quE~T~-?ow*KaF_f(# zbVV@QrPSPLms0CSyOeR}gk4I_jdm&H%n7@cnj7s>#+ehg3ggTPyOdfu+NIRoXqPh1 zoUlu&g`-`{ICH`-Wt=%-momYeuuGX>PS~YPFemI%CN$=-OUaF(rW$kDrDRmqg2r5I zmoly~hh0h?t1>6-Qhu?p+OKsdq7j`KZ;YzW2>{9Z8&#izdWqCz@ zjyc&NvVlFqM$8Gjluev;wTd}$q40!gnK@O>CQmwzJgKW(k>p6^I{T0(9c_@_k&PS+ zSiKlZY909|I-f|q;atB9ITxC4BCYb$p|EhSpm1wAS5UOTxuT}f+n45CY~;&wF0I=V=hEDkIG5(Ol5=U{R&p*a z{Po~mI@Yf<=h7Mc6F3(;E^@AagtV$^Avw<`a;{E>T#G!X%N+2XSHOu(2d?xmKvJp> zjXK7_ttx&DXquAuk8W6NDtZojfgAGAf9@dk!bt7wAj%M)a zVk64IdIlWq^cV*lFC1*lp5$Qn?g1rsjE&r}SFtwNgPB%ISnkGq zke>f34^o{dA`o-GubFfDg4|1I8)@gaN$#a}TjF4v+Y$%U+*WchE!;{DriH&A98AZ$ z{W%z)8rJjI@Zaa*QW+VVgUKTqr#Mo0EG5m&FzoFzKohq&|7j z8Z$_qX{0)&JU4+WsdCoN6ixk_kjhyD+48$Us(v+CIyww#H3_||OLn+=nd zMX_07QJ0{*h4@%Tb2q0C=SWg+*#PG`e^&s1JibzIGdY`{jeo=$9(V|+mBK$iV;|?3 zSFdDR%8iHHU>}st^X8PX4YX(=%1MzK3m)N#+3Hs(9(|SdP zucE?Na@(?~@a4IgHok4?X4&|*rJEh7*A*4Mysq4)-1@at_$t8`V%E1m#^clXt*=Nq zoxcnyGn%ZWYDdsJiPU2!_E_lIN%U6H<4Di$!3>Bm@a^!C?O1RtdTc;ruOqK|FjU;% zAj#@2`eS5oGoLkH1;}2_e9ts6e>Z{y126}m7P7WJd^Vo~Q1=b+Ez@^5!1c^KDF9D0 z?*iuaqe9U~fc47*U}o2z1RGGv7=~@d+W831(SHQ`I#3ZJ+z336aAlbJ3{d^b6T?h% zNbSj<*^xb`4`(?D19xIy4MZoS13}|~z>>KNEB{J$EtS zjS>6|u;Ce=XenH`Jj%Ia2^u*nNUuMFU{HX@90_!E03HQsJbGZ*z>#d=H4gvqqtMek zY+B%Yz}jOm8$sRRPNeo&%tp{3}%xrB_$?u;vq1L^Day9N1n7qcr;poP$Yf7!hYxi6q4JKP+i zx#RKAn}=1l-oU;21M9$Pp10rIdWXmltj%am!kOrgw4_2P2hd83nn+BJ4ni^c={Rha zMNK3omkuK_Ii3*weWDgMMI8n4p^&hsv7>aszJz?7H%?4Gt}v93a|b6--R!`^%@K7Jv3XoGw_=mU2{QAYtw-@IO^E>b8TSJb?Ge3RT*Uw@05f_z+O z`{m^0TDK+nxaPJbAJ^Pg%Ez^EE9K)_`0F7b*RgJY`8b~%O)P5uL3*J&gI3DN@0Z&r zl8-BlYFZ~BXA9eu zk8`2${BKS^9$Xe%Pyq7r!$5b;GbB-shL!kZfRyK`RiS*mo<9h_1z0UV0qSLYaR2I; zS*KpAA5bIgtQYIwgMu}PPbuK{1mKSX$|*Bfn&vUKp!IItha_t;sMeHswb%DJsDU*B z$x>76fk<=8w*qg0RxOw*S9hcE<)_>*{43bu(6fs}7qnph7XL*8?HNFUK${ux&W*2i z_>}Mf0{Vd1Z3cq3z)kp9uwZ6~p<0696J%fbmZkdvKYtA&?Qr}?((h8=ss%HLU$&14 zyahV7!*TtXg0|YvJsSR~wPDpq2vKOkta+gYvm(()a03pKHfV?QK03)R1biI_G8J_C zK5){4Ih+8!1-c<&uPV@16k0GV3N4rwg%-?;LJMX^p#`&|(1KYJ_*Pr}#&8-D-*QtG zl5b4`nc|fzbA&#^MZn6pA`50Fg?!7+&><+_a7F>;hToW=o?0*~2rZZ!afS*O z%!&fR*Tw4!!6?zYnfg@H=06r^@I?#>N@)DFkp zqdlk{j=NVUt9CeUqxKgHwC|L9>MhVc__!eDTka8UWn$nrM(c$FZAHqr+>=SaG0)2! zW_s>Z9;7<$fmRJGRB(0`gcXEX?`b%8Z{v{O0tWzeqOnn|Fkx7jik_WWquif`?@n9+ zG3L;AY1R=Inh)JyW1vyV>DO!mK$$5-IxWl<|^NU1@pc5NgT6a)<;le!K{Uq zZ^43Db0Z7phoo*~!K{UqZ@K*}&q>UJ`AjJsSupdCj9W1CW{X=eKZoLR3ubk{x;a(( zm_x=Hc8lb{lfo(BYKNYy-$XNA=p&}7=jtYYV|1*_x8S*YyZMdb8^n5U4gY1j8Vvf; zm<2Q6NqA(07RalrLcMnM4*z3u>@TFySZ9( zEZ*_2uwXtMI4;m8=Bj>zrVyxPnLya#@PN-PX&!uw zS0v9sfV=TFid!&m!5WIUK)2koPcM55zN3+VZ}H|a6}-D~88Wln=PlBm7cbJ0jFeX- z{c(I}>BePOln$N~ZVL*Sv{egcW|UDxos4tO6uwq8&V3_lP@q%pGfH?>+0pn;#<^z- z%WItb;5rZD+$*AcBp;=EFxtFn1hax31hdHT$ht;=l~vPRdMB1xKqS$tcVcwt8v$#? z4YcS%JVA(}L-?4Pe*%C6wjRo1_^Sa|BcwJP?@0gwpn!(}YL7bx-f?)%*B!|*3}>k= z$f&D{VEYpx;$F03g=hXa=8wkf$#CqNa3^>wdv;C&SJbGtIHucH2L8c{z*1KhnV*^#_1NrsL@Nz%I_j-IvdEi0?m(*tDnQR%qs<0Q8!1)rW>iKha1hjQHsE{Ct%^!FSncEs+c#CNnBG} zyt_$6w0L(1GjlShL8k3^>$s^3!L)M+qTKJpIf7|l4jeLVUD@eOV#Abdx*0kI-<7i6 zS?eS(>o^uSn+qgN+xOXSj&4nF!AC9$N;Z9;N%l2-1x(uw!PVs!GlhL9(+>K;dEf<= zQKr2&4(&kn6Zi@$pS#R+*8~;I#aB>JuYB%m&t0b=>pD;+<7cc0rtS9SK(ANSzI^Wd z#h$z2cImu>`!D==H)_3ZZX-)>;M#y`yNif!-CtU%bAxdeyW36`)Zl)?g}LJjL4DjW zS@KS*^TXo3eD3k{J$H}xFc1i1zE{UQ0tgO{Hfn!koT`r8F7?JbvUvC4qk<-sQ}fq7 zqODAHr-oL2Oxz(x2% z9D`hQ_<<|#VU_3e{0+Bk1XoDt9_X7g!-!lfjKabwjL5atjmY&nd7pN!Y~*O|yP3rFNyb0c#7fYgo1wHA)ZwZ0b)s^ql^_dqn}fVy@i zZ$`KW;!PMQ*Sx>t$NiUX)ea!NV%x#Ab3FK$M*Ea&#UTVUTMI^Wx;1n5!C)Yg%&C$UVmc zKB}boYA?qtl4l^m-FO?t$@ONeVMwmoC!YWKj(P^U=FMX&cz5HPVW#i%7U|B5*MyIl zmn8jBeCM{}iCMCk5tE1E9b*0+Z+Fwp7y_m*l)UN{cp#cC zhMgWxLh1XB_^vW9vZ=mWoJChj@tP~x)G9W0iuA(d7x00KhS8MG3@cP{b}HN@#ClWu;=hfM{8Mp(e<}w5EC_eGY6WAn zNVv=7xNw*F%LsQ_FA(nX49Hyz_mpiA?y`k#3U?b(2v3OSguASd%VG=uVKaRWn2#Ay zhp$~k$Vyg6_OmCrTg(&q5rmN^@N*?|Da56NDBN5RSY3u6^6Dr20YKee7n!M-bpO3G z?_=+Y1M#3V=fdJ~AhtBwp-`=pFp!3hD4-&}s?f5ey zr7;+3UzzSsVz>hRm^}^TtkO5fuo?*1yn%ov z5_xb&J&NuF*zQ=?oH+pS0>a6i0B5noTM6%C?rg$m0ZX8edI;P703Zi#UIEyDuS4~+ zQolF;wV#6gQlC}4;lS2A^B^wSyaPP1&sHPLCQJ5c-B(?*l)ng_1Phn)R{*3XWetvO zCRoEvVGXlAF(7jvIySq>8gl(OsMIN#oUKRtC@yUSp)Bbr))-GHt2l}+9}U<}B3aIu z3-}{KS=5=w0Nw+byR;*kn$;I|Gp7Rnh;TM9phmz_k@D-(rTjifElY_;?f+%(TL7!N zs&6hki|xi848dGL~#Ay8U7m0EOA zYoIMEGk<6P{{EeRDs2_V&e*Y4>kLv<#$lW~;>gU@wmKcHGynIkeO~vH&;*KACnq^~ z@3o(6uf6u#Yd_DJf;j-jmLV16%1I>MjAbO<+@+WT{guX4NOx%3kY^7^ukR|W0TD-Z zWhx17YxBOG%jSJKm(BZfE}Qq|TsH5^xoqB-bJ@IabZacwnA*HA@3Q&P>$^1Xjc$!~ z?nre$?5J;&80yMYO}EjlvDe8~4d)}{Be*hEQ*d-^ETmGx_Z8^^Mz_Xd_TKwp#}_cY zYJb@Ae6CC-k3pM1$JW?!=&VO__HZoE9*(uo9*#Z7*~78c*+YKX(cA%z$=qd9*IR(s zT%`}-^>e?iS$oZT!|Z3co1mTnUmoHs{&U8gz<8%+w=Uy7AaR}ZT}=o+4JX%r!g88R zjcb3&IFlJ?yeW|wA^bCDcpXkGjx!mc2eC>JYl4LM7@+AmFji=Omx4lIQgw^pX zfm%OKPV&w|pc3fy8mb3mT>E_@@*yI!$tRyRClW8|GGW2q-00)+uTDuGpS$$&=v)a< z(6&8H5$EJSsiml)a1cB2k zqVzKWvr)GR0+;Oo(1lc2GkO4!F{1^?_smKr`b(dr$`mVqZW=LoUne_>Uhy&6^@Mr4 z^%Y^0y9lCAUy(X}5K!r5OhvU^9$2>3}JOCN~9Ej zM;J9!BB;Dh2#9HDI@U)@FyOvk{B9!z+-3@v`w4A8L=Aog;Po32Q-ft6z8YE2l9q9d zA$h1-pdS+=v(J`dT(wg`6kfwYfsu{|->*T(yFp-}q`lJwQSdTJdNUwn#>~r*^R+Db zv!><>l)B|VOykestxNuOllAuv!pQ0C66&XfKx_CRm2v$@7-fAhXnMQjX)c?-2EaEYQB)Et?3*GR?_sQs@Y3L)2#A7d@FxUOl5dKvyo7`C8MPBp zh}kU3LR}J;qU1kKV>-NbNp6vn)Di|sZ;?!!387pX`XfNoL9lA^^WE1eJTg8xTWV&D+Z440==$`vIb`E;TfBw?%{i8NY( zHwJG_r}qk-))Gdo0z$m4fY=Cc5XyX-NzICLI%5fw+9$3|r4XC7{tUiaqI^_XhajSU zlw#wj1aMa6qry0Q0HD+YTn}J2^7}Y_ZU!)I15Y;#XfCG|`ULy36$}QVeu5Hy9f6IA zw4cy6LSPF4?ju0v`V_PM-++u6KO(~S6X8R;?8MfH20p!|@OD}EOs zFarFL$|nGoFyYUN=T8ZC;#j!`$K5TUud5&zMZC{g2{@ zos2jZ7=aZm#aGo=S)wtjAH|z|kl{|`h2tS{^Qii%4%f(V&oG>U2`?wTDMo_Hm{CC4@89qbNS(bGLG0?49_X`MM^VOpKib5`(XJ=Pq-Peg+%-ujk1Aoi*G7 z@b6i}AHxskBQY&%Z?c@AH(5@Hvpq*Py5c?baV8Q_A0HpqaVAYx?mPb^BFgous)I`t zqbuH{pTXviORL?Du6U0@^H}fu4IgK+n&*|Tpx?ci$C)TKMpwMCB0jp}jgHqj&ZOC5 zsLxqFynzT#-%%%05pprdu3TyaNG!6no*^FHXma$6gYOjl?1SXa#XXV}w(9Bo?bjj*&v_|*?(y>gmHwdP z&9D|0D4ufh$q_U6Ah~m~{bJFY@-z1PrJsUiDfdkxta+iS?a*j_{S#r7JqFSgf^eX+fUa`qbfZkoX3 zExrZZen>4)f6$Q-HW!)`c)Z28ki~HJ8v2HHkleZ0p2t?1u)erQqhMd$<2^|38(QO4V|Qro3q#OAi`S*M9*=M+`YJmiGU?V z^TO(+cdwxXI;)e~*ZH8Mj_a&WdiNUo-Y?T|zU!Qed%SxMeG4pK=i(mkUPE7vbyQrR zb@4^5z|O@zT0l7;boA~u#0MQUR?fve-o1wSpd*j%+GkzxK}WVo=d24p=$NB<;e(Dj z2g&h4$DD)Y_@Lttk(~8GN9Q0pRwr{0l6yYr=sie|4?1dGoz=;6?=|#%(D7N}N`2M^ zA9U29KI`I}Zhl{U3k^Rld@Y8sKZPxO4Luk4NS|b#b-~5<-o1vt+=Jx4+=Jx4l@_&~ zi+j9#4Sl%>$$hy8$?-wQ=Y;p1i+eQatWJ9O8sdYFIS0w{K}V9#*=vXoIx@Di*AO3c z)UdVJ(3f|R+?TTa-HUs4_@myvhLpALr?8#9hIIDsH6(2BHS}EEvsyS!pLM|p9Y=PM z+;ee{bC4V#bUdGfdw0!M&)1QO zaYDaj1su%y*w522jU`k-jngZkVVlq2#;;-fgv&&Y-vYYSA=>cwu?}MwtI~`7>LDbI zZLbADz+Yfp(opbKqVpaqUUJv4@4fGVblQUv4rtHY^r>+9$9<6O-SCj9LYt zFazicv;kuUpi5hAsOTPq-i!CL-AK}$#H`mN1fB^jgYo1CNz$Vr>|v$T7LtAid5&yr za4ty;3fK!-yIczjIsuFkmtC+qyIjZq8jyK}<*PDR!OpS~k9&dQCEZw;xM3|^|CA6G z0d61({tH2||t@BFP_LZHEqEdgS^;*VI^E8w=&k1|gO$Qp%p z45JkkFuZXLug_T7NOIf&qHHYCs0cZJd4c3`2*KivVM%khOppCGoXm>r@KYrfO(GBj zbCo7T3;gE+@k@9^@C}5T0Qs9hqA25T7YKeaLjPA6QOfmeN_FE|Dc6@!t|?=5%2KY; z0WgSj-RJ<=K5RES03ICx%P3}a0GxZ1+UNk-bCcTW0GKzajShg(bq@C?wco1&@Ko6` zyMWqSN1+UQsj5-2`Y{wQJ?LFm$U*Pe{T$R9=DI=-a^3;x>i003hRXn7(`lHUg&g5t z)7*{iKzB&UYiR8jYjIl=JCHUN{tyY64bx_h!N_Vc)A+o2--tA(Rl)JPHbnV+AyL}~ zH$2u=x>Oc@#$C5lv3(M1An|+=Z!j3bf4aFjP#KH_BeaE@JK9s(bf~GTE!3J_6G`>9 zH+Kh{y4#FUI+SkjmC$Q?v#l+(84DLLD}Mjd;_@KQC7L_tNj{&Ee1cGMo4b12ha1D+tQPf-o~dqi6!MS_aq4tm0XPpEv=xNTHx_ac@sbf!>-;!

x3a<8nEAytn2@P~5kW zZ`tB3mh|u~n`e=?FqheE48A2d56-od+$iMbA%xOkg6geu8&tAbQjr4El9dHl8rMT2 zjj_3BY|uQbk&qp8*H2f#brc(|ELr;hughH7n7bIFU_LKy&U7MnHKXv<>6xRtWjRly5B`n+EDHJN?R@ic_l7t^qSm? zv*j!YDDa);Rvo2+aL`~n%XP!5Q?DNAoeOcb{!x{1i1ziyb?VV+2B}kLs=!mDs84&0 zd7V8sQZlTHbai;;tyAjuRtNAuz9Ow*o;8n$k1{xN6H?Zdo3^k=I5sc}dsdYNvLdZ+ zm%eu6q_3xO0?ciiwj4(kHcU@~B{FcuIB>d~^0@~YqaFGicj#wHL=gT>YOqqzR%bef zohh0uyZ5teb|?;;p371*tlq%lu9lh^ptMsgjygBn(gS1LZI#Sz# zFFudsNa-9E*{&Bfn$dc>(0Xx4AjKFBc;sZx&93|?SCk9z$e^P9+H(7~=(@flTS9X-W6t2_gw z^J+eBn*vd(`Pidgfce8*xAIvr9?fU80bWQ0w7Pq1cxO*FOMgQ;56bBtZQoV!3%vY4 zCRcFU^ADcIL#(9a)~MeDqWZ_#ODp520gDNG^+Q%rsNC8M)q*D%st3i>i_vI{9JECa zUQZqw%x=)05(l-l6!r+zp@){Dsaotc+E2cz>v8rpAM43e7g&uOTwNLVY^^<6?rk}v zgLrpYbdW*39*AWzb=Bc!tnSg7p%C!b&o*6Z^NzTi7 z#_=4!+aSdD45~TH#zM)#(EfU@D=&n5fq834B%a5pb` z83!x$gRmoT&s(F3MB>@$O#m66%scu|_reb5$bmRu}kswz`lbCU~*t#x75Zh9ak3m0oN{7v$ac z?yVTF(6#kc)PkpT8;XQTW_H(EKR!II}+>%Ofs1DkCh+9>;!wXAZNpCv3J`qzgBR)OLQo)I9kzfyqcgX z=`=%BWqw5u)m(?I_mAoUZ(I%Mx2WT^tI@s*()wa=P4$Q)rmPhaFJ-1ge| z8}?Ur`*BAo?vO|i6~=m1>|rbXt{BzozNdUcNz^w574#k)dw8<*jEUH>bL`>qy#Qne zpJ5+lh-haA`S(WId1*a5oEdyL`GOi+w>}Rb%P6j9;GKN}w(jhc0G_@F+8$-08`B=v z=I;&k@BldEI*$N#XQ@Dw5=&yDddUsby?Y0(T`dST!|QD4h{ZK$e#lJ|iQu@P;Af@j z*&oO(FmvVjBI#0I34*yRPHF`PDH>t~b46LmnH)nE38PStt<@Ul~g=d`*Q)rd8 zQar~Z3s5tRxh_D&-t8$*&dSz23uDv;!~Mb4D7QO3_a1vD?!8uWQf2c!aZt(|Joo_X z_jz)L?~P80fGf^bdg=3ij?q4li<&)PxXFVFQe7}dPL$kiWi4gA#S_!sMuZ#}x?%MC zTeXX?*7$2|6z{Am8eJuqCTAaa9P#AH3{>G%p4zd_g`%#mc14q=-sClDFxoX%+qC$O z)6TY7hp$XLyOAhC>?vpAK&*}1!QJU*@v(<{0?e@IkEJ>5Noe*hOwZGhvCY>?PuR-S zh|z>?R$-$mbK0=T1STWR+ETxB1clwOEkO}-b6`6QyU7xa0Hh9K1x8bMKrnQLJGGDI z&cly(ZOy^aM?VkMdYe09yxY4A3*CcG4b2-?l38|Vy+^k&HaI;Qk2AfLH}kc;xk1Y< zG-tiv;6`^)US)5^e7~oWqIrLS39vjj*>YonTawYWaJz|sQX_6=9#QAYZ`5@DaC?;A z7jYy9&K`o^mKgJ@qo^EPw?VTW<^DIF`v53dGx#WINZ{yiHGg>)sUgg;H0r~TQ?g)@| zF@)m9t{!@rXLPBL33{r{?ng#-G>@Qs(?%$R%P8d_65w_l}+h zHqB}-6RZ=QywA(C!S@^u#?ygdW>i67SjlpM%3XAJ+tpZDtu^6GycO>E4y(sGS3)7t z@ou8nRced+LJ{@wmiw#hWvC*(JNCC~q0GD1b;_68SD~M@8;#Zd(<@zVq|Blv6iS_v$>Y(B+DQq3Fs@=bl0kO^=WxnjT-z zeWJ2Seu$38rRQj`Kg3;SZ=@Ky8iBo>?o|vSf%3)Gp!JJz=TH%I#H76(Xf2=FJ3uYa zRuTy!(HWlH+*H8jyk3CpgK%1DB=g8h*(^_#9EF#Pq=(~5Eq=5z_MBQ_D+*Zr2;WgL z`{qp$3_ZD=TRFoUX?mK!SB?%cw=Zn+KXGo~U5%z*H@NNscF)&c+}6d$U{4)eO{Lg7 zcEdJreJL{T4-xIt9?9EdKWRZj9<6niO7FnITbpu^wY`SUTdb{S&+-ia@@H4fxh!~& zJFHP?&lS4pD(!tc=YJ2f-Sv*K_Hhm+rUu!u=#g69?UNvYx3dSB*NYB1SR0(;!@`af zht%|-lXv89s0{7d8*jaiwo+FY&E@K0w^FMvtY&GC6Ghh9v#9h#wV{==ae77*Y}Xu1 zSgna5YHx_Un>`oN-;8iRe6klLAfEkiUT^Q>L!z}K9SH~VjW5Gs++YSI zlky#HF%9*X`2JOGC>eV~%{Z=_`pRdALa|ur!4siCNR1Ef&ZyRuns5YAWVh<-^A(~L z{F0l`_||W(6ex3ZCflC0zPR9!YN+CCBJtx4%^huR9qopZ^imr)s*h4V0PcLKGO zSfA`Vi+vw>YtUf>N_L%%4mjr|DfUal4B`uXrnyww$Tu#CTqA1fZ&Dk1W6pSyUhP?OMGi5sZGH; zymOMVkbhbrrkZ@SO?ByU|7|rf)$M;o6&?4@m=uVinW-!MJqvvcu2gL=t1EnSP5+O4 z?*Unb|BRc4CTn_#udx^gILY%l7E}+L`%7&o%y-AwGXCRRgX-UXzW13T>Aw!>h|j+_ zRIa}Lp_DpOpoO{A?|nq!O+>`#03t7pwGffsLw#&ZP`#{(4bfr$qP_yBuPUGv0#bjy zIi>z;j0dTnHyNp_P9XLFF7Y6x9s&YCRQMh>5qND=N{E5aiN2}CD7gdq9=pVp#9x$_ zw3Jy4E_jBn@@z7heD|EnKubz@>VvYtOlJ0+VTLN^MuhI9t!)W~Dhhn+>qfA^R7bYk zow@jyhsvGsI=IB*58d(3p);ayX6y+%vbfRReY6JQL}pAx`ajzl>zENJ|@7c+LJ{9$LO?P+s3p$V&WS`2=_CA?l&c6z&{cAlYjyIvj7j6LBt36 z0|6h=VFhJ4J}Zt#ZO3ppG}kJP*Q&`7np+MfC=#mB29ZL_5h8|%JdH={`R5nAo_kTx z4;Gj@=TIaf6la^VC>E-;u+j#?F(}G=U<=9j&&sNPxa<>`m*_$!fXgm%`EMP@%7R6M z*GnH_^p9K8!*cwgI6j=~cuX9>;BjPVd5A2M)wS{`67GBX;mR2Z8UCSozXoprcM8xq z26Z5hQ*J^w4YZ#JZ5`J6wdx75CK^KOf64D7!r;Huk_cJ$3H;%)q*sL%!%0dkNKcZK zivOudkBis9_isYQ{}NKHJX8^uGFpX*Xg2f~TNPTBJSP;6peX;gk#+a!OXv#lhXQ`q z22Tk1zisfF0)Ej3pBC_|Hh5&C)(oJHLRfy_&5&p8!H#Z5=^h9c%LV~`bLX9C(4;5v6G`A_Of66j^dO&oWoD%$J%`83+9P??x57Tsq<^UcutdHv^&Y z&X~+P+$25Ic>WHqfef$xWG`wB54XJ-Myk2BqdR#Xynwcl?Lbo~01Ke$?;)KqGZQI| zEDAr=8mkFCnMuEpK2RG`Em1W-1&2jxb>%=Hq(_hoe&b}ks4Xg$YVGaLXfoQA!NiKq zZkSJSBns?~90Bnx>0-?|Jh}yBe4kmq=zF1uIi{KuikF4^4^)OQPzpa(p*n-AJzA|w zQmQfN^J5J3#P1m$v+XUZ&I_mG-mRcx$Xqz90ypyHtRVro)UH3yq&TEC20 zRMT86)i>@pC`~SIGwA3{TJuR4(h6SRj@s)p%_t@gGG(eHsBTX|uryDY}_SF)+aX%AZafMBty3$bC# z7|0Sw#<+6D63?%KEb14AS*bQhgL@Wzm$D^PH;aQ=^#oc$dS|Ettj(WjW$Y>V&Q;IA zudy#&9geMS0rO4>s_4LC5I!6TFA0Y*kcB-EA&b`xsJ}C!Y1BcD^pS_84o>{GYkqA_ zt&qOf{GClk5Z56i>_aPmNBcn1AHT!YZM;65ev$%YLzL6}?P_CGT^Ur}DK!}qI~aj@ z38*`QrD{?TszhlhyhLS#pjW7}v^0D`J+gT~UBQ6(jexe72WN*OW#O{0ni8E|t_q`I z{BRk>SELlFl*J*tHU}5SLMjyvMY36`uFb(nL|vXz-M$v!)CWmaAHWa#UbV!(w+y54 z@P{j_!vRPtHDkax8Pez1QctsfgVN_bwAJCZ7w9tG$>h2VQ)O%}K(p!YX|e_bo)rSB zI*q$g@xQ{VfCzUI_^!L-E$lL89#IdQDfJKAqN*?zKM_~sQtCA$sxIwQFT?F}e-G<) zuDUc8j|IRdsQX7%v)=uUNLd*4p1 z;{3Ha0KUV#tmyCW6$ZHGf*3$Zb}@UEkuU)2?0nkuaH{>p-Kh3IFe3}gYeEOYLcW-g z?>E_dU)=W7lWc9hu=d0DG5I4P)M>+nBDEXsVq8#jvYHURYaOJQFul4xS`NP=Fy{0= zdrVOMdq&O;O|2Iwj!4eeNX~!4Qqm%|BDnLw;@J_5rJ9l|n2M;?QMfi(t^vB1ry|0d z^+LC4O5-b(+KsT)Owvr#$M7d_(M?kJE9bc{@)o5&ZSu9 zfB{`)})#lI3#v^~yLXz7itrh~=YyK(S@h3cVPaT~k;^WX zO{sUt^vFAc)s>5DXJegnR>j!H7Pju8;a!-uWMxIcZZ@^kHrbDJ-H| z8!n42E()lSJ$akoM6P1BM0mgp?Pe^ro>R_W^yQb zY#g{->gC_0JQt>b%9Al`V0o$NH9ut0-;_nBi_^(=LPqtt+DcPbS}&8@Ri3A= zxSec%duSj9Zp4I26tm@M2(vM*9#OXqw9=Gi4w<4be%rY~7ySI#{u$EXzp%$LRGWSw zS+h2+KE8b*7_N?lV}UuzV5su0(4x>STh*metScN1-GaHLSbS|JO<5tLVXg4YZ*pPM z>Ygr+2T#2TI`|z{pxn>#I=zcY9F1JEb-Zs6=W}J!Z)J`vbCY^SdFIy4Q5AJ72MM z>H!f;<+oG>?D?)W!eYP4`L2t~Vw$a_xn2l|P5BH6^&bZ2X4gf_X9vr7hM;{yw~eR| zVm&a5rIu)WP3Ue|p|?iWWkC$TR2>$@xi%>M{SMVBKtKUtEL3i7qeNIj=;~_DSPhWE=7u4Uoqw0$ylZQL?!L^gFo{saGN^a(yg}bZdHPY*D z(*(7s?Q5OCCty|41?a-%`^1T1pBDaa0zohsx6tvK9y~=Pq6gB znyZ8jTkn4HLD2d*HnT-)LV>mF7rrQVm*bF4C59vOA*U`4hB6r9qo3?oKi?L-8Jjt0 zmzQzb5}Q&cL8wLVR?lqh3x?ETbeboycuezq#z0xP0*-&~<9cT%P>u-z^&eY;P-*&O z>39gUQR{>2)FI#TSPXLoN4KWb*L+8Iqj9R;+k??qg*vFxvlPwD=bg{3)~ViEJ#XRz~ArQ77T>S@VdxF2zI->O}7Y zZvSami9!V^XR2!{pMPOQTcJ}`LLRGeQEV8&ig)EKOhmkh69Av_VI7y2!@jaqifr>D%v%J)8TIomQEFv#LS<@YP+cEXw_#~8h}nBJt8X#p*VNLW3ihch zj|UdT0+B#ieL@`%st2)|{X7mr)cfn=?C5p>_fF2Z6$m zeaF=&x1yH5?>izxrP*URLxqi47bZnUur=*scF)6ZRQ7o=V|^-bL~>qAW6m-G^a4Gs z!GiGm6ps*Kcakh1ID=UbeM57msY^FIO8GN~(UMM@=0a+cb8m@7unG$f3`W)4`=BTU z)m^ATkGcD(I==Ntd#&o`4kd2Qm@CRcca$5J0ysM0zc#I&xg@2IZ%(0g9s>)#E$Y8< zVI<`5ZRG<0=7HMUo!H3XJ7St^)#t|?QR9!KGwRD*j;!^URFHXpjZLbTVI?}Mx})mq zl={v#|B5Vl{Wv+bGDIb%UWJ3Nuo=YF)&BWuw5wSaF|}vAuieb5`?mU5>{9W8@2Tqt zFeCgq^%LJfz5luc>R-1GJQxc=466y4O1|pl%)0cU15d=%pKtf~s58ES+LyxWXDBlo zYb;W_=%KW~v3#vB^|rJM`HR!OmMfox-UH=FoyN@Dr?72Y{Ro>O%A@LAz7&oQMYgMN zZA+;yngg*f9V!d&2v;1;>~`N; z6Wi{%^F^I924W}tx9#-z`l=?kwff)Zza|t@MJQV@(2sMr9H*CF@NbBykABF%SG}ZO z{$%TCu*+gCj(_#3f7yx?JL(fSH}tC71p1`#er9W*dTiSfbwCZMk8b0kr~ia>x^w#x zwI4pGeL?kyz9_bjo!;WBGF9=*>aWaHZGS8V>E@sByLM9AzY51YqKh%N3VDrW-gww<-{SdtrlD3>c# zA!7Gn-$L*J!6$0MuY5S7zKF12Lui=Tl+p(c3bVqQSm2P_=ku@dl}y6=L63jAf2lgL z4J3KcJg#0uU8t{aLuP+t90$>NLVQ7HegP?cTLmN7*TRFaH6f9AKfnBSU+ z#(J+vvnN)D)u%h6%Ub^Fc?MD`XojOWv5Fbeu%0#0+nEb5w9jxg&x#mQRIsH?hN|Oiq{#|175yHO zv0Lb9sh!{@XD~QYLYDju2w7xugDn(A>$k5G0=jkwT7B)$YeM04vR}@YPiFT7El<5G zin*46N<`J$QgJLBg)m_gs@eI3OzOWP#FjbI3z;2tdG;JCepVlyKM&1)Bs@!&O`Oj} zO&-%e@O9Aoax)Z2XAUk}!kI1pVFVRazt{#Tj8lKuKo)$sx&ns@qj4zFOG4@|wnyQx zNZrt<7DW%Wut%uGwFSGiOwOvux8r=vaR_ZSEX#5Gp3E|Fx5W|E@ znMCLo?lP6d{+B7LjSE}*5azw80$cW&SXJrhh!EIzvw?N!J*7{66ZJPIXDQ(Q!tB2{ z)4Ch5DAwEQi0AXt&?%l@C#9yDoX~|NUIb2j5PTa5B~@coU6oR8sZ2KgLOhU_<%8Km z#P42cUw@G$hLK2kPt+@UbI)tv0!@ldy@rC#!95(bqxpBkOmT>QRrFzaE-Xiz z3v-HccICrrNifz%9Smb#40T1m&J=3>;J2SzoEW(tdg zriW{5!r?`052jTn$~i>*UNi8QI8CDJf@)goQ|fJfnpVFXLP-vJolpP5rZ)9&L8CA? zzB&s54I+vcUl51LR3C2H;gnWF3k2gPC|^F~YVzOjLC@~o!eO-ZbTsKAwsm$ToAnIB zh}yR!0W9^jft51D#A?DU@+}q>?!a#}9>&HTT(q%7l|&ET9a>ZxiZ3e7%21iXux*BC zo5C36hyA^Q@S+e_xT1Gq{VRKRs8H5_9|p_cH&UuRs1^sU-%ym3tL4EkFZT##%OkTn zV^LnNrX2T|K&xAXzWgr=qUswTihgffIkwtd9mI(z{|E{l|J1CCF{*TE%Rf&D)iXa_<|(rWW@^{jE^z={53NMRWBPJeNBSLq_C zBN&llKvS2-bU{t%mR41G+&6Rb+V7S|{PWh9E}rFo)PHR?rc&D1Va{aH&L^;?=Y;=b zE&ZG$h(D2xsr3V~ConM(k3XRP0mJXFZB5nvq9&9ChFNv(fNFX91vL(1&MUZtz~f^b z(eMHPnKd=(Y|U%^e_kIMZs4pu!TP!K(W#XVh7Mq z`LFfwPpg00dK`P1uIqcECU#K$%sd|BTueINpG}J*6^KJ_{~B|lMJZrWzP1$0lDKsV zQxe>+ghKb34{iOdJ0BmgB9e-rLs6w5>V5kplcK}HmK9js;TTe*Um0SAQU5(;r77Gk0Zg* z!6(+@ZWl}~Eqrhx5(rm+1%(aO&q`;LYI7fssHD}OL01e8sM43!7q<5OeCHFGU7@fcjSx6>v*moH;&(Lk>V~rz$;y*(+>=UX#KsGG@0vxmDjub(wTv7q(kKRs=7q zrkHANN?YTr5s3oIw&UW`&f3d;L5sIJGrgp0?N6kq<78;Cz8vhRvLI@(4$S^UBv4kN_Lu`9 z^%4d?PE^GpD+koLBiWs?RvxKC8fbKFNCRT8g`?wL zb!a1H5!?zB#U$Gi*^h9G)bEAO<3O`)YE2Hi-i96UJO*}?yP?sw@~qqW4l`dR zO>&2svZLF0t2V9LYvfMlVU)}US@~~3^cigUqzVohH#u024U_R><+CwdQT5zB5et;z z8YRp_7em3pd118yJ)%~J#_JQo-xg){t=OZ0{kUx%>jycu!m@?`9c4R-vNZ**J=WJm z@2tsI$E&G0Toui<)MHy{Hc&a}#@17406ybg7b?#$@`!f0b6~Efto7rOZ=v(()%mLO z%$Gpu-KH5%h15S9QE0>ANFbvBgOQqw+A=7!8Eg^9-{NfC@mt(d5mtYPi>+os9fcCN zE?pB|eDf0Z0|Q&fF9SDjz{(QVWih3Rtvnlp@!1IX=}09tL=3%o$5#c9^j;dQ&^-ax z)kEQhZE18BSYivJw}4A5ut+^^MzM3K9J|oMkE6p5m48VUN6UhdWN6opTD50W^k%Bq z^`%HZULMA*T^TaXU>CjMjJfIX+FLL*{WY|1&H0mpvpF7^6rB^OCyL{Oi&Y!i&SlW> zLh+qzu{Q>5YFGvPrV&i@b}?FbECdQGR!GzrwjYV98-nTgVgd86YrvqUwwLKA7gq`@|@ZvO7U@XIdRM4$& z#*Zkp&#+@gwe-oapfn!)6;N^r4)(K81lER1D@)5N;{SP~I$Sah zkV;^$-+=#5k+%BG_GmB?uZgH{Z^L3NDcH9Jqa?Yn5W|wd+)%td5R0IkJCmWbdI_g$ zaYJZi5tQKaHDT40Di61Wk>jG$Icvxro1-z6N&NuVhpJC(OU(*a>_iD$U$vCu8t$Ul z5DmxEfplzbGW?xIqO<*O>@nm81?Srlo&MEX9nn*w$o!rkvzhri%KgnNO?54|*5l0K`g2{XK?+D{8|wze2UsX$aMIifBf zV4&vXzKJ;gaz?t_->D0Mc@b{5-P+0SbRW<`@-GBljeRz1vI&88b49at7w#r0?}c8d zCR-r6Z!TxQ-~-I>7<7bnV3Ny&<=ig>UB|c5e08yG`Pup=XKtS!qJnZ*A@gq_^DbOJ z5vg1|2Yf#37yy0HM1__rx0=FsEnx~Tuh3;oZEgx1&h z-9#D;K3_TXb)?X|&c1PuUL>aTscU$tC);zRmUy_<#JL*AC&?!7I2 z@(x^C4((Yc^{H|4wsc%>s$ruLN&Pn-(=fLb6<%r-1LnhiE1mP?3@}}&4h*Moua5#F*g|1)@b|EX0oUf`ZTl5(Hw|7EP+e4buer z+77FWR+Hx$?vcAqqYQSm`+I@Gumg7-q*krqM59-k2VwaU45CdBwzDiQ}Ph zL($B9`mqdK5T4f^EP%b%(++LF6Y$%T=a-)j^L-lW@T`A>@WjN1qPWwf&!RKqzl!iY z@@~_I@RJ@mpXW*-XL(M%^AePCFnOCfyL?Q$5%G8mc^~Z6L)1IN^&=cl`W`$-IO6>X z!to^Se%SNrK=?WM^Drr@PW%Z^^uXS7k;bpXpJy?vU|(>Kc3TYpnJ7C?E$Xln*@VXI zH2ZuXRyzu+i>3(AFw8!LsnqE~L@`)_4hFY;oLP4}5QirLH%c4`gFU`G)$W2_V?Y$* zNdKx&p)V4Dw@ui78Tg%mpO=5~^C5hi>3mwt6~-mp2$+3OzAVkBQwjP>9uAwAhr?j` z)FLd;N3mY{5-tN=4ST%Ef3Ml^6WK=h9=NX-cTZaZY{xqWf3^)f-eCD1Wqt#?&E@;E zoTuQ=!$A|JoG$$a3tI@qg$H)35bs?4Py+vX2+PANMwm#zW zHN&$^E%19%;^y^T)kQPy_{E29++7{e&btwQ)e=7!cRTJO_|Fu7H*dTCpMzg9{0Mtx z3G1*Ejyx_=1-sp@nGW5{{uuHJBOT}x3yO|iI_S8*wOwW)^&X{Px`&~26<90)FK==z|J$J9Mwhh&MpS?Vz|by=gFEC zMH7jq7cbVwA%x{d&tf$0!P=ZRJkvgg@Z4Bf1^c<=7{eMx=m!z@bqVY8!C-ilAuP9? zokCb4j;EpIhbJu>5uW?47JwFm>J12!ACEZgLp<(5ng{#2@Mj)J5tdtHFkna6l6X=0 zY_9xOSlT>Fcm-hk+5Rn-KWRh%9>6Wk)1x!mVNbx1JVQ92FU}w?R|2cxcP_fJ+*5!M z7vsnmLzSE1st}F~Td%=hZT0W@c@xec9M@%R+z2lKyaIl<{{w*c0cN`N5C6>858Qr} z?t3kFrbYNAz>mRRJ;=C*{)b++^()M8psT*iGrwWyH5Gfz}BWI@*n5WH#QcDzQO!T z{?qO^bXjaVEr9zo$WJ;dPusQq3x8=EuMXmG<7oWKG)}{RFdXyioV?n21@uhBse=7n z{KoR_L0C?b&x1}bm6SiHR9zI#&x3V$6!ADoJ0JGdL(C~L+-Zd4CsMwwHsZVt|^t8w-YFb>~Yp!=!>8KICk}Po$GL0o;>J;FBq+ z-0qfa3-78l5^dnv_5{!1ld-x}Mxu3YWm5vTHv+_|9KdT*-Pz6XmF-JBm~Z)_+4V{! z3EY+J?rrT!tTPfFDO_NUq$vxUT6JL96RFElof&)eb=bm!|G!mvU&9KnT>*A+y~rjH&AiO%L}4fvl-^xg!A<$WJtNe%=QF zDq$TU$)Y<6dNQv}M=xrXArdgTkZmM7=MWLp;2Id+X{oA?_5?p6lh8PUfI_lvw+uqxqY)N!AwX@z@tkP{tLKIql#s&xv3nz_Fo0J_S_wZJ8 zZ&w#SOO$9vIny0opiQ7a4$X)HY+V9JZNLECskV-;q;3@eY`^9^db3^96oez$nsfpZ7XU)` zwtLfI>N?@BB-prno(BkbTt{h zHb^A8H{*j0=qBN7;nAGwZHF{*(CW&zC3-RtE*TWT=(Pf8yIZ@A&Zcw{3D^RI1(VJ~ zILl7Xk|qSPd!qv+*w}+eP6kcu6E483&@}lnf>RC_T}GQA$1<%;COexu(6caHrUiR4 z65Y@+la>1W5`^2%r*&H&r?8W&VByf^8|iEd1owsvdgmk)U&Ch7ZDg9(C((mB*_Ru= z60irI5VQmY1Z*(TRJ+lFI`1*0r-Yc6?_hvZc2*JE+Cigrv}7UZV2}u8Nm!+erKO1} z7!nf6we+^Fp(_%nVTT631iR==LLel-Hi?R~0d}%C7(SN^TZU4M#C>GLm2(n}g+)BJ zP=34sAPs;c;c&`c>(d7#jb>f(4~at?WD2@!@SH$ad!za$qp99(2lSuysK*ZWs37Br zbF(hNM=F|?X%S@(wS$x)%8jwrS4$B4 zZsdfeOC=KN_TJ{i`X&ez4&d|+HzSwX&doUN_dD95es1V$>g?^bq_8zQf^yE$HX1@} z6Z8!&p?fmfZpIj4NhI<}2%sCkbCoURhqfE7qG%f!M?u%=>1xTQQs_7n(jG^^3!1=; z#hw$%>+xEm+ZvN5x^-7D>~d;^<(COUKOtH~8~Wo2QV|wKqXfGn9c?+E_|_GlNPxEU zNx|Asixg;s($zzy3w;fSo+DKhs0!zb8!(pbXG0htsMwXKTG-X zCWSecmX5^x+tbO`rMK1?P#`e_iPCQB?xC<1*`O6gPX1D7+bk`ot0{|t1$(_Lq*8Yh zDy~LPkLJ6Lo;FT0Q9VS@fZ-sE3+~FwIW(hZGpBcY(KT&IQgrIk(`@z<=m@0iL^NcK zp$R5mhAq`Mb#nq66w`c-{4`?|n_j^N1NRP%iKYmLC!{e%9I2dGhfAbU6HRFDMl%I1 z_!&c`PRuVFAgVR+XGw&`+cu%VQrKo)T2h`Fb)+~i0{k(n)6DXsHxLADLZKdk3+}i_ z;O=}zMavm#P8oBKx|B4VF_htvV2p)_qI06HllJ-ytwz5IkRJ3_N8Xh)t^U-?p0n$)1ClC zzXJeCTMhpB%IVMZXn+B?ui^mJ`XU=p%<9a?h2k_c;h+c53e zX{<{$XOi$CdJzMyT?a7MV0_fE0n3G*-RK*-IJeG}MJBdlq?|$>+M^Q2bxO7-o0h_@ zSwq3o-I)Zhb7BtcrF*^(c8?<|6{jGq>mV>K#Cf0g))vu@k)*!sV8rP;S0uEzu50hu z&_3*L7g_@E0YE*j;gmfF7F>qbt{`Po7Y8p`{7QBv)?i|@vk4Pd03koQX3aHf#&7Ou zUvG3KusB7zn`}9|R~))a)G36t0R}@Si)pClEV?CR!3B=a{OrB?v?tS;%37ZkoQy;* zI{Ua)CZMiUMJ*!@2j>JP$Rr302=%GOntNA=*I_GhsWml&nNz?~d+wn|yK zn!^c8I|AWUS5vdij!xE8%b;jE_$4^70>zxHnRpKtr@FC}0<|lN;j?H!$amOGr3Ha= zO+XWeu^i_@2Of4BP-N}lv7FFH8j1BC&_mmrx}m}9)9vSzoOLQ5I+RW?k;#UoErH0E zWlcFI@>{zz*%Y)HF8XCVTiHO%u`c%knb#(Ra^M722$PgLkgSs0@+aGl$r7$BYI!7U z@#sUCLT@W*`T;IKa)Aodb6C!zduPXnIo1l}NM{oC5ShFVh8;GEbv04}0tytQzlFW2GcZd!r41@cshYci1q{puOLQ;ZHkvoZ0bdKWM}7r~PpoMts^&*f9K8 z1HV=&hR&aM;w`~J4=Ii<%Tr;5#k!mZ2?SRfEW2qer?E%7((nT-xUPo57h!3zOmKz2 zJWRV7uW8iJgi)rg_?2f0eoOF5VNuyl$E`bL)csjI8&4+o8QVu%P5lnmiu~`+O%HER1dE#xSf4fp5LP zfcEDEUVeW8;4`q-g34nJ3&tMX2JCOO;VrOFMS?bb2KE&=OJu`{E>Ayx@4-9PSaE;B zZTA=KM>=Ql+VBFzV_X~7u{1X@p3k^%^{X%$hju^mW!|*!hk4Ml(>#n<%Cq$T0@^hV z?pr-bnweshZ9ZP4lcC8LFxIG-R!h5;U&h9d;aEN^&5WI99APPKBrftT0iH9Ze7Utp zI`Fm2NxP;CI1&P<1#vW8H2f0qXWn*r+V=^p{hxzf(_7P(_7{cz+TX@+4{*Cj@YDDl zhW!x_{50&(c;FXdKkb3Jx7t5Md93>B3?sZnug=xLyTz^tNT`{>vrO>T`FrTu>7ggv znLH)!K>+1f@}HHNpl7_M|NynQbMoRnxQ zU9@Un0(J$G)$K$}b};C(6AiS#VfqUUxjpFU3OD9Tp6q^QPc*xuWP)nJ{R>#+&IDIxsgrzk0h_#jmWid)gL#ODF zh~R$lT}7i6Z5bFA+6AEZBjR04gWevk>`6FH6{p%_80>|R%W4=ppi`=O5+jjO5;)OO5>z<#jo>BgbnpXL#K4Bn^GN9(s6EeBET{kFPN6bRIxhkZ#BRk zacX=F#^c(GUwO*#OYET$^fbU^(zL^nhwvG^C@+my#p={DeKk+l(a^qwv>X}Iusk4T z3C-tFAFwlb=a~r`vZ1j>tjnK=F;A*@c@>OmZ6!Z3zK4Gi&Qjy+7+t6C7Q*!wjoR|= zq_h3#%$M4+^>H5Y^y9Y$FS=41qzvlzQ5Yx0dK(Q*ga#r@^i1QngASGr@Rw&be)r=A zr_*5RP=;eLbV@7Tl$N~)SNP(;mWHOnG8)>t@*u2_=m0cWCQl0@mKIJ`@QI7BgNP>| zrnWyfuIszp^>s!kuCJ%GPRhi(Krojoe;rn~Bs$v<0hEeHwOE(Yh-+6Gq%w*^Bcoku zu(sezqer{a*sEP>JfdA`Jf>Y~Jg!}79Mi5eh!-jAc_xcf9gPyPHrSrUuxOl?yErX< z8m^>;X*jKcsRG9TDjE+!!$IMv(v=Ur3&p#Z2E9FO=K9vTz77uTVtXX+?OR~*ZVl78 zy$6O)=61;eKU3hV+ez(I_?AdOr=Z1*E6LQ+&?(k3#WNx=>)beXj9R9nQ@_lJwT@YC z(N;T4ro<%JXCf8q*OWvsv<$DO{4Ue3^I%kID@=E-?z78w9zV)u}2kB}*I_^@}*XilzBM65EkgqK;bjr8c@p@p{f)_)I zXJDMt)-sfUrGP8ruoSSeAev`ne8N(|^$?5_DU35HaT8s>0|_!=2yGhLT1(?O?Mhut zw}e`9+!@KW){m?-(#wf}CgE}#kKqNmX=v+m61HD(Sx$q4Bm^K@1%lRc8roVr8CH#~ z!z0AynBcOEtg=xM5T#9{wT#9N?Mehr3IfaaBK>`m)lwRo7>@e4$4&GUthEw-8C$U~ z)iRcfZ3E)j#eW%7A>wc)!WvU2(ZfjPF^ve)l!vw1fEUb4V+&p|D}G(?jCj}5*eKRU zuWze3)zRn_>+LjjKu3fymqzier=fiv5zge`N*rjA-+%+#i}Or|4Ru0;-YA~q1G;|JP14w$9x1P!VNKK&^r$S?JLTo_H95IdCKrR4=>_Y z!|2r39vFMI^$?85wDl+q9laJdc?h1wi|8~?iPh0E0eJ~Wo&ny)bhe*~uvmDn5bFvW ztFW-I*yb^`#SBi7=d*%4Q?`ZtKq5xI>jb<4_;I$4R)@;Y$~ks(0e~#U`9ii zzX71tSLdXo1J==CIv!*X!%0)8fyRq?ks=Kp&`Aa^UP4U)2y`aX+^g*~VK`45HY8LF zV}-UlUa*viQyq?y z^gyCCp4YB47z?hj$wR8>fXh$7s(qc3-Q)Pyo`Us7yhxn7h7MQ@2j?k-4Zbv3b|?V0 z*JN0V#i^D?iC7(9KynNlMP%GcyeMJ`P2NTYdrrO2gFCXJLGQdetQOz8gD?(jD}Lo! zjbH85@HDIz^HGU;U6X{0Sec0B21@5Awe_9?s5W>(v&oou2P@v6N_W`VgE+<8|#i z6WG-XhD#e@v}h|4eNvFEC$eEdb}5nFA{f>a*+XJoN@N!Z0Ua5?0%&a!4C@cV(9~M_ zD69p7RxJ%}y`2Ve2U;s&5O>rHjaS8bJBxtIqpMql+gSu%8krN-T3P*6ps)K@Q8e_V zY&{KK3%AqI)|Ko5St(FTXgn&`+gWlJ8M;4>TCuKdK~Y(Hgmr7|cDKe>k_dbez^y!I z$lwy;wxcMF?%(TJ#^>lqljV0ARK^)?oPFA}4%SFE?WMQ}7f@{_KR`V6vpK(cbWS+b;6iNy$5 zEv1r5Jgu!PV4;+%o(0r8zSNvwr^Hg}L>r%nwOEj@T@7Q0wz5=*wUwnhs;zDvH4^`O z1ph{0BhP$fr8TI!T3A;I0(GllWVE#hhSu%t_Q1MdyB>l;d@KqZl2x6DtZW+3i)+1y ztmKT1f`B8E3XuxQ1?FZ29o1IGnJ0`T?MOHJdY9-9S*IdAhb*`jlWN}zZDmSaCV?w) z(u~_kO3ai*g%Uc^MmJH1DE%PK19(w7)<}tzxt=wm8&NF{OFEFxbgk4KLsmo_qK3HZ zhEeaf21kVNK-&8yebLKx`gM;v={GWctJXcGYDHG}NC9gHFCYo75fGwVWvv7*yh{<% zfw<%`01MqIxGbfdu|y@?l~q7e*s5yE>cfJ-QW``8Wu@$#jo>Bgw0aG zm?31j?M0vY+BXhkwYJjG)>;}ZcoBUM3?1DeATg*C-#SLu0qgF8RR?rPRSc&vUX;L7 znALD$U{AS<0hWoA6h`|x$-qPQsaVuI2r!>|Rd7Rk3t$}7R{S~-5eA)#VOY61Ua)9i znbJN8&_ky}fYsu}dXR^KnG2HB4u(+-i!Nm&10TezZ}5dh`&ya0*g0_-Vjf=L&I;MD zt@w2w@{1=k4@!ICqa!%jRl!Lkyp%>9ZyqW$#c3&hbX=!#GNTglt#eVyL9{@8Wx!em zE9!vQIL}1bP!1YZV$D(btvaBgbE$>Rd8WVyW}{)@;CR6@ReWWlM*BLfNN}F`<|J1j zPJ$_m1xzQ>Bxl1_*-~|uTsK(3k(j$5+8Z!+m9FAM&qDZojN4=s5q^n!6_dW8diA@;`ed9NSemeVqHe#n0BSXNSlMNH?J3>y%d0z zR?&D8FK}Tp^3Zz^Uc{h5Zx1f6Z=LJwFcp1wNQ8PCI<7NbCisl_uA+ftbBI9i=f$~} z2E9EQ)Axk9*3mdAR)+}mC3Aupb&eLn&KfY|&O0$!bur$;0Zd z!i$s{aId!F*Llb@7VAvZMPlVU53@urH0YhjIt+>iN`pC}z*R6F&{q69k4CnhMm1ja zYBY4>^)w#Wt~8E{wVrKDXX$7PZfP2r$DY)U!6^OthK|Iu}0(g#wHx=HT5`a-6)>;}fwJZ62zIMg0^N_1i z1R7OhZNRVdc=DbIN90{X^Qf-HuoDgzPmbFAzD}>VryA*vHD9lr+(n~Sd>a{%FI;Kt*RJrF zry9Q*II+|0foUP$V|hz=avA`rdj^J1v(8P(;fj5Z?@HI#nT}<$PfO0LXq>@|YACRC zq4x>#uBCBWtPcOs_oO)0(Ksd6+iB>4j(A`|j`h)qX=qxlUxY72>ptMk`)#(df;Rc+z#9oZK0!M?$TlaSvW^BJ|!O-ppJc2HB4n zB8kQ+yxth}*1X`vIOsSneH7NG@q$p#z&NF?_?71reqY3kq-jhBDUtMKSmil|-!pho zA{zAe@G`+-adI*ySRziVXpo1Ho*!}Lq4!Mj&WTYePIWXi*O6@U5L_+3t7x#Qz3I_A zBi^+%G($L%2|h2rt7sgOQp7LA!Ykpepg zy^F=$iNPS8NJ0!6VZ20vW{b8@v12pne7qj+ah>Yuvp{^E;<>){^sN?Or{iYw8F5-g z;}~A#?9?p1H;Q*H4SIXJX4kjQ_036I$E|mL9i3nwl6qc}a~dmCKOs)5Xq?0gT&B=` z4D%MS7u!@|&@*_+ahA77dv<;6Twez-*SDU&Q;;;u#Mvk=YkG=T2Cy>MiE}M_vgcMt z=ojBxInlFUTWthiM?gKTxtxYI6-0wY@ysZ2%BB@B#BHY?xe&007Uyns45vZ~K8_d6 zLgQ(?AdSOb^wzUI4tu#yj(BmM9P%@vXYe9j8qeWHx`i~^S+go^1R3-MUJnzxPIdG- zCB6>Mu5UekUld=bMwom7UgS)JtF_3@VM2OO7H?U?rnje-T;Dnd(!M!K>$vrWo1+;|RLb z*nyX^?HKf~5^sl-=rmuP>S%DXjBN)-qgZQcFda_?5$qSIRWvxAh+L-9}BP7 z9B%xiizl`_hqtNZqM;|O9nuoqBEG9=9L0;s4r9?lyh*6>j zh?lB`Te%T}lxyV{=!K$H>ZNL~MsLIjtv6!Oczd5`t-as9lZG!}|GR!Zyr1l>_3X9w z-fQo@_K$bJ@65C!pkR`A1Qc9Hn#3;?;E^i7Twkvi5VM6L8Gxm`gLmI3lF1>!Boa-B zcul3X(R7_8SEQ?tl3W)yB-ta)c9cZl_YX<<%MLg?CYcsCB)OuoBv&<-Wab&7OENEP zNOD7CNp5N^$qK$jANi8p5;i2M!}rA_mZVi?AiDa*XjUcc zkvzySK%1mi*cilNkPTI6gjY|CgCA*nCM-jM z=_JZ_l1xi%Y!+l**v=~;3^2#BF|unCd!z~@nm@1x8>%o9Fl=FuFs52!J6k~*kQqrv z*ci!xut&y0&MHeXC2Z#$$R%N8s~`->fn-f%TQN368K#}*K=^YRP~b0NEGx^wyP+(9 zm!cqpxAPjvgpAlD%OIs^GuaW6F=0DzfmF!gJ(2@qfC9<5u$_}2XEk;fWKP*jAhlRd zpi81`jHFItJDWfl&`>0;!XB9eVSwq5jgdXC3X32NP$0RivDZKt5KD4HV^=`dls$(T zh5@CK%nEzt0tf?=kt}I!`SVa?1ehLzoKtoY9JX9^^J5~3I5R&k z7rjaG65@HB0eh~1==_-YuJhw^(an!BH$NsgKkAe&lcLUqF>fa1Jf@RZYzeGxNMf9u zs&ta62boZobJL=-+h!r1WMpR1=_KY&C!8%7Wd@MRpu)@mTPK4$Gdw|bD91RIFKaBv zZ_>pA(!jf9(JboU=O=Z*Rme2Wjbs0(B=)XyNB}wX9H{+ITNTG_4t`GW30y{%7%{h zVtW|NQwr$P00!)#w%O7yOKcBGhp=&)#Q+0HR)q~WKWzCr=$sh1^v@Y#6I@uX3LBDelL#BQ##G9}5^{|xDa$p60SY9`8p|K0 z;gW;ciTf}V5w@^B+hWg(LO2g{QQ2nrT8sJ{iF#p3FFY@?;W7x9)d?kZ6G{)+3o@aEZbAv&gcAB=pId3H8!NIta2^rB zak_#rC4da~emKY{G51j`-hEW3cOSJ<^t0Fbq}R&9}d2BW1(MojW1hz_14iL$*l7#AHfHabZX!Y17~>UC_)u`>M5sqP#IM;KnISOck) z!IR)X3x(~?f#^U>k|^8DL8hZC!QoUXo2~>22M{u=z!1@!z2p>FjvB;r#I(pTNph!k zR@o^K1}JbGEi1bM!hl!~DIHzC99bMzXkQMgUSX31AUS0hKo*s~0-^&g>Bd}dIR;L< z44x#3-h0L_f#qO>6S&cp#xjQVPE%&D&yJ@wV1Rp&r7>TCXxU-Q-1?o!85Fip9R0M>0e z4=kfqga=(kz$0Rky=W*#lQv4D#Yxy`j3(u; zGeVoB2_u)$qzs5Ap))Xght6I1J9pjh-1WOU7g=OHvokci0W%rnN!t-nBFUPGCgrS! z)scj=3$@)W6Sv*UXfD-_(wQL%ry53+>djq9!YPN*q`G#8BwTqJO*$a`8Im-kKN(Hh zE`1x4Buq4EQlm*`O*E9dmA+v)&Y!vy> z-ApALzCUc-b^$=V2Sp-avH$ieT3v|xGxy|X+aqJt+i4#w6ct`_X zHz9Po388ZwOO@{aI+O60IRu^rfGjF|1>~BtZbIm^HRap*}raA>!|I*tV>`6U*^vq7&1d~;p1rG@XvC?JNvA&Lt54mfj$xIv z%|f2-V#ZZ&2TRV4lw8*5BBgt7|<5p<>i>Fg) z4ZTx8LN76A+9Y?6GmfZQ89PTv%!neH)YxrDz*90m9O2Su1{aB*m>%KH>V&LA{@EyZ z6BW;)-A6ci+J5ain8-)xAWSJ7eQ_c zdxWGQ<03}l9Wc(yYH@@M$BMFa1RXd>NX8J@Cm=e8j*!qn5IY6JEeb57m+VE~BbJ0~ z0b)sXIK`~zAeMe|Llj~p^c2KeA3+Y=yB(uoz#9<*^Z_#>2CQx!>ez^IPk^si!4A|v!rS@4h|lgY-OYnsR(9KY(75=t90JwJgc)+e)N`AV=Qes+ zBTw@x^(4|$0g=W?R2of&%ntJqt7~&6 zMdu<)UX)d7lpUp*2_cPybo2FOyJ=6D?nQT%tNja>7PF$+Q`XijinqS7}7)3!dM}`)bR@ zt}0s^sk&6?M^yvB%SbK=+e4!4F~@c}R^Fk%OCjkLLb4Ynvrew8<5G*xN<6^{Bk9IAr5$t48M1io4BijM5x)X`*sy7+Mxpl%=2rEd3iK zx+=lJr%76bjT#atpv%FfNa}=*%mMPdNTtz@H>EWQI3FTWX*Bf`Hi>jgcI6T!mTrQD zrL-!#s=>ih5{kFEi;f5RVCyoZNKD1(GR2WBBWzpcY9*?ZWLel~h5+&>VwLtX)?S*k zOs>m_!wI65WWdZwR8&n?=)6QFFM}*Ai~rHZ&OvvPw4!fO54Kix)q+DKkWjpB`d6vc zL#5F?$V{#vU;)1g0!o(7SEFnl$X;dXQ<^+UReP0#F^oJ zdo5D^$V-nyGA7b)5|t*{Fq&i3&s1dL$ng@0Dt4ZO;^n(@RK?^Z6lWz(cpZerqc)sk zbHXO)LA0DC>Iychh8hxw6! z6%Su1$3%c&_1D2y;ON9+KVP*|zCXs4JHMsevq;BX8|k$2HKcscf$^j{+>(N?A?536 zj3=E`zJ|0GH=T?pZBo95wAaLw^3?(6LrP<)Z!fk1>xsB>TVL?CtoIevkMX3eC*w&? z9*EV8d9c2a?;)K+z@$%NRO@_IQ(T2tTs@1sp~Y2@vT2cBJ*ml~!sg+nD>Y(E(ux4x z5-Ga~uc^?=4z;*Mx`u#gk|vxUQ=9ab94PmYG~y(g(WDs!Xp_`yca%u=G@*y&lJ-oA z^cn)RNiM=hWO)MyeuH)h_XY;9<7Z)_YlUVN$%t;-e`kU?Y8 z7y-O3&Y@fZG=SNt#N=dq4Uvmag)XDTr@V|7pYk$Ve9FrRl5H8m;DYUP@)fYhxJqHW zE>@K!8lN2ib_&MMK3muU)ZV=~TY>h#qv{bb?U6JH+s#79gzaLPRR~b11qp@i zB4MSl!>EC4)r*&P)8RIirIQValXdfCbqWEx=RvM0OTStdzv?DwlvAj966CnD10W@3 zFM(WEmQQG|Dti-TkGNo*2MT(46|V=Yj|1Y)N4uNQEX~q1-E5(HI3CO)X%{x`T(R4^ zUpL*4j~B5H(fjs__jS_?)DgR8z|Ko-d=DCz0r`^X3qSD=u*W4fo&jNJAT#HM-BCZH zHTB`^QMO%4+U_XZE+-9klnrLyyl2H)q&7!c8-0v@lp||OYIC#!Cecd1d5;q7rPQMw z5^6xS6{E{CK+*HwrKcv0HE`vnr)U;!f)dR#_HfEJ_Dne==3u}&f+VcL*x^hqAOVKc zvj98X1+bOrtOCfetx*`;m^MrNcQBr_DuzbOI1Dz^O3SRVf$`PG1o9om0`k@X@+_aN zMc$4_@=@2I43>j;Gioua_2EKnFW3eI3=FPna|mFsf^ZmMaUhuxwu`N&Etnv=DvjBd zfdi|D$DFGsIGyqY7Pkd%K=-a7W?f=qB>J*ldEta^6~$qnj`=A5t30v}`{%5&7+Hgt+z_&X#t&C@|ix3FJK&Y~LY|j!D$P z*w-=dT)krxJVzVy=xA}S-Z2h-!o;5iHOp*==k^_5nH{!FF8AlqCRi#t*(AjKqGcVi zwsF8RFLo+eI$@3YSx+NKLRs5LP+%KzG=t^J%n$Z}rMt0H!CC`sC&CG?!xr`rSlXhi zTvs`29E$sQIa|7D%UQ9di?&>sLD4k@J9H#;Ia|c%)t0UV3a5ji2xm*z-L^c&K~I0e z{Vuyum$t{av|W&y`Z3Oo3u5eJw3(wAx|}2j#Ms9;Q?nO%#|%Tq#n{JaEJp)kX{gTM zkI`5)>oGc(?p>mDR@+4A^RUC%Mc(tR(DSX(>*w(9swEaMBWW`yTr(%G7^lIU#zo$bcB)02B&1!o{$dpC%W2O3 zXb$)MIS-Sc6Rf|`#ky@s{S7$VKNpi(oN*bye(FeQS^Bnu%sN?In(*f6Qtt z-eNYi37d|4&jJEhP^i+A!7>F~0<2Z^3h1qJ1@v;q%CUrT&`YZK&7JnXnbDUKeH8(x zG9<=?UYm1>VZfn)!q}Vif3R-ey2}Je-CCV+t6RdYZV3)z_8oLLL3AO#D<@c&ynxoH z$C2+v%X79PKM5}~6-!=&*=%{n+nmYUtjXKzu%Q^dO&;bL?%i~jI!dC${xJ@Fov@C& z8a>7xrcSg+xx?guMP_c!JxV9nY3wM;1Okd6(N#g(L}v?co|DDD7qx&c=MV- z+S2W&wr-ZH9oW4+fBO@Oi}1)x2==$IZon%y5$*}_D{UAl*i8p^JfLPv9fYbLkw2V<%W)9F}sh;kHzG57^8gr+Tbdjd`+e;wTG2nN3i+Zdh$yj z)R{u(S6z4X>3LAJ$jna!{+$F zd0UTTyPV_27NJY$L*3|f`o3rvNezOxp#of4Q3QU!_T&hfW~ijFRV?su;}{Er`mAG-R<8 z%CcBh48cWLIXH6;UkTP8lJheU;OiqjFg2no-_gf--hP9q?NVQUKL%n+t_d5GFe}7D zHM%q>`GpIWMz;XX&^d>IaZfTUY|llI4P|+7tBi1C_L*^p#i8=K}Wi%p4DkacBAD#W}PH!=(urX+R3CTRb(vWp;U zEL&49*MMC#piwgIGD0z!=3!ARErBvId0SQT+jX(FTteJADKgq`v%XqU&uJ30i$=jG zY?fecj+J1l5YT!yYA={ZiF%xb)?>I(Q7($GB)DvD>R-tB* zY$9x*b*n`zk8`z^w$!Ogq@DO5U6tVApCruBd)mXSY9%TpVZ%bP7lgr#AXCT%#Ax!U zyjn!nt6~VE$z{}SXe|EA#Vp1UkU5Du<(6!;ykkj7wUB5nVAQyzjd~Wy|3+aJhDO@M zXnRe9f&FJeC2wM4~9>V-YV=fs*#Nh9B+!8ruG zGq#0KA@1@H@neXaM1Xsc%m|w#nH4s^0CGWDo7WYdf*Xih6=|GA6{8uMa9yO~21t#hjgj#10xh@~gzFxvK%%<}d9kLX3bq{T zQ`xo+HysQXkAWZeuuaFf2?XrLNG1_b-x^Y`tl;Z>)oH}REE0;n#f2G7NmM6^N)t9M z_Y+*SF_>%=H8v&cagr8UTHVA!ak(sw@_TC(drKo%{00PDJ)0@jIz;txk{bx9LZvT0 zF5-}6Lf8b!l*W==&{&d78tW%dN>nEabN6++)FGzx_INI5*LCjS4 z0~xmb8mLkoH7C)B8X<|EZFZAf6orsPvyHYHNkq+yG;tGTQ(2pNBjBt=g_l9h?I4vj zn`qSWAxZ+FEGUeVvQX~EZh=yryiGqQzPX%x1LM4yPpU7E-nn42D7g#%#q^GdxW6A0*d z5~jnmm4?W+UR#O1khY6rH%YIsM_oBlUr?giL{Th6qatf&5p`Meh+hL)6E;S2OJgfx zf~JY4>Ler@6)newC@S(m)>E~j=E_A;(M?b(ii#G-c|=`7z_fS+L`~`>+0@t_OkxMN zOPf7T!joLT=P53TSbq0|Vw@e>CZ#kd(oPbUMix@qE7BOrWnsHXR57X@rDsJNn+2H{ zHcoO$*k~bVA*$GU4Q!=Y6E$UsC@mz)ndvJ;tFszJ%Z;*|hI9@Au0x__R26J0MKxeE)icwlx(jqxOPBMmoX0IdN#FhtqgKcE0P9S(Q z8>4v6jQtVGny`sxB-C%rNz8&}KHl2EG@&TQNc3fbI5WN>vE3JDT>iZqqJS3jxl5A zinf>qQN_psCZRYh*>sX<=5dni5}RNd+E`sIhXE}_(jsifRMr|l zjhvPcFrgMmRUF;dvdmCY?9>&MR*Upl9Y}*_O*1r`s6vDR4k@t>A>l{u;TepSi{c6q zM+*R>_DEDGiGDag8V;3+GGCNq^PmPF(Vz&D6$BJf?Ted59FkCs+0~b}NK_|@N~7`5 ztTkp)Zz0b|UXL_0!>id?oAa89Dad64tU z+5|iVW;7gu7OEYQm4vGzeVl}c{C@LLyeZ<4q)Ja@Nt%QWNjfx^B-B`v35_M0)L0T0 z;H{@F|4x^GFY~Vv#ZD5RMEwMC45=im{$zEZ*X=$&Qckc2Xr?D*ZlCri+HvpF<>TwdjNCkI@ z_DK|1$b+tsgkoLh6uwx>pu z1CwacQSVdALb$0V?UlrF5^5s4%2ttIi8CPLkfb1N=OoC2#*$pnSevFDFdR5YwBBdzGRh#6r2it7D8brx0!lbXb=$iskqOL>?A7tv3b zVIKfKTG^>ujlk^%NRx=&i!M$qXE79edoL%|&(X;JayRd$3v&C|y$rH|I~8~!Z`#Vy zd|*o;=8ohNSbps@VwbT$td{(vu}v%au@kOv$3cyC1(wUJ17REiJ~#=YA2sNjL-|aF zSSG5J^5qwluPeI;1=0p6&xhSzQ8mo5}F_Np&MA6_FfXz3> z?j91_gC`Sg0S3$>B+DAR0;0AYp)E853MA}%KF|QUsw_*@qI#S+M3WD@cTQSBx>!r? zE<{Cjv!}JFE;=2HgJ03wbo@Azz%Ceqw%3cB~*B)f+-rU-mSCE>9V~~|t09%keyT}Z2F|VoRK6@l*;+rR%e}>$CVO%&HOt;xubOS=W7T zRYIvO850w8IxDqG(4Wn?-=`;69XMNV&i02BsQ89 z_9E$|BtJ$nFKj3Kw-)urV{4{So1*>nIY=&ww3F`EF2;9qTrMh0vLtNePdAYxb47*c zkaR(kCrOk|kerv;ILVT*A@kQsIZ4tgnI=e*!bS}`4}Hz)n9DSDnab~*UX@J6=qgEm zj704ZN!S;-gEPJ(D}yMMWLPq8QLMBn!fZUWe62nI2=_oEYE*%t?)oy3y;BWz_57XLR<|3hAm0Gu+hZD6qN|uQz6QK5XadAg;9IU zg|=lJ%K%HVSJ>Dx2oqs`1s7c`%5yQsGd%|?S?x}6a&dFlhycqqLUUi1sHg@MX}0o- zT{T619rcPRZYf`-^4v|Ok+(C88A%W>fSgx$3FMNp)aP0PTk&5m=B8;nnT7$CV;Tmq zOmj_H{Esg7nc0!gf!*G)6(WvG0Wysg8OtcuifUJjDAQOZEeL3Pl6GO`3FNf0Bx-k* zyctm~BJCt;6*fkq$&ZmFB{p6F(VQaR+=D0@RE1E3U@xZXKu91kwY_}ZS{n(jHN z;W&c5=D^G&tRdV&xPY*Tuz+wL!CnJkZXj@_n?bNwB^cUq9AO;6mH}2Sw#IdY6(Xc# z9yiIG>lWsbL^9!8;IiXuSxPu%!y&EO>r{6Tk9l62V^ofAyM>;3`5j+KOX}E@mAl)SAj_&BoSt8Bxo%{9RlOoH;o9? zi>?Po&J2~(CxQn?N=2mumKz)%ECmmgvSaw)4-h<1%xBW2bnrlSAk|+?4`qV~`bzoY zNbo>L$(#F%;6>%c2%`J)LqpkNB+q0|jGj!Ti|OH$S*i;xjGh=qCJ`PS?$29U`oxK1 z_6dt}gTp9GQ<;Jlz*HNb%lBE<6cg3)yD&chIbB7%WdaOBEr`8r^S=ZURO|S-EQfn zyCv+Qg1Ky(1HdeWdY7Tcu#?^)Pwy&p7;GL8MLgGfo8L9)Ff8&++gvtHFEGntxo5Gc zFf_x*?Pc{IM}%ty)%`7R%vf3fHoc~YcFTwEZGN^+qucZrns)~u!dz}Io8M1w(>wIW z-9dH_dq*#;_ijMTQ}XfH(}LfOb}UZz!EJh}k3B6o&B~d}=J8Qr%TsjY`|b%Qo@10i zY`ZLir(S~*^}ZC}?e{VRjEwT%H@ua6wC$eY)83?D%lgtby@5Z!M{XEwI;(ddBG_m4 zy7E`|Y}vzDJyO?NxU1%3j81<(;y;EASP$-(=o)^0nU<#q8yqy|viVuOg-$5iZCb20 z!df!N8n4}^1db`i+KL=Iiq-KrP86$yaV#j-O$B{kv3e7ITd_JgeONJ$&An@PfHQON z+AX_S7qL6=91zjF1H9<(UAqH(R>8Y=OUt>4-2r>WUAy`6zjy5pJO@JjZrMRQh1~%* zEZ(&{z~;rfcB9w)ekc!a-;o+lSfyP7v2Aab;Ma)y)sWlv+J#M z_qD*b{dWaV7rDj!RBIdLw*PhoPm{g8?VnwkS(u;g4?a-KZo?(u8>atg5A`jkSN=G# z^`|m;vea(^k#d!3{u2g5&Us+QV5@I2M*`FDHU7u;VR`Q`{zCh>C!O*z$M@U>{^4SN z)L)svKe@`}XLmOyEYkcfw&hhAIcJKU`eV|R$NK*qx$xi^UdUy!fUbJrvxZ)?V&qI^g z`Vs4;_RLH=O#2r+%<`+b2+5`W+u>o#ufE-gQNr6$UOVc~nP?Yg*LQEThxy<1^qGFu z!@mOk-a1{==?~Oj^W@YIeun>emC28TEO`D({XL#s^52HnUZ(RS+xrtc*tfY&|N1+m zFe#7u6{7XGJoxMm=~uVu&rG@Wv~SkK%x}rVlwa~N<;xzXe8t0*H~l>R$))|%?BOr% zU|-3TGySxOng5K3DPQz3{JMuJzu{rZZ+V#Vbq`ZsaSs3FQh%KE+V^YQ?EgA& zCG?x1Z~d8Aud?7w2EG7n(-Z5Z`e)zc@Ux+R4w&nP)hE`g zEO-&*3!c0l_>zYo1is#6U)z2e zZkpxN@ipb)4(PZ1D)NAw`rW|uz`X_^2i^o8Gx*KGrC-yt0Gt2#uS@2laT@Y-XrHG8 zasGT8@C4*n?s4ryte5)hO%Kx_7C*FA-u#~&{#oQViTt02DCYlO;0a*3o8S)sPkH#) zfZLHigxvNIv0i1tZ$Ul-Y}=FlScmj_mCI}32B3`FcfJ7qByKKze#{7nD82Ke}IyZl># z=Yehiy%Bg5*!CaKHA`?lTYeUJ0eBhI_UFRKP?%imFH0U~y2;-$Vx-6;UDGqlf(b;i zKgNL1LT<}{2I7hJDwBC(8MxY;-^!6*ukzr1NN+E@KiT+%jVTL$9rF4A;`;Lw!0W(! zprvEO09nXdfThE(6>Cdns_$e|P@#0B{HJ zg3;dxybgTU;7;Ii+@#w4(!iI1r;L1r>A$Q~GRymE;1ysyex`vNufaa}t!=NxuOP8p z>My|`I{abihkxYer;h_K0$cz1J>bgg&Og5Zd=_{dSup<_z~z6e&kcyzfG+?qdgW*S z)Ro8ir|Fqx<{3=6v{N~-Ugg0C(%Xyu@ifd!14v(sNaoM}Cf2Jgcp>CxfisA(^_}+Q z)Svh84?}+qc+At^@Z{9r^FQ!Ut}=OSm;tu^{Rq-e0Q1FGme1SS_S&!dmeZ$w@>QA=RTjKwhx{wnoj%`XKL^~5 zDBAZ?;H$t1gFg*i`;X3F8xg-}!=-0=l^&*i<^ODzuX>pBag1cW%7QN;|FdWh3>(C1 ze3TZl)&CLb z+spb#ee@7Z_18Vj{OWlVDwoPHd6@D|4|gK}YtPsf?blMkvv^Q&9eUPZbI)@5F@3?q zY_IV9oji~9a}{OgAu-ky-~{Anp&kF|Gx_Cx6f|@W9XXe_MP7c_U-usu;1Qa z0d`Z;?K?MseS7}`m}5k*+jss3*th@hfxpj+(H`r-etnp>^n7b^S@18AyX*Fyr@PD% zef!RHfc^6MuD!c%-}#|!@p3m&F?;{L7a&w7~hvph7DOXtsX9;W=}OSZ~aJe)&;wJ+Tz&u8uY zR`D{Y|0Lv9z{in~ov(=X()p_W6%Nz>(8DZ$&jVZKdm0?3yzW7V-;NCS664R7Cs+#9 z@-|-U^jV%hY$l`f%Wv2!zv5w*ccaD0iI=?jmLDasm+kKrPyd74#t=rHY_@i6VJ=OL|JrvJVEd;{{g7yI)~z)jGfL8L8@Sg*3+2;|p*Ta0`V zxbo00x!iLkiY&}Wx%(p5>4AIQ(=h7URHtE7+Dt z?CYv(*1mm*`7KmA`75@`o44UNZNs$h!Vy=I_W1Yc?>9aF=6t{5 zVb1qW88`ob&;Pgf_xJpNYkT~A^#5khzkdn-U-0mUf$e3_CoXw%j*rTIH$M11+V-;g z)t;RC( z{E~+$zv^MiuX&jAji;P_{EBaT+5Xw|R5sbBfCF2BAV z^s78M_18UoY6txdPd>7Py!>6RJmz=K!{giZDNo{kNxkk3ej4)Q#5ljR?-S2@^X0p@ zrDyw0d-*fJYaSMV@G#}AKj-Y@x5L}Z`d7k}Q-Aj7o&K-wpugbBslVu9@dpo6e$~S} z`PVg1PW`&~yYh*T^CQ}F-5Y##2YXsP{fj%uuY2-O?;tPn+nBqOV9F_Jvqy(`emnoX9xXiPfq=M4>P~L9;UqDVaiJ$ru>?RDZlPv zvFBHuJx_NJ6XpDu`qiGiatHZ>Cx77%^2HCj{Ofj*Z+LRrbMaT5KFeS9Fy+f0e&x3O znt)dzZ-AcdFJis4zbb#t;eF7re3czP&yZ)WRi2#XEqVA&EYH(F0(=>A>e=#$^(qTe zkZ%BU8$x*oxbfF_Mej2)-5jvhe+%U0Uj9!3S9tj6fcJQq?Q_9P&-^w#O!=mVDZe=H z%9Hl>Fy+%9+A5#%Fy-wZ-YW0#Fy*&A%>36qOnJq^*7UU=rrdAeUq*fH#rb#vcn$h3 zh_vlZte5t0>qi}C`3vVAX8ws!JNz-^_Z+-L%V*|%zVvC}-5zH8DNmp23s+qF&u_Dj z`Xx_J{W%Z+(GL3ao}Bu%pLhBH*$(=3o}BtKUvT<=yMz9$C#U{G^b&oU{LUhx$Q2X~N%f9vGTzxD4Oj_;t~?#Zd2@Ng3P=W6ZeQ}lhr$chbiCuXD9zTcZqwzr)BdvFle4^JnSI_{7JP7r{EvI`-`GJu>&ZX9gM4AP%YP?(#yHsI()V$y z&F9}Z<9`bIMW1IZyM5>CHvAXc@U3mQ9232t{`uSRD}ifjcgc5^JR9Y;5TpM(U=Q&j z;N#EK^`7_$@Fe=L9`gGz9^Ooh^NuQ`e+IbuMf(0I_1^)^{U`N_-v`Xk4{?7x@P3{0-vwScvn!Z1_`d>AegSI+x|s4W0@MFnjQl$A*;nrh#?Yjc|4(4f zFMQvE`0K!ae*XY`@!nnX9XOOf?LLgxAKfMI=Mz@~7oNF0s6~3#_kLi0K7xKj{3_t3 z(k}UZBI>^ZnEUw_$cbBlC%#YDTk6Mwx&9@L{1`CbM}--p|7Kvm&(&b?8DQ>z+YNpj z@a9jTeg?k-cx_7Gxnp_n1LpjbG4fvr=J`Ts@C9JLU(jOO@3X*_uot(RQvO$f*%-)D z@G>ypKjZr^%>SFfi=RRt8;r3p?>hWPz---Kxdq3~m?=8Umd}5Q) z9|z{=A?pl&J8j?_PX`fj$3c zeVz}z{^+jYqS5~mV4io_@$eup&(9LZ{x<+~f6`*~+kkJu`Nj-R0Q33Ew9(H1^YhQ^ zM*bGyG1Qm#-iOaSj{_IH@%^*FC5*R((Vqogh5f8Q{qHw`d7fWo^8e4k6)$k>>F0sx zy!H6cfO%fOZ1P(HzJ~elmcbjuUjJ1-ANq~@{wUk08hD`O>icrw>C<{YLHR?#;~U7s zvxR$-#{A~{VZ_s16bcoeclS}&;L`v^>{v$GwFX3n9rNk zU(g=FeBT*eApZF|V4km9`JXcVCi)XEsngyS;2ZDK^9$l{5qsUd67s#k%zq5HcG1lz zKLwoh_G9k_=J`Xd(f>tY-~T@XoWXo-{o^8V0rQ3RpHBie+}8KES>9(U_r}|Q2cE_J z3nKP>4NM9CX4~(tD40ON_3U6*@VCIRXJIlxd(a>M5qK}kqdxQB1m<~{t>5k!pndQ@ zsm<>`;Au<-tw#Svz^m^FqVeOVw%^q19d1Lo)78j+smcLVeM#jdxH1M~fO zG_lxI03P^&^XI34d7jr|%KsVQx*v7>)As>Sp3vu2tj~vm`TQ?w^e+JO{=t^_3E zrxt$^c=@wQ+Pk?>@|0`gBz4|*~e*Z$H$^T!0r||g!i=X*I^f&fbc0An&y!Su4 z_V_{I1&q%Llm0>A3*LUC6`1!QSB?Bprhf?gH-nD>FMIRLFfh-b$BcX&c=C$#ze!+w z)qY~UYTL7d?OYSKtQB$NU~VmiLSr z=zH_Qi-7(4st))v#xJAUUVFg|pgk*0{;vo2{jVLE=dIR%4-><`>P-4$!1jGMnGbKiT|00$lq;xW6^+aS@o$Yg&x{5-`u}mJPlJ zyz1q56L=GiZR_)QzR5pC?%VZ34c5 z^_A(l|BnIl{EOdL$o796nD1}&8vFZz`F$uk(Z4r%3vdnA>t>Vx+kguXlm*wnrv33Q z;F7mL`Vere!p+YYnI7kTO(y-Pf&KmT=Yhw(`Suzx&wp+Eehrw<-=15FrN>#8hZzU`8@opY2Q5XxL4oPz_-)|A&${*h)4;9I*e&E+>u~>O?E5zG z>Xe&*?s+l%2lm4a#a}9b{rz<{@TDtmJk|sAdFPDL{|~_Y{vdvSg8tSBT;ttOydL-* z?ms>becJmb;G1yXT9dv9_y*>)4TJN**S-DX+kt(5co*;ro~PUXeJ?OSAG>1eHxImo z_G&cweFFHLw?Fw5a0?m-O(6Du9+>w-ylDSdf$Kg8pD_6Efcd=9mbVVf_l@=#`6e*m zZ?W>-wMdKg|B|uiS-`#5v0s7$^M5WdpH~;2uK2~k{&~%~c6e|^XUkAKRI_X*&NdAI(&6SxWeR~=~i?*Zm|TW{*~ zOTaasboTuQFyHUkgc|F&2+Z@#YX*M?xakh&Ta*4Pz}FTrCXM_XzHQbX9v53`+=9d^`{X$0o;7i-^-0xx>{Zv;+aaZ5&@4K4xmeJtDGKMuU~BK-1kdw_4j|1KK*e&Cr$ z-F{^rcopSeHS&)G^Ss}V$0gv|YInczW#GN*Za(-Qzf&W(AqxJiK;3bq_Vf0@D%=c^fc`(-JM}RBQKeoQjzeD07t zKTH5u{2t2NrRh_^RorhG{b67}4_z?$H1OnGoxlAIFuzaA+B*wegT@Js{>Ompy!qvK zf$jUe^p`IIkN-3F9LD||z|)^WolN>Q;DI-|`UWq1(0+9$|88J@J{4Ui?RNsWVhVW}c@cPZ*wy!^fHN;BlLd?Z`flJ! zj1Sv?9|BH#`?HI{d|&9C$?sFZ?eNcn!T%L_3iDrs!CwLP=kpuD{(SIfz#ZR)j~o5} z1w4!Mw(ACe3wYe?k3Fd9EpI(~0dNlfVe3~9T#oi1GwB}$-nfK18{7)K7y2y*9|q?8 z7{?9n1s?GBiv?i5k7(;N3e5MZ?D+gi;KqM+=cn%k_V1_OPwd?vegv4`H%5PEd;bnF z-{)L0<^LY={DRw$T?W4O6K=i!Dlz@V^zYY!gSR2zqW|3jZuagU{t-Bd{MsR>zwG`& zoFC%(`7Weq`OgGi!G3nY$nOL8*Si-3pZ`HOfBgt>;XmU0I86Dk1LpgEH%xu1kUVp_MIWd;JsnezZ19u^Nr2#y}*3m#rod|fP?SD{sZ#~ z>vJC1KTlo)_RrTZQ(s0K+w1n7F9L63J()l(+viV!`F`CsgZ~1U&&w)Ieg6iy*W0iD z6L9jEP(LHz^>X-+cb@btV1ECL?eA*f^Qf<#4}KWfem^Mh7hgkt%ny~O{8nJTA5dGa z_B{%0uUarCfS14M*3%K-0X#q00~zb{R$%{r=x2cU{s!jv7pwfez{fG)v>N?i2d;-d zRvY}Efn&IzydRkD`&r;U*w5MgzYN?2Z0GMk2QECrji)u>g_pbg?Oi{FjLcOF`h4Jx zEAD>s#lZaj0c+0>11J6wYXqh!*5`G=A?9DECEf?j&xcxnhy%BK`6Yq*eKn0ne*pNB zw|{*SxZ+jF&-C91fUoRv?f+rm1&oholm54X`M!?rpHBb}e9MiG-=jYESL|=v_xr%> z-uS%%%;(WHM*bJTt+21j;J*dt_uNiNmo}$H90al?v)IK`PbiMWj+~?WqH?eTUjo54SyX@KNZbQg7TJCBRpd z7joHBHuJzkuX{}+?!Q1Dgi0o#I+@F#Nas@W-R7zE=vdH~&gD`&i}EMlob4+;(Ad!U z>Oj7sJe3(88aks%{0L)i+oP>wiI{4EnrRV@w7j!MzHohKYdlf0G%O9*o=q1XPLE`R z{rD#K^l+wwU!=~+j=>>(xqG~n?mMMyHa(IWN)HaBeZyS(%z?pNHppcA)1$dkB0EwN zOr2u3kS~^?HIjWITO2H%=>W|^6<_ckDV!dKZ*hD z0sBa{)XHy;H~gV&DIMXsC+o=frAt{+i)BYf@g?+35vE5`OLBI@Bj!)Rg-NvVEsmhs2peR*WAU%I5N!GqCXBp(CjTpfILf##yTk-<>Uv z4CaSLONx>PFXc~VhessR)`a?MGr1TH5>1oMqxjDK{R8QuBta36jt-rG!M2cmj@34( zb+ni+*)pS6qtLG_v9=63Z5eXfGNO%Me>9I~8pgjw`ULu)(QQxg3;drLJdus#yY_S0 z49N+&4XLCvElB?E7R;B@XuZRUecF0tOzV-gtw-Lr40&xCql}*x$cFimL8&C;4rEJx z0}l_vC$qVX?33j2fiz|>l}6Pp^l=I%4EG;0p2-O(T?95WY9`y4$Fw*SM1od{ z3811}(KOjuwusyg9PCK6af#aZa7SBf5Z`ww>}ZRpno20IDjJK2amQf?$F^!52sAI!J}=x36pyY76*@Z9ZH4m`{Hd}{r78n4=I2M87(V=*nTb2<@irFU~LB?b|^7%sBaK^G2ctt5HWLf+A`bLK+A~;Y?_kpKH z9oc>=k&V$0!4J0$52T0tvc&`0Z010|csgCo(6TM@TmU4pwK(`hc7HzGzmo>*GTb9I z9&Rn30ebR4Lx+%8DS1#yLrf!;JQ#ytBvSiYThY}=!9Rjd?rtNmJ0vjsVvnRA?tsr6 z4Z?lc-K7p6I1q131Ua;Vc?Efej@_YjX#m-h?H?LBGc4%9p%jPLU^+MWWHtbbQ*dzP@Mx(p zS~^_FVwKJpDd1ez_DGC75}-q)B~uW9&L~*5{dsC*fNMv?XI;X9mEQe1W%`b?U*B4+g`pI{8ol?p5R-3?d~hoO#gy zoGF7t>2$`-LWlO5=|rZdgAv@<%5m$knU`FII({&4=0tHYgK6c|z>}$=zERT`C?bVl zFv7@)I%f+kq`A4(Uds-j#Ow$71RX;c;?t!l_TX?STP)*} z5fQ?kPUZ3^U)8{@BW@%$I5I57jihpeCsJ6#AXm@H7Rie)D7;{7kWLEk;6eoHaGq3S z`}??u1@7<9jgHXk@Iy?Q{sNeh5^r_-3n;YjlyalP!uRJ3Syr_l`;iRj5N=!YeJr(q z1lt3l*bqxZDVyWwqyKa|CxX-1(zCq5p~7gt2nUC3D18dMeXfF@L zQ{aXf%t%(WX%ix76pJhr2Zu{cj1e|Wg(B|)Xhcrx7>t}Ko}wZuILM|LDHSm=l^NE| z5moFPP^BWqErn-BczedaXA_O&@+B#fcNinV0B(6w+2PCsSc_iEM#fM)UBr@$85j}_ zxC}NoLwQs%Ure!N%&86`fe-Ve*b(#W< z6Orm^+{WgIxUV_gHzF(zK8-uKp%W?AN7`Q)wB9ING?j{cB$bjo&7Lm$P>0((HCjCCgI`H0uBU5vy##NLv2`x4;S=~H8n8UaAL58Y_Pf)23c9;lj(mjx)%si z(!!}Cvfh`;*aaMpBVB|9*|$(1>Gzd*PmU$a>GL2$`@3L+~|e8LUXMJ&zVUw6jb-DKjxKpE&lMeFMD9MyXp?A(iSL z9tSdNVH}(K;$WT!4aQJMlpVV|u(4HAch)TAs32uJHAp=y zHnI=K1~X&ETThm3|F!qX{ft-)9nR0TK{TN@WDH(zY{mwjH`2P*pwwkRgytF6+%gZI zfRo~cWw4M#!{R6NSUS&z`r*_iw67MY-D9>EDY@Op*v5JQqt$WyjOSwE73W9(Y{AqB zN-*uJyMAdmY2DPIlXdHf0yW!v=x?Tm+}C#>LVdz~?o44IKYT{k&l8;Hj0%K3`C>+p z-gKBXz_YEW!^$?faXzGEGst0!@!S!5F5JlTpqz9>|4^J0m%3;7q5Wx`0I-cmutD9j zTk)F;1K4b(=qPeF0aH(5h^V>netR>O#a6qoG$MCyroHrL&A2NjQaLW7!TT`*V$4tt zRp{WoKaXG3)dTFwxxTUQ(j#%~HgT|nUQS_0|HR1PL&4xkx@3GAzAc+X*SOm6(AJqt z<|b2)`j^~ErnuyzHE_eHlek!HtHMzwu81nKiR0n=#Rra}%b}p{tXmG^usd z(ZL5%j9Sly$9Mu8!n9N|jr#-^&7(XwubJt&I5K*Idrc%z59ggnKPF!88IT#KBeOXP za8Q}fnEcy&VgT$rXbfhv+1I|h(OVW`a-`Wd24Su*C2J{IZ$&7f?Yc3s@OB@zu|x9( zc6vIe)zfVnO55gsW+7sIv^5U&9?EA%xg*gHom3UOO}0R(I3%MJWt)yc!%EGvnG_~4 zWNw!)91o(8NBTKOMV7+BWNY0~e@dGMWB|Oli8Dm@dUycQD+t!N=M+ID8WM z>U=2v;7Y-C1<;={+gds8j3#o7xYjIgT8r5XN9SSb8*_}VJIYi6$A;`1Zb_xbkWrtv z6A&A5+pkBvY&qQhw#jxKXLjrf8OYI?k<)9jH<#B{*l+Dn$HCVEPg{65;9Mq?%^PhKGFALaeEIYpog)A z35tXL{gNMVH~PH2mgt$|HyxU(5{|JsA=;k8jcVoRQ8-@}saQ>GcHqd873Dc%8@sS$G?V@8Ma8BV-tJnbYi9oi9W2V{!( z1K8wg<;|8I>9MM3PY#Y?Io031MVH}cYS{(0COATTLaH5ksw|+Iym%0Jbq`v4de7=4)&OcrS>tA$Mz7Q1Yi=%}s(7fd;^Ig#{=;V_TQ; z=Bkr+>E>ICsMZ4N8n3y?6MsNcNU4K`C zwuz?HBXatV4W+q{k-_XHO(_Rmk>fN{!uaSL;mW?nb=V3Rfpopp&|Mv8^5T>q&4@D3 zvq3TC%S{9}20Ul6UT4}S8lbWj*3EZd)_B|BcB>@kXVL*?7i3Rv`7lc2ACc#PFqRWP zZI1ex6D)N~n9s~;-~=H}5qXWRzh-8#(S>5mc4R-!g~If(S+utn6m3+Z<`y}V$g%i? zrF<_3Ebot9YhiINVkFCQB3{d$*Ly)6l;O}qAKRJJZ5^d>uxP{0nQg=zHnQFv&)Dqr z!MF0oGiXR0QuPlRgU$3M_oSXLaK-N*D#_$z1{I|AH<=){lXDnB4N@cQ$@IfQ>oALsl$l*jx<`pW>Y&e6kS7QKXx1!Zx`NL4)a( z5DOob!FMR#H^9fjQLA#>QNn|}oa{O<1G01ac~WG$i1U`t>|UkWZ-==T8_gA>M$!`P zL^&GGl;{pl<=&QOL>vc|C=KwmMR!yjH zyaza*^lr&G+vMdWW8^fPf!q5KP1zxDwA%|%K)KpF=%y}e?u?q(F zZ~>M^_&OW^1lk&-Ngb%;z+s+P$g(E4XLu*T91S1?*@l|AA;-r`Y!9=oOZl5Yl&yVl z{8}~vcW>5BCA4VS2k|x;P6xYWW3Z*|NC;Int~l>s9|-~ z6ARg^Q7=01v8#u%m1T}Z9mZ4~ep~08NAr4ujOy$2O{SIE!@IMRX&~C&#pH&Kdg!wq zCI`mK(`M(am|3vz>Emgh94T;j#SAd&aTho^JZhg$bGgEiiR}2O(B9KJS};Cghm;J| zp?t=imeXhHTvRs`4_#IsVb~-*fXKcD2gx!ms>hfnW?$;8jt3Q3RON_8Mu)thp+=xe zt?nQ}&e#05)`?Z8QgpYpoW0{^Rx*=mh2@^rzCD84S~V;U#<(rxwKRae&Ojb-5^$k5 zbBEalVoJ;jYSgOZ>CP+R2wOyy_Q{#SYOVdUhnI? z&TXHZA##VF@6V*MlS2)ET z`ICu!hddB|)oYNmjxy{>b@^Zm%h3a-wj6GNxG{ha4a(-j%saZ0%RvlkAGJPZv)wkcw@cQgtQs~T^kS8+GqhFcTQO~RFnIZP4 zdbS><-uOf``R>o9al+{wI%+u@16RX7mu8HfkX?d3>W9sg>&WAY0=HUPZT1MqOaG9b z-)gf-w?un9%&C1PJS~+eSIg#ot~}sFlOMoSi+xX|2XlOcWml$X6REF|$tKPm;Rftb z)noTyCWu~aO5tHh2?qw4hvY!^k?gQ}{AjBplQD*}+#kDb9&gyQILNjRz)>~WXYUE@ z!f0*R_f9x($}S4WdwkytyX}ENJXOZiCuu~t9kVwZsfR_TR`azjX;oW?V(@= 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 0000000000000000000000000000000000000000..f3999f08c6e1fd99804767b867b71ae143b17599 GIT binary patch literal 189624 zcmeFa51f_Nb??2;IWsT}6Fmr2N@#jiG-wbX{-`6t^uRC(%>c)l5zvq@!^}Y@4l~nX zFq-CG2WCLy1&a#CSWQmaytlU3z895xsWrKyfFai8qGDoAygh$B4WTy0G`H8L-pu{} z_OqWe&m5tkP2bOb-#5=^o>|Y@f7V`m?X}nbzt05=T6^0zexmw{#OP=C>}#&PYK~Vs zw>FXRtXKGdA~E-x+4KAuE!D=DBgVwPY0SjM#{Amf81w5r#(eCD#>{%hnCpKw@~)a; zO!?co-?|t$o#{9(zV_q3!%-`K(%>US7B4cmz z-}9a_k;(H%zn3gAkr^+T$egY-zR`J8&HH|T`+FvO<0pQ3@9(TI(eQig5)%#H+y2o+ ze|MXS{`)chyY-NXp6>n9T_*a~TTS$jj{g7QO}B1dw|v>+Ws6(;T21}Jrge3#oo%Vs zuDb57zTWOmBmdQ{x28+}Le`~PdpD}7u_S*yRfZUeO*1q(dzV0

ox3VYQ+uGONtM3)v9h=i(2N>JX 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 ZAmwNu9N9*CLHboANWXLmmyRp^{{kMCYR~`x literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..2e54640ac685e0e348793f38f4f92593dcba77ba GIT binary patch literal 610752 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

(^m@-;=g572muA-W9CZ-YflIpA$V+nq%7k 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b1307148f34cd4bcedfd89161421b88c6afdf341 GIT binary patch literal 322180 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�^19Ib*isouOBIdx-WNenyOgEtZ49wuDxT+1w_)0X`0{KIx2nRw zbi!#uCzAK%CwFbN?ZDbHXz1n{t)Q!Z3b)E7piNjf&CW*pktt0YV=d1eCGWWHQ~m-S zdSUj9ZVWj+5Gl)4MPJO9NB^3<(z!F*WedHwz{;t+SaPG^W@g&--;7U;?VL%Ugzk+y zV_JH`8T3)iTvg7r^qH(RD}LC<@iXbKc7lth#x66+)07dK+>BRlY&EOzXE>~ynVbL8 z?ya=vHKb_+-Uw7bbPI6a6mAXVR%6{Ns~cr2G*+T)7o%6Ee-H5eo?Xq*ip)=Auevc- z1|AHTWf%{fXy%5m(WHl|dt10|D-z$FX>MxBv+{=R@XB6}oq5^P*bkrdktf>e2hfMe zKJZI$Kf@}=_i<0d-2{I#f$FP6j0?mUZeT<1KM^McKEzXBIE0Yqtm`T)z|tr+D%6`y3sD)bU6Q6Xi_)e z-by9)lb_zylfQ}d{wk@`4zH4`Ov9_BhOVt6zl~i0O>?6iyizyj7E|3MIuDxq64hz? zDZF~-GjMr~Sqsfzyhb1VIDQjNh&S6Cx9&-2Rg8^}n{d{@##M^y3-mt9Ou`=!uTBZ<wE;alb#QZA`AMIQis9@>IoFaUF5x%SlUs;6TUWDIK zgny$5zpn@{UUm4hqVWDA{6|Ij3q`nFgzH41|ERq07U5?G+JwR<7vVFC@M?>z4hpLp z-o)2x$NLp%e`UkN?AnHh_^TTp=C5yfn76`V-P~VOxa_Bp)L!>fz?ZJ>WZlB%D$@Ry zKZO_{q|wlMCs*OvTr^8>F9Kqz!}Ij6((&BhQii^YhkEhOZ1N zta5z#oj?A9$f{Kw+%xz33@>H`)=frSg)_X+;j!(d_!#RZr@es3Ti*!&O6vdm%|KR| zcCEy-Nm>PY2Hgt9uzBceXsToEyP#HAL(}L(EPO~1f7vIk8YC@jv~Y!mD=loYaE*oQ zENro`-NH@_@38PL3%e}rv2dG(+b!H_;bCCtJj#Pz3{7WsMDTo8X#_8DoEY{{DW#2 zu~3jz7~P^0inHrLkjW6;QWBa)I$&5!Ej*GVVl|L#3?$e<*$0JBv~aS8N-F=Dg)=Oi zX`yzudz0th{(`N{3Fbb_c1P_qZu(belq^N8{yYB*i~G(ftKzh z(;GkN>NbRkzD1b(!SBR;k~i|M;qBz*muhl~(`0^)f$w1ZOE@oHe#~_k`}_DiMfkf# zxSt1Ad13&%M|sn{uknV*EYtT*uK$8TYQeec9OjPs9yGkkzbV$0_i^nOli$7z2JdJ7 z@m}BGr?DRzzhZZi@2_8!`BD5>Uf)h=Oex=sXan;f{G!ZBc3bKDwuxO;Q}{mDw`nxG zBOmVN7eDwOX9c_R?m7G-PHcC6s2bTZ#;1QN-}m%!_w5UgyZjQITgxkd)T>-Fj&LJ< z_to9p{!jeq*390-^X~rnN8Innce?{~j<|i9=iPx{9C7!>o_G5%IO6tGH~TLKuLZ9= z;=VK6t1Hp!u43oe?A4j?@@sJiNV`Axyt_Ah#C`7+ar(|X?smuFXU3LH?|Dbu1Jj;& z4**Zj`5?XCX~S^`h|~A<5w|ygoIH+GmM^+2m|pevWyh)ChFovy5%*^y=jHH~ncVWk z)@)zN5qIxpyzry>j{ef)?rqE=^_%#sGk-s}D;wr^-2R9cu6p>QAI`6dMB+`E`>*NF zmLQ)4+<@Gtbolo{Q#|Yi?>nDcskLho*-n#uXE1+0nfa(OH{|Y~nLecahhkfva-x|- z+-&x8m^iik8XjRe{K@|Yoo+bD?FBFYdKY!|7{Jv1Ad(=>;6 zUj~iO?V~*X)8S##5q|w-M}Dp7y4*5eknci8*Gk#Adauwy^?T&BFyi@sOw``Cb{m-h&Xx>l1 zpi~h}KWTY>^!~9GnLg6>Q=etfRr+x3p3KqFU4~8xX~Um}Z{~=Y!+TP6&jYUjuW-_j zDvvF(t(pGvLvDZNQ>taL+z=|>-NLYZD}_U=P>`Xk5PgRk@JhL*PybfzSeesbT0<8Fy~h9~jp^X54B zK+nV}@E3~SlX1$?pA(1NP$lr$r`#BLm$Nl975tq~A9FX;e%^WZdH3OPB=g4=A@i$= zlHI{8x-;*>!+Sl{tC=rPKl$z&^2W{D!J`i$`)@`*`-1y0viakR zNao;KlpCEnS%Q9@wK*fbxtleNA=WL%QqNMU-)mmWCjgZpcb zXg=>?DZD8S^DK{!wY*8kr_m1HJ#^gV7b=CS2RnY>?$ zB+W_Mw%SJ|-jea!NQ1k7{1MujO+&qFZG`+hIUtL04f_AfbnZaa5qCav8A5)ggUowi zKlfen$_I4&GuPnNJi^phpy=I^6d+0H$Or@ z&pPftfDBnoG%^_+-JKar8Pwj@*2Bm~GLhb^T-3ASvvvkDK`!s2&yu}%_)6~YV4sI& z-{4AyR#zU~!u-pFVf1-4_A&lbSNdeb4$=oAcQ3xt2g#usIn<|fz47PV1?!MQq9?1l zRwt9r?Y;8Y2juYHMaK$qICRB*8Rnc_=3t+c4n}Avw3SD-_9#24dXgMYUW7hBbKHG@ zvXuir)pH2DKL~G1SCB)-t1q9Xcr-Gg%278QIA_`LXmJK0g!bpMM=c?*4)L^%#9Z?8rgc_`Uc|M3?DbG6Uo2r{YIETI^^J zSEX~c$cwRvX;(&elhf`d_y~>pvgmw2e0KW#UwVIN|K{pu`rpm$+~1t(W==OUTX=Kk z(2vlEi?(N_5B5VXMlJPc=5= zC(u7e-}wx6co-e2$n40=t~)!mMkafFb1u}oJ+q$q>&+LZbLV`PQx(woG&HmhsvYp3 zza*WTKpvy;FU9{w{Ey=Q^-I&arTXP7{FmWBi2nfot;Dap#`7P8e?R_x_*cZFD|_-w zsl&bT?XF}k+trW0|KgMB+>3-Q|7AKirha}Fea~)#|D}{;U+g(|fAl%G*L}|2TlJiK zG_xl^2=4J?HM5^_)B4Jm(%rlTY_^ZvRH|T#a7?`26SGpOEL? z4F04U$Uf&*fFFa0Bs@x{eLJCXKk0e*KLF(2`yjN(J?9>#T>a#;cNhM=eZ2d4`+4{C z4)8uhSwcJikaF+I-<@ErPrVFGC2#oZn@xPmsCwGX{B(#gIwN%E<{ZDC%lgjExxWCa zO^ZennafY(>aDC}Px@R2nf7FVl$f8Lk=T*H7yT(kuG4X+aDNha4EG-{N$1YQJq7of z#2t%UcBSo8tbtKyVd~@)_@(=W{l7}*lwa?xqwe1G zjNid-D6IA7#vrKXJoXrgP7Jf;QN@ zJ$qpOQO2rAT?d)`{2$Sq%Sb=zsN2PNNr-yAn>Nv(J?ic|pY&nE;z!*BHAmh3^KkR- zuRZGCP21{)&R*U=-hI6NdZ8m5s5Z5eU-VGB=)de0+Fx*N?Zu%lb?@=xoKGCv{{Now zwaR{A_EFRRMepmUi06;P_XXl@^y87|1mvlF)%G;5Kj$3EmqF%~@hEcdyO8oxF6>&a z_d4=I9%?@W5z6xm%68UKcV%pQzA3XkzyAWtxq$Lrew1%3#`4fq|EUwuy>A?H_q~2d zWB#nxTqn?e&%uVw20u!?fj5x%mB?_0msa_i^vGH12hKj^?&bBtf6ID3OCe{;brZg}dJO!z#;ixceun-d=DA;CEl* z1-DPw&ir!F*SL@LP>KCTuVI_TDMt^o@VTHQ#EJH)nd$y#uu`xChXS zlXE^uuXmak_Z9R~-*(R6effd&khzo2Wz@LlrPLel$8gIIF2kM1-Aa74TrX8t9OR?A`%jKeYE_|J3#m z0QW-oZuIdhG^E=HwRoruw^z`rB^nPx9JF{d6JM9?E3;Pi*5| z)JvH9yMy!tgdd>4YPWUJi%ivbwvc8W@qRIue5k+u$b7G4h%EP=hpZgriX7KKV`XL! zr}y{dSCFRP*53eir@qkCBXaMZ?$z62;yfc>sI#WT9{PLesSc?p)urlDb)|YVV|ntp z8(kO}2MzM=qyF~cCq3Ew8u57hc=z%4^X}&z;APGFgkMjM$jh&%ByPW+>T&z^v=Fyn zPxEp6^_0Nv*VA0wemzy=R-dT0I|uh~a9@Z!j@z%NnYe@X^k>x5Ew-LYsHbT~^^`<5 zjgk#A`33bZe|QLOhL6dXa4(I@5=q?4wR(_YVN~ zqZbEw_mcMROgi^8V*!mx2FPO{^at?YJDoVZeZ2d4`+4{C4)Ff`e-539u|PUG zG3nUD`>$~=e4^%a?Zdadd5YJ<2hR4^8=3BQD3YUinyWtF;t`;pg#lW^6<5z^coqM2 z@#YXmX~MjEL~o+!H2;16m{K?E&3@2ycKK)yT>SA3U*K;pZl4F7&PwQgl(q0y;?*gE zeS8{0-W1frMk4+4f!4w&@QOdp*^3XqtT>(bn7IF;9QN_)`M3{*{vT&8oIR-KiSb`+ z!P7j{{`Y=SNMUPu6@D2|YX;uq#h1){yc$OjufLY8_&dEo{(JG$0sK1L@9|FI75(Kv zwSh7OB3${ZUA)aJJosoWS@ee=)#UJ_6LD?BsFCy6itu}i@P~@4J6s5D!DRu4Jy)x1H!tK!9Eb=C8+sQrp!CyP(>(AoDK|qr)@lX@chXlqLKwfC7=L7vXgTrC zlfoJ1j$@A?1-{$a`_Fn*sS~@8eeRn}{dDJ4y^`0ujMf|?&Lgi!7~^ZL=biWqWj@ahB*2A|l$Vj$F9+eB8*_LuJvZcHRezIr2DifZGQMHWUR%aK zK;ml*A0oZxf3zR>TH>p`6`W0=Og#gP^}C{*bBtM-dt~e%%jC|22hAaeGE1_|KcN{b zbCDRgC~yP%e`h^R`Al;%-zR;a=I9b}(o>#^RZkiD5|{qyQ->)}lk7W6oamleEH_q_LIf?iy zlfwM28Ecbhc6x%+jg23jq;iK@mkGst#!F^}`Xf)DMhKoYcRHQASA3lv2z8|0fu^1L zlH@(vQSsfcJJE(LbpfyJkMG)=k!&R20ru!o=A7pEoxx;wTD{+opH?3Y40@aoABxF zQ9ejnq{|`ZkCdlR>zBmQzR`i$?n#wZFHAy45nslYRZmSKuDPkGPzG*waySPeS&d4j z$5Dm|amq?(Z8p5J#%c6Xw=iK(nBTcEhY5mTe%1aIadi8M$`K(*jsf<;K|r2 z^vrKV(mUy#X-mW%=co;JGY7gWe{R(aw2Rv8x!9M1L3o7^ZUUihWy85G4BcVOk9>yr za6_lmak@*5Zla&EJ>o}Yl%A=572;#}O5tgM{jhPheXZpaSGLh%ufjw-m#uFGepxsl zYs%>Ck=g4%(axI?=7wZHeID4;FI`Z1qUjy1_dW=(-VJVwXJkzr#!cm%sUh9+Tm`fj zQfFm+uh2GK_K3ecYA3RS*HK;KPj$!(ty1#yX?&J6!7%O34(2gi;W73R$0>940Yihl zy!jn?_zdBimpoa;o^$pe=$1S_1Gs_3xi@3|E|iQN@tK6rJ$cskE5pgH8S$!{)VLMy zS@xr!=(F+Jic|iCbxZe^|77Zs{qgRYsx5=eQ#>^%*?lCUJsi}>*|hI6!sfBwp?O~B zuQTR+4ep^ik!+}>A$K`6&r{#rG*T9l17~_pC=aFWOKzcm-(r6GTjiQz`Itlcu}zuW zzgOHMSyr^O?r!a$_U5at(8gXa>D`f4+%u4=Uxx+RA`AK_=1SA<->HnIZqON^PwU6{ zYi<5<+L~nhEbS?6-IL+xA?udB%i6EYDqq_Cvy$8`u z*p@q3xBB&KPdC!;S{tr4!pXEBeu3G@N%+~|y3MJfe*X2zWX<&pmMpq{!QzJNV~us! zbMgQ6(?F&Xc+!qfCNnP3nL(}Nt9@WI+}Pl&=qhzay_oZpw4bvX$4GyfAANZW?m~at zuD<=IT%_r~4C99hI-^)V_%!ELSd-(-=Na**^Jlg{&9Ag*?PFKIB>s(j=-`%2fAVRg zw<_bD*sy(+ZB$*HNjk;%>_oTO>#x2|_M#LWR{hE5Orek1V$Y4JUV=KHdi3k;sKTH( zMRq63x;Xr3&yn^gQP-iNcxe0-Xg`JQK83$;Tf)dg<0@>(Hrc6j+*k5r>9b|GHE$wb zCxm4Cwr3d9R)*t`AdiOJMby3QaLM5PlXy!RLx!Be?c*YY6;8?EX8bmnI#GVPhB9bA zT4SQZc!)heqQP*T@zC?=UPF$7phqu$KjYB*8HZ*<;W#aAuzMWi($cXe9(^S@LyG=b z#>ujKVdsnZ-8XWK1g}0_*<62oB>OHqA5CbDZKY|G>T`xN;jGU6>KE;?y=7~W&kXpf zV9dLjeKKRO=%!y<#vEC<3(pVV##sxU7bNbsPlYs2X6=)4GPWT1Nzz2P3DSwCBT7>m zyKkIRwLN+?);;M{WKOT-VEado+K{~PN2Rrmf)s!F4HPQ07%kuC8v=3DrG zI310j&)NJl^nrddLB46;os3!O|4U+9vtygKpi3|LI?63z-dI&~F5}nE;l1))=u3wy ztA17*iXVzpR{c$>Ig7>GLeCeGdRu0lvC?|wKV!Q^SL5Y&duE7!&+uaQ zD^OPKJ8^Hx(dQN7{ypnp>NkyDfo~HR*@Skca|cZP&zrIPJF%B&%Q~y=RFO~`r}U@94q-ScIP|5@UC>yw-V07`?isOw$j8yFUQL6+VX5CKk*pRIFIp( z^7Yf)CmGqW;c?x!Mvm(&ov%UX##Q(u)uZrcU?=Yii>q8mc?A`IC$JhJ-evJW z1onYHVeyB7{-b*O&prYa{ujJQk=J3M=sgA8N&WU)TzUDA;=kl0K;hXU{J+beVr~bD zp8ott@y{&6D~s?8!6pA)#8vvsio$D)@CNWWAA>V({HCICohQ<*OuBhb^zJAMzo!WQ zW)c1;MfjhCtNwM9o#+h~g|olA@EG}kZ$l~HvHblSyo-;lM}SKI9&ieiI)l`K@G_wP zDE;^%+)TQz);#s~b&a}ltfMo@FKX+zpNx;aQmi4hc0;PQQ?u91(#}ua*1V~ulgqkp zTff$erb8m$p&HR)w!5ai-AqPXvYneYnuvr9M{Dd@zjke^qqb#zyO({cb1}cRy`ZIe zt@qp7{0Av{KHo-hCcgFmFH;oL-9>@5cPTXuddGIv>#Q!j)0o& zUv_mOdoFImz42dJ+D-5pJ{W@zl{96C%DS?zRn)s$jK9KLOS(EAK+o+@_ z?f$^&ao=`cDwH(_J@!In7}Q9Q-jhyT0QzaRHN{3UmP{IGif zH~{RedI|So_t&A9T*lac-y1sYzKvUB>%F-93Gb^q%-*G!*pEVbU_bCTHcoHku=~Ds z4-mh17W4?;3+$bB*zE)E1^y=dlDY4vFASf!MSmae{e<@uJ^PMAUWKmg&KkWU?33~IclAxLTeACz-$%NAz5V zJOJ#S1D|u?7q}PL2kZm(1NQ;<1N(sk!2Q4jzyVM>I^bU5K42fPAGio zTxKr98DyyOwxKnfv#)| zYdrei{VCsW3l=O|*4VJ9UUOn0@tIUQ<^w2?ZX@^0uVaEaX{+KkF_ztz{{G$slv=gWi24%mw*(<(M|B`TKB}C&x18npIw3R;m}3&CKId zF3C;w&J4uSJihO*IR&TP&J`nT?#8Jc9s5S6z%zbYchYxxXs{v69QIWTiz=PuV0n~H z*1WvRuJG~xoGt!zWd;AS0sjjF{)PE_;!h3u>pl}-wshr{?XmALkIMe1gRin*?p1eh z^Q&&{9q3q8`8p@6BunO{%CLdYQ-^)=Wz1n}jj>B>y_LP}Th$pB&CTp3OlL(T^S#VF zcEfvrJM(#zt2h3P%e=t}birkQ;e^JxC(!}bx9q0oqQZnpmq*kA`K#{D91nHx%cCHF z!o`R0ulsNO@`;cA+&OkP?P_j3-93?eiN>QBlBZ{beA& z+J{f)2i9M-rT@xHVVVb0pCws4P0Z^eXQyd%erAZek8*B}IUL0sMW5%eKOy9#Bm82E z*2c;zisDEwsSiHIm}jIuPGT#9G!#yKl)rKce~)%o*rz>kia6Y3RsQ%X{6p26;~h@B z?G$mAT$_%tFFPEJx8@Y_8spz74aO1w^NHunL1kDzHyt?-TBDd74#?vT)b?L|#+Hww z*;w5kOy?4^X{?iKzr-Bcb~R@br~}4dTk=QH>ub=hi1W=iRmVY{WH?!QVA`v+t!23j zm(#6oo{By?U!K68 zo}>Ruq`6HinpcVxLM%+*@2 z_F}HGbDw7>(k|;sm3~;9uoX5;zan*D_N&;2TGD#+t$z(Ijm;KuK7w~<#j8sEjc zi?@&WMc$LV6%~wtdFS)0{Bi79BpS-hVQ({SDkJY^DM*V^1`|adr)D2@WHSL3F}taS3ejwo3LpLYyV)_1i~T;TThtk zuNpm2-M(Sxs?mu`$u|`JGHcf!Z(k&?6PK;}=9`LZWI|iIiSn-|EU0JiTRr%Kp~L=N z^3Yv(qFEov^Cg8S#^)lY=bE1ic{U!gHX8T(jD66kra?YG&Z5TpG}cJ{ncwiAAu zdNO5c;4p-gIbXTtOMEI(}i;2u8h-}csH`7A7dBH(_^y32O zN46=wBfGL|M^JhZPtdu`@ed1yS;1l@OLdv*C6aMr{4Wu!gaySF1hk#{ohn%Is! zYhZ4qeM?6B{!5&jjBJB6{|!3xNlO=7VN+w{2Qq^KmC|M z9s@Rw@(uEZ%`W5@4bbYvzqjgTSL?u0?)t^1($@4VfO{qlvQD`&zGKn`%3l_L*vOSS zr`hl3o2z@g!qmsFBYb-M?tGLzJmzf7m%Cq=ZdC9sqWu-&s?7$E*}GIDu`L;`Gf(Hf z(}{_l`4oExCKE5n@4W%OMtAjOW{}53TOVb;>2XuqcZ_F%P|04C6BDU3?Nvmd%V$vk z69>JvKRS^fcWz=wIL4Z5Y%u*@(P!<|9gS=n2hr7?!)>9J{2HN8x${pENBybe+zOu? zk;RUDBW+ywRfc0Pz7~o-_gW+6QyhgW>{Y_(>rW^TeHTt7JV<{z^o<{~<-7IeyJH!C zmG0Q<;rKN6_6)wRGBB1R&l~I=rjj@N_u>yvibQ{M7T*ogNc5?*bf#Ks_nJSN!W}2m z%si6rAKsDYzTT^R+aP^y;DlX}XtHh3b2Y-m5MQFdoy@vV8<)rnyIXj3NlUrD3! zh|`pIkK#Vpy8jAy>MPA(jdgCgt$oABuQqo!uQ4{Ui(jq!nb()hrTq`v#fS1b8{_MB z2{Js&-7ItCJF=6V2j7S=*HZ>x4Dn7R5_|Yok-fOVJ;WUzvh|7Rj_eJW?%)^Kc4Wt^ zuf#t7CF$o+-IIT>+OtElmldpS&!vo>zCZNloT?r9c+GIW-zUweB;&6d&bL(YCK)^O z{y*%!f1Fj-dGEjX`7sRR2xnj>P9~^lU{Ewf4~U8>i3hqC;f~~|8C?l=hkiNwK)A!h;*WoBT7&4L1X%|Yf9{Cs8e6Y z*=co>Az|nKipfX(QdxjN#JlbM}>P zXYE+BFq0gfnCc`yS7jT}wKcTO-O@B4nSVRBaJP5V^wmM{U8g;S{LYqAom>3_Dg zL+M~g#Gc@mzv4`tdA~zlLzjO_Y%M6>=EVI?PVW9Px{C?$V?%TNj;1Noh(EC<8fLuK z7T?k|r50NU+MmYO$Hfs>9E(cO5Suvccd;?-;|zgF;|9iQeTN$pe3P8Gq#xVyrwX&E z;}mr}jXI24`Yl+%Fm6qvgZs>GaE#_Y?48 z%I5Pwkb84lk*^nd?cjstr3OB90{H6}dT##)-Icz0k?{_^__@;G^G)>%Q)3gkk$KZ7 zFCHdtpBFzB;5jM_yW0E9>^(JO%z-A4UvviY>`vdN@3W=xlzAF$S@Kxr7k{Y!|AMsM z{;1dYv5&h6n}~)fYqJfBKzoR!Ms3cX4&-A=ARm9j_iMoYJnGB#8rs=5wTekiDf1%$rGzd1YB=l1L^^OCoFdu6942 z@5lIFu{ll;g!mpsXx8~Q#~M#3l3SwsPG0K{SUX?kR`|lh{Lw5BDV2L(fGe@uPV0TEg8(xinum zh4>VAggRPi=gJ%`Q};KxPbUuF?UU9G1wUu6Zz=D@opHXI=gCj^ztVRjgStsy@k;-q z@4C_YcWl_pZP-T$J0_5}{LHj|*yC;D$1ZDRZX4%VoaOP9c;~ZxYo-qq?@9+I{#6=R zkT!i}S?O!MhP*56BOlWH#}c9s=i)Ku)|#C7D1yzn+I)Y*y8KWp=b@d`R~l-a3lC{5 zCEn^U#^AG^+6#O0s+BX>boQ(O4l;;}uex!~OnyvNdo*Xw-0@NpwCD4ydcLIb+6oYj z*OoGWoivCXN_y=k)Iocu-6UxHW65)6?oWGh5?_P&yf&lug5IIrma_eA)|=~U?6CBp z$D8e`EycJaJ>1|C_D-9Ai~1`$gcF?{!pIi6J;#1?=5wjE{IWKZ^*6d&`-Ri zdY_-$QciVjDc_|!BrJ1sGe%!v=YlSDi)HgA#@-|K@eM`ohmK@9mxfY?>EQ6prmbN#&ZgF&VEeg8;9#&po`Zq6s z(kHi@dR?ru?OVo?H|AXI=84L0J$o~BmyO!F#>2Fok>GdD_a#FP+V8d2 zebs>EJ1@?JhKRJi6 z1LRfv$!J^oS<>|a!<0dBFCZ_{H5=ZgoLYy5Z|YRW1(a7~I=QLub~D*hJhQJniEy)W znPN1*IbV}vuU!Xrn&}PsF^ol>T&7%?%oeuq`*C57Mi#za+WRcK$a`>)Q8&hX1Dn zd#YO=pD?uwKdTBqy9zIV^YVYZ^NJT5{^C!a$DFoTzdNnUeO<%Hx8IX_q2b~G<8;(s z@S|7zs_=>bvi01*dE|wL|M|Z?cgOi3@BApQpOf+av5cAdCUVp~fp6Z2W4BwE<3KJ9 z>YE`3T!_oj58DB19r(dh9sy5_Ufceg-*sAzf89Z=eEU1!!%my=A9kk7Jc#$Rfa`!~18afPOgv%d91~C2IoHG!#_Cq- zhMnpBg}x4}uRQCV^PL|Vc%H#C&J1%)D+BcZbhgQjttN}+kH-b?woU#S#hZ2#dn*J;O6IVw)F=v&+ru4JdQrfqaJaa zpQiAa@i$j5_VN7*29j|erC@_3CSEw3pVAcvd%VGmeP*BQI2@Q-dHnb)AM8u;`)^{K z%o0}MaUHcP`WwS_vQ1{K-bwPC!%sNbGIqQREItpICKEa%Uhba;mqa*V-9HO_+$S#X z*Mjc?&scY*FWh@v=LTM8!T1BjsrVFrmnSlKbDcDQ-{OZJ2`p-EWFEr3$NE=%!oA0J z*7MQ^gD8)Fd_mjjZ{WTS;-|>7+!bE9_ju_a@I(@yJa?@X`tIN4dCd zUG#f9&L8uT$-pC9Z@G^?WHRu`_WNmzizj6J`~85s__n}rKfkN^$sJvZ6C;@pi=$7e zJo2ye9Ug_&N#5oEv_O{RKDi2?QH3X~aL(bYJPQANRrv2)Ty8pF<165L_whmScmV%4 zcp`v*7d#ojp94KE<ubb zm8*Po!4;oQt?0bD`xC2{ujw}S-`3ytn29^yDN-`6jNJx}|%~tyf-C@kkbIkRCSm{_+ZdeB#RG}V?dn?8 zeS7UKii9ByKHkhzgsrqvTk0m`o{Lv3s$b`?p!nDB1JQ=r@M32Eoo~o z9XMA-2HJre9jdIdK?640i@H0z0tVgO{xFY18cJM$<<*~9byeq@t}k`2>GnS@e%Gg^ zSHA1h;#<<`)oXfhCYl*GVBphC|5N8p>7H&G57}Sh=?AhMQMf5{o$LTb-WOH_k{XTh^xCi~YEJGps#6Z4SMs<4&WW zvhXU}tjj>+5kWdQ)?EyI)51o0-aW_b;{@jm$6v4g{yOr^Wq4Lgn~|OOG{N(c8y1>7 zE5Hv~{4GI*Og-XOaJnE9rFKEWuNB1qHVYrM-wz7n|A>W%XM-ENcD`$miNdMB47J%i zD2VTE`#r{xTj6J0m=eUlxr+igXz?LI!X32u5eqfYl7HRhBWUiZU{cZ=K9+NFGh|EGC&&;yoB@wKT5s@e}{Sl z8hX-S3##7^QAYp~hb+`RWbSUsyyjWgY)xa-k8c`H1F2=t5>eQ?3NpDV6&EZ@aCH= z1HxQ(kI#$*tahS1=P#Q1{?9X$JPPul?woIPww9Bui#bkTxlLyQINA4o|Gf0|;T*a{ z)HFH=%HFfnP;29H5}V7~%QG~AJuIw$hS1f8xDOP_*$VyWEjODzMdx!Sl>1@ykj})? zWMFHP*%#EXd*(szI0)rs7daWdWE=K0ZX0JFC;Ibk=mr(HxocatupL%^pP?*C&cs5O zUPF3ObdzJ^qc%shx)z-+kRh$x*&i`5uix01JIOoB<{S}h@nhIDoAXAJ=G+6;1GdW6 zG~Tm)-JsB<^!3FoA3+BwcQBJD^9+d%SFZ)~Z_ zGdf1Ix&pY}!L(CvyJvzHkox^Pb7te>3cUIm-KlLxl<4ajkT7 ztcQJNe5QDJ?5Vu&u+5Fqdkc+lHt5_*Dt zU0JPbu>Qn4PE8!WbH|3f?jWVhJlD^szWaBS>Wnki4=UxAt$w8pxM2@lajUIzdlWa> z$=BMoyu5JoUXLxio7j}EWxWKGfy1@&e!le=>vNntmFxHDj6dbajcv+f?`rnC&^4Oy zZhTWdlDLceAGn((K5*gC7oE49qwX<7iBafwA&Dl-Gr?5GIhiGSuOB>MH zM~GMF7U=%%KCNA(@}&$gn#&gc0O-cPb=c5?y7lY)7V@riWWzZ`y{wC^Giwm?XZ*mY z^wQ-}Dj&XyG~`#h|32D~+JpSuOV}5$UKacOn)a)s?5oqh8MWm)+Hr_`v@XRCNqg2O z!IUTZ4dK>?+h$+~znHVGC_DGCjbCy^duoPeYOQ;5VJ_=SYDb&noAZ6F=QUax!C4#F z9@0sPfo3SZ0FF7TU^V_gkdR-cDo;$J8JyEwmTU+L0| z_mwysqELSc`$bp>q1|E&+0NQRALrzMy@<{1rt>+MhCNjU_EZsPwsgKdmqzl;l)KCZy}OgU!JUdV;dJq)ArWovEOq>%w5N<=SPsEIn{~ zJIopneKPIlo^pt9I`>6qWrZ`@87BVN`U}T^H?zi0U;A1pF^~`G3_Iee<;*n`Cvmvk z4N-&-mH(s2SIGpu>ppMcLrwIh`e_u zU=yNp4VK5ojsJ|c!Qk*Qlz&|p& zVP&Xbrj+TFt~=w)7Kpj!xRHAL7oquw|k>`{n$^OHK3x z6VFdP-BhpjLu*T_{b{mkI}DxLu-BB_WW3RGzVi}mu(8rM@~SvO^yh9OXTnEFOS~#u zRHh!({r%;!HsA0Sd#7-RKSR!cQ~wc$52Lj07MHyG=ju&JViRD?6M(sZYjmQonN<41t^LcC?pntaXBJ#UF3w=#lJ^P9}@)@Kr z=LeayheR{g_n*T+~oZ6%K zEt9`g@jJxlf3NHfq|VhxPl&?@jSv3xe9Bp$-IUk?phRiQ@4=s@K@bZU;zRPh_6-$R~N4wYLx z8l>4q+^@rZ9OwE{N1Qd33nSaZ@MUxb-;tr*4}rZmcTebksQP5~3BR0;)Lng!HFw&! z_Jr26-t5!)3&d;O;ce`eO`qOq?Z3z8k?Tj{$?St=?BGY-+ydI_ZD!9VJn1qmucOQb z_q@&PKV3LK_H-FLcr#wmIKfRC*@fN6VzY8*(Z_+gG1p z;!CB9s3BVRCk`2YK>b3z>`8>?lFgD&(7xpF$2D>mKlSkR)#O!eDyH!?>B?U?w$*q`n-cO~Lwq6PQeR!) zF+dqMmgBJj`oV#68$ZUIBVpow16rspV}mksD*0+BUq9sAINn$Aj=f9Ec;35sr;WGB zmPchw#Ju#QhKf+z}>EGnJx_w30ucw1p)7^94yYvwHh^E*mCVp+51S%P$ z8_>L6kIJ&2iuE7*c=Jeiq4~W3G%^6s!*Kcr(A3)KBBokA4Ak>ZATHtZs|R)Pak`85 z@~8YLOo*Qz`J3&%n!kSjPdd0!d0)B^{9Ud9_VMEg z=1orXQGDp^B;Pds&1oR)( z(;xTww!{FklluiGis@(qrJcGOHQ0c`2ZBF^GUN1h+ zx{C)Z_eDq{XqI0WUwy^(*Q61(-R&!H>UM;(w78^m&4TV#^Cf`o7gjKPJB=3(-y-x? ztT>`vlxroRJrm0hq0ru{8ZlmWE32Vqaqi}o7nopX-OWbhd3*mWo;oz^>QBu7#Csez zW!Lh&+vty5*i+s(R?C#E;-KX~Ie4dbExB5!f6eXbS+aU1mtPncO4i-$=q`If`8CUs zws@mUl7v;RPH^m&N!XlhwdCr#%X?RTvD-#Jy51=--jP_!nITW0j7prP;+q3G^9mrU zrB-_)kUe~C2}{5p!Mwb$=wAML1#7=G?VYr>nC0l@D=I6<-aQ@_BAKYX zlfU4hBm7+YqAvK)WwbOPNM|}^@k4?VPVk*zLa-Sd4nh163*tX-VH{bkGr1lYWMFhq zkWTz9!8me`cBQqlxP@&NYRy#Nr(2k?P<9CVE*mkyITj`@oNr+}(4EX$4zk2;W35&2 zEc$R{hw`KI^-O*Rr*V&ng%R4idyYNp>s-nw9M~f`otdG98Vra|=Ik$EuW&jevz7^d zh=GRiw*|qQ>0pJ=7EG{4D#+TC))tkIS~?=RcL*{Wd{vNe5oCeZqLvEM$a@4?-+EM# zaIXsDKSrPAq6nKVcro-AgwA^ep|kp|kQPjMLd+l`k6B|S+fJyFwMoJAygnrKVQ(xD zI-7j!`&6$#3QeJ&gfqc_WKO7+^aL4OX&s_>Ig+OH{jP=0hARCDF=;}E3TRGwdFEey7+JbrwY5B4Sa{p91nU`~GZS{O~3{>`q1 zSw{2L!rJEB&?6T&$ zd93~mt^730)ee#Zk4N;VPZ}mVK>X<{d`YwYdL%ox#9nH94t z{67-MyRYV!)NyF24px1C`yx&T3&i864=G2|q`iyZ{rpn=GW^D~0`d`Nv1qIA-rkzq zN|wI$p;*2oEt~QoE!Nv-WzdFscxWuUe>m}DM{8~dCsv&6f3G8+X*QlGAJvg|v(cjJ z`e(4>IENJ^R<*+M_4!@g#JYo9ymzwO>q&0%-VuMHu)URA+le|u4`SF?_-5WX>8A}FFYB0n$!87E)>p36K+-;fDh}|$t_1d z`6#@$op-bnI&I`@#1|&4Zj^7NT-rIK(;i|STZ%d7-Xoth8kEnLPRV5VGAnuQZEhal zm3)PKkng$sOdU!4pFz7ZC-hMHLNpG0$luYu&;&lr!P9Cpt1iu!1}9CzoDQTUcV~|$6q&?*n7BubqK1RI%Mw&jY3YYd5cO*S} zNrNkT>4Yn`w4an-{|3Dr=*5n}|IhT={T}q9UF_Qp&6GFMYIp4Ez18%R*7`*B(s!R; zIyubc)_WHo>Si^!*{)9e{HC4Y$h|tX&rpnAIIK7tKcDt)3u0j6NVfXzQ7ad}Pn$s_ z_%7`lGOl*bdDKA+T2eRC)Jfwth7&opVx{k)=knAMt2FGoMGm!a;v>7Z))luW2B7J} zQZ4?@=G(5^Q-vMunwLMVq;$f2vPgK8`d&=>^NP}%BGXDgPi#XLKu>u4b<*1t;}l6w?A*=I zlQ9GNT@EtF9Y)4%GpBZXGG-VV!)o*iWz3<9jFEhiobhE$=q%9}Il{^zE85&x%&C?$ zhS6vbm{r;})i>#cf+pxLntud(ZI2HWL|4%hKO7EBFb#TrH|vcUHk-OeqFP|GArr>F?Y;_lpB-Z~O8& zx83=b2fo^Q`>VGfE$jf?NP`<@x!9RJ`s4}bMfPI>Hmf4+C; zn?p07d~Dwp&qcpqIP~gkKgo|dJp1o^|7qx7|1)ZFA7y6cKgbpHRBLeun8jpp(Qr)F zD1Vy4Otp9zsOR-ST*6J21DV(u|0naOah}33r?LBWPVUGgAIw zyGs6~!3zX;j*{v3Gm6(HxXTIaKYkp+ycst}C^-lUafq8fNSEw0=${N%1#&K`c=pQPpe;;5t1(ypt*zg~quRE0lYh5wbsmFJ4q&rW`pJD=%Z zdE<)S?ymOEwA0q<%rlcBv~(z)I?d&<-WN1w-WQAddMytP9@@U##ISfpCkiFcHE^zd zU{ixNzL)0e*SIX!i_z4-G&(uTBq%-=+;8Cl3svv>p0sejh0>VnyEMXrM}RJkp@Zr$ z8ZBUmRg8>q)EbWnG60`N+mK3(`althZ3@N#8ZkOfSEwqUt!=JoCcY7cj@v zbMkrSZKMIiRpy!hW%Vn9cn{TS9x1Vc66Xr=-?pYh{f__m>H4@2gWpdsBdOHDb0VwX z@wkikGRX3Zro(46Pt}o{clD^QW9_@GeiN5m@*cX5OWwb(;~hpPK^~N@Lt}7RjD;D0 zhZw(^aU64B#%{Evb`N58!6^r&Qxg3l=1f|xuVoGu#E)1jHLNL&#nQWAnsi*^m%A(k zOgbH&C2S*Bm1gYj++!@Pp2b2z^Xy2BIVD|R4P($WV@cm~z{h`8T38Ymm0nEg#TOQx z4si1n`V`v`GIa##ite>k_Ys zdYol5ZaVQ;b1PXe_xdNrQobJhPTWy$x{cmRe$-}TvHV1=i(9A@th2m2BwyYfoA_@3 z6=|)-t(kb0mULQ*J4W1Vh)XA9bggK=TBl&D7`qu17DjpK(iJVF@pqV!p7Z5Y}CJv`+)fnQm@ z`?u3!Aq{USFP>l3uOBC;+IpwuL$5b@_vO!}mp%esM2=)jIu*>N8p-RhSQ({2!H9u53>AI49Ve29kil6BU?{13%5 z_-&@F#&0rPAa5hrUvc%)MB==eT9G?Mm!k38Fh7m+SMclLx0GLspPs8c;QjqA+^YB6 zwlbQde$hS@$voBb(^u&froo_^cL7X)u5sj4i~Hl2bRaIAj9KiZ@TwyBPXopGzJGLwrY-pRa&WZ|AMfE^ZDxR3$I56}c*xw90z z6XyPA-q6-*P~SvGPS&bNubzR7{fHrq-aJDXy?Gb6>CLlZ(VMXi(u=*p&jgW;%8~^O zEAO9L-PNtr8{}`^akeS4Jn^%pcRycx4_F&{`LZ96Gtgmw{|OFQFi{y}9KCtD)tkxf z=#c>WCgas_=9Iyv$C^?gAcG6nzy2J)vE3u-xkL=dm6RV37qF} zyxEQl892{Dj`I8I8@#xx400;B11g8dQ_M>%aFd`RzGu86zLh>>fgqzD$sSqaTq`&U ziypz#JK_7>_65ea!qZS^r z@Er@=5Kr38Jzo$-;Uj{Ce@Bq`{nHSpA@5uXZl3p}=V`S5m=_rTkkG)mg%sJ~WYIwB zg)p6aw_fOy6VJ&nzThIG6?#8r{ldT;AXFYmKQqt8JNTt3dy^caTq| z1h7kGEFd|S2$YJdHcu;mHD>UiSD}geOjLLxPh~t)J&x+aEhuyS_>_jy^&k0rKjR+h zb1(4&0sS}xl@I@E1{nlV9`#eYF@DwK9$C-9vX#e=ukyjZ1iznr+!M@+H|~*+Y4iyl zS5_}~qplhUv|3bjYEa37Opb+Vm-&F4@=P^v_EFQ@*sviAtzb8G_O5u>O_cA^HfAJd z*v4^ko#`W%=;9fzzL>T#v%{=W_9rs=e%31c_i`Hl+32p$#TJKO-;6$NC}c;mEPur$ zc3ZJtI`1M*4`&^A&Bs`?by9@{Yl=v%61FE#+!YSz<^EahG-mK!yUY)KY$b7w#aKAIFy&_F%2wreZjIC}kea_G*`2OAA9cRl;RN_8{KD94oaua_=$_NhN%Pzo zNt}xk*@f6GEW~bMVVHTAv3W_bBL;gE&6VMs*ZSS%`Hb60~g7+%eo`~Ap+-zU)fkq7mZBTKw~SyYY_ z$pcx-&d1Gvf_d`42?oEPTpkc<;L$o=eE>f`Hg6u_%Zm*DWR2bm)caKyzW}(OpT-z+ zA8qKy{M;-Ab@nX3r3VXib9$D(9DhibzARbYbIVQL?W?cUxnMD(aS`a}&zLdOc8~^C zPPX9diB7hdHS3~;=l|p~BP#(+!|-K>blmj`bilOtd9&1BJ=?cQcDMCu?7&7Z#p+RZ z;-ti0a|(ra4PrB=Z(-9`!NWOp$?OnS8{@Q!DBoS3biwXY&JWF(_6 zcXLP3!>Y}OksFh$c5_P}Od(&=ePd^cZpo>e46fUBr{wpdUwW!++Bb1T^5*8w5$W%B zLWOi}VRV~Hk6Sj($pml(J0_8VgqMz3_84Jy3}Po&7~uxod6TvmYU(mYY%M-{kW(63 z#~L2C)&4t5I0sY~=*(wjY`^573zw7jU(FPxi^v(PV|FQMli@%<^x zHvGb3BkZ0uVT^8(IQ;lF+wY23dNrLep_4|!qR9dJ2zF~i*Sb0&yti*kV)*IFx#6eT z@%KEt;|;xC$}io$11-ce+R?AFj4^!kwCOkMxg|(C-P*Wz#oDscuSi!dy(D>T`7`B( zZHTO_{h=Ay>z3b zqZ?ig-8x7=Lto1-`1+*Ue|zbFl7}-`ThfUy^Q5CsW=mSTF}uX$qP3@kKQs3d_HUfN z?(IenodNAy6*m78JKwoQ37*L$&MQVZEgc>;H`#srf`+`gl_jyDcqTh*RX2a3G}74; z<3IT4UbBWUhBg{eolxdB+{e%!yJ#Q8zbQm}xs0F2Fk#(d%&&juvV54aOn>XL{2w#E zIXzC@+qkr&+31YZsp5mg74dm&f$FKZ^hcbYF*Y&4={Mf(hxAP&S4Ek(Ay{(29;O<5 z_#NVRgdaPvbzAI6ES)d;d^W~Gr%#(Xx?Vc@(K5U!{c*s|+6XeY<^HO?ZVKq&{k*bnw0nv(ny2PU zo|K2rlr}<-FpxS3KNyHlb^S%fm(J>xq7k)0<@2ldo8+|r?JoOGYd(@2k{>E#3fZCZ z`?OXa-=3qNQTgrqlixlrCLdoWe6Vg*FG0ULMdXY4QGRK^;c)uOkmSs2Xp!c-Xs0}i z=dZN1xDmHkpqqB`%a;9EGE!8Va%1obHs6^<8|z1Xd9^3Cp+;vt@&q-Xm3yD7%F`I~ z9wA?q{3o9_w;#rkMUp|15#s*{Hiz1s?izVSAAt-qynt*BJMuRi)i=o!WMipKeJbS( zWob(toH&J?Qdx9UWjJZquu_}Kr>cB>)5%1veU-1KoKfZ&r)G@&t&8H;X4}uR37ssm zxYQQoMtkyM(kCv-CdDI}t#ml8NBrfvlNaqM*I24XAdc^%>#xucmEDcPac&!Rw>^F^^ZiX#xDt z_^vkT=XV#l+Nq$z2OsHU6yNAmiO77?y3Es~j)q1rRpF&7{AX48FRSoyAPb`T#43Dp z75)h4;-nySj6Y!r_IWOmllzu3lw7w0GZ> zUaj}wUTIJ~vdY1WxA?+~xAww|x0r$2jdy?TLLQG>R;k|N>@6Dj%N3Pf+TLe>Euymh z+57x{Ha%Bub!H8vcXj$xtJw*zR}R`X@1x0R8}pK@u`9h1GgK|6+$f)%p)E>R@XB6h zFJR!vW^b9~)9DlJ@3wwNw}gv6c2Dylb!&FY3L;>%)~EH5`z?G&kady$v~#VC91#R> zqg`u#WR74Q9fx2m;RGkMerut2D7#a!ARXBuK`m17D1EYP zAfFAC4#?!&!bS_5Ei|%M`L_5p3l*ipNw>SEx3{;)u6$JVG-zW^q^G%X_Qi4UIk}$Z zHqt;4+CKHaPQiUYV}UCm*>Bq(mS#|SXf7vwg5OU*7NAlC&x!0|86p{8^<=Z%`8&#J zo<;1U_V)G#X0^fW|NWv4b-3xqUad1!`0zdSg)=U^FySc-PtJ#HX;(o$l)ljDloDtlq^ODV%2>oXC|=jpxdz#B!YOmE#8YT%itp9Qb(f?cihaBOP6>)h|jBWX20+?Q#6cjHk-dJO1Wz%&WvP zb|xq466e^NITI&ytdjIJ+BfIMx%E7iEhUr81M`%TJ#@|NkB#USLdv0iTA`0-OS>so z%vo644^0{4XNI216o)TKhoEqCRhOasyGO775r#r?vHWXv{*IX%zKhe?H`!T0e z7|nNuD~#q+)#3gTH=QaeeV5C+%-)Z)e>9olcI885V_(b-gKh`&FY+SYRvNozY~lW{ zPVwVE+;Gof<%{{3nfJzW50%H~nL8eR02*bvrFytbm?LnIbCfhfei|vI@lqv?P?9uA z$4#5lB3T|sS3+7UPl$A(L!IWZD$f}3XdHW7n^rw(g-u#dmkDF$tms^rTRTn-bsOT; z)Eeqm>ri3Bsjj)Lyfl@1ILp?B_794mj>SX8zSd>=WAI*xlUE(|G~@Bxrh1O=y~j=L zy+{5|N2j`zn~crrqPV*s&4wpq`z>1S%n!Ow2HNDa4a%=W+hFQ}4&XY~-|jZ}-aB1& zU&)DUZR^@n8z)cxq!qp(9Rg#2>(rfvKh=TsD5GKe-!qKrdGDw0!2Wfh7)nWp>Wt_F z&?Kj_iAU%z>!PuC;#^pIo4Ioo2yZnxi9^xxPIvtFiMXu^{Z(gW3!Plfm7#J7x` z5Kl-}h$m!|?CDaG8Q4u5nq{-41A`BF>lftBC68nATi1cix-L^>SU4j6lHzPU`pvS7 zTueGkJQ;~UhPLbxIE2o6V(DMRtNAJLq9-riY&Hzt>fGER`l$Ni=Dj`nde+RHJf{;T zHW$ZWhu)Td9X;(C?2#UoKjFm2yzHWD;vTT=)3do*v1aBg(b~k6P|eI| zqY>%5j14#AQ@>v52i~h*PE;q=?VC9tH+6b-L_M^OkGxtY^}k&UAL zSWA1gceO|Hs*(H9*-b(V_<&K%NDRM|pr?4TO>qR`SA1&otPhzqm}%PH-&R*Coh+$(@s<-rKj?t<7-j) zAm5v^sP8fDYg% zgV;=T&|cuj2<58gLB@232XzWGJlGPVeCp?v|2p!db}=?_M_%$?ysYpZKmQ@JY?PlQ zXAJ**!|PXF&Xm|YE>mm;Mr3z^{M#NsNI$nMul_@FPbY0}kLUI#k$*A#NdBoG)0rNj z%LxA|PKc)8cei`}JoQ}&QLbYh;o|i4gXOmDkIT~re_Z}!POPnio|7lzPT#+lK3Mxb zB9uYn0Iy9yP^P_`_FOypN98eV@w;q8;cTG%XdH2B$8dREcDOu#aJc;4^l;%1h*vy$ z1-v3&+!Z@y{Hl)VTj8Jn;!e&FabtbOU2*pA$JQ5)+VZQPs72nJvUZSGk{@ZP3>vT8 zLfr1Ttdl~69h@toeGNM}<@|K^=7;ESpGe$mzCDrH0R6l^%TM2z-4z~@?mH{lJb0MR zMfB5~4!ddUZUQotF@rm^zYxOCWbdao6(`@}(a)FjlA#*QNrp0IK91idpZxKg)>kE~ zy?O)q;%HR>wi4lLOl^Y~l8FyE;69*cP(qQ1QoAGF%Jud1? zT>6sP^uMj#<~)n@Riy71pB~GHi>>zqbD?4aoBr2_U#g|JS_rtOBeXSX`(>{g9s9O7ZTKPqeJ*PLvShVYT4p`qV|KEp$1ESe4% zk9D}-xNhqmdH9+=aHG7W{x>K)QD46&FS+oQ9A=EQ#Df3(Xq(KshGa58XM(#Jo$^i9cuMxbZ&wplPplTEkA0hYrcG zEzA+NloQ*3T)td<8K>@NGEd=qJv_4a9~fs2BG+7q06)Z`n{y5t*8Z8Nhj zzlN}T-xz+U)lGi6T*v%lT;`4FDVaB#RBrfqlfs-!*s+N>OdCC$<%nJJHwrH%-YE1X zmgj4}#|r@%=jANb}&-i{+a5dNZE>g==IUyw?$T6aACJ&uorI_ioNR z?48s8uTzi(oD<|`a+^_AU8|F?|HK{4KCC&b>wK;dWBkh6@?%NP>CyaZEWE3|QQ~3Q z0Eu=!?~f<1ncVW?tJGf;^o71*q@Ck_?HPoG%CHnk<0n^;`VH#0|z-CJ;&m!QXM zQ9r^Qt+>;n5BMZ&y0mxUark~`>>k=N->DHML(GYz@7}{0ciik1#*qO?hRfd_04-#b;qV-bxy5x2 zoq4wb*=qPalMm`^q>C~0{3?I_7r?v7nA;hDG{+8>`)LD`!`}uX^XO~W@jX|To+lXI z$ZDI`a%7g9%jA#6!rBwPX&HF<;I?p?0wDxM$Iy$v9T@4z6IG< z*9|mt72256c{1^O;dc6U+BbZh<@}@rCjI|#UMIh)(z;n$cijd3PI!iXS$F0o^FsSB z%DVUsHzf{4iNg)yFPWH2KbQ@FzX>Vq(m#42_1FONNW}xgVErr!2Z1=XPZFtPil($1hR!+Xnu# zz_&Mfe?5R#`~OYx{qGT{(*I54{B^=T`u|fpC(Dz{8~mNj|NC`M5^u_uQSa5i1buNm zwxvUy|D|`0Mb)1tlAdnlc4SL4^NL2s{W=654OoH4dJYe4#;NPJ>ZeWb=68s7}Cf4n($ zciBmLc1D_?qH8j9Y0amakOML7Uo>abxFABBH8Yf#!YE-vkef6wH7sPH1?y^e2pSIX-S zZ)7gDSbe-HZ(F6j*A`k$dHXyXPNOeEhpcnqRNhbqJ4xuK{!?@CK|3~(-morlLq0rX zeO@|SjnQxI!A|@0*@^P6`uD^1+c41H@H2hB;pbSIGyAaH`!4Ov=o*+GidH+E?-|=V z@xI3S;{9QG+mBcIP?>KcUfE$8{dh)v$q!yKCkG3 z<5(_QZ0;CF-#bwLAaGZH*ytT^{TcSCyz5K|@pCYY;vP?2;&tXNuZf>);mKy&?HT`z zaJgX3X zj7`lPG>5(r9YeU`zQdNLFb) zU#YwJR_f+5bW!WjL4C8Jxzx_so!C6STpq{GTI1s{mrqGN!`ZPquk{&hoS)&WiD!)7 z;Jb;J3(eH)_QW%cDepVHJ@&Gh=ZsA<*Gp_Xtnsz-?NBEwLoMOPQXbKKL0~K$aT?K) zz0BOIf8yB0Gfg#zl)4N)teKSo(~-hG*TZY{@1#g*2I)vM7)FkhPtO-vL&@| zrLC~y3AF)qS0lpxJPG>k)NdndAKF9Uvfo1GZst}$jkSeOirIH>>`|CRyAH><9@ZR5 zdDZQN3PZp2nv>Xi*!C;?sJj=#q@{RHM;E&TS!v=Vj2qAH6b((knxszHH$xxQtT-oY z&P6*;;xClWK9Njkzm2VMVF7g7p5`3T6y=NG13k@r0eZe*^a3HuDBaaBzVK9Z9<+_n zrlf1vT8rdFT=EE+6(TP7W<92QQGK~_&D~x=x3{jS_QtJ;tnY4^;GVM38(-l6Bl4fm zmqg=nq)*>4GBxpH`9<_xyJG0NSR<=ppWwPUI&na<{q=g%o~SWMUEI^*O;-EdyX~;o7DL6ceD6o+p}s3TV{=|@TRJ}9 zCSW}7`YyYGOnh08rOLS7bXntOw z%d?(4=(@SAYtC~`^l9!?(E5{;UsQyCrd?2XJJF8~!2{f2nGI{*4;i;lw1lrG!o!HL z>_p^41OA#%=SH<*1Qggz$3nO48px;L7l9!J~8ebn7& z3-hUqz2|K(GQ76<3bqw}Md<@H&PtN^m~eQ-K`$~Tbe)k$YAeyiBILQP-|VIdzF&>G z>WKF|)iE~IPLB4P@#51ufz}5!|E%}x%-N7XmHBWhacj&`8$U=LxJFh=c8BL~%xj!C zHt^l6vyFMq-DvUn<{*4?@LhaU3%_uC?_Q-F;!JI&?X8tvQ$nw|+w_CkPom@V+PCrz z4Zedub+@T!^pxY#1x{t&kVz~rhFbgcoHI3|x_=xfTJChVB4hfXg*VR@ted>owD&st z0pb3BH`xl@!WqLF1MP@q3bGjx4;X!do5>HgdUJn`flrU+HP+<}D#n-OPyU?vV0k*@ z@g)Z&9~KoRQ!b6!BkV6YHY;atSJgOAYqX)7nAzVX+jQ*rT+OYG>?JNY>6KSJ6N5LE zUO2gajOI8e@+Wt0E{)2)7Ww6ub<6~te{LTR(;m$k_1qq-ydH1|4b<3Yh0r%6v?O`as@h(lo%4|%CIadAGJWd3pC zk)P2--{EH&Lna>x{NeMj#+91uiC^SyWN?ms3)GF9*l>6<{*%za$!$2i zgS9By25SHtpdbFBsnYTF^vJXp#XFn$G>>zRGJhm5LmeAMha*aBnvwDL9KVjy{Jlb0 zuZ&Fgc+41G>B1X+`P__0SL!z!PG;RX>SJbjyb-0`nx97Kx#U_gdy}} z2O2go{zFF=-;i&Py-?P^yAZkqXFLAUk56a)>mtfo%eU_)UnqPEy1qQ)g+e%S=jd7z z`p0?vZl|4~Bl))43+-fQm~ZX}8;etbyu0)EXWgmdNBLh%Uw4V>dtqq`u;1yY-@Vu9 z;6H{S2f%v}$^Xgx$wpOSkfG*Le14wv!GBNiuDtlq076Ca>l-qql0QD1 z_yFdK6Cd?ndHnpzM%K@p9B1P1@`|s~ID&bTbAo~mLKiwE=PZ88AM1}MAHn!?OaM3g znaABvm)GN-;P;c;{svP}{v#&s(FmC(fy}o*?SoN$-4Vbq=3O_Bd5>$t&kEpjez94|h{fQT|l`je&OEZ`QKKlaL@hz0Iv8FOelT-3NJmikIVhl(?;=jUSAhZMfvF&+<5WQ z8)gveJzjeI1GwT_Fy(mnQ~;Ozuqw$sUibq6+;EOG-cUkN;fwM7C^W9$npTi_}tqp$| zd>44i`hN=;fiT-Bv*L4s;y1ti6Tx%fNgLkWLP;Zi%iAwyBJa``5r`K!XlQ2B+-G2%`4g3L{pMM7*j+34Z-#|HzfbX&HaqvebdwUU;-ud7| z;C_4`10M$W^YgplhrlVa$fyIMvFfWo(s7D5PUy)(z^d0xc?~6zW}eL@IAb%d~U>d^~zKa-iv$2 zx_=1#E$~+@J`LP|6yL>F`1~q-VHN&+;F1^GFR1iaRJpGKuRWVOweDZF?gEv4dzH-} z=IohItXgjF;7qM%bJ^-!R`ojbyQ{yjk*-!){DSE=gUb8LRb6(wnxk!L{&%8Y z)O~{&sl7GS?qcidUZXv3@?1GK(1g-gT|DYV@ul9yx3214!8d#B=V;8j$TQX6xva!W|N;b zDE@ButyivDeM=fYX2W7?bx?tr^(90Ahkf$r4{@gEiuIv#pd;%@*?e6rh zZY378$Fl=gz{Zoi#u;h_i)p!2)U|@TXjAD;5^9B_pI(T9N66( zzzl5y_;L5iQs{1vc`DQ+KK6DRh6;YeUl7Gh5S8nim8;jR>=kFpaTLSNJCF$%`SZ!R z$nMx&!hx9V_3K7yqw_M2rz?9_FYD|HehI$YlQoUc_BEZW(yMQ#!r2IGl79CWahBh_ z$blF6=<%HXnV-bx-&sOx*I)G+a}`O|Exp0k=*Zi9own&kVb9iNQ{!TUMweH>%AVBV z*`S8|lv5__YgXRWx#m`{QSU-Vxo3If(-7nA2SVWIdgD>yl9lds+!-IZ=hFuY;;!+i z+$S*(kh{j8!uMD_j<9!U+5Mfk4+|%p#-Z|OZj@zUbqC`D;jaUgkDm$hJ$H)dUpL4r zew{%erN&yp-*KF!^zSZ;@{HhY#sWaaqj6@4GR(4YwuN&nOjkR3x8(eQ48O)@NEmcUZXD!a)nSS$MyN4_KJB@DU3iweWEZw_CW& z!XXRySeUbL*uwo59nT1C!e9OYOEqup9UHE0{-@;l8 z>n)5~*l1z1g_A6dTi9mdGz+I&xB%$RM1Bb-kxz{4-C3MdA$XBD&y<{)&G_AA0J}|a z9`eS*TE_A2Imi(~^a&}!`J5L#35fjCyi?)d2D+Cq-elbFUV(l>@B-2m#Q%0d;>pH= z$jv>1gilZQ-~)nu@0bE?M-E!}mf*F>uQm^M30}u|+2T3D%bAz8=!;We8#SV*E8-HB>o(IPoO~a11cQGk1TB;pvyFN*KHA6Z=FwTk zww9;mbOsvx16kV%JDh75`y-=UpQN=Nbi&fxYu|D(%=BL;OoH&}fX#h7xw~1*8{ID> z-8QwWblLkMyI}OZPIez@z8GQufrC!}S=PFw{|#doA0>ZXtjU;g;B<#AA@ZlSoi6FD z@u#(F^z(IQJsq8_)&-ro)~$Shtog8q`LvH|&4IOEtu?WJ6pLrD?a7qubD464pIO^- z9?!EK0c+txH(6BVeauD zU6*vGf0DTK*}{id-=*p|)h5?@=bPn-n{<^&t?R_3o9{rEo+hv4(@omEQl?1EvnM!% zIHJUHJk`k3T`$3_mOFnZ14!iPO|eob60zRjEWAEI9<#QtJJxgV$L$K~om;+7zbEMG_mDu$dfDnRNeGkPfo95*@Tx zwcfe+o7|5+i2r+JZ)4VuQ<87jl$;E80ACmx)#1rf$*d@Om#p$>6+4PuEct_P>&*Hf zc3j$bBzqEMz&`q{=XK6w1ew4uIjzch|piDEXJP2S>)Lq%f6MihkOW=Ml={# zv&}#2gYc_oS0MMAHuxVo{#n)z_Y#MX-KPf+ z7<&lA_qJaM+A3h15XJ2j#Tj!pl+(znqsYVj9R3^r{%L)@hCL-y7>oN?Nc z%?D%;u+nm3lp#K96EKh%;9UA_p@ z5^=nJ`%ZS_yX*iYJ2;bIL^O7MUhnY6a)#H_^gRJSA05|?@_B`(@Sw(aKA$J(dnHq% zlu30XepNk<&wDaO{jdLB-+bP~w%YKX&M8$nT1ZIB`SL=#pk=5GE>i# z*@Rbma`WTX{!CA%GDb^6&vd`BTToq#cO~z|r-~x(O~*J|(BR{muoME|g)w30T=bf``?w~}*{68Bn~WE;9-+nUH* z1M;hS-1Ai=tGcHPOF?KhK`)SdVbfaLeRp`M(?o#h)UrY=+2Nj&of(m%7fUqm#}S{)D<& zYV0EJJ|eqIxw#4G4!!5t`j&m4=%h1&--||f<3}{onD0s6eR^P5^;Ab<;Auac#}gi1 zH{fq+dZ4_6con~7tl4+8oI!%d(+H2!RT>HPum7WT%HCF&>49@7+ZO65qx zyB+WweYH<7@w562%2=9|WPD@l(4J3>%u#ycJ;@xuANkHZ$cPO0MnD&}L-~KHvU~E&JAVRm`HXgo^j+y`P3c)?H7@3 z3}?MEXgum;+pk zCN_@dx#NyXo)ungSv1+Gv^zGH+4n!9yy~0_<{@fOZ&rLB)K6k-VYO2Jn%{7Gr6(+w<@dn zEW1?T^BU5Z=+%0}Ztz6e7IY57_@-iMUbZ$JVcFjCCoo$djs9_(I#!m8M z@`{^_UyV=j>q!nH)2|sif!kq0C`ObE)Yk z#1|*Zi)53riH9b>AM$ScEz@^H3)9Zhl(%Cv4l@=?cdr~El@B-p>&vVVy2K7IFy zLw#zTt+_@haiz{%D23VYiR>GBluDmv-|sfuT)%v3JM`tMcYX8i^28@E z@=bEOChnC(bsof@2T#*qn?8)Ps!jSdQ#+A-7;DEJ)WN%S4<`%De5NEm{Y}EgennV~ zG5j%HrLF>bH+7Zt_&r!x%F7Asined+DyO=-wo+Hv`&H^{4z>#^etFhB^jpFEHhz!r zYvZReMm;oByEZf={WqX*J!y)T_FL(Pe2X@Fx(}U2<9}CO9q%_)q`oRVuK2}E@~?4o z(69Qj>hz!Fn;DCx7Z#08CG>GRIQO4=^yQiIr8%UR2jok_(C7I6f-$aSlJC#FQ#K!$ zZUNdMhdyKKT73fiX2vLzZMJ*`#$v|iTyoW4#FD# zbUGFm4UeXb3}WmtSPqenf9{M)gLuXJ;@L5Tl`Q#9_^#ns@SXTwd(g#u%8&L#sLhD3 z$gNFk=g7>KXV}kF=UisSM7!#rDMWK#eTx@05ApLW`itfhY?{)YF*d1dXL1 zlLH90`Q8`{8%>21-RAL*T=&LKq#=4HH2zNbdLPb-!?K{HF+i%O>U2-Z3trF|$ z4@cz;b>z*Z%)Z+8(goniF*_aiVXbHL0`aLOTRxrc9O2n`WHWKC~IGy;!)pI z%l<0AAN1_WQzf<2vGhCtP!+$E{(sqf5BMmnbbtK3QbkNUw|eh#_oAZ9dR;d(DSvF!x& zKOjTAUDPrB;LaVXlhfH`dT(Hdh+>of>8HpT#J|M!p>2zX&O~BJU`sY=OQOMXl_(c0 zgDiWz^hPBnBcgwz!UV_Fq)L0BgN(o3&%(CVslGOn`d}?;}|=tR1Vyg@bJ^ic;f#R z*<nH0M)ba@T~pVG57tAd(phSOiIy*3+mFKlyhXj{*czjT&DgI}*Q> ztlfRE>9+#!!tZ954!%H^EZ@?*y!*XCcu8Cf*|V zwSW%;enN&f0=8&SA2NI&;6s3w_#Ow`=mFCk1IZ|6B|pChoDO)O?EihhilICn^?|?f zfh&DrC|F||Xb&;4DZQPrH=toE>DMCfilOjH7Pk=Y)OLw}ypQ`_z>j*kukmpwS=?f{ zXUqN{_i=yL2YwCk=b+yp)Bl@~``-a4pkwiq(@*dFDu&Wq=>s?Vz`Z`O9(AP{@*nL3 zCjw4Er&S9#%Kr=>_r-w2(Yb6uxa7Xd$9=O8T;Kyg<^wh>{+&MV8t`5t+#6;05WtF|@XdfPV^hQ^m-i$e_c=cBY9E+nZ52b| z6#%Znk8b>?@+$Umf6)hi+Xtq$qZkVB6Ts!@&y@Cb8gLW_5CyIToa+HQ0PhD(eGJ8~ z@#xYhyigxF!3VbZz;k@y#Xj(leBk?h;Ku+TL4SLM;zoL2^l|^C5Bz7qg=nlw|L|Xc zp8%XA`~Sv=UI0w8VM=*)0`|j!+V5q0jYpSF`Huj65bjUQ?y-Q=M}QCH@|xg7zrY7x z?gOv)f$4oW#ZY|3KJasZb8+CHr1w{V_j|wx0iOb_k77 zSd_ygp-LHq95$q0AZrOR>bvjVDmshLcZlzuNROmL4pgFsgCvhDl9A}^&K>!i9`Hs> zIC_fyF-hpt9WZ>{w&~&g#SiRUc+W%I?pH#ghfs1KE6f*RM7BD=Fn`ld#nl5Mk=TMw zkKMIt^Zl!lBavct{?>aRgoyC+{GFTVHG+kk3JQoobacO^LL#Q30J0LSEN4r2Bx@NJ z5sAghup}=mK3h*1>1`SMCBH%=llkNv$@3~9q&FMokiTP1{-zz9?^#^1Nh)9&M7G8F zvTs8Q7Ca_r2(q+rkX~%@7D%Q@vv0fo-u!|sqCYXwL#4KS)1%9-7iyLhdYz0iRUQe# zyCsu}l4{x;D+&(#;D}Nz+2uP;ZRf$`r=j==5O;M zyOGQ=2^YKX0!Z=662t^3a>GN(QxIawNpZ^@!+fN|$-68sPCu95`)KC2t&mx#SARh3 z;gpl<0l4Y5Ke&_Kl9`KVg0^plNW2*1^5ye$mgM4jBl)_5h?Me%XLXiu-|`R%s!Q3R zQXn3XL2o7|M+7eCi#$l7cn0AUz|ccOMC~QFos;PW4rO5od!3y3kPC&iWZO>Sqn$gX zE&zoC&{KjO;PoQrZkF>Ff2R=PVMrWaft9-oVsUsyAg6)2)*}tnOL&RY`y>JGoA(aOHi)N>Z%4hD6;LtV5-hbH}$A9W@_%7az(n;L@5ebQwM zyz{huhnR{2nd3x~>!kOGxWgla%xw=nuy~y(@8x6;IaB_WijY(8U1T7jx_NNuQUb<6 z3&vIz<}lf?IgGu9WMj+~-;4rG_vJW@;W3zF5=*o=>bN1JzKg9NHY6$$CT1{ znQRQujbx`|y-GG@OO2Q(b2nqIKsGi2PLMrcx;x0lLS`59WP&%4y%6(wOk%i2NEg|e zSVxe(80jY)yEw06-peh)dW!5@Fekt~m0OCr3E9h$PRvUQUr6>!lmpqo|DJ5nrC@@= zt-}15?A6F8*;tSsAv+iIMzWFLezK9TWYhuKv|d)Bj5o-3o@{TC?R#XqK(-5Id#7yE z9S8FNglref_Fmb3TDJGe_I}xZ12)O>9wPfTlpopaF!v|>c9b{SsPAyhU%9nNFWG=| zWO$1V?~~zo$OfOBCmZ>qbv~ubPqvM+ZIbP9*^ZL!7}++{D#L$-JW*?A~` zvNxgp$-WExLiT2qH`!Z|AF}gt){5f$wq#*kbMvMLB_vD z_Wf9A%kFgNf#}O+ScAL~Jd^BgC=ap`&Q7xNJuTx)$OawBoO2Ig9ZdF*G2bM62k6NL zzrRX0`27gkperT&LEOJ3dnf9F?1#{9F%RV)M!LzKi*%C>w|!(Io)Q`UT!!0aI4VkV zH>2&Vzv!fV z=*Z)W`9tw%gjx7~IPQe-q3R6269Vn|lN=VwP{6}fm1V6}di#jq)Z`q4U z&oH^8A-~AiN~J3 z>6%?#igS@1=+DEs35PRLbUpQ@9PVi2TZbn!3pz14oMX>`JB6W! zj1^=WNp|FI-!N#OA7@mMOF3fFJOd@rdSXK+9t$c_AIW%?t~6?(`lmpjgPRK<{!tU4=% zpsw3boE12nZA6+b+g}dS@Glv)yd&X~&>eC{I1#^_KZ%dd8D3JMY-a2c^M`!=POaL* zCzoEd7puY7aeMe;oH6X4x`&6(Qd@=wdRcJx5S3A3M>lG4s4fac#tf^AWmro=w@_0o zmT|k~vhWJy_^XMRP^LJagBse%#dMQ1^)hmcpPuOY=Z80{Prt(iq{_6&F>T6%XtPo2l@P?Kj#C`e*DbO zTFsVctjQVASm}+0D99X=o|RPa(RkpJN}sXDfF=$!Mw}^;ACgNXnq<&)LyvnDdqzC> zihVNR=%Y;aF)$TlrxDeJ$sQdQBGU3-oj(>&e z`28w9-wV70xc*gFgcGRSZsCgHJa$Dm3ZD2BaA#(j@ELx;hIaF77017&QS+s!tE2j2 z{`icic{P*j*@(1InvLl5I!V6`d)`hmivecHDWDvwEY_hMoKwr7*Bt!{WQLr`ThSc! ziGW?Aj-*x8FQ{YSca9l)J#(H{C0L%{I3SD`ccs=XUwyv&UJOKLx!%C9}X zOmM2M2)$tlyYQU7e{-1-kaNy{3hC~ie?=IyA@5Ahe-8K;dX9&l1pe1rBTsJ(91SZG zj?dW5mqza5Pa(h1zr+80^n7b(AP<@84BT~@Z@t4@W`6{_*r*?4rjmDqkyfP5O8R`& zrjobEnpIXU@<@FO>7mz{eu;Y!yR8=FaSP5x{W!Klc+Y%Plmke{yB0VRfXq>eS_8lI zRu{eVLE%t%4CjL4xn@R*K>9{WF4BTFMB_zn-T`|!+KTR8j13q!l3+s*zMb@`K9%&&+XMT!*FXUSx1#artJ^XI)U@+cur?%&p^OijX?QfTP7i5~Y@ajXw{O;II zs1xu#WSmG}ziQQ!yit^O+QWYo`W42iC#`1lbD|E)WYcrjn9}F%W`rHZp0_8IK4(p~ zd}U8Y8WMmfo=GmH@)OpA*l#lS-bmj^F>B zmFV?mq|t(MC_#GmKW|@5eo!VyV!wj!*$cwQus=%uO8Bt!g7C@FuLQae;~A$CAB9D6 zPKSR=ixMv3m9VG4joM=hcv)!!8pKca5P-86(0mLO&X{P4X9oFla1> zuId^JgJf{1{%MXtJTTPvX3!kuyx_-h|I7rr%F_MzJ!bF;<{>J~9n`D#@p_~QGJ%+T zKqqtT1z|jFagMY4g7D#LX^!JiofmnZ#u!xqbc$l`L$Y801Lw~F^x^VwXUiLC-X|N4 zZ2O)q`(Yh*2yVzPqp1+lVF}0*WmpZH%zlrs2qs!G6Y&xK_t9BEqxiv3F+40uhK%Bd zad{{#a{Mjg#TD@(qtKC!K557-3IJySNom1PF&~&#Uw6h^1!jv^0)e~7Pe5+tiT_v5 zcqwkTk@QP_4#ejOn9gLA@Vj=1fD_Lu#kr`6!xjR(gfzSKE)qvm8F_wWm zQTQD`?taK(Eh-O7E75(VN0uqQ-U}pgmmm8~8zt=-ncE)DFW8QqbZqOpu~|?NB7$x; zDCFp+JOta459jaLDQ>IFzZd0Wb4uJ1TDE;_?)GKa0^PJDb-G8uk^+$1a^={UEnX>- zV+(%sLj~BNPusbD9fLFWd9VkGP5On~^GUG@Q1agBPzd5qx1_Hl6KX@m^wC4+5&`WV zQK&hawki9kL?Nq3ansyguzhQq#7`=eZzGC}Y=>;O%XYVH_scf1713#Ao9ckz!?3wP ztfldr>_W29Peg$?IP9w|lkF6A791MvOxXroG7gQ}5B1DplCX^IaO?q)jdk}j)Gvqi zZ#LRAhkLM65$x1V$6_d zgG`&>{{41i$$opzA-pR{a?6F#$%;37^`_f-ZvWFIXG~XwvpH7;L*5>q%gN-Q)#eKv z=3Xar@y0^B>*GCX;{>n|#-U*j)I5hWc<+5mxb%p*-%Cf0IRhIGI>{M2G4U%{#KK zSmZ_qYfY~{{6=)XeKXOePyn(~!Xq0+KV%w#Ao&SOFQt{zM{Syh6eVr=$>dN$h7;AMc^MO4Cb{ zl1;1YA;2*T2>0E9%^vXcfZe9mMSI|$>G=a-&-9QyjAwfO0oXG=UjlZ|HCkO40lN*# z53n26>QbX{Jj=%fz|E(vu0+6|=}7_XS>96tD{WIOPr#n(oevm$Q?hAwWdrt1|4P8< zZin1&1?-uhI{~{5$MOIt4t2bt@n7?3I<|4Lc{_>n< znQJ!A+_+##t_*ElJwG>dBZMudS=bs7XRh41a&2zT+FZ6Ud*$l2YuM_{TQgTL0F=3K z>Bcp=^A|2?MnHMUTsu ztV29mYv-?CB>AM!GP6=W!V)nnvgfZ@2uisu7Ou=(>_PIt#-F4z{7J)~t(ZsTZrZUG z>a`x&Sa{E-2lH_RyCeUBd}w%kVB`Jx?jqW|h_-P4LtF0MzTly|q411A93Bk;I5Sc- zbHQat{=?z~1wWT<-(EY-;Tc9TGkxe_cP|CdUBqSgr7wx$BVI0fii|E;;eUNPU&AEjT51xUY@e(Z<`4gFN;eCGl;qVt^# z5M7E#m`ZqLdvrgnABYTjE-)2t)Q?i%Hr!m`CmtS^@IdNi2=8|L-?_m5&IP>3(*Hls z1*CqDnhD45_h>`^JNB;;rwEzLs$E`G~M9PAwFL4YP#wVZ^@kke?lk)R7;BFM> zr*Lzi4qT;bs{>^t-s-~%T2vlR5HS0qy5TV6Qdy2^6H%63ph3Cdw)4045y&gucAh{t z;4yU|$@3h1q>b8vuMpp>_};71Kz! zfi=JdqfV#}z$4LgBbdqrFYJjp-1Ls7dJmDqfuw-w2PY*h3L)#OFa?)j>3}9o23E@kx?tU?dI1v{~d0^)S zS|Fg+0n#MIqa@+cg9TYr2-yhw+C@P z*@$%h1F#11VyEKGO8kb9)0-`@k-j$_uz@#dkOn7yw?eC(8et-x+N&rN()5I|5EnkA zOPg^T^?BM(X`_6Rh8WZfBpaT`%T|A{?WFurei4Qi>7u^pD}?cX%gNe#EzPbZgZ3#J z-;=c*aMw%>6toivOI+#DE>NNjqrr=YcFR2t(US2!S-TOP1+4Huw^AmoqLFd``);q^1#P| zk$AFk!bK-ybi!pu@erQcEuD02AsdDGDA{O0uab?%#lxnPvMSlGm2EodAiP7i+hx03 zwrTf++-a^#wnn!7WZNj)wBtc(ZIL$ab=9(@r$GTVy+3w&^5~@XPSg z$=uVj{V~}XFv`is37rvbhG3p-bnxh$Mfwu(51rhRl%$pjfC}q}6LO`Wtkz|I`hB-}AJ8{)+x^Cu@`}#i05`6N|s}8^t3UDa|qfOQ9Qw z-_&n@A6<%vAN&-{;D_|#i$ROE$&gXvB^yOKWIhI>5D<+;G~CdbMSX+st{d?Wm4RZE z@Dy0FJ@Mb)hkK@k%0ej(DKvVGi%zd7OVgN46}J!DsdftPoF;BY@TI-2=x!-L6cl?3J)5n#LUo4LYiN>VihEkHDh_2$Kd5) zyw=C@KeFyNmk7|t6m5aF=D4}gXo2}SE8W8%GQA@FHXgghmU6+Ba13+DO?+_DG21JU z8ZG` zHT>&}D~8ovL3O1Vsyi~ib0B(Ui1?pADq5nW-@bF8H-Pgr3V%%m(zE^Ch|U5!x$4AV zh%Qe2CH+x2a3(+{Y;vKo^@p^xQ=pqq9%Q40;Tb16l^~)+u&G^P`X}ahxOPVCPs*EO zl<*W-u|4tM-_EXYR~X7Xj5Jru8^Ulyd8e}CsK50v!)bbmmEEcChvpJuV-)8Sm?Ti^ zBx#h5kadu+^2yREdGMn`WfH|BJM+c6g=A8E6O zgrBHExdbOb886wxb8zB=wbsIC@X9-+NJ&#GhPT;9^RFRMxQ~BX$MIa@9;<5BUDj9p z7;iA|=8r}~k{lY6Nb2^tuOAW)nNAA71FV8Hw$c289eX$i3dgVX1-q^oYZ=Q6c6}-K zcnV*zXCV%}m^p#8Cu_`*GGRMxwC;lxt+>~LsR!10(DVt-%-|gZt!e#aEv4ZMufSv7 z2pk^4!uk=vX^jL})PMyIPogbq82<0~68|HThmA6ykaeTJAqEb~aHlbes_jO7gW0nY z$h5GoTOZwsPU#!S4;iBSA#FYlbjn(Q{3*#GTj@^-e;&XY*wjx^UML^KwfWzpc|HU; z#VFw^uwr}S|CKgRal4IYXf*a}8K!@t*^j@}hN&;6-y3Aub3Q>~EyAZ5g4ZYjY=ZNA zVDAPl_6yhvUa|e&2lKP?x8?8Hv~&B8;Y8s)PltWBjulWmFbCj4x?;Py*NikA#>b)Y zd`>nx-^*kNU~Wq`I>IWlQ9;!I;PIqQTM9Qn@I(5av~`jCbG#KM2qDUwi2X%DG>Rgz6(37HjF0GCiG#X!5rF`!#*;c6h2@l?I!kQ z1nrkoUwGu%vjS<@Bu&me=sy?jhgNyxNZZqv5>8*TP(@|*%H*T`>EIG!zB-RDj?3de z{_+AeE|b*$3jQtJ?%0*O37T0q^T%g{X4)S9Ez3CG4DG)9lI&0wyAA#C^N5p`CCmLO z(rZY_cn!A(u;-6-Q+nTEYF=&0vGg`CTU3)BXT2CewZzl@XVLzCTaYfFGUCFy5d{z=nn+v(F>XYiy%wpANVz*dNX~ zFC3nM8+6lQPd_2B97*G#SWeg@ONP_}`GHh{AFxHWVzzqoNaMB6v^&@{`{ND7~uZu8!)$qo6a9R2I?_dX*Fck@24$Ph z_S!$1eL}$AUj1K8XYK1S&c%k72-AswXumV3MEC%E*&oAQiRUloz2a>H(s=tJ;z>t7 zKbmk}_=}15!Xf#OTLS4w-$xTp2*D=KN@2z!JW3Cxh4z9GruI+BFZsDgj&mevuwPq$ zqdfh}rwj_H492<3KyOA_;M_(jGuktzv>id(RHh2tj9CC}fKr|dO;Y-x-5L498k>{) ztpAA_{(nb3-EcPuXpB~j^3!*Y@4\O^sDA}co>$LXBL(-18g-#Pw`=%`O6KWL+( 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 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 0000000000000000000000000000000000000000..239f5009ce52cba9aad303fdbcfbb4aed4a7fbc2 GIT binary patch literal 565820 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

Q=**F}1Pxan(J_#-^S8BX84FnX~+s%w2w3 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�c!@v&vG z3z|jvSJkK1nwcCD{?XI1E)+Grh56);WH#Ld{z6+}Hgnt!>*yl11fS-h(F$y08F9Q5 zW!SUFVuz1T3jRVnfuo zVl8GZ1aJP-p%ma^knhBb@nu(0b+)vdk(k#{p+7`Mu zNh7EqnU`LWF(m8GSEHQ1xhwO2g}eBE;l-lk#p_^__9-ht-FIq*UF8e*9F8bE4djIU z+gjVYGpNbFsP6~A!eo7ceikg3q8`LH{*Mj{Zqj4Ya88}t8$B}`Xsk1y$Enk9g}=!o z>JBT>z3xco*&$T68Z94LZ9*%>$F{;Y$?gTb#rLQl`Q%*f;_5cYeV2#EGYk%~bl;)= ze+IM;x)vNAdMPY2;$oz4^tG7E*wXkDkyjLZDmxg5(VzK5=q#&l3KBxdkT?tHnb~Mz zme3Onh8nz8cW@D{MBItA0f%;sW?<3+ESiB%IKLrAm1vL&_Npv$drT#7bV{c$7|}67AC$|xocKvwrbXD zHZi`_tk-<6*~r+S*`e92Nz`bxW0UfdH>S$cw`P=Nj{15ryD}#*Z!q0XOA6-~O)TzI z;#ZnidcSN{d9#YFieqRkXH%6MR`ZaK{({<#aJu~pkMte1YyL)uT-7*^&XUQj?iL9R z!Up&bcXR4=$|&CWzVSeLf_%QBQE}WP+Vr#OBD7K-nlG|&wN%4BGS=D!#{1`}kngbH zN$&7R`Un1SNpN*^@91&ZGXV~vRIG)jhSQ3k^L~s?OeFT5$znC8cE?x{zp8sz(=7P02f`Q}zqQ8iYxQB5g+6M|R zB})W#ZHtuYiCJ((lW9mK)PUzOd51>RHuzBF9lq$X}t*m|M3R1%d-a zj^Ff=Xyvr0!>SvrilKr=m?+Ja&NuWdTXX6ZL&bW3MUrBriMi=D)4pa!sF3%uD6_ag z-C-CiTTfu0TxB=Het<(qc7THo)gynCJM8QEy;qrc2j6>sb^*s=bUP4I9(p7^H{vw8 z!w0de;u@M&1O)4&YI79k(kuF2GH+>N(=#$8f1pbEBj4;U!V>&dA7LQ*_D-PD11ssu z=p=MEj5d6tJ&)F4)RJpUP-)JH=1xQ=!Z0H7X_5RjafmVhKV*El6L&7|pyO&-CyN#% z`ZPQ6vFB>eyIGP+LfiU}sS^?tR34hUnlqZmn#-C8nk$-nn(LZBG`BTRdG#k~^w)0H zStg%MX_j`K&deidW_Cku`6k@OSq1rI*54IhDfzB+2#T2>i5%_ObL^>VMYd{bjYaM0 z+Gb>{M!_S!prN5*i{1)dH4iG?0?25#WY5u=dW8Y9M0B0<(2|wOf073(o^tB+ANR;J zvxVdi-&(9j*|*l}vGq2a8Mf{1{Om0qEF8_8oSh@kSzhh-z`e|)o7Yd?)jlIR18fy| zKPU`-z2NYx5dl#bqJ3l6$MtU}iQZz`qw=27A>(=a?}Vu`V~I2De)af@-Jf=uq1`|BiLg)VoYI{gT_aG-Jnqrx z*}?mFpL*ZT{_21QL9c@6gx(KZ5OE`NZS*fOTjGYq4`^27aJ%YXM}0Y+5}=pE6^AMD!ql_ATbaN8NwX(HXzdpjKql2iP!B7mLlTP0YpSpT46Qf zqXiZtK4L&fL`K}Zgo8~4cn9#>AB22(?Z-Rr+`BPsc;5;{qJ$NC-^@jc?^I5jGOVGB z*{@*sOEoG@iAKwPx~4{xqjAx`*2X2>NFITH&7_PMnJvD4M}9<+*Dk+b!PLSbMFWeY zN^I#MxLG!%Jh~#SVqay;s?4hO)qyp4Yev*&qn2V;e;jS!I}L61f9dOGRa-I?r6 z7gMhwa;)!0OZJRWOZX0l$aV4+3c1NClNP2aL=HbromN=*(|LBtYKnERjl}kY?E|}` z_P;p%;CR&Otn)uEIp{2pq=UT7Yl6>Z-v~O$9fOtz+lI~$vyYe_=@H#OCL*pZZb5VV z;Af2^Yc41bNO$VpWuv4SO%H@};g#eY;RrsZzpw(|Gze6N5HCi8MSsRXFc>8C1A)Fg zdT|vo5!YTlK&A(NtE<6k+VI>Sq?+??8y?NMkL8_M?xXlrIGBZjRxt1T@xCvwJ;2h9 z*H-*pV}4IA+-zL;^NF18Ozw*{mfCWSowlCW60N&-qxOZaWpYx= zIQnabXMQ9J}|$gDWO_;bl|*jby=L2$WZa;2i`PSp_fIevtH@?P!G zx@;60o9cHrIOtF7gQ<~jMc;HcvIBz*kt16=&k#ARj1L)y!FSkKk*ru@VrO~<#`|)3 zi@RFXSX`#=FwD9P#`|B;N||Oq*kO=?dt{x<1=kO5cJvSY=2hiA$@iIGtANvip}~hk zLc$KS13VZN6tgQ<9>1fR5G%24s5mSeBEO(l2&ZJBtRvb;-I;|4eEZwc=oKFCU!5}gU1V(_vVCHNjpB=~;%x4FKML%#D$h`LEFZ5^b`(YJ*nD;K+_rf;% zVJF?WcE=iefJjgLRWDX!y@(|J@lb=Xjp1a6rwO?dc&&0uVBb+_g0(rC*4i3Pl(s<= zp*7J)X)U$UT4!wwu!z%+(azAlPMVuioVq2wC}V!sQ#3P&!y|Sj|4qT$!oP~H79TE| zVW{SLK{ZcYrM7Ylyj35nr`E`757tK2J)yQr3ma%z!#d76c5}{gj6KJBNsMrpJ%<=M zKFcN>7Y`Lfh#Z?u!_59NTW0P?-QhaRPF4+8Z>@LR%!Ri&-rmK*-OxV9|Nbz+vjVw{AOqHY-bpQKxYUZY!LP`09zRXDnmhK6gDyzuQi_4?re7N zYXlwjZYS~v)3ITx>7|uwM{2FLgSDR8LD~SWk=h~PFjU)?_eW~IbrX|}Q#Pl1rSHtJ z%$f>Yt`Q0ylk&F|Y=N6+Y4OyOXwGEcmK`kbRbg6rrE)y_92crP)Fi`sZ(4VdJ;#06 zK;Jivr@LkzeD0g+rQRm76%GlmFy)5IZV@^DL4`cico99z2NY36j>%N4pEp#jpRpKC z&0v z$yiVshX7XiEFAUANs+Zb4;W|cOKcQ)k2N%z0?S%TsPP*B8*?N z=g5*TRM?mtH|b*f1>RyWc#9WXG~?9ig4I;(RyK_`nYQ=sZV@@oIi7WT<(%MR>K5s~ z(c__~r}s3UWZ!1~PXauGZU;Mr-U+jbco=CB{UoL;_Eh}+X6bQFHWrnEQYVE;<6?O9>Wb|6mvX^Z~a)% z8Oe1FsE7!S0IAXZrIFZ;=;g$#h|D;m#2CEVBoLVnBGZZC^N8PTh#Lome0L9AWm#qq$oZ9? z{^IVqt{zq-^y07SL8KGU{sXxq~Xmp@0$jP*z>??!S_O@h20FFA9*oqeaz0- z?eX$vwarKQ{7`$MevHW_N#Dj7vIByv#9aD7crQ5!2TDs2*vLFi#!F3MHosxkCNqPR zKw&a7KAxXX!dAu@FcPsD$Nf0wdmQLYG}z8?-W|aGP=0?fztf-le*8{v{z4B%A4V5O z2mX31kcefU6C`XR3w)CN;SQmHiK#k5Wu;lH?W6rgJ3{-Dc8d0(c8>OEEaI4Uo%XnP ztM-C+xAva4pYDEAOo}qKSGp>rP1cpK71@1r7v`PJzX*5nwW3ROJIyE!D{CyfRlc4M z0(IpYBFD4pnW)MBQX5$Jm=p5k`iXS(iznniG`ho#8ARlWhhL$a^d(xd33SO88Lc-q zksp-@)9W{OLXAO7LTW=7h07urMH$CTifxLki%)C*d&FL&xT=ZrQAR`bW26dM zUei)^jEYdRxo3#VYnkccSjYtCeHxGP%-VRa<9L4}L%fdWJ3Wdq8lN`Oa6g&*Dcn!P zM@{1QMNc=GF&&$k4m#p>8i;&j7`=!SUHNac2Zl1`=sp(eOJAvtRW_Ox z+DY1T*ufd?T4sNX_7WCxLwi_zTYFObNPAKHQtPVgm-I*SGl6i8}8ttwjyOBACT?IcCA%~T9@ln$p3^aTiXV~$qiS(Y&K)A(jDWQOPQ z{h!5b&t=T!z1du6a{cf9vDncV-W$n#Blz4XUXS9lLxefJHv?qmfY5BNbFq_oygwIo z7Goz%h%L*plXckScB1)3K_$r*%qof^TJ5*m``Vq1Bibim@;v!z{~7R)m3X|G4`0b*)X72nG7XvJ62XDG`!{ zcaookeR%b8c&xt6>MUk=oB@?NeADNEz+!A<4&V6MAhpnNKgn=E3l!&L5wp3@GmJ^R z7SWo(=f(HN@cD7PHwGle@ppz3pN0{+2ZMY+d}9}KGtt6np+wRk*jBmfPAQ!<8?b?Y zv{$r$Ywu`3YoBS8wQm_;v{_oUwut8{ZN2uSE;VUoiU6~>5&R)nQjVN^1GqnzHej@4P!8*4mjuhjOaQ_%@nUcbG;QvVBFFjpJnU@vP= zO+`OJDU3zeX*PR~O-8oHzZyr#AIgU-vQYMQF}-U#j9#ZR^g0Qak1SVNb+k6J(God+ zvRh@p#9^M}DyQ$AFSxvOHFEFZvC~uO)zasXuc`lvfYQL}!6hLx!z#lUM3zO(j!BOl z6Thk1-_0e_4;3pbR~m;KPu6D%gJpuG7u_TRKH~{-xDV?p@f*GTe=|Rq`Jc~BPvf{1%YC1BhRKfz1CW1s++4@mn2Ww znd*~%B*QUl>DQ0hcDX}Q=-6LyuJx=u2$C8|8VNG+;HmDj>ys8sg3h2mo=`>+;ZHz5IIWdJbUP89dMq=aWbSX z^jdg*#G|Of=%=xd<1RM)+{~r9y^C?xq9#3k1oN8|MxUwTZzJas<0Af2ynkj_78cd`pA1mPK%GVNI9-eZ;PpWnTpFRb@Hs5~?;O)LGaY*~3! zMNY-R%C2PAeUMIbaeCDG-H;n3$0U_7u1H2wFA?kGWwAi(AQ<|M>Hnqjopzrl1H5H1^()0S! zvbIuv( zTB)u^Yp!e3T4DvRIv1T6D1_*Ob+J6!>DubL==$rDb)Lx=Q(C9}ncgn*N|ssnL{_=~ z=9T9g7n&6r6&Dr1FF9ShqO5g!efjl@>1ZuKteR{%lWjpA=ycdeHq~1<9B&BM-`2N7 zLAXC0G~*4mRTaW2sm!43bjm2s_%VA9jeI%$3a8L#Ofg+=7G(a;{9B7i%OcB*R*S6L z*f_y>|HbaU{XK^pXr6s`Zb0*FlKU?n#hxv_Px;jOuJBI@m=%;r?l3WIZbV|_qUbL% zv*PZ=*EajHxqs{|^RkMOM)k%!^?WB~?h-FD$zH7c|Hf+!5VkN+!t%-T_hQ~##8|>CFEKo?;(4iI)|VOPdO35xlKEc7SYep^bzIl--bSt) zxLe2gme*^r$SJ}dVSU5g^ay2xdWzN;e-x}U*M;hwnSXCxOI;KQwAS_3b=3{i_0x^h z4b@$v)~!X#lhmPTk@w6x`&E|HF?UVg(fs=bPpCY+SiGlXnxSU>b@^(vgmjfZR>f2+ zspheu_pE*0tGWsGIrVEA1pOZPC(kqn!aUxBdepAMM`4gOgO2`6PROl{cN<5^@5%>} zty&Mq`eXPNq~^bvkFwBPJhNPB)zezANwv9Rdxm<2Z`pHff$ie4%fGNzb@e!l&hjYg z4x{|nvIATc>>au=EI49jWNh@fn09fY@t)1!H2b6ZWcTbU@5Z(!yU<&Z8aW8#B$22+ zDJ74Xm2S-F4lr58j4#9&tp<(dpt2f&w486hh{P(cD?nyBpIB*_fAM=Re)pI2xux8% zrJSH_X0xUB}F?5;pVhR>pQd^8-Kof#2N4bpus2XY~=8QOaWVXl*-eqAN)B zz$^9A#pnj>I_bt^57TvHb@OynbgOj>bw_j~lm1E`n3{`9V`^smuV=E;aza?;&MjD6 zxVC5tm4{)aCS`BR_Q52rsJvP^u}Y}ER^64}v(>dWb*HH2c~(ENLDw)(U!vdK*wna- z+Nz^`H-Co>RP5;gOkZY>(IR6b`5t+Q;*Mez*{WTpfhhYfr_${UU9!E29RFHhq1S1; zT^IX~4l$0Moq9VjblC-KRh|1lI?o!s2l;;Ri$sCWC-{DdU)bYtPilGGV?M=J#XW4M zYSzESxlk|3rRp^bC)r|sqjaydwCReWhGZ@$_1*AQdx@|!m><#eFK6~eix7R$GUja& z_oAm+%zTQk*D$|JnMv_GzuIu!#BYAf{U*jXKJy(YYz2$$d}0UJANl?L{MLS6@8|c9 z@)u9xtA642na0|zzRG0vaP2Vs(*%6e1YH~5H1L?M8>L$c3LABcb>HhY==STj>(1z0 zlO`mqQ&y!_q_5A^W_8crlcUYm=lK*w6t*o2Dt0X?FZob0#JFugjVlJ%^bmi9Lr*aYzw? zCj1nXeSbq`tH%6_#Uz+=b?_uDwi#p_V&`JtWM2>8p@Vav%V5+p9~)S!j(J=8&h#tr zA0C(z)Q8+*ukfsh{!!)8y<+p?9GeYnKDha>aeJ*ERP>b{lE2l{VJT}%wOMazb5=DU zi5bK2BkNgLZ3T-Z_@@nqSi69EpU=F`=ch}!F5x@A2(Px3nP1ARFXi*A7)uS`^Bvsp z28q4=_6|@vXqf#CTvxMtTEon*27%?mSy25AoNu!hen>38+cYR=oAR-`k9M{$Ot(VU zLAM-x*nnT!s+*(x5sNsa`%ZUK_p|P@?u72PE{9&gNhyt~>)}dTkfo#6ZF%m=ypM1m z<`rs-J{4a_X=`*@KzTZSvi*^vI$t%gx)7$Mz}i1+hmapxLVn~Yc&kMAkq3=EVJ;g) z4c;`?6HBBG(#v+c{gt?TLWCqFBoLR~P-u}tDPE*l zfuhBwI7N!PySux)6?Z67Aduae*${X4&3?bh`@g# zwh^oSjcm-sk}pC|WJDH#&OAO_jNV$zDK6#|mx0IvgYbbIw_!eYrRdCNCr$|Pn1J?V9unY}z`SMGYM zfMW`}z$2DbbhLOh+iTvzu;9-wp&_udZmSF;KhmXIVuC>K=5c_x${&vRX!=oG^54@< z^?`YgEcGrA#~ zF7Vjqd6k`Kp3E%o_baX6JKz>or~Sd+A?v6*tqZFku_rPzdS6Ub++Xpf8V4-^M@s6h zW!o*{&AJ(_I@k&KR<-y(FD ztb-`dX2yR5E=UqOO;PW@QQMAego#q8j+(Ns=K3`ru#>?3^~}LdxKPb z(%sS-bkB6TxkyOeRiJptG^r8sxb}9gE}-!XJ$F8@z3Fk$X}wIVp_$z$D87JXwPaEB-jR< zRrjvyV8zUv@sK)MX|2eIb^k5d+ymsk$Dr~1ArEqFFrL$w{iNxf{|s=L$0d753%L6q z8jCsSMaac+5Lt!2Si-Zl8dO%Im6mhAiLWc`kT}fGkAuirKEDDQH~8Hr{I7gMTa^<3 zDODE=OTXkMHb~lv#dwCEdZpW|dykb!(%sc%a#xHzDD*ixTYat0OK+o()j!pT!F%62 z`5L+0&2S~fXU@vnikEv8FZT#t(!&bd6e){e!UpqwsZ_cZCh4T|>F|0VV<+I7y8OuE z8e1j^8nE#^p{|?fjiL|zG=o*esyS*)vvtgKoH75AeGnrpO_p2et@_V;3OnH+*-poD zq}d;%N4lAlvvUqH$9>nEZgcxAHf$gH&uaEy#c#BsCsTg8yrW$Y?mg`HS~W?D%P-Nrf; zPVw7k&|{bQ7uUGI!|%T0uYbZ@sG=gMRizbMBwa}Kr@wP6R^h1btL}y_6G&F zndwV(PI_~FpxzrK8tYr=*XVE1m;2oC^S9?I;b|MvKV^7jwagxtGdgz)UTzn1xeBU) z>x(;}8JuQLsfkyMJw4xr@Q~i}m zz!I}1=B^fJESg!qXCt7k^&#udHmNpyY=458=QJ@#oTH7?JEv>Tt6Y#{V9@1Y+mQ32c8%|Zc|^R8bdNT~SjK&c->$i+y@|g1;Ptk2 zq)B0A#hw@^v$rrC#Hf}jMa6SYz6+ADiKt^~oqUYuT>q>?W(A1I7JDs-tVTlCb8Y4{ zH}acXL1Zr|$a1ll-`K@<3?vTo)014M_|5ZN7s2WZ*G=y4^Z84#{mS1fp_1NJ3HmsFTV6f&)AW6W+hTXa=j47V zPg7&k|H`osVeG5GJ9_}h+VSF*d=?`vbB{&S8f1vnKG;QTXw>? z$8vmf-0w8sc@UQ4JGUR*TX_ud{L^cHy_en|zP;&KHxHN@_^v^p;0F!+hTd;9B5bA%B~QzqrlR_XatB_g z95K&CS1sjEj+vKYsh6Xoof6 z3^-ljy24LyDfcriy-WF&fAtnzv&oPBqEb}c)F&i5C9MF3Je>pvImm-i=c;!^9{lt% z`bhovyt?Q+=m+S3*N@Rp*4qgk#V^v3ozQV`rQBWUgsaB*X`G$ zpkkqT7r9&od(XO;XVX6t0;^lEs_d%2s_kmFvfKAe9p6P4IIIUVp*0@OxqzDNR{B8C zm?fCMH1BOu#1?XItIKrd7O)SZxosX3{eA5196md2b)4wb+&RcaU6-v=d)RnJ*YPA> z_i^&;TK|^6BaHWHK~ow^A=4YBHC`TG9I-X3GI~#JTHG{EfVQ7@ptd^J-|k#V6EkOv zb;hR3Luy~D^sQBL=h-_nRd=51S@@kxk%Z}7vL`hkNmy8i$3kRa5tuAP4wiHBYtcNL zc-A+7z*b`FU7Y?--uGj>5Ac47*D0>k;BuDhGJ5L@cejW(9$``b<#$B9|8`O^-J}O^#bh0*mjV&GF)KCBAsMv&w?YAC`})FjnlYj37VK6L!||HEQEB zqfhNFX3x&Re0f*Vjjr**sx;U~D%5Mu?3p3gFbUYl(rCHLD$@E16a5a%WlpqfL|5)< zhary5oh+Qoou9ircRla+5`Kk3nvmOjk78F!mEWKKmjaqKSQ8XUzd~4}MU7j8uZ!q~ z*etR)Wn2FxmhboB4D*Qn4MW*v++vr+q(CaR@0m!rd|6PvX^{YFy&F2`+cZPd(vhAHg<6Wl_CW%KKdVb*|1vuhzTjo%R0crATC=xxS6Qv%VMd zFhW00KV3gtzeK-Izk}B!{YIfwTwri!V@g$O|MZg?*_qziO>;Wuc47B*bb(W$$Zn_U z#m(5XwU7Clva;>vO)5UpKVn|Bqbh>@NJsJ`qsfoVthHh*h&TC>P`L+Fbzjw)KG2b7 z1!nW%pFC`##c~X{Qe!!Oh6`qwZEL$)yL0wa+3aiSl<0KRd56nt*Ew!W+?RQr@Ob6okeMZQvauc{Hh{n; zFxrk>>;S`k-0cGe`E`Q3g5TKcc^+zo+jitPtG{ zdy<1vHlJgk`hJ01=}XKp%fj9Ah~-aKpNToV*#|Mw zHUKuzRrWu^>ivdn)hy>xF6~@9xHWVC)uUhCp5;vMdhANMP(LVOYM`mX;NTK=p4HN? z;1n?_G9Y?tOlVxs_;ih*c9OQCHaPyi!>p3N>eUu^U|M(rZ*H;T2UQ#yk~iq89(7u& zA5ZLfWMUd}Fc}PHVL#@gpX6&95+Y-<8Z0(|!X~uSHY8&!=PJv^0kAkyr=O0aqfUXw zX^=R_`CkGB`MRNe%=HpnUbBJkI<{lCQJwPQv+nC4T~jQ@k64N>dab^{zP)}dQZYwA z5g%&4ewTiW{w!GB(cjR&(Ld4q2%h2|I4IA5^Gn^3mYlB59G0~!`*_Z++{=0A@>dj$ zFKk+5SNx!Oc}bJfLN;wRFV~gNW$)Rw${(xrRb#4^HB0Cp*<;kO*{K~~ZXd-L#Yknk za*oQRl4sB4Zk{J(*0b4NQ;!{VeXP@nITCCOZ8y#T?eTu-6Xe&Y{=fcSfkzuu1nq$B;!vaN#y99!coSt6BgJON-P2@gu4-3lrX<|+ z_p6v))8DFvVq|T$`Zr~?!c}!e`CM@x{nM7HV=GxJIR`t749IeHm5jzRbkqvuL$(?l zxZ8w|+QMramuxHcg2!HL_Ytn6od3}}9L{rh6C`Ba^a#J|A$QNXe~-TUi2X?9v#-h* z%8Rvz)DNHUf9;{`iT^YZOEE_OGk#Nl{UZIJNW((?QT#&@rY%fQVoPJ&>_Is*nCKXj-+?J|RnaFn4||tbl-@2KR>ykZyCSDz zO{IU;<*GK!$qr+i>^!3#bFvNCEfviabz7d4-YQWwn%T2OaNZvvv;LTxY(D&x;Y85V&_DcH?H@w9G_v>bFJ6Kdx_60UpHo*{tM{X;CfIq81Gv) zy3x36_|u3%QE#J1$3BVctZ~s!(B^5J6W&BTQB5h!wfLZJYuuvxsuE1A*h!H>hU6Z7 z9sRM*a_x07Sj^-hR{d^pelV*)2ClAFiLJZ>^sT5^J&7 zd-TioXRs1?z~U`fi26i*p+1WhE46wLVVUqkY;E|O{A-(?KNwv{HxDZ|48RyA7hGfQf)=;GV&vv$d4RT z#;UF}wfupaY_{27<~DTm#4tlXoE>!gtlQY+*sN!sqZBsK2~^0HPTz<*jxt@d7R#~Q z<2ZYktLnA!nc({`mSbZ;YT(46*YFm92%Xbd4BLq1*dLu4b1d#r{P$Wb?F#KT%|Oj4 zmw6@jsz6JR+7^lubq_kcnyY?+A>jkDUk@-?N%zfabk%&U`Z}(a__~{smW}AKtz3Js zAN%=qKR-RrbrPF#hM!zPTU{m#avKS`10oOj=?i}P3VrpSlTYHONuZDk8U>(K!(Xsb zZBhjii5PUdS~Qw1!k zT3YP}t6L1)WIM4F@OOIFCz2moKz?K^`H_?C%Y4l2S&I1-x_Ne6{s8~v3~Oh0(2Zo5 z>?3-snlsV=%JHbvZ0B(OilcX~7O5lS6$P z|4sME(#W>at7E#wjfr>ER%#Aw*J#!!Y!9l(-mk7!uF72FP4!u&JsFZjCjuxWXY+R1E(S+w~jx_JaFhZQsAovgF1SJ|{+1Ho>)uJ*1D|2ph-9PQMRn8U-> z%+1Q(+9TMrnb+`o8@xaJ`1#GO|JuJz;K>G2%sMp+J<>=Ub|w6m$Y)V~V_wC!kKd|k zrTsx0s6C{87+q!2ru40Oidjozx$-+TTPdl0l`FpE3_BqmtC5G{$bekso(C>+hH5d` z$Z^IhUYkK-8?oDVG}Jy&IDxbr!+u}jx`NKS0Sb4xo^a|!UCGzQ4?0GsmESs-2 z$cn9MmoiNC2ePy}FY=51*I?Zi{cre7e{%jS^w0GN^zcj$@Wh>cl&haImS6gQRhf?PImbRZq}Rb-#jwd&e7C+qt9*M==u}i3_Rl0pW`*X1)GmpaDj7A#gY{AnTem-5$PnT1}Ph;@(PN+{QJe5%Ee^7rA7Em zhp-V>^f~(1dZYfE-cc~>g9S$+PG~5!7n-4?x(O46;lgQQAsh<}l08yprsk)8m$5eU zT2@weF@3qkc?J0|@Ny^O<(3yeEE!W8#4O+x*m5tC%T1}A%HFe0)v?UibTYm%4x6D!}N|P_Jv|0TE96F$9k-}jD_6)A!kPx zfy5FdL(ZVD#foo4BDNwKa>Ta}G!9@l4siabz~M}tA9W9Tc*3c_;Q9axpFl*yPk;{= z27|kxab4z>AZJLAsVc4L$=3~ETy(pM?%wLR>vbTJp?{^XMmyPqgumb_XpxC_LQ7$Q z&{LQ!j2D&&i-aRWGjR($Opn4rxh(BVdQ|4ntZneR-N?Pd&de1B6Yz3vi=P&+#LF#U zD`0E9+=UfB%-3|R`o?^XSDIx$6Wpxxy)M;D_KqXwNUR?h za1^H8o#YO8QFS^S798<7vPty&7!7v(z2;YKJ#9PfPulEQd)p-?`_1l}k2H2uu3>uF zms*P()5LG+I_m)f)9I;Qg~pO=PAiB6<;?9$BxGZq-B<|{t3hrHwqq-Du@AevoAW)u zxu3*$J&R17#*ey2OmPz}bsazI9&&LH%OgvBl=u5c70L86WDgYc`+T^K8j6XpvGg)PE%;hbP5hDv+cetjy% zKW#P}Wo@#4q%U^@T+$=*J2TOtE_zGHLeCN_yxb9GF0keHtSG?C4XC--2a<}vd_tbbzt+&-X*C&{M1;Kx4;FSiQVan|udcM(!um|Dui8;2! zyo}u#KU*_b`$=;~J6RK%FvG{OY*uYOt8S*;S_?A?9(r%pTID0feJuA+L>+7EdJxB8 zHRSsVTyn)*uCdPN+?R6x>#z{(&`n$FkhlaA*O8Ljpm47ajk6$e9bZb8i+g0G?qk89 zzzOw~S-0m(BYMn9byXRyqKicJt;|+$@ufOxiT*0K;)OmBBuscvZdmMayr&k}iJrX1 z@tOw~8-#7bDX_RFqzO;N#)hjftzUp+VO+*(c-<^>{Bi^G{PL{|vJ37PZYt_qTpyOb zWu*!1lU-Ea2>y|Qm1T8a?#1d>HSgGamH``#sdl-^0sh4RtX&h;LseHY>m$u7%$Aya z!FSQh@)J|bF4os!JXG7BvHio&%l<$6t;}=8IN8ya`;j`wBe%!ypIGzdSFZy-(jR?e z>o51O3K-bHK)-?%(yviLkjmwmOM4Tm^$`L{is~kNfylk3i%Z&)jP&IS< zIcYK$Lj;d}EQV4r6TAfy$hzT#5SK=O zHEtBXGNMJ)j_4k-8{>Y^&$Fi<{WGBZ)p z59>CL%=#jF*7ut=rDy$ji%eM7ec;ONMNRgwO<&te+naWy>=PVvnFL%xtgYeJA;4)Q<_c73dapHrPJoTBuj!cVQ6`d6CVd&12)^DwuWpi`?OH z?O>vg6#=I5rZwHIzE}KEt5dgAdMQji-Io+ciT}PMuf84&BG)-)QTJHR*Tvwox(ETPZYAn+=nLgk7ZDh;VpuqncbP0ae zuxn@{mLng_p^n}dV->eJ{<@~6)jMpk~k!u>Vt~!Vvkuy{$&{3E0s;(1R+(BDC z;Q!Neti&tO_=IjsTu7oJC9QjBl=ICjh`t7I0Q%P;fcNFM@1Z$#-;5xfK zMCd0>7bXfTgq6YpG}H~S_#k`~vV>eLxVh*j28pNHw>%C$mI2n{YyPQeN0;<~+5)P8R`4df z^OQy5<^H68rXFOL!e%Fx#ZilRGV7zP?5&Sl_pvFoxnTP%mgAZIE{EQZO`MEQ1^t$)J=FQ!cli$2XYSQp3U2qzr0`oUaqm|dGWlGW~Irc zyXaW>MlRR8@*KTxNmbLTRW;k-AGvJQ!d={n$;?4815PF~U83?)A5wp3cH69vxdC=o zbIViYM>5Ed$WzPnZ3FEx;H?_rP~TDE^sKHzzS?zi-6o-%p3l8pnXcLGtMltd%n{yT zK~RH+i$h`?ZED;x{3u(muSd^{JrOrjld2houG)&O+Mcj3Xl>=&stV@;xaS?+O@J3i<0z7or^223`AiCo>-1s<~HIDy?bLo_bq zaRW5|sk0mJkd2Q>NHUfqmAhi(qY{f@srsaJRO#usl$0w?ebT!m4oRw~PY^2g9Rz2g zFM4V`{_H|wjIaZHaSX|LhGgi4&q660%2l)#X{;1~6kCZC#QM@ASP$2yl&6khhiO%2 zaCWDh?zz9ivCxYBz7>V{idGi4Eio&-K*xeb`Ni^IDzYn<(d%};s#A3$+kH!G78_k) zy$_~Kx*2)9E_mc4V3MArwkJOl3d2Hoixg_I?$l&^T31@{g)6s)KF~kyV_+`6=eX5r zqH|v+0h_@E)5T*rbD6j6Rd}~#vu_@qZvO-}qhH~Nkh`Jn8vh$Mg52Sp=<=Aq<5J@l z)HoVwL$oUG8ZsmuExbxi=3C5sjCo2Q^*z(i)P9m-9K6ir>d#p6Kj>YUSvOrX7MU0Y z3NyIofW<=cBg>JCRagwU4!#>C_VMqI*7>+{{`@%})mza0f{X}gtZe+N0zRogYgww^ z6Z?H6>V1xn`v4ZVKQiYfYLXoEKMCeU+6{z1gjT{VVIcm~9FW*9JQOYopM*C;9y-cW zv=AGJ0pbth_hKKhw>VMMi|&Rs$pI;AQjKXHVG?_lRhn(hMp@hZ+I(HXt-?h`-HTn= znK{2SnvR9}^yS{K7=V|%l!=bZc)4$C1{t%BQ`oe%hHahu6yf~$|HORFZ|W5F46|CZ zt?UH6OV4^C?5xq&&#nKm@n&jyo?Q$3V*5u9%jm6&C+0A^Sh$tCxp~y{?8-#{Wi|qK z^jllsHsJTbLSl|Wc#P_K=X(8iDr{_tme9QmFLxxK*e6m z&1@E`R?lF2jI(Mmyo1;Ar<&7UwUCV7Y%KZ=F1f#dCI0R@EQ#D>yA9ddPlSFPY|bJl zSHb26pFBWD5U?NVXsj$`q>`VgvD>z)cWj4wiFUrHY^OTJl>ejbuZc7W z>wDr!O~iWtO{BLD+kFT;ZV4wr;)PHkqzdMuN$?lF#U`Rw>?QUP$BN^`W#U!wlH`?q z8rH*YX_@KYXHLpGl6^VnS?>M3oB7)cW*2rY@`l%KYe@(Ca*xunkYB#3A`F(jflPEP zVYid)<=!*)px13URlvXSa#u4|e~A8(JL=A6U(F_%SDSCB9W zBR@wqi^+%$kH4x>Xgg^|%@ply&Dexpp?zv{D{3u2D90Ilsq>W|OxJjpkCPo(%p|cq z+uw>>hdjSD2sDPHuO?wVrV)+E-OdZJ7jhaaXKL-Nv7l z^C8dZD}1G_<|h^);ec!es9q^GpwUyc3XELxdVIO{HCs0rxtK?^x18wW0D9`0uoqkL z4-%1xttbP}12lQTTBy0N2UVeZVl zzw&z*v?{b`*Vb-wx$fk0C(*HRpN@r^ii0qFzro8bss5|Rg$*5HwdZSFkjwo|@t=FL z<~yykHZm^B=KGQ(W*g008e1sGs=t`n0--9VLVO7{nsV-gi9M#EvE(Tmd4fic0~c_u zKu%WU1#cpgD_6wjyrEoYIs+mXIsYrz?pq-8P^rV${RRp-c)1nW4yEcdXnbKR_&rSK zk6;L1g;y0>kj-9kQ8x;?SSxf9b|WE|xO+;(og%yxYVc>hL`yLi9o0c>DgGh$6Bmjz z#NFa%B;$e@AvH5RW2*mEY6F^xG*UU=QAUXX#jqElJu*I!D&P$Eo^3GmG{0{CgGDmCgq*Do zTm5SN&3Yf*JVx7nc9ZOV9Lm|3xx;CY^Y1P{xOQZF=|Fm`4ia-X`!t7{C%^vefaih3 zf^G+o3wav4fR6Qj5v7s;M4Mt>#_8jmYQJhmYR_r*Xj^K!Cgl0NEd8<8$|}xuuQo^h zh|PRTvbkp!2dO+o(w936ze=9S9EWuLjpdNDx(l%!tFa$zu^MuZr`)?ES72qY>O44H z1&tf%ru*oo$H>|XyeK&<`H}2x5@>wIi_#H=|3}X7DZAd5DkrE~7M=Xs?CTrdaN_P= z!Z38xJmEglktp013WX%WUaS^^L=Ukw8tQkkn>ZC~u~A$lo)u4tFU4n~og_$o;r1Sw zdNVB`V?gGytb5t%?C8j4hTuuT*1`!zF-)JGDH&VpQudI|XHFHz*kGDiIfrdR`>UgB z9@hM9)RW6Cubs~3?ez*jp0EVf&AR@PG3+2%M}Fi2J?oj4bF3O#KY%I8&GrQw8k;eD zcGqE%V?Q|W{i%?fyP4cPJwiNtdCjCpy4I(U-_iQM0rManoD^&oGAGox@s==6#Hq+% zqwmEGj5{4)u2E?dv}t4zH)}!?u7<^%2A6NJJf(^@epCIbI?pET6y-TZSI*fVpK2Nw zq%VHeFg#p&-cru&&H#^vXt7nu#u~8Lj*i+#q_H1~I*vq~MItVteeNO~PdNXl*pBzu zjn70EpFl$(0@uOPm4s|OSN2lzH&la5E+u7uxvv|DU%QtK$a!*6kML+yh%TzJ-7ca% zauF_e6+8c*hFU5f6c31Z#QWkGQ4p2VMk&=W^jmga-N_=e1DohJ(_M8aZ*%^vg5HHO zMO8)r6wfZv(3iWZtO;Dwv&iLMX7{yFHNDybmc3x(1>^U4xxbn8@Q+j~{^q}OyDFfL z4dyMKhn42b*(G$FX{REq1J*6D96M~g+o|kd*e`MD*Nx0m*|=1Tkr zhfl@B)jwM-GO|ZToojlha8S82SAT_x?(c~I#_~Rcev%1T@_G1I^TA{#nRa;V@R?3NiOPEO!Pk3sEfwioy6$t;N1b#td<;xJ}$Eo)NE$uf+evEU{d) zk_Jdq4Oz+4Q?gQfq#w-4q`Rsm-BrEwI_G~^;04FR-J(V8_cfKAEgeW-?&;pD&T6hi`gkU4_}-2w=i0)gkj;a)f9FD z$~D{U{nC$q>X&=2+vs{~4+{5+oCa_4yx3;(oismdKWO@CPixj|HJY^vLjxw1_pM2=sxmdI{a4Mt6h#^* z%|>f#9ARW~XVEo19wcO@g!$N!*`To$Yrc`Y&D`w;n?uCqr?~rHRs1}%aUQ#Ihj{N1 zk;Nf`_i@svC*c7SgjSn?LT!D@{hOKxczC|js#9Gl-@{!s|?uN<9HQ#2W8q$8qSe|*0 z8G^DLb9QtT;MCJqi!8(PSY*Qu(_S*HcukRo^T!is(B-yHV zuHU=;OmEdx&+T5X>)H7X@ICA2>_0Q0AaHn4CjAQKp>rF%h3}1sAp&e2do3b0dCEi%+KHCh<(51G1>wfKjb_N~m!w!mU^<~15ThGId+^P0hH zE^@LETfPR5cQX;7+{1GW-}V$TauunNWAR5=jOQTo2_5yBI6M_pa*4rnkdG>Ss|uxu zsuVBx1J#}Xs>Vy@iL=?YaZETWTt!QL0E>Jd~wafQvOJH0Ai4F_dO>F%-) zmJ4if`#>tdE5E6@w-Kj z^rpb<25W=!8tx5M(Xs9wp^J=*u8c{DD~i9QX{~*w=}vZJj=2t2PiiBvQqV>Lk;fjo4_a`eJ}_aoLAO@?F~NXQx8#b~G%b<%N?81NFd z{C1t?xB(V-iS}NhnO+l#Cy}8tps#X3A|DAcA|VzkTa}lpi0a?=nz6~Z6MN~bkc#7I zs0ZX{zX?XPR6TT5GqIicn>b9Ijz_x{YjHt*D1H=^$rmalC#k*^Ewz$5Nt>jN1{>y` zEYrrM-^nm##$|WQ8Ie0G@Av$61r1?Zf6I2KZZL`6EgeC1gk)q{?O zsWn!{E$oCi!6xztre72~#VEYo1u8rB4s|g3kv8TMJYo)PzW&Kduv)^L>}Q(=wm;bA z*j;9`Q%hLZ3!I)h-*-7j%yG+Iper}3UO(@%OxFw`=7W8FOzwb z@pk*7r+x>K$>^`ib-vXEaF~s6wE!)(3=6&%9Cm?&+@){=uj&#O{0_F_0bbQ>GKK$v zhK{^Q3X+klG*=a4Ju2Z%Q>g4!aVneISt&abBXk-1*LYHT^i(m~D0|UN3=>1ew&KtD zv~rxc0^5BIxp)Q^S)xj^lzgQSusdwM)hhBJ!$in_RCvdv=&g z1^*PTDC$$}R`R}NUTM=ZiSDYvikB6GDr+k@R)w>L;Fp@u%q^EQx9mvALPKT&oAM;} zP^H2@qBdIv>-`z?&K5})f5RhojcKP^>mxS5*{Z0?PNol3>8Pgob)a68|nXqPPfZJof|#~8P@1)D}EZj%GB*M?%ryTY0?oXpj4*o~1`@@YthJfAPm zIxRyo)*{tAkdXsutE1SA3m_s_IPPG}AA`d?d|Vj~5!pyZE;5M5^FX757_d|s3LX)r zb!poZEp@N;2CPONeyxR=CIq0TT8WX!#V_Jaaf-M@+<@i2Dt;Ez56MH)N(oX= zskby;nkkh_9?5&Zd8TekOG|H_IU(y<_O+Z>Y=yW>M82r719hjw;{8PAR%OS_dY6}! z@2QA|oo7guMfHm6pt`=?C+wj!)Xp+hn${>B@kv5d|1d?aQ}-u7vd}!3`I?@VqUBnv z0P9cI6Ko>rS>KA6>qt%ZxZ?yiEyugGVAFCd_huebJm+CKioAa(Tjk|HB%lgrp7P+H zA@+?%HI58l7V&G;p6KzhJL39io@>6>-eGcigJzl5N7FK)o=;rq?%FSw8MO~;_3Dj^ zMv82-(q_d**xg`VKo&y5p*s@N70LJwKX){?V-hjPENu7^EV|quy%YcHFnF8>jf>zR zS2&)cuRas|eZ!7tlZz`OOJX86w^QX4ab)A;rYnC?rO_*IpLsR$RnkR$DVoYcd@gv4 zMS@mzC$?xpY%y3|N3?euE%gfPoq@%$LoULkU^G;FX|yy(S|hEN-b-fNliWDK6YQ< zsQraKbVC$birL8VR+X>%oI1hmKXx>hF<;Y=$;<&(RaQr>f3m5tIcVF@&e}fFely)X z&72y*m0RwT<5~gxNFe-^v+G^-Huvp>%FgN58XauTVyh^D%QY}^Nf$6)XlYmtbLE6~*@kp)Uc zCeoGP6ASiL-6ysgm~H-LUD7^%wQ!l};-e5M)(9=AUJS&3|1FNkcCQg{iI@JrT=+>| zQd8-Bsh>1Znj_7Xc1ioOYhF=<9udemIG7$VR?~60BLAC+I1 z`p^7>0?#+_4!+eeB=k+A7GcHVLn7Ux|B4BV8yEjcBWmhvUuwdM$=hhxYSQC99G4ci zP)A#gF^*AeQNJ=>QxvjG}cxkD$K{_Q}l3qyx zhM$tJd~2C{BF!$NTjr*$tJxoOM7X_Q=U*yVTR5VqQE@@>$&x?dgSk^SlJ2TQ740ew zl~drLJXjr5bGN3KG08ZRzTBlIdnP)9@eiA+{#Es7ihMdd8h23zd|@$~`I=)^KU(Kn zuZ9ma$M&q+c-*I&F5I;xgHFh}+-pi-0GINPH6B(UOsd)|YIggX z9&y^U6n~L7^dRmS&HI4=V~w0h?rIwPY8Dn{IX_tq8e8$U4k06_K;tSlFFRCcP;5s{m!x7Rc@US#_0Un24> zB66c*snS!mk6yRi>h5NGvnjCU9R7F60IM;RRS_0v#rZK zpaale6OoM>RgOza^~{+-0bx`H*okEFaH_K-W{$d-n)L3ypc-#{&BNboqqpHLpyxO0n z*2u*uX@#^>Iw_ry-tsDxYNTz3*U7)Ljr_;-)fxIsOQ!mp!qD0*Kd!*4FsJZp(PFkj zRI&Yf5UhvinUu|AM@JA$VqNI2n#g|NP1K!EF@5%gi2SQ!AkWYYc0z1c$FUW#r+Je3 z0&=+*@p6mVnAytaOWm}Sv;AHB9S%JmTQEUj;gaG~=9=ne?cw0rgF44U?^2&pekbWy zSQHo(v?MqtWK(FD#+SmTM!bvM8l4hzAnrxHwf3PVgm}D(b{VzVCYnat>#kdh7b&wX zo*S>2uBfZ&Wy!{7>{G0Thu#tH++V?@54x%|nf77mE1B_7W(=E-oGih5$hC608Yt(i z4%g)muY$<~FnNWP=*W$vV$Wp`KNEM3MByR$R`F=8VX8gKbE+35rlb~Me`L=_I$Fvc zpSH0$k_yHuwA3l^cn%)9V!G%c*+}tH41QD({HW>D4r!0{4=;n1EU64i!%)M(Wc|0^ zsqfQ*GG>uI{F0rPQ|k@;X1J}3-Di5% z2RryPLGZ8BW9MTor`fZ0&;1G6D&Klzu^d)@-RgfJ=J=;UVDJ-Sj+92-!mJ|xj0~q^ zy-nP_c)jM0rk?gHD6At(;!D(#61=X`t;)&jredaXhtD4w+fqX zhd<@V6^oqoQyo)YS6wUf)@OVP)_)Qzg$T4%M|`PK;sDTCiZ6ANEXZ4tVLs8l&U&|y zewY4`7D~&c14zbmO5;L?%Rz_%@OsyaE