From 6f5792eede4e8cf3aa05639ea66ccd91b320222a Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Mon, 5 Oct 2026 13:41:01 -0500 Subject: [PATCH] Some test games, microphone input support, and the start of some rolling demos. --- CHANGELOG | 66 + CMakeLists.txt | 25 + LICENSES | 3 +- assets/Framework.singe | 4 +- build-docs.sh | 2 +- demos/README.md | 114 ++ demos/insertCoin/art/bossArm.png | 3 + demos/insertCoin/art/bossCore.png | 3 + demos/insertCoin/art/bullet.png | 3 + demos/insertCoin/art/cannon.png | 3 + demos/insertCoin/art/coin.png | 3 + demos/insertCoin/art/duskSky.png | 3 + demos/insertCoin/art/font.png | 3 + demos/insertCoin/art/ground.png | 3 + demos/insertCoin/art/hills.png | 3 + demos/insertCoin/art/invaderA.png | 3 + demos/insertCoin/art/invaderB.png | 3 + demos/insertCoin/art/kart.png | 3 + demos/insertCoin/art/mountains.png | 3 + demos/insertCoin/art/raceSky.png | 3 + demos/insertCoin/art/runner.png | 3 + demos/insertCoin/art/scanlines.png | 3 + demos/insertCoin/art/ship.png | 3 + demos/insertCoin/art/track.png | 3 + demos/insertCoin/art/turret.png | 3 + demos/insertCoin/games.dat | 12 + demos/insertCoin/insertCoin.singe | 1207 +++++++++++++++++ demos/insertCoin/music.mp3 | 3 + demos/insertCoin/sync.lua | 337 +++++ demos/insertCoin/video/plasma.mp4 | 3 + demos/insertCoin/video/tunnel.mp4 | 3 + demos/kit.lua | 657 +++++++++ demos/mirrorball/art/bob.png | 3 + demos/mirrorball/art/boing.png | 3 + demos/mirrorball/art/club.png | 3 + demos/mirrorball/art/copper.png | 3 + demos/mirrorball/art/glow.png | 3 + demos/mirrorball/art/logo.png | 3 + demos/mirrorball/art/roto.png | 3 + demos/mirrorball/art/singe.png | 3 + demos/mirrorball/art/sparkle.png | 3 + demos/mirrorball/art/tile.png | 3 + demos/mirrorball/art/twister.png | 3 + demos/mirrorball/games.dat | 12 + demos/mirrorball/mirrorball.singe | 949 +++++++++++++ demos/mirrorball/music.mp3 | 3 + demos/mirrorball/sync.lua | 301 ++++ demos/mirrorball/video/plasma.mp4 | 3 + demos/mirrorball/video/tunnel.mp4 | 3 + demos/neonCoast/art/bob.png | 3 + demos/neonCoast/art/car.png | 3 + demos/neonCoast/art/flag.png | 3 + demos/neonCoast/art/glow.png | 3 + demos/neonCoast/art/grid.png | 3 + demos/neonCoast/art/gridCyan.png | 3 + demos/neonCoast/art/lamp.png | 3 + demos/neonCoast/art/logo.png | 3 + demos/neonCoast/art/mountains.png | 3 + demos/neonCoast/art/palm.png | 3 + demos/neonCoast/art/road.png | 3 + demos/neonCoast/art/singe.png | 3 + demos/neonCoast/art/sky.png | 3 + demos/neonCoast/art/skyline.png | 3 + demos/neonCoast/games.dat | 12 + demos/neonCoast/music.mp3 | 3 + demos/neonCoast/neonCoast.singe | 1030 ++++++++++++++ demos/neonCoast/sync.lua | 273 ++++ demos/neonCoast/video/noise.mp4 | 3 + demos/neonCoast/video/plasma.mp4 | 3 + demos/neonCoast/video/tunnel.mp4 | 3 + docs/Learn.adoc | 9 +- docs/Reference.adoc | 710 +++++++++- docs/images/learn/29-databases.png | 3 + .../{29-shipping.png => 30-shipping.png} | 0 .../learn/{30-cabinet.png => 31-cabinet.png} | 0 docs/learn/29-databases.singe | 133 ++ .../{29-shipping.singe => 30-shipping.singe} | 2 +- .../{30-cabinet.singe => 31-cabinet.singe} | 2 +- docs/learn/art/README.txt | 4 +- docs/learn/art/stages.db | Bin 0 -> 8192 bytes docs/lessons/12-score.adoc | 2 +- docs/lessons/13-game-folder.adoc | 4 +- docs/lessons/17-light-guns.adoc | 2 +- docs/lessons/28-online.adoc | 9 +- docs/lessons/29-databases.adoc | 488 +++++++ .../{29-shipping.adoc => 30-shipping.adoc} | 4 +- .../{30-cabinet.adoc => 31-cabinet.adoc} | 6 +- src/main.c | 2 + src/mic.c | 671 +++++++++ src/mic.h | 98 ++ src/singe.c | 878 +++++++++++- src/vfs.c | 361 ++++- src/vfs.h | 2 + src/voice.c | 381 ++++++ src/voice.h | 103 ++ testScripts/micVoice/micVoice.singe | 218 +++ testScripts/openRoad/art/arch.png | 3 + testScripts/openRoad/art/bush.png | 3 + testScripts/openRoad/art/car.png | 3 + testScripts/openRoad/art/hills.png | 3 + testScripts/openRoad/art/palm.png | 3 + testScripts/openRoad/art/sign.png | 3 + testScripts/openRoad/art/sky.png | 3 + testScripts/openRoad/art/strip.png | 3 + testScripts/openRoad/art/traffic.png | 3 + testScripts/openRoad/art/truck.png | 3 + testScripts/openRoad/games.dat | 9 + testScripts/openRoad/openRoad.singe | 516 +++++++ testScripts/packedSql/games.dat | 9 + testScripts/packedSql/levels.db | Bin 0 -> 8192 bytes testScripts/packedSql/packedSql.singe | 82 ++ testScripts/skyStrike/art/cloud.png | 3 + testScripts/skyStrike/art/enemy.png | 3 + testScripts/skyStrike/art/fireball.png | 3 + testScripts/skyStrike/art/ground.png | 3 + testScripts/skyStrike/art/jet.png | 3 + testScripts/skyStrike/art/rock.png | 3 + testScripts/skyStrike/art/shot.png | 3 + testScripts/skyStrike/art/tree.png | 3 + testScripts/skyStrike/games.dat | 9 + testScripts/skyStrike/skyStrike.singe | 322 +++++ util/demoCapture.sh | 44 + util/demoSync.py | 212 +++ util/demoVideo.py | 144 ++ util/insertCoinArt.py | 552 ++++++++ util/learnKit.py | 29 +- util/mirrorballArt.py | 212 +++ util/neonCoastArt.py | 405 ++++++ util/openRoadArt.py | 219 +++ util/renderReel.py | 2 +- util/skyStrikeArt.py | 157 +++ 131 files changed, 12161 insertions(+), 74 deletions(-) create mode 100644 demos/README.md create mode 100644 demos/insertCoin/art/bossArm.png create mode 100644 demos/insertCoin/art/bossCore.png create mode 100644 demos/insertCoin/art/bullet.png create mode 100644 demos/insertCoin/art/cannon.png create mode 100644 demos/insertCoin/art/coin.png create mode 100644 demos/insertCoin/art/duskSky.png create mode 100644 demos/insertCoin/art/font.png create mode 100644 demos/insertCoin/art/ground.png create mode 100644 demos/insertCoin/art/hills.png create mode 100644 demos/insertCoin/art/invaderA.png create mode 100644 demos/insertCoin/art/invaderB.png create mode 100644 demos/insertCoin/art/kart.png create mode 100644 demos/insertCoin/art/mountains.png create mode 100644 demos/insertCoin/art/raceSky.png create mode 100644 demos/insertCoin/art/runner.png create mode 100644 demos/insertCoin/art/scanlines.png create mode 100644 demos/insertCoin/art/ship.png create mode 100644 demos/insertCoin/art/track.png create mode 100644 demos/insertCoin/art/turret.png create mode 100644 demos/insertCoin/games.dat create mode 100644 demos/insertCoin/insertCoin.singe create mode 100644 demos/insertCoin/music.mp3 create mode 100644 demos/insertCoin/sync.lua create mode 100644 demos/insertCoin/video/plasma.mp4 create mode 100644 demos/insertCoin/video/tunnel.mp4 create mode 100644 demos/kit.lua create mode 100644 demos/mirrorball/art/bob.png create mode 100644 demos/mirrorball/art/boing.png create mode 100644 demos/mirrorball/art/club.png create mode 100644 demos/mirrorball/art/copper.png create mode 100644 demos/mirrorball/art/glow.png create mode 100644 demos/mirrorball/art/logo.png create mode 100644 demos/mirrorball/art/roto.png create mode 100644 demos/mirrorball/art/singe.png create mode 100644 demos/mirrorball/art/sparkle.png create mode 100644 demos/mirrorball/art/tile.png create mode 100644 demos/mirrorball/art/twister.png create mode 100644 demos/mirrorball/games.dat create mode 100644 demos/mirrorball/mirrorball.singe create mode 100644 demos/mirrorball/music.mp3 create mode 100644 demos/mirrorball/sync.lua create mode 100644 demos/mirrorball/video/plasma.mp4 create mode 100644 demos/mirrorball/video/tunnel.mp4 create mode 100644 demos/neonCoast/art/bob.png create mode 100644 demos/neonCoast/art/car.png create mode 100644 demos/neonCoast/art/flag.png create mode 100644 demos/neonCoast/art/glow.png create mode 100644 demos/neonCoast/art/grid.png create mode 100644 demos/neonCoast/art/gridCyan.png create mode 100644 demos/neonCoast/art/lamp.png create mode 100644 demos/neonCoast/art/logo.png create mode 100644 demos/neonCoast/art/mountains.png create mode 100644 demos/neonCoast/art/palm.png create mode 100644 demos/neonCoast/art/road.png create mode 100644 demos/neonCoast/art/singe.png create mode 100644 demos/neonCoast/art/sky.png create mode 100644 demos/neonCoast/art/skyline.png create mode 100644 demos/neonCoast/games.dat create mode 100644 demos/neonCoast/music.mp3 create mode 100644 demos/neonCoast/neonCoast.singe create mode 100644 demos/neonCoast/sync.lua create mode 100644 demos/neonCoast/video/noise.mp4 create mode 100644 demos/neonCoast/video/plasma.mp4 create mode 100644 demos/neonCoast/video/tunnel.mp4 create mode 100644 docs/images/learn/29-databases.png rename docs/images/learn/{29-shipping.png => 30-shipping.png} (100%) rename docs/images/learn/{30-cabinet.png => 31-cabinet.png} (100%) create mode 100644 docs/learn/29-databases.singe rename docs/learn/{29-shipping.singe => 30-shipping.singe} (96%) rename docs/learn/{30-cabinet.singe => 31-cabinet.singe} (98%) create mode 100644 docs/learn/art/stages.db create mode 100644 docs/lessons/29-databases.adoc rename docs/lessons/{29-shipping.adoc => 30-shipping.adoc} (99%) rename docs/lessons/{30-cabinet.adoc => 31-cabinet.adoc} (99%) create mode 100644 src/mic.c create mode 100644 src/mic.h create mode 100644 src/voice.c create mode 100644 src/voice.h create mode 100644 testScripts/micVoice/micVoice.singe create mode 100644 testScripts/openRoad/art/arch.png create mode 100644 testScripts/openRoad/art/bush.png create mode 100644 testScripts/openRoad/art/car.png create mode 100644 testScripts/openRoad/art/hills.png create mode 100644 testScripts/openRoad/art/palm.png create mode 100644 testScripts/openRoad/art/sign.png create mode 100644 testScripts/openRoad/art/sky.png create mode 100644 testScripts/openRoad/art/strip.png create mode 100644 testScripts/openRoad/art/traffic.png create mode 100644 testScripts/openRoad/art/truck.png create mode 100644 testScripts/openRoad/games.dat create mode 100644 testScripts/openRoad/openRoad.singe create mode 100644 testScripts/packedSql/games.dat create mode 100644 testScripts/packedSql/levels.db create mode 100644 testScripts/packedSql/packedSql.singe create mode 100644 testScripts/skyStrike/art/cloud.png create mode 100644 testScripts/skyStrike/art/enemy.png create mode 100644 testScripts/skyStrike/art/fireball.png create mode 100644 testScripts/skyStrike/art/ground.png create mode 100644 testScripts/skyStrike/art/jet.png create mode 100644 testScripts/skyStrike/art/rock.png create mode 100644 testScripts/skyStrike/art/shot.png create mode 100644 testScripts/skyStrike/art/tree.png create mode 100644 testScripts/skyStrike/games.dat create mode 100644 testScripts/skyStrike/skyStrike.singe create mode 100755 util/demoCapture.sh create mode 100644 util/demoSync.py create mode 100644 util/demoVideo.py create mode 100644 util/insertCoinArt.py create mode 100644 util/mirrorballArt.py create mode 100644 util/neonCoastArt.py create mode 100644 util/openRoadArt.py create mode 100644 util/skyStrikeArt.py diff --git a/CHANGELOG b/CHANGELOG index 7d56b4c9e..f32957f68 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,13 @@ SINGE 3.00 API Changes ----------- +- onOverlayUpdate is due 15 ms after the previous call began, not 15 ms after + it returned. A script that took 5 ms a frame used to run every 20 ms, and + one whose work varied from frame to frame ran at an uneven pace; now the + script's own time falls inside the 15 ms, and a script that takes less than + that runs on a steady 66 times a second. After a stall it is due a frame + from then, so it never runs several times in a row to catch up. + - controls.cfg, settings.cfg and gamecontrollerdb.txt are read game first. The four places are the same, but the file beside the game's script -- what its author shipped -- is now read first, then the machine's own in @@ -1114,6 +1121,65 @@ API Changes New Features ------------ +- A microphone, for singing games and anything that listens. micOpen starts + listening to the machine's default microphone or one named by micList; + micPitch says which note is being sung, as its frequency and how clearly it + is one note; micLevel says how loud; micRead hands over the samples + themselves; micRecordStart writes a WAV file; and micMonitor plays the + singer back through the speakers, off until asked for. micCalibrate + measures how far behind the microphone runs, with clicks played and timed + coming back, and the answer is kept for the machine beside the audio + calibration, for a game that judges a note against the beat. + +- The pieces a voice chat is built from, without the network: Opus encoding + and decoding (opusEncoderNew, opusEncode, opusDecode, with a lost packet + covered over), a voice processor that takes the echo of the speakers out of + the microphone, suppresses noise, evens the level, and says when somebody + is talking (voiceProcessorNew, voiceProcess), and a jitter buffer that plays + packets arriving late and out of order in the right order (jitterNew, + jitterPut, jitterGet). SpeexDSP 1.2.1 is new to Singe; Opus is the copy + SDL_mixer already carried. + +- A SQLite database can ship inside a packed game. sqlite3.open finds a + name the way io.open does: opened read only, a database inside the .game + is read where it lies, with nothing unpacked; opened for writing, it is + copied once to the game's data directory, under files/ with everything else + a packed game writes, and the copy is opened then and from then on. The + .game is never written. Before, sqlite3.open took only a path on disk, so a + database packed into a game would not open at all, though the same game run + loose worked. + +- musicGetPosition(id) says where the listener is in a playing track, in + seconds: the mixer's own position, less the device queue, the machine's + audio calibration and the game's delay, so a picture timed to it lands with + the sound however long the song plays. It moves smoothly between the + mixer's buffers. Animating to the music no longer means counting ticks from + musicPlay and hoping they keep pace. + +- Sprites can be added, multiplied, faded and tinted. spriteSetBlend chooses + SPRITE_ALPHA, SPRITE_ADD or SPRITE_MULTIPLY; spriteSetAlpha fades a sprite + from 255 to nothing; spriteSetTint multiplies its colour, so one white + picture draws in every colour. All three hold for every draw of the sprite, + turned, stretched, cut out or framed, and cost nothing a draw. + +- Three demos in demos/: Neon Coast, Mirrorball and Insert Coin, each set to + a song and timed to it bar by bar, beat by beat and drum hit by drum hit. + Between them they use the 3D scene with chrome, glass, bloom and fog, + physics, cloth and particles, video scrubbed by the music and played on + surfaces in 3D, and sprites turned, scaled, stretched a row at a time, + tinted and added. The tools that made them are in util/: demoSync.py + reads a song's beats, bars and drums, demoVideo.py precalculates the video + effects, demoCapture.sh renders a demo to a video, and an art script per + demo draws every picture. + +- spriteDrawGrid can stretch the rectangle it cuts out: given x2 and y2 after + the rectangle, it fills that box the way spriteDraw's stretched form does. + Cutting one-pixel rows out of a strip of road and stretching each to the + road's width at its row of the screen is how the arcade road-racing games + drew their roads, curves and hills included, and it costs one call a row. + It also draws the part of a sprite left showing above a hill's crest. + spriteScale could not do either, since it rebuilds the whole picture. + - An OpenGL ES 3.1 backend for the 3D scene and the GUI. SDL_GPU has Vulkan, Direct3D 12 and Metal and no OpenGL of any kind, which left the cheap Linux handhelds and the Raspberry Pi with 2D only: their Mali and diff --git a/CMakeLists.txt b/CMakeLists.txt index 70647daf7..b82dbc1d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -405,6 +405,10 @@ set(SINGE_SOURCE src/midi.h src/midiIo.c src/midiIo.h + src/mic.c + src/mic.h + src/voice.c + src/voice.h src/netTrust.c src/netTrust.h thirdparty/tinysoundfont/tsf.h @@ -439,6 +443,22 @@ set(SQLITE_SOURCE ) set_source_files_properties(thirdparty/lsqlite3/lsqlite3.c PROPERTIES COMPILE_DEFINITIONS "LSQLITE_VERSION=\"${LSQLITE_VERSION}\"") +# SpeexDSP 1.2.1 (thirdparty/speexdsp): echo cancellation, noise suppression, gain, voice activity, +# and a jitter buffer, for voice.c. It has no CMake build, so its library sources are compiled here, +# floating point, with its own small FFT. speexdsp_config_types.h is written by hand (see its top). +set(SPEEXDSP_SOURCE + thirdparty/speexdsp/libspeexdsp/buffer.c + thirdparty/speexdsp/libspeexdsp/fftwrap.c + thirdparty/speexdsp/libspeexdsp/filterbank.c + thirdparty/speexdsp/libspeexdsp/jitter.c + thirdparty/speexdsp/libspeexdsp/mdf.c + thirdparty/speexdsp/libspeexdsp/preprocess.c + thirdparty/speexdsp/libspeexdsp/resample.c + thirdparty/speexdsp/libspeexdsp/scal.c + thirdparty/speexdsp/libspeexdsp/smallft.c +) +set_source_files_properties(${SPEEXDSP_SOURCE} PROPERTIES COMPILE_DEFINITIONS "FLOATING_POINT;USE_SMALLFT;EXPORT=" COMPILE_OPTIONS "-w") + set(ARG_PARSER_SOURCE thirdparty/arg_parser/carg_parser.c thirdparty/arg_parser/carg_parser.h @@ -603,6 +623,7 @@ add_executable(${CMAKE_PROJECT_NAME} ${LUA_RS232_SOURCE} ${UTHASH_SOURCE} ${MANYMOUSE_SOURCE} + ${SPEEXDSP_SOURCE} ) if(WIN32) if(SINGE_ZIG_TARGET) @@ -677,6 +698,10 @@ target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE thirdparty/luasec/src thirdparty/librs232/include thirdparty/basis_universal/transcoder + # Opus is the one SDL3_mixer builds for Ogg Opus music (libopus.a in STATIC_LIBS), so the voice + # codec (voice.c) and the music decoder are one copy of one version. + thirdparty/SDL3_mixer/external/opus/include + thirdparty/speexdsp/include ) target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE diff --git a/LICENSES b/LICENSES index 3b78f9048..a0a28edde 100644 --- a/LICENSES +++ b/LICENSES @@ -40,7 +40,7 @@ lume 2.3.0 MIT https://github.com/rxi/lume manymouse 0.0.3 Zlib https://icculus.org/manymouse middleclass 4.1.1 MIT https://github.com/kikito/middleclass openssl 3.5.8 Apache-2.0 https://www.openssl.org -opus 1.4 BSD-3-Clause https://opus-codec.org (bundled with SDL3_mixer) +opus 1.4 BSD-3-Clause https://opus-codec.org (bundled with SDL3_mixer; also Singe's voice codec) opusfile 0.12 BSD-3-Clause https://opus-codec.org (bundled with SDL3_mixer) plutosvg 0.0.8 MIT https://github.com/sammycage/plutosvg (bundled with SDL3_ttf) plutovg 1.3.3 MIT https://github.com/sammycage/plutovg (bundled with SDL3_ttf) @@ -52,6 +52,7 @@ SDL3_mixer 3.2.4 Zlib https://www.libsdl.org SDL3_ttf 3.2.2 Zlib https://www.libsdl.org SDL_shadercross main 2026-09 Zlib https://github.com/libsdl-org/SDL_shadercross (host tool only) skcms 0.7.3-SDL BSD-3-Clause https://skia.googlesource.com/skcms (bundled with libjxl) +speexdsp 1.2.1 BSD-3-Clause https://www.speex.org SPIRV-Cross main 2026-09 Apache-2.0 https://github.com/KhronosGroup/SPIRV-Cross (host tool only) sqlite 3.53.4 Public-Domain https://sqlite.org timerwheel.lua 1.0.2 MIT https://tieske.github.io/timerwheel.lua diff --git a/assets/Framework.singe b/assets/Framework.singe index 3c04fa1b3..980ebf2ba 100644 --- a/assets/Framework.singe +++ b/assets/Framework.singe @@ -528,8 +528,8 @@ if SINGE_LEGACY_SPRITE_ARGS and spriteDraw ~= nil and not SINGE_LEGACY_SPRITE_WR -- spriteDrawGrid is the one Hypseus writes with the handle in the middle, -- (x, y, spr, rectX, rectY, width, height), not on the end. local newSpriteDrawGrid = spriteDrawGrid - spriteDrawGrid = function(x, y, id, sourceX, sourceY, width, height) - return newSpriteDrawGrid(id, x, y, sourceX, sourceY, width, height) + spriteDrawGrid = function(x, y, id, ...) + return newSpriteDrawGrid(id, x, y, ...) end end diff --git a/build-docs.sh b/build-docs.sh index 57ef6eb71..b47ac2b95 100755 --- a/build-docs.sh +++ b/build-docs.sh @@ -85,7 +85,7 @@ cat > "$stage/README.txt" < 0 and c < 96 then + spriteDrawGrid(art.font, math.floor(x + (i - 1) * 8 * scale), math.floor(y), (c % 16) * 8, (c // 16) * 8, 8, 8, math.floor(x + i * 8 * scale) - 1, math.floor(y + 8 * scale) - 1) + end + end + spriteSetTint(art.font, 255, 255, 255) +end + + +-- The same, each letter its own colour round the wheel, cycling: the high score table's rainbow. +local function rainbow(x, y, text, scale, t, align) + local w = #text * 8 * scale + + if align == "center" then + x = x - w / 2 + end + for i = 1, #text do + local r, g, b = K.hue(i * 0.06 - t * 0.8) + + ptext(x + (i - 1) * 8 * scale, y, text:sub(i, i), scale, r, g, b) + end +end + + +local function scanlines(alpha) + spriteSetAlpha(art.scanlines, alpha or 255) + spriteDraw(art.scanlines, 0, 0, W - 1, H - 1) + spriteSetAlpha(art.scanlines, 255) +end + + +-- Loading -------------------------------------------------------------------------------------------- + +local function loadArt() + for _, name in ipairs({ "invaderA", "invaderB", "cannon", "runner", "coin", "ship", "kart", "bossCore", "bossArm", "turret", "bullet", "font", "mountains", "hills", "ground", "scanlines" }) do + art[name] = spriteLoad(DIR .. "art/" .. name .. ".png") + end + spriteQuality(art.bossCore, RENDER_SMOOTH) + spriteQuality(art.bossArm, RENDER_SMOOTH) + video.tunnel = videoLoad(DIR .. "video/tunnel.mp4") + video.plasma = videoLoad(DIR .. "video/plasma.mp4") + video.tunnelFrames = videoGetFrameCount(video.tunnel) + videoSetVolume(video.tunnel, 0, 0) + videoSetVolume(video.plasma, 0, 0) + + -- Explosions on the overlay: square sparks added over everything. + art.boom = emitterNew() + emitterSetBlend(art.boom, PARTICLE_ADD) + emitterSetRate(art.boom, 0) + emitterSetLife(art.boom, 0.3, 0.9) + emitterSetSpeed(art.boom, 60, 320) + emitterSetSpread(art.boom, 180) + emitterSetDrag(art.boom, 2) + emitterSetSize(art.boom, 9, 2) + emitterSetMax(art.boom, 4000) + emitterStart(art.boom) +end + + +local function boom(x, y, count, r, g, b) + emitterSetPosition(art.boom, x, y) + emitterSetColor(art.boom, 255, 255, 255, 255, r, g, b, 0) + emitterBurst(art.boom, count) +end + + +-- The world -------------------------------------------------------------------------------------------- + +local function flatMesh(verts, faces) + local positions = {} + local normals = {} + local indices = {} + + for _, f in ipairs(faces) do + local a = verts[f[1]] + local b = verts[f[2]] + local c = verts[f[3]] + local ux = b[1] - a[1] + local uy = b[2] - a[2] + local uz = b[3] - a[3] + local vx = c[1] - a[1] + local vy = c[2] - a[2] + local vz = c[3] - a[3] + local nx = uy * vz - uz * vy + local ny = uz * vx - ux * vz + local nz = ux * vy - uy * vx + local l = math.sqrt(nx * nx + ny * ny + nz * nz) + 1e-9 + + for _, p in ipairs({ a, b, c }) do + positions[#positions + 1] = p[1] + positions[#positions + 1] = p[2] + positions[#positions + 1] = p[3] + normals[#normals + 1] = nx / l + normals[#normals + 1] = ny / l + normals[#normals + 1] = nz / l + indices[#indices + 1] = #positions / 3 + end + end + return meshNew(positions, normals, nil, indices) +end + + +-- A low-poly ship: a few triangles, flat shaded, nose toward -Z. +local function shipMesh() + local v = { + { 0, 0, -2.2 }, { -0.5, 0.15, 0.4 }, { 0.5, 0.15, 0.4 }, { 0, 0.5, 0.2 }, { 0, -0.2, 0.6 }, + { -1.8, -0.05, 0.9 }, { 1.8, -0.05, 0.9 }, { 0, 0.15, 1.0 }, + } + local f = { + { 1, 4, 2 }, { 1, 3, 4 }, { 1, 2, 5 }, { 1, 5, 3 }, { 2, 4, 8 }, { 4, 3, 8 }, { 2, 8, 5 }, { 3, 5, 8 }, + { 2, 6, 5 }, { 3, 5, 7 }, { 2, 5, 6 }, { 3, 7, 5 }, + } + + return flatMesh(v, f) +end + + +local function octahedron(r) + local v = { { r, 0, 0 }, { -r, 0, 0 }, { 0, r, 0 }, { 0, -r, 0 }, { 0, 0, r }, { 0, 0, -r } } + local f = { { 1, 3, 5 }, { 5, 3, 2 }, { 2, 3, 6 }, { 6, 3, 1 }, { 5, 4, 1 }, { 2, 4, 5 }, { 6, 4, 2 }, { 1, 4, 6 } } + + return flatMesh(v, f) +end + + +local function buildRacer() + local ground = materialNew() + + materialSetTexture(ground, spriteLoad(DIR .. "art/track.png")) + materialSetFilter(ground, FILTER_NEAREST) + materialSetUnlit(ground, true) + world.track = nodeNew() + nodeSetMesh(world.track, meshPlane(400, 400), ground) + local skyMaterial = materialNew() + + materialSetTexture(skyMaterial, spriteLoad(DIR .. "art/raceSky.png")) + materialSetUnlit(skyMaterial, true) + materialSetDoubleSided(skyMaterial, true) + world.raceSky = nodeNew() + nodeSetMesh(world.raceSky, meshSphere(320, 32), skyMaterial) + world.rivals = {} + for i = 1, 5 do + local n = nodeNew() + local c = NEON[i] + + nodeSetSprite(n, art.kart, 3.2, false) + nodeSetBillboard(n, BILLBOARD_Y) + world.rivals[i] = { node = n, offset = 0.12 + i * 0.09, tint = c } + end +end + + +local function buildPolygons() + local hull = materialNew() + + materialSetColor(hull, 200, 210, 230) + materialSetRoughness(hull, 0.6) + world.ship = nodeNew() + nodeSetMesh(world.ship, shipMesh(), hull) + world.rings = {} + world.ringMaterials = {} + for i = 1, 6 do + local m = materialNew() + local c = NEON[i] + + materialSetColor(m, c[1] // 2, c[2] // 2, c[3] // 2) + materialSetRoughness(m, 0.7) + world.ringMaterials[i] = m + end + local ringMesh = meshTorus(7, 0.6, 6) + + for i = 1, 14 do + local n = nodeNew() + + nodeSetMesh(n, ringMesh, world.ringMaterials[(i - 1) % 6 + 1]) + world.rings[i] = n + end + local floorMaterial = materialNew() + + materialSetTexture(floorMaterial, spriteLoad(DIR .. "art/ground.png")) + materialSetFilter(floorMaterial, FILTER_NEAREST) + materialSetTiling(floorMaterial, 30, 30) + materialSetColor(floorMaterial, 70, 55, 120) + world.polyFloor = nodeNew() + nodeSetMesh(world.polyFloor, meshPlane(300, 300, 4), floorMaterial) + world.enemies = {} + local enemyMaterial = materialNew() + + materialSetColor(enemyMaterial, 255, 80, 60) + materialSetEmissive(enemyMaterial, 120, 20, 10) + local enemyMesh = octahedron(1.2) + + for i = 1, 6 do + local n = nodeNew() + + nodeSetMesh(n, enemyMesh, enemyMaterial) + world.enemies[i] = n + end + world.shardAnchor = nodeNew() + world.shards = emitterNew(world.shardAnchor) + emitterSetRate(world.shards, 0) + emitterSetLife(world.shards, 0.4, 1.0) + emitterSetSpeed(world.shards, 6, 16) + emitterSetSpread(world.shards, 180) + emitterSetGravity(world.shards, 0, -10, 0) + emitterSetSize(world.shards, 0.5, 0.1) + emitterSetColor(world.shards, 255, 200, 80, 255, 255, 60, 20, 0) + emitterSetBlend(world.shards, PARTICLE_ADD) + emitterStart(world.shards) + world.light = lightNew(LIGHT_DIRECTIONAL) + nodeSetPosition(world.light, 3, 8, 4) + nodeLookAt(world.light, 0, 0, 0) + lightSetIntensity(world.light, 0) +end + + +-- The modern era: a wall of glossy bricks on a dark floor, and chrome balls to knock it down. +local function buildModern() + local floorMaterial = materialNew() + + materialSetColor(floorMaterial, 30, 30, 40) + materialSetMetallic(floorMaterial, 0.8) + materialSetRoughness(floorMaterial, 0.15) + world.modernFloor = nodeNew() + nodeSetMesh(world.modernFloor, meshBox(60, 0.4, 60), floorMaterial) + nodeSetPosition(world.modernFloor, 0, -0.2, 0) + bodyNew(world.modernFloor, BODY_STATIC, SHAPE_BOX, 60, 0.4, 60) + world.brickMaterials = {} + for i, c in ipairs(NEON) do + local m = materialNew() + + materialSetColor(m, c[1], c[2], c[3]) + materialSetMetallic(m, 0.3) + materialSetRoughness(m, 0.12) + world.brickMaterials[i] = m + end + world.brickMesh = meshBox(1.2, 0.6, 0.6) + world.bricks = {} + world.ballMesh = meshSphere(0.45, 24) + world.ballMaterial = K.chrome(240, 240, 250, 0.04) + world.balls = {} + world.spark = nodeNew() + world.sparks = emitterNew(world.spark) + emitterSetBlend(world.sparks, PARTICLE_ADD) + emitterSetRate(world.sparks, 0) + emitterSetLife(world.sparks, 0.3, 0.8) + emitterSetSpeed(world.sparks, 2, 7) + emitterSetSpread(world.sparks, 180) + emitterSetGravity(world.sparks, 0, -9, 0) + emitterSetSize(world.sparks, 0.08, 0.02) + emitterSetColor(world.sparks, 255, 240, 200, 255, 255, 120, 40, 0) + emitterSetTrail(world.sparks, 5, 0.03) + emitterStart(world.sparks) + world.sun = lightNew(LIGHT_DIRECTIONAL) + nodeSetPosition(world.sun, -6, 10, 8) + nodeLookAt(world.sun, 0, 0, 0) + lightSetIntensity(world.sun, 0) + lightSetShadow(world.sun, true) +end + + +local function buildBonus() + local tunnel = materialNew() + + materialSetVideo(tunnel, video.tunnel) + materialSetUnlit(tunnel, true) + materialSetDoubleSided(tunnel, true) + world.tunnel = K.screenQuad(world.camera, FOV, tunnel, 80, 1.8) + world.coinMesh = meshCylinder(0.6, 0.12, 20) + world.coinMaterial = K.chrome(255, 200, 60, 0.25) + materialSetEmissive(world.coinMaterial, 150, 100, 10) + world.coins = {} + world.bin = nodeNew() + nodeSetPosition(world.bin, 0, -100, 0) + world.binWalls = {} + for _, w in ipairs({ { 0, -4.6, 0, 16, 0.4, 8 }, { -8, 0, 0, 0.4, 12, 8 }, { 8, 0, 0, 0.4, 12, 8 }, { 0, 0, -4, 16, 12, 0.4 }, { 0, 0, 4, 16, 12, 0.4 } }) do + local n = nodeNew() + + nodeSetPosition(n, w[1], w[2] - 100, w[3]) + bodyNew(n, BODY_KINEMATIC, SHAPE_BOX, w[4], w[5], w[6]) + world.binWalls[#world.binWalls + 1] = { node = n, x = w[1], y = w[2], z = w[3] } + end +end + + +local function buildWorld() + sceneEnable(true) + sceneSetSky(DIR .. "art/duskSky.png") + sceneSetBloom(0.8, 0.5) + sceneSetAmbient(40, 40, 50) + world.camera = nodeNew() + cameraSet(world.camera) + cameraSetPerspective(FOV, 0.1, 800) + buildRacer() + buildPolygons() + buildModern() + buildBonus() +end + + +local function hideAll() + for _, n in ipairs({ world.track, world.raceSky, world.ship, world.polyFloor, world.modernFloor, world.tunnel }) do + nodeSetVisible(n, false) + end + for _, r in ipairs(world.rivals) do + nodeSetVisible(r.node, false) + end + for _, n in ipairs(world.rings) do + nodeSetVisible(n, false) + end + for _, n in ipairs(world.enemies) do + nodeSetVisible(n, false) + end + lightSetIntensity(world.light, 0) + lightSetIntensity(world.sun, 0) + sceneSetFog() + sceneSetSkyIntensity(1) + -- Behind a 2D era the 3D layer is plain black. + nodeSetPosition(world.camera, 0, -500, 0) + nodeLookAt(world.camera, 0, -500, -1) +end + + +-- The eras ---------------------------------------------------------------------------------------------- +-- Each is a scene table without its bars, so the finale can run them again: enter, draw(t, bar, +-- k), and leave. An era's own time is the music's, so whatever it plays lands on the beat wherever +-- it is placed, as long as it is placed on a whole bar. + +local ERA = {} + +-- Switching on: the tube warms up from a line, INSERT COIN blinks on the beat, and a coin spins +-- down into the slot on the downbeat of bar 5. +ERA.boot = { + enter = function(t) + hideAll() + end, + draw = function(t, bar, k) + K.flash(0, 0, 0, 255) + local warm = K.smooth(1, 1.6, bar) + + if warm < 1 then + local h = math.max(2, H * warm * warm) + + K.box(0, H / 2 - h / 2, W - 1, H / 2 + h / 2, 255, 255, 255, math.floor(255 * (1 - warm * 0.85))) + return + end + if (K.beat(t) % 1) < 0.5 then + ptext(W / 2, 200, "INSERT COIN", 5, 255, 255, 255, "center") + end + local land = K.barTime(5) + local fall = K.clamp((t - (land - beat * 4)) / (beat * 4), 0, 1) + local cy = K.lerp(-60, 320, fall * fall) + local spin = math.floor(t * 12) % 4 + + if fall < 1 then + px(art.coin, 8, spin, W / 2 - 32, cy, 8) + end + K.box(W / 2 - 40, 392, W / 2 + 40, 402, 90, 90, 100, 255) + ptext(W / 2, 430, (fall >= 1) and "CREDIT 1" or "CREDIT 0", 3, 255, 220, 80, "center") + scanlines(160) + end, +} + +-- 1-bit: two bats and a ball in green phosphor. The ball crosses the court once a beat, so it meets +-- a bat on every beat, and its afterglow trails behind it. +ERA.pong = { + enter = function(t) + hideAll() + world.pongScore = { 0, 0 } + end, + draw = function(t, bar, k) + K.flash(0, 6, 2, 255) + local b = K.beat(t) + local left = 60 + local right = W - 60 + + for y = 20, H - 20, 24 do + K.box(W / 2 - 3, y, W / 2 + 3, y + 12, PHOSPHOR[1], PHOSPHOR[2], PHOSPHOR[3], 160) + end + local function ballAt(beatPos) + local whole = math.floor(beatPos) + local p = beatPos - whole + local x = (whole % 2 == 0) and K.lerp(left + 12, right - 12, p) or K.lerp(right - 12, left + 12, p) + local tri = (beatPos * 0.37) % 2 + + tri = (tri < 1) and tri or (2 - tri) + return x, K.lerp(40, H - 40, tri) + end + for g = 6, 1, -1 do + local gx, gy = ballAt(b - g * 0.02) + + K.box(gx - 7, gy - 7, gx + 7, gy + 7, PHOSPHOR[1], PHOSPHOR[2], PHOSPHOR[3], 30 + (6 - g) * 20) + end + local x, y = ballAt(b) + + K.box(x - 8, y - 8, x + 8, y + 8, 220, 255, 230, 255) + local _, ly = ballAt(math.floor(b) + ((math.floor(b) % 2 == 0) and 0 or 1)) + local _, ry = ballAt(math.floor(b) + ((math.floor(b) % 2 == 0) and 1 or 0)) + + K.box(left - 10, ly - 40, left, ly + 40, PHOSPHOR[1], PHOSPHOR[2], PHOSPHOR[3], 255) + K.box(right, ry - 40, right + 10, ry + 40, PHOSPHOR[1], PHOSPHOR[2], PHOSPHOR[3], 255) + local points = math.floor(b / 4) + + ptext(W / 2 - 80, 30, string.format("%02d", points % 100), 6, PHOSPHOR[1], PHOSPHOR[2], PHOSPHOR[3], "center") + ptext(W / 2 + 80, 30, string.format("%02d", (points * 3) % 100), 6, PHOSPHOR[1], PHOSPHOR[2], PHOSPHOR[3], "center") + K.strobe(t, "kicks", 20, PHOSPHOR[1], PHOSPHOR[2], PHOSPHOR[3], 30) + scanlines(200) + end, +} + +-- 8-bit: a formation of aliens that steps on every beat, the cannon below firing on every snare and +-- taking out the lowest alien above it. +local function alienPositions(step) + local cycle = step % 40 + local dx = (cycle < 20) and cycle or (40 - cycle) + + return 48 + dx * 8, 60 + math.floor(step / 20) * 16 +end + + +ERA.invaders = { + enter = function(t) + hideAll() + world.alive = {} + for i = 1, ALIEN_COLS * ALIEN_ROWS do + world.alive[i] = true + end + world.shots = {} + world.alienBase = K.beat(t) + end, + draw = function(t, bar, k) + K.flash(0, 0, 8, 255) + local step = math.floor(K.beat(t) - world.alienBase) + local ox, oy = alienPositions(step) + local frame = step % 2 + local cannonX = W / 2 + math.sin(t * 1.4) * 220 + + -- On a snare, a shot from the cannon at the lowest alien in the column above it. + if K.hitCount("snares", lastT, t) > 0 then + local col = math.floor((cannonX - ox) / 52 + 0.5) + + if col >= 0 and col < ALIEN_COLS then + for row = ALIEN_ROWS - 1, 0, -1 do + local i = row * ALIEN_COLS + col + 1 + + if world.alive[i] then + world.shots[#world.shots + 1] = { x = cannonX, start = t, target = i } + break + end + end + end + end + for row = 0, ALIEN_ROWS - 1 do + local c = NEON[row % #NEON + 1] + local sprite = (row < 2) and art.invaderA or art.invaderB + + spriteSetTint(sprite, c[1], c[2], c[3]) + for col = 0, ALIEN_COLS - 1 do + if world.alive[row * ALIEN_COLS + col + 1] then + px(sprite, (row < 2) and 12 or 12, frame, ox + col * 52, oy + row * 40, 4) + end + end + spriteSetTint(sprite, 255, 255, 255) + end + for i = #world.shots, 1, -1 do + local s = world.shots[i] + local row = (s.target - 1) // ALIEN_COLS + local col = (s.target - 1) % ALIEN_COLS + local tx = ox + col * 52 + 24 + local ty = oy + row * 40 + 16 + local p = (t - s.start) / (beat * 0.35) + + if p >= 1 then + if world.alive[s.target] then + world.alive[s.target] = false + local c = NEON[row % #NEON + 1] + + boom(tx, ty, 60, c[1], c[2], c[3]) + end + table.remove(world.shots, i) + else + local sx = K.lerp(s.x, tx, p) + local sy = K.lerp(H - 70, ty, p) + + K.box(sx - 2, sy - 10, sx + 2, sy + 10, 255, 255, 255, 255) + end + end + spriteSetTint(art.cannon, 80, 255, 120) + px(art.cannon, 13, 0, cannonX - 26, H - 64, 4) + spriteSetTint(art.cannon, 255, 255, 255) + K.box(0, H - 28, W - 1, H - 26, 80, 255, 120, 255) + ptext(20, 14, string.format("SCORE %05d", (ALIEN_COLS * ALIEN_ROWS - (function() local n = 0 for _, a in ipairs(world.alive) do if a then n = n + 1 end end return n end)()) * 50), 2, 255, 255, 255) + emitterDraw(art.boom) + scanlines(180) + end, +} + +-- 16-bit: a runner over parallax hills. The ground runs at a steady speed, the runner jumps on every +-- snare, as high as the note being played says, and the coins are placed where the jumps will take +-- him. +local RUN_SPEED = 260 +local RUNNER_X = 170 + +ERA.runner = { + enter = function(t) + hideAll() + world.collected = {} + world.runScore = 0 + end, + draw = function(t, bar, k) + for i = 0, 11 do + local r = 40 + i * 12 + local g = 90 + i * 12 + local b = 210 + i * 4 + + K.box(0, i * 30, W - 1, i * 30 + 29, r, g, math.min(255, b), 255) + end + local function layer(sprite, speed, y, scale) + local w = spriteGetWidth(sprite) * scale + local offset = (t * speed) % w + + for x = -offset, W, w do + spriteDraw(sprite, math.floor(x), y, math.floor(x + w) - 1, y + spriteGetHeight(sprite) * scale - 1) + end + end + layer(art.mountains, RUN_SPEED * 0.15, 170, 2) + layer(art.hills, RUN_SPEED * 0.4, 260, 2) + layer(art.ground, RUN_SPEED, H - 96, 2) + local groundY = H - 96 - 64 + local b = K.beat(t) + local jumpY = 0 + + -- Jumps on the backbeat: beats 2 and 4 of each bar, a beat long. + local whole = math.floor(b) + local p = b - whole + + if (whole - (sync.barStart - 1)) % 2 == 1 then + local note = K.note(K.beatTime(whole)) + + jumpY = 4 * p * (1 - p) * (90 + note * 8) + end + -- Coins at the top of every jump, a beat's worth of ground apart. + for j = math.floor(b) - 2, math.floor(b) + 4 do + if (j - (sync.barStart - 1)) % 2 == 1 then + local apex = K.beatTime(j + 0.5) + local cx = RUNNER_X + 24 + (apex - t) * RUN_SPEED + local note = K.note(K.beatTime(j)) + local cy = groundY - (90 + note * 8) + 8 + + if t < apex then + px(art.coin, 8, math.floor(t * 10) % 4, cx, cy, 4) + elseif not world.collected[j] then + world.collected[j] = true + world.runScore = world.runScore + 100 + boom(RUNNER_X + 32, cy + 16, 30, 255, 230, 80) + end + end + end + local frame = (jumpY > 0) and 4 or (math.floor(b * 4) % 4) + + px(art.runner, 16, frame, RUNNER_X, groundY - jumpY, 4) + ptext(20, 14, string.format("COINS %03d", world.runScore // 100), 2, 255, 255, 255) + ptext(W - 20 - 9 * 16, 14, string.format("WORLD 1-%d", math.floor(bar - 16) // 2 + 1), 2, 255, 255, 255) + emitterDraw(art.boom) + end, +} + +-- 16-bit, the other trick: a kart on a flat track seen in perspective, the sky turning with it. It +-- laps once every four bars. +local function trackPoint(a) + return math.cos(a) * 144, math.sin(a) * 104 +end + + +ERA.racer = { + enter = function(t) + hideAll() + nodeSetVisible(world.track, true) + nodeSetVisible(world.raceSky, true) + for _, r in ipairs(world.rivals) do + nodeSetVisible(r.node, true) + end + world.raceBase = t + end, + draw = function(t, bar, k) + local lap = (bar - 1) / 4 + local a = lap * 2 * math.pi + local x, z = trackPoint(a) + local ax, az = trackPoint(a + 0.08) + + nodeSetPosition(world.camera, x, 4.5, z) + nodeLookAt(world.camera, ax, 3.2, az) + nodeSetPosition(world.raceSky, x, 0, z) + for i, r in ipairs(world.rivals) do + local ra = a + r.offset + 0.02 * math.sin(t * 2 + i) + local rx, rz = trackPoint(ra) + + nodeSetPosition(r.node, rx + math.sin(i * 2.1) * 6, 1.4, rz + math.cos(i * 1.7) * 6) + end + local lean = math.sin(a * 2) * 8 + + spriteRotateAndScale(art.kart, lean, 6) + spriteDraw(art.kart, W // 2, H - 70, true) + ptext(20, 14, string.format("LAP %d/3", math.floor(lap) % 3 + 1), 3, 255, 255, 255) + ptext(W - 20 - 6 * 24, 14, string.format("POS %d", 6 - math.floor(lap * 1.5) % 5), 3, 255, 240, 80) + local laps = (t - world.raceBase) + + ptext(W - 20 - 8 * 16, 48, string.format("%02d\"%02d", math.floor(laps) % 60, math.floor(laps * 100) % 100), 2, 255, 255, 255) + end, + leave = function(t) + spriteRotateAndScale(art.kart, 0, 1) + end, +} + +-- Loading: a tape loading, the border awash with stripes, a bar filling to the riser. +ERA.loading = { + enter = function(t) + hideAll() + end, + draw = function(t, bar, k) + local border = { { 20, 20, 120 }, { 255, 255, 80 }, { 60, 200, 200 }, { 200, 60, 200 }, { 255, 140, 60 }, { 255, 255, 255 }, { 40, 40, 40 } } + local seed = math.floor(t * 50) + local band = 3 + math.floor(6 * (1 - k)) + + for y = 0, H - 1, band do + local c = border[((seed * 31 + y * 7) // band) % #border + 1] + + K.box(0, y, W - 1, y + band - 1, c[1], c[2], c[3], 255) + end + K.box(64, 56, W - 65, H - 57, 60, 60, 200, 255) + ptext(96, 90, "PRESS PLAY ON TAPE", 2, 160, 160, 255) + ptext(96, 130, "OK", 2, 160, 160, 255) + ptext(96, 170, "SEARCHING", 2, 160, 160, 255) + ptext(96, 210, "FOUND GAME ON", 2, 160, 160, 255) + ptext(96, 250, "LOADING", 2, 160, 160, 255) + if (t * 3) % 1 < 0.5 then + K.box(96 + 8 * 16, 250, 96 + 8 * 16 + 14, 265, 160, 160, 255, 255) + end + local fill = K.clamp(k, 0, 1) + + K.box(96, 320, W - 97, 350, 20, 20, 90, 255) + K.box(98, 322, 98 + (W - 196 - 4) * fill, 348, 160, 160, 255, 255) + ptext(W / 2, 370, string.format("%3d%%", math.floor(fill * 100)), 2, 255, 255, 255, "center") + scanlines(120) + if bar > 40.6 then + K.flash(255, 255, 255, math.floor(255 * K.smooth(40.6, 41, bar))) + end + end, +} + +-- 32-bit: a flat-shaded ship through hexagonal rings, one ring a beat, in a dense fog, every +-- position snapped to a coarse grid as the machines of the time snapped theirs. From bar 49 enemy +-- crystals come at the ship and burst on the snare. +local function snap(v) + return math.floor(v * 12 + 0.5) / 12 +end + + +ERA.polygons = { + enter = function(t) + hideAll() + nodeSetVisible(world.ship, true) + nodeSetVisible(world.polyFloor, true) + for _, n in ipairs(world.rings) do + nodeSetVisible(n, true) + end + lightSetIntensity(world.light, 3) + sceneSetFog(30, 10, 50, 10, 120) + sceneSetSkyIntensity(0) + world.enemyBase = K.beat(t) + end, + draw = function(t, bar, k) + local b = K.beat(t) + local z = -b * RING_EVERY + local sway = math.sin(t * 0.9) * 3 + + nodeSetPosition(world.ship, snap(sway), snap(2 + math.sin(t * 1.3) * 0.8), snap(z - 8)) + nodeSetRotation(world.ship, 0, 0, snap(math.cos(t * 0.9) * -25)) + nodeSetPosition(world.camera, snap(sway * 0.6), snap(3.4), snap(z)) + nodeLookAt(world.camera, sway * 0.8, 2, z - 30) + nodeSetPosition(world.polyFloor, 0, -3, z - (z % 20)) + local first = math.floor(b) + + for i, n in ipairs(world.rings) do + local rb = first + i - 1 + + nodeSetPosition(n, 0, 2, snap(-rb * RING_EVERY - 8)) + nodeSetRotation(n, 90, rb * 15, 0) + end + for i, m in ipairs(world.ringMaterials) do + local v = K.decay("kicks", t, 6) + local c = NEON[i] + + materialSetEmissive(m, math.floor(c[1] * v), math.floor(c[2] * v), math.floor(c[3] * v)) + end + if bar >= 49 then + for i, n in ipairs(world.enemies) do + local eb = math.floor(b) + i * 2 + local ez = -eb * RING_EVERY - 8 + local alive = (eb - b) > 0.35 + + nodeSetVisible(n, alive) + nodeSetPosition(n, snap(math.sin(eb * 1.7) * 3), snap(2 + math.cos(eb * 2.3) * 1.5), snap(ez)) + nodeSetRotation(n, t * 90, t * 130, 0) + end + if K.hitCount("snares", lastT, t) > 0 then + nodeSetPosition(world.shardAnchor, sway, 2, z - 20) + emitterBurst(world.shards, 80) + end + end + end, +} + +-- Now: glass, chrome, and physics. A wall of glossy bricks under a dusk sky, and on every kick a +-- chrome ball thrown into it; the wall is built again at bar 65 and comes down harder. +local function buildWall() + for _, b in ipairs(world.bricks) do + bodyDelete(b) + nodeDelete(b) + end + for _, b in ipairs(world.balls) do + bodyDelete(b) + nodeDelete(b) + end + world.bricks = {} + world.balls = {} + for row = 0, BRICK_ROWS - 1 do + for col = 0, BRICK_COLS - 1 do + local n = nodeNew() + + nodeSetMesh(n, world.brickMesh, world.brickMaterials[(row + col) % #world.brickMaterials + 1]) + nodeSetPosition(n, (col - (BRICK_COLS - 1) / 2) * 1.25 + ((row % 2) * 0.62 - 0.31), 0.3 + row * 0.62, 0) + bodyNew(n, BODY_DYNAMIC, SHAPE_BOX, 1.2, 0.6, 0.6) + bodySetMass(n, 1) + bodySetFriction(n, 0.8) + world.bricks[#world.bricks + 1] = n + end + end +end + + +ERA.modern = { + enter = function(t) + hideAll() + nodeSetVisible(world.modernFloor, true) + lightSetIntensity(world.sun, 4) + sceneSetSkyIntensity(1.2) + buildWall() + world.wallBuilt = K.bar(t) + end, + draw = function(t, bar, k) + if bar >= 65 and world.wallBuilt < 65 then + buildWall() + world.wallBuilt = bar + end + local a = t * 0.12 + + nodeSetPosition(world.camera, math.sin(a) * 7, 2.4 + math.sin(t * 0.3) * 0.6, 7.5 + math.cos(a) * 2) + nodeLookAt(world.camera, 0, 1.6, 0) + if K.hitCount("kicks", lastT, t) > 0 and #world.balls < 40 then + local n = nodeNew() + local tx = (math.random() - 0.5) * 8 + local ty = 0.5 + math.random() * 3 + + nodeSetMesh(n, world.ballMesh, world.ballMaterial) + nodeSetPosition(n, tx * 0.3, ty + 1.5, 14) + bodyNew(n, BODY_DYNAMIC, SHAPE_SPHERE, 0.45) + bodySetMass(n, (bar >= 65) and 8 or 4) + bodySetVelocity(n, tx * 0.9, 1.2, -32) + world.balls[#world.balls + 1] = n + end + end, + leave = function(t) + for _, b in ipairs(world.bricks) do + bodyDelete(b) + nodeDelete(b) + end + for _, b in ipairs(world.balls) do + bodyDelete(b) + nodeDelete(b) + end + world.bricks = {} + world.balls = {} + end, +} + +-- Game over, and a countdown to continue, a number a bar, glitching, until the coin goes in. +ERA.continue = { + enter = function(t) + hideAll() + end, + draw = function(t, bar, k) + K.flash(0, 0, 0, 255) + local n = 8 - math.floor(bar - 73) + + if bar < 74 then + ptext(W / 2, 200, "GAME OVER", 6, 255, 60, 60, "center") + else + ptext(W / 2, 80, "CONTINUE?", 4, 255, 255, 255, "center") + local pulse = 1 + 0.15 * K.decay("snares", t, 6) + local s = math.floor(18 * pulse) + local glitch = (math.random() < 0.15) and math.random(-20, 20) or 0 + + ptext(W / 2 + glitch, 170, tostring(math.max(1, n)), s, 255, 220, 60, "center") + for i = 1, 3 do + local y = math.random(0, H) + + K.box(0, y, W - 1, y + math.random(1, 4), 255, 255, 255, math.random(20, 90)) + end + end + if bar > 80.25 then + local p = K.smooth(80.25, 80.95, bar) + + px(art.coin, 8, math.floor(t * 12) % 4, W / 2 - 32, K.lerp(-60, 380, p * p), 8) + end + ptext(W / 2, 430, "CREDIT 0", 3, 255, 220, 80, "center") + scanlines(160) + end, +} + +-- The boss: a core and four turning arms with turrets, firing rings on the kick, spirals on the +-- hats, and aimed shots on the snare, while the ship below weaves and fires back. Its health runs +-- out over sixteen bars, and it goes up on the last. +ERA.boss = { + enter = function(t) + hideAll() + world.bullets = {} + world.bossHit = 0 + videoPlay(video.plasma) + end, + draw = function(t, bar, k) + videoDraw(video.plasma, 0, 0, W - 1, H - 1) + K.flash(0, 0, 10, 200) + local dt = t - lastT + local cx = W / 2 + math.sin(t * 0.5) * 60 + local cy = 150 + math.sin(t * 0.8) * 20 + local spin = t * 40 + local shipX = W / 2 + math.sin(t * 1.1) * 210 + math.sin(t * 2.7) * 40 + local shipY = H - 70 + local dying = bar >= 96 + + -- Stars streaming past. + for i = 1, 60 do + local sy = (i * 97 + t * (60 + (i % 5) * 50)) % H + local sx = (i * 173) % W + + K.box(sx, sy, sx + 1, sy + 1 + (i % 3), 255, 255, 255, 120 + (i % 4) * 30) + end + if not dying then + if K.hitCount("kicks", lastT, t) > 0 then + for i = 1, 20 do + local a = i / 20 * 2 * math.pi + t + + world.bullets[#world.bullets + 1] = { x = cx, y = cy, vx = math.cos(a) * 150, vy = math.sin(a) * 150, c = 1 } + end + end + if K.hitCount("hats", lastT, t) > 0 then + for arm = 0, 3 do + local a = math.rad(spin) + arm * math.pi / 2 + + world.bullets[#world.bullets + 1] = { x = cx + math.cos(a) * 110, y = cy + math.sin(a) * 110, vx = math.cos(a + 1.2) * 180, vy = math.sin(a + 1.2) * 180, c = 2 } + end + end + if K.hitCount("snares", lastT, t) > 0 then + for i = -1, 1 do + local a = math.atan(shipY - cy, shipX - cx) + i * 0.18 + + world.bullets[#world.bullets + 1] = { x = cx, y = cy, vx = math.cos(a) * 240, vy = math.sin(a) * 240, c = 3 } + end + end + end + -- The arms and turrets, then the core over them, flashing white while it is being hit. + local hitFlash = (math.floor(t * 30) % 2 == 0) and not dying + + for arm = 0, 3 do + local a = spin + arm * 90 + local ax = cx + math.cos(math.rad(a)) * 60 + local ay = cy + math.sin(math.rad(a)) * 60 + + spriteRotate(art.bossArm, a) + spriteDraw(art.bossArm, math.floor(ax), math.floor(ay), true) + spriteDraw(art.turret, math.floor(cx + math.cos(math.rad(a)) * 110) - 14, math.floor(cy + math.sin(math.rad(a)) * 110) - 14) + end + spriteSetTint(art.bossCore, 255, hitFlash and 200 or 255, hitFlash and 200 or 255) + spriteRotateAndScale(art.bossCore, -spin * 0.5, 1.4 + 0.1 * K.decay("kicks", t, 8)) + spriteDraw(art.bossCore, math.floor(cx), math.floor(cy), true) + spriteSetTint(art.bossCore, 255, 255, 255) + -- Bullets. + local tints = { { 255, 80, 220 }, { 80, 230, 255 }, { 255, 230, 80 } } + + for i = #world.bullets, 1, -1 do + local bl = world.bullets[i] + + bl.x = bl.x + bl.vx * dt + bl.y = bl.y + bl.vy * dt + if bl.x < -20 or bl.x > W + 20 or bl.y < -20 or bl.y > H + 20 then + table.remove(world.bullets, i) + else + local c = tints[bl.c] + + spriteSetTint(art.bullet, c[1], c[2], c[3]) + spriteDraw(art.bullet, math.floor(bl.x) - 6, math.floor(bl.y) - 6) + end + end + spriteSetTint(art.bullet, 255, 255, 255) + -- The ship and its fire. + for i = 0, 6 do + local fy = shipY - ((t * 900 + i * 70) % 420) + + K.box(shipX - 2, fy, shipX + 2, fy + 12, 255, 255, 150, 255) + end + px(art.ship, 16, 0, shipX - 32, shipY - 32, 4) + -- Health. + local health = 1 - K.clamp((bar - 81) / 15, 0, 1) + + K.box(120, 18, W - 121, 30, 60, 0, 0, 255) + K.box(122, 20, 122 + (W - 244 - 4) * health, 28, 255, 60, 60, 255) + ptext(W / 2, 36, "BOSS", 2, 255, 255, 255, "center") + if dying and K.hitCount("hats", lastT, t) > 0 then + boom(cx + math.random(-90, 90), cy + math.random(-90, 90), 90, NEON[math.random(1, 6)][1], NEON[math.random(1, 6)][2], 60) + end + emitterDraw(art.boom) + if bar > 96.85 then + K.flash(255, 255, 255, math.floor(255 * K.smooth(96.85, 97, bar))) + end + end, + leave = function(t) + videoPause(video.plasma) + spriteRotate(art.bossArm, 0) + spriteRotateAndScale(art.bossCore, 0, 1) + end, +} + +-- The bonus stage: down the tunnel, the coins pour in on the beat and pile up, and the bonus counts. +ERA.bonus = { + enter = function(t) + hideAll() + nodeSetVisible(world.tunnel, true) + for _, w in ipairs(world.binWalls) do + nodeSetPosition(w.node, w.x, w.y, w.z) + end + world.phase = 0 + world.phaseT = t + world.bonusBase = t + sceneSetSkyIntensity(1.4) + lightSetIntensity(world.sun, 3) + end, + draw = function(t, bar, k) + nodeSetPosition(world.camera, 0, 6, 12) + nodeLookAt(world.camera, 0, -2.5, 0) + world.phase = (world.phase + (t - world.phaseT) * (0.6 + 1.5 * K.decay("kicks", t, 5))) % 1 + world.phaseT = t + videoSeek(video.tunnel, math.floor(world.phase * video.tunnelFrames)) + nodeSetRotation(world.tunnel, 0, 0, t * 30) + local beats = math.floor((K.beat(t) - K.beat(world.bonusBase)) * 2) + + while #world.coins < math.min(COIN_MAX, beats) do + local n = nodeNew() + + nodeSetMesh(n, world.coinMesh, world.coinMaterial) + nodeSetPosition(n, (math.random() - 0.5) * 12, 9, (math.random() - 0.5) * 5) + nodeSetRotation(n, math.random(0, 360), math.random(0, 360), 0) + bodyNew(n, BODY_DYNAMIC, SHAPE_CYLINDER, 0.6, 0.12) + bodySetMass(n, 0.3) + bodySetBounce(n, 0.4) + bodySetAngularVelocity(n, (math.random() - 0.5) * 12, (math.random() - 0.5) * 12, 0) + world.coins[#world.coins + 1] = n + end + ptext(W / 2, 30, "BONUS STAGE", 4, 255, 230, 80, "center") + ptext(W / 2, 80, string.format("%07d", #world.coins * 500), 4, 255, 255, 255, "center") + end, + leave = function(t) + for _, n in ipairs(world.coins) do + bodyDelete(n) + nodeDelete(n) + end + world.coins = {} + for _, w in ipairs(world.binWalls) do + nodeSetPosition(w.node, w.x, w.y - 100, w.z) + end + end, +} + +-- The high score table, which is also the credits. +ERA.scores = { + enter = function(t) + hideAll() + videoPlay(video.plasma) + end, + draw = function(t, bar, k) + videoDraw(video.plasma, 0, 0, W - 1, H - 1) + K.flash(0, 0, 20, 190) + rainbow(W / 2, 40, "HIGH SCORES", 4, t, "center") + local rows = { + { "1ST", "999990", "CODE CLAUDE" }, + { "2ND", "888880", "MUSIC POORARTISTT" }, + { "3RD", "777770", "ENGINE SINGE" }, + { "4TH", "666660", "PIXELS CLAUDE" }, + { "5TH", "555550", "YOU THANKS!" }, + } + + for i, r in ipairs(rows) do + if bar >= 113 + (i - 1) * 1.2 then + local y = 120 + i * 52 + + ptext(40, y, r[1], 3, 255, 255, 255) + ptext(140, y, r[2], 3, 255, 230, 80) + rainbow(330, y, r[3], 2, t + i * 0.3) + end + end + scanlines(120) + end, + leave = function(t) + videoPause(video.plasma) + end, +} + +-- The end: game over, thanks, and the set switched off on the last hit. +ERA.outro = { + enter = function(t) + hideAll() + end, + draw = function(t, bar, k) + K.flash(0, 0, 0, 255) + local p = t - K.barTime(137) + local last = K.duration - 0.9 + + if t < last then + ptext(W / 2, 140, "GAME OVER", 7, 255, 60, 60, "center") + if p > 2 then + rainbow(W / 2, 260, "THANKS FOR PLAYING", 3, t, "center") + end + if p > 4 and (t * 2) % 1 < 0.5 then + ptext(W / 2, 340, "PRESS START", 3, 255, 255, 255, "center") + end + scanlines(160) + else + local q = (t - last) / 0.35 + + if q < 1 then + local h = math.max(2, H * (1 - q) ^ 3) + local w = (q < 0.6) and W or W * (1 - (q - 0.6) / 0.4) + + K.box(W / 2 - w / 2, H / 2 - h / 2, W / 2 + w / 2, H / 2 + h / 2, 255, 255, 255, 255) + end + end + end, +} + +-- The finale runs the eras again, two bars each, every one on its own beat; its time is moved by +-- whole bars, so the beat lands where it did. +local MONTAGE = { + { era = "pong", bar = 5, label = "1-BIT" }, { era = "invaders", bar = 9, label = "8-BIT" }, { era = "runner", bar = 17, label = "16-BIT" }, + { era = "racer", bar = 25, label = "16-BIT" }, { era = "polygons", bar = 49, label = "32-BIT" }, { era = "boss", bar = 85, label = "BOSS" }, + { era = "bonus", bar = 97, label = "BONUS" }, +} + +ERA.montage = { + enter = function(t) + world.montageCut = 0 + end, + draw = function(t, bar, k) + local cut = math.floor((bar - 121) / 2) + 1 + local final = cut > #MONTAGE + local m = MONTAGE[math.min(cut, #MONTAGE)] + + if final then + -- The last two bars: the name, slammed in on the downbeat, over everything flashing. + if world.montageCut ~= cut then + if world.montageEra and ERA[world.montageEra].leave then + ERA[world.montageEra].leave(t) + end + world.montageEra = nil + world.montageCut = cut + hideAll() + end + local r, g, b = K.hue(t * 0.7) + + K.flash(r // 3, g // 3, b // 3, 255) + local s = 10 + 4 * math.exp(-(bar - 135) * 6) + + rainbow(W / 2, 170, "GAME ON", math.floor(s), t, "center") + K.strobe(t, "kicks", 12, 255, 255, 255, 120) + scanlines(160) + return + end + local shift = K.barTime(m.bar) - K.barTime(121 + (cut - 1) * 2) + local et = t + shift + + if world.montageCut ~= cut then + if world.montageEra and ERA[world.montageEra].leave then + ERA[world.montageEra].leave(t) + end + world.montageEra = m.era + world.montageCut = cut + ERA[m.era].enter(et) + end + local saved = lastT + + lastT = saved + shift + ERA[m.era].draw(et, K.bar(et), 0) + lastT = saved + ptext(W - 20 - #m.label * 24, H - 40, m.label, 3, 255, 255, 255) + K.flash(255, 255, 255, math.floor(220 * math.exp(-((bar - 121) % 2) * 2 * 1.7778 * 10))) + end, + leave = function(t) + if world.montageEra and ERA[world.montageEra].leave then + ERA[world.montageEra].leave(t) + end + end, +} + + +local function place(era, from, to) + return { from = from, to = to, enter = ERA[era].enter, draw = ERA[era].draw, leave = ERA[era].leave } +end + + +local SCENES = { + place("boot", 0, 5), + place("pong", 5, 9), + place("invaders", 9, 17), + place("runner", 17, 25), + place("racer", 25, 33), + place("loading", 33, 41), + place("polygons", 41, 57), + place("modern", 57, 73), + place("continue", 73, 81), + place("boss", 81, 97), + place("bonus", 97, 113), + place("scores", 113, 121), + place("montage", 121, 137), + place("outro", 137, 200), + -- The time at the end of each frame, for "what happened since last frame". + { + from = -10, to = 1000, + draw = function(t, bar, k) + lastT = t + end, + }, +} + +-- A ball meeting a brick throws sparks where they met. +function onCollision(a, b, x, y, z, speed) + if speed > 4 then + nodeSetPosition(world.spark, x, y, z) + emitterBurst(world.sparks, math.min(60, math.floor(speed * 3))) + end +end + +loadArt() +buildWorld() +hideAll() +K.run(SCENES) diff --git a/demos/insertCoin/music.mp3 b/demos/insertCoin/music.mp3 new file mode 100644 index 000000000..1cb0d74de --- /dev/null +++ b/demos/insertCoin/music.mp3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ee7b2aab6dd964d89861e5846aadb1cfe5cd5a4674d7727724c12fbd0d2d01c6 +size 7993344 diff --git a/demos/insertCoin/sync.lua b/demos/insertCoin/sync.lua new file mode 100644 index 000000000..057c06ed5 --- /dev/null +++ b/demos/insertCoin/sync.lua @@ -0,0 +1,337 @@ +-- Written by util/demoSync.py from music.mp3: what the demo synchronises to. Times are seconds of +-- music; envelopes are 60 samples a second, one character each, 0 to 63 in the base64 alphabet. +return { + duration = 249.792, + rate = 60, + barStart = 1, -- The beat (counting from 1) that begins the first whole bar + beats = { + 0.0067, 0.4511, 0.8956, 1.3400, 1.7844, 2.2289, 2.6733, 3.1178, 3.5622, 4.0067, 4.4511, 4.8955, + 5.3400, 5.7844, 6.2289, 6.6733, 7.1178, 7.5622, 8.0067, 8.4511, 8.8955, 9.3400, 9.7844, 10.2289, + 10.6733, 11.1178, 11.5622, 12.0066, 12.4511, 12.8955, 13.3400, 13.7844, 14.2289, 14.6733, 15.1178, 15.5622, + 16.0066, 16.4511, 16.8955, 17.3400, 17.7844, 18.2289, 18.6733, 19.1177, 19.5622, 20.0066, 20.4511, 20.8955, + 21.3400, 21.7844, 22.2289, 22.6733, 23.1177, 23.5622, 24.0066, 24.4511, 24.8955, 25.3400, 25.7844, 26.2288, + 26.6733, 27.1177, 27.5622, 28.0066, 28.4511, 28.8955, 29.3400, 29.7844, 30.2288, 30.6733, 31.1177, 31.5622, + 32.0066, 32.4511, 32.8955, 33.3399, 33.7844, 34.2288, 34.6733, 35.1177, 35.5622, 36.0066, 36.4511, 36.8955, + 37.3399, 37.7844, 38.2288, 38.6733, 39.1177, 39.5622, 40.0066, 40.4510, 40.8955, 41.3399, 41.7844, 42.2288, + 42.6733, 43.1177, 43.5622, 44.0066, 44.4510, 44.8955, 45.3399, 45.7844, 46.2288, 46.6733, 47.1177, 47.5621, + 48.0066, 48.4510, 48.8955, 49.3399, 49.7844, 50.2288, 50.6733, 51.1177, 51.5621, 52.0066, 52.4510, 52.8955, + 53.3399, 53.7844, 54.2288, 54.6732, 55.1177, 55.5621, 56.0066, 56.4510, 56.8955, 57.3399, 57.7844, 58.2288, + 58.6732, 59.1177, 59.5621, 60.0066, 60.4510, 60.8955, 61.3399, 61.7843, 62.2288, 62.6732, 63.1177, 63.5621, + 64.0066, 64.4510, 64.8955, 65.3399, 65.7843, 66.2288, 66.6732, 67.1177, 67.5621, 68.0066, 68.4510, 68.8955, + 69.3399, 69.7843, 70.2288, 70.6732, 71.1177, 71.5621, 72.0066, 72.4510, 72.8954, 73.3399, 73.7843, 74.2288, + 74.6732, 75.1177, 75.5621, 76.0066, 76.4510, 76.8954, 77.3399, 77.7843, 78.2288, 78.6732, 79.1177, 79.5621, + 80.0065, 80.4510, 80.8954, 81.3399, 81.7843, 82.2288, 82.6732, 83.1177, 83.5621, 84.0065, 84.4510, 84.8954, + 85.3399, 85.7843, 86.2288, 86.6732, 87.1176, 87.5621, 88.0065, 88.4510, 88.8954, 89.3399, 89.7843, 90.2288, + 90.6732, 91.1176, 91.5621, 92.0065, 92.4510, 92.8954, 93.3399, 93.7843, 94.2287, 94.6732, 95.1176, 95.5621, + 96.0065, 96.4510, 96.8954, 97.3399, 97.7843, 98.2287, 98.6732, 99.1176, 99.5621, 100.0065, 100.4510, 100.8954, + 101.3398, 101.7843, 102.2287, 102.6732, 103.1176, 103.5621, 104.0065, 104.4510, 104.8954, 105.3398, 105.7843, 106.2287, + 106.6732, 107.1176, 107.5621, 108.0065, 108.4509, 108.8954, 109.3398, 109.7843, 110.2287, 110.6732, 111.1176, 111.5621, + 112.0065, 112.4509, 112.8954, 113.3398, 113.7843, 114.2287, 114.6732, 115.1176, 115.5620, 116.0065, 116.4509, 116.8954, + 117.3398, 117.7843, 118.2287, 118.6732, 119.1176, 119.5620, 120.0065, 120.4509, 120.8954, 121.3398, 121.7843, 122.2287, + 122.6731, 123.1176, 123.5620, 124.0065, 124.4509, 124.8954, 125.3398, 125.7843, 126.2287, 126.6731, 127.1176, 127.5620, + 128.0065, 128.4509, 128.8954, 129.3398, 129.7842, 130.2287, 130.6731, 131.1176, 131.5620, 132.0065, 132.4509, 132.8954, + 133.3398, 133.7842, 134.2287, 134.6731, 135.1176, 135.5620, 136.0065, 136.4509, 136.8953, 137.3398, 137.7842, 138.2287, + 138.6731, 139.1176, 139.5620, 140.0065, 140.4509, 140.8953, 141.3398, 141.7842, 142.2287, 142.6731, 143.1176, 143.5620, + 144.0064, 144.4509, 144.8953, 145.3398, 145.7842, 146.2287, 146.6731, 147.1176, 147.5620, 148.0064, 148.4509, 148.8953, + 149.3398, 149.7842, 150.2287, 150.6731, 151.1175, 151.5620, 152.0064, 152.4509, 152.8953, 153.3398, 153.7842, 154.2287, + 154.6731, 155.1175, 155.5620, 156.0064, 156.4509, 156.8953, 157.3398, 157.7842, 158.2286, 158.6731, 159.1175, 159.5620, + 160.0064, 160.4509, 160.8953, 161.3398, 161.7842, 162.2286, 162.6731, 163.1175, 163.5620, 164.0064, 164.4509, 164.8953, + 165.3397, 165.7842, 166.2286, 166.6731, 167.1175, 167.5620, 168.0064, 168.4509, 168.8953, 169.3397, 169.7842, 170.2286, + 170.6731, 171.1175, 171.5620, 172.0064, 172.4508, 172.8953, 173.3397, 173.7842, 174.2286, 174.6731, 175.1175, 175.5620, + 176.0064, 176.4508, 176.8953, 177.3397, 177.7842, 178.2286, 178.6731, 179.1175, 179.5619, 180.0064, 180.4508, 180.8953, + 181.3397, 181.7842, 182.2286, 182.6731, 183.1175, 183.5619, 184.0064, 184.4508, 184.8953, 185.3397, 185.7842, 186.2286, + 186.6730, 187.1175, 187.5619, 188.0064, 188.4508, 188.8953, 189.3397, 189.7842, 190.2286, 190.6730, 191.1175, 191.5619, + 192.0064, 192.4508, 192.8953, 193.3397, 193.7841, 194.2286, 194.6730, 195.1175, 195.5619, 196.0064, 196.4508, 196.8953, + 197.3397, 197.7841, 198.2286, 198.6730, 199.1175, 199.5619, 200.0064, 200.4508, 200.8952, 201.3397, 201.7841, 202.2286, + 202.6730, 203.1175, 203.5619, 204.0064, 204.4508, 204.8952, 205.3397, 205.7841, 206.2286, 206.6730, 207.1175, 207.5619, + 208.0063, 208.4508, 208.8952, 209.3397, 209.7841, 210.2286, 210.6730, 211.1175, 211.5619, 212.0063, 212.4508, 212.8952, + 213.3397, 213.7841, 214.2286, 214.6730, 215.1174, 215.5619, 216.0063, 216.4508, 216.8952, 217.3397, 217.7841, 218.2286, + 218.6730, 219.1174, 219.5619, 220.0063, 220.4508, 220.8952, 221.3397, 221.7841, 222.2285, 222.6730, 223.1174, 223.5619, + 224.0063, 224.4508, 224.8952, 225.3397, 225.7841, 226.2285, 226.6730, 227.1174, 227.5619, 228.0063, 228.4508, 228.8952, + 229.3396, 229.7841, 230.2285, 230.6730, 231.1174, 231.5619, 232.0063, 232.4508, 232.8952, 233.3396, 233.7841, 234.2285, + 234.6730, 235.1174, 235.5619, 236.0063, 236.4507, 236.8952, 237.3396, 237.7841, 238.2285, 238.6730, 239.1174, 239.5619, + 240.0063, 240.4507, 240.8952, 241.3396, 241.7841, 242.2285, 242.6730, 243.1174, 243.5618, 244.0063, 244.4507, 244.8952, + 245.3396, 245.7841, 246.2285, 246.6730, 247.1174, 247.5618, 248.0063, 248.4507, 248.8952, 249.3396, 249.7841, + }, + kicks = { + 0.012, 0.174, 0.511, 0.731, 0.952, 1.091, 1.277, 1.509, 1.730, 1.950, 2.287, 2.508, + 2.728, 2.961, 3.088, 3.286, 3.506, 3.727, 4.063, 4.389, 4.621, 4.841, 5.062, 5.283, + 5.503, 5.840, 6.072, 6.281, 6.420, 6.618, 6.838, 7.059, 7.279, 7.523, 7.732, 7.953, + 8.173, 8.406, 8.638, 8.835, 9.056, 9.288, 9.509, 9.741, 9.950, 10.194, 10.414, 10.612, + 11.064, 11.505, 11.749, 11.970, 12.179, 12.388, 12.620, 12.852, 13.293, 13.526, 13.746, 14.187, + 14.408, 14.629, 14.861, 15.070, 15.302, 15.523, 15.743, 15.964, 16.300, 16.637, 16.846, 17.194, + 17.508, 17.728, 17.949, 18.181, 18.402, 18.622, 18.843, 18.971, 19.284, 19.505, 19.737, 19.958, + 20.178, 20.410, 20.619, 20.852, 21.060, 21.293, 21.525, 21.745, 21.966, 22.187, 22.407, 22.639, + 22.860, 23.081, 23.301, 23.510, 23.859, 24.184, 24.404, 24.648, 24.845, 25.066, 25.287, 25.507, + 25.728, 25.972, 26.180, 26.401, 26.529, 26.842, 27.063, 27.283, 27.527, 27.980, 28.386, 28.619, + 28.851, 29.083, 29.292, 29.524, 29.745, 29.977, 30.186, 30.627, 30.848, 31.057, 31.521, 31.730, + 31.985, 32.171, 32.403, 32.624, 32.868, 33.065, 33.297, 33.506, 33.727, 33.982, 34.180, 34.400, + 34.621, 34.842, 35.074, 35.294, 35.527, 35.759, 35.944, 36.200, 36.397, 36.850, 37.082, 37.291, + 37.512, 37.732, 37.953, 38.185, 38.534, 38.847, 38.975, 39.288, 39.520, 39.729, 39.973, 40.171, + 40.403, 40.623, 40.867, 41.064, 41.297, 41.506, 41.761, 41.947, 42.202, 42.423, 42.620, 42.864, + 43.061, 43.317, 43.514, 43.979, 44.408, 44.849, 45.070, 45.291, 45.511, 45.743, 45.964, 46.184, + 46.393, 46.614, 46.846, 47.055, 47.287, 47.496, 47.729, 47.972, 48.170, 48.402, 48.623, 48.866, + 49.087, 49.296, 49.528, 49.749, 49.969, 50.167, 50.643, 50.863, 51.072, 51.316, 51.513, 51.734, + 51.943, 52.187, 52.396, 52.616, 52.849, 53.081, 53.290, 53.510, 53.743, 53.952, 54.172, 54.393, + 54.625, 54.846, 55.089, 55.287, 55.507, 55.728, 55.983, 56.181, 56.413, 56.633, 56.854, 57.179, + 57.493, 57.620, 57.853, 58.282, 58.549, 58.770, 58.897, 59.106, 59.582, 59.849, 60.383, 61.057, + 61.382, 61.603, 61.753, 62.171, 62.404, 62.845, 63.065, 63.414, 63.727, 63.959, 64.180, 64.389, + 64.563, 64.830, 65.167, 65.515, 65.724, 65.910, 66.363, 66.630, 66.955, 67.106, 67.291, 67.500, + 67.837, 68.290, 68.429, 68.743, 69.300, 69.730, 70.171, 70.426, 70.763, 70.960, 71.285, 71.517, + 71.726, 71.947, 72.400, 72.632, 72.841, 73.062, 73.294, 73.514, 73.735, 73.956, 74.188, 74.315, + 74.513, 74.838, 75.059, 75.291, 75.500, 75.732, 75.976, 76.289, 76.626, 76.835, 77.172, 77.299, + 77.508, 77.717, 77.949, 78.182, 78.507, 78.634, 78.855, 79.064, 79.285, 79.505, 79.726, 79.853, + 80.179, 80.411, 80.620, 80.852, 81.061, 81.281, 81.514, 81.723, 82.059, 82.500, 82.837, 83.058, + 83.290, 83.499, 83.731, 83.952, 84.288, 84.428, 84.625, 84.834, 85.066, 85.287, 85.624, 85.960, + 86.169, 86.390, 86.622, 86.854, 87.063, 87.284, 87.516, 87.841, 87.969, 88.178, 88.317, 88.631, + 88.851, 89.060, 89.281, 89.501, 89.722, 90.059, 90.500, 90.836, 91.057, 91.278, 91.510, 91.847, + 92.183, 92.404, 92.740, 92.868, 93.077, 93.286, 93.623, 94.064, 94.412, 94.610, 94.842, 95.074, + 95.411, 95.736, 95.945, 96.282, 96.432, 96.723, 97.176, 97.617, 98.058, 98.209, 98.406, 98.615, + 98.952, 99.289, 99.509, 99.730, 99.950, 100.171, 100.391, 100.647, 100.856, 101.065, 101.193, 101.529, + 101.727, 101.959, 102.168, 102.400, 102.621, 102.841, 103.062, 103.282, 103.410, 103.549, 103.724, 103.956, + 104.176, 104.304, 104.432, 104.618, 104.838, 105.059, 105.186, 105.326, 105.500, 105.732, 105.953, 106.173, + 106.405, 106.649, 106.858, 107.079, 107.288, 107.520, 107.729, 107.961, 108.170, 108.391, 108.623, 108.844, + 109.064, 109.285, 109.505, 109.633, 109.958, 110.167, 110.388, 110.527, 110.840, 110.968, 111.096, 111.282, + 111.409, 111.549, 111.723, 111.851, 111.978, 112.176, 112.396, 112.617, 112.744, 112.872, 113.058, 113.186, + 113.313, 113.499, 113.755, 113.952, 114.184, 114.393, 114.637, 114.846, 115.066, 115.299, 115.508, 115.728, + 115.960, 116.169, 116.390, 116.622, 116.750, 117.063, 117.191, 117.505, 117.632, 117.772, 117.946, 118.073, + 118.201, 118.399, 118.526, 118.654, 118.840, 119.060, 119.281, 119.501, 119.722, 119.954, 120.175, 120.407, + 120.628, 120.848, 121.092, 121.301, 121.510, 121.742, 121.986, 122.195, 122.427, 122.636, 122.845, 123.066, + 123.286, 123.507, 123.728, 123.855, 124.169, 124.401, 124.621, 124.842, 125.063, 125.283, 125.504, 125.724, + 125.945, 126.177, 126.398, 126.618, 126.839, 127.060, 127.280, 127.512, 127.733, 127.861, 127.988, 128.290, + 128.615, 128.848, 129.068, 129.289, 129.625, 129.753, 129.962, 130.183, 130.624, 131.077, 131.286, 131.518, + 131.646, 131.843, 131.971, 132.180, 132.331, 132.644, 132.853, 133.294, 133.817, 134.049, 134.200, 134.409, + 134.757, 135.070, 135.512, 135.976, 136.185, 136.394, 136.533, 136.731, 136.963, 137.195, 137.509, 138.077, + 138.623, 138.774, 138.960, 139.297, 139.517, 139.738, 139.958, 140.399, 140.632, 140.945, 141.084, 141.293, + 141.526, 141.758, 142.013, 142.187, 142.396, 142.861, 143.058, 143.302, 143.430, 143.859, 144.184, 144.393, + 144.742, 145.078, 145.299, 145.508, 145.752, 146.065, 146.216, 146.506, 146.947, 147.296, 147.505, 147.737, + 147.958, 148.178, 148.399, 148.619, 148.747, 149.165, 149.525, 149.722, 150.071, 150.407, 150.616, 150.848, + 151.069, 151.290, 151.499, 151.731, 151.963, 152.184, 152.416, 152.625, 152.857, 153.078, 153.287, 153.507, + 153.728, 153.948, 154.169, 154.389, 154.622, 154.842, 154.970, 155.283, 155.504, 155.725, 155.957, 156.177, + 156.305, 156.607, 156.746, 157.071, 157.280, 157.513, 157.722, 158.070, 158.407, 158.616, 158.848, 159.080, + 159.289, 159.498, 159.730, 159.974, 160.287, 160.624, 160.845, 161.065, 161.286, 161.506, 161.727, 161.948, + 162.180, 162.400, 162.621, 162.946, 163.283, 163.410, 163.736, 163.944, 164.188, 164.397, 164.746, 165.071, + 165.280, 165.512, 165.721, 165.953, 166.185, 166.394, 166.615, 166.847, 167.079, 167.288, 167.509, 167.729, + 167.950, 168.171, 168.391, 168.623, 168.844, 169.064, 169.285, 169.506, 169.738, 169.958, 170.179, 170.516, + 170.841, 171.050, 171.282, 171.503, 171.735, 171.944, 172.188, 172.397, 172.617, 172.745, 173.070, 173.279, + 173.511, 173.720, 173.952, 174.196, 174.393, 174.614, 174.846, 175.067, 175.287, 175.508, 175.729, 175.949, + 176.170, 176.390, 176.623, 176.832, 177.075, 177.296, 177.517, 177.749, 177.958, 178.167, 178.399, 178.620, + 178.852, 178.979, 179.293, 179.421, 179.734, 179.955, 180.175, 180.407, 180.628, 180.860, 181.069, 181.290, + 181.615, 181.952, 182.172, 182.393, 182.613, 182.846, 183.066, 183.287, 183.507, 183.728, 183.948, 184.169, + 184.401, 184.622, 184.842, 185.075, 185.272, 185.516, 185.725, 185.957, 186.085, 186.514, 186.642, 186.839, + 187.072, 187.292, 187.501, 187.733, 187.966, 188.186, 188.395, 188.616, 188.836, 189.068, 189.289, 189.510, + 189.730, 189.951, 190.183, 190.392, 190.624, 190.845, 191.065, 191.286, 191.507, 191.727, 191.855, 192.180, + 192.308, 192.749, 193.074, 193.202, 193.527, 193.747, 193.956, 194.165, 194.397, 194.630, 194.850, 195.059, + 195.291, 195.524, 195.733, 195.953, 196.174, 196.394, 196.615, 196.836, 197.056, 197.288, 197.497, 197.730, + 197.950, 198.171, 198.391, 198.623, 198.844, 199.065, 199.297, 199.506, 199.738, 199.866, 200.179, 200.388, + 200.620, 200.748, 201.062, 201.294, 201.514, 201.723, 201.956, 202.188, 202.397, 202.629, 202.838, 203.059, + 203.291, 203.511, 203.732, 203.952, 204.173, 204.394, 204.614, 204.835, 205.067, 205.299, 205.624, 205.764, + 205.949, 206.077, 206.518, 206.843, 206.971, 207.296, 207.424, 207.737, 207.958, 208.179, 208.387, 208.620, + 208.840, 209.072, 209.281, 209.514, 209.723, 209.955, 210.175, 210.396, 210.617, 210.837, 211.058, 211.278, + 211.511, 211.731, 211.952, 212.172, 212.405, 212.614, 212.834, 213.055, 213.287, 213.519, 213.716, 213.949, + 214.169, 214.390, 214.610, 214.831, 215.052, 215.284, 215.412, 215.725, 215.946, 216.166, 216.387, 216.619, + 216.840, 217.072, 217.281, 217.501, 217.629, 217.942, 218.070, 218.395, 218.616, 218.836, 219.057, 219.278, + 219.405, 219.730, 219.951, 220.172, 220.404, 220.624, 220.833, 221.054, 221.275, 221.518, 221.716, 221.948, + 222.169, 222.389, 222.610, 222.842, 223.051, 223.283, 223.504, 223.724, 223.945, 224.189, 224.386, 224.618, + 224.839, 225.059, 225.292, 225.501, 225.628, 225.942, 226.069, 226.395, 226.615, 226.836, 226.963, 227.277, + 227.521, 227.730, 227.939, 228.171, 228.391, 228.612, 228.833, 229.076, 229.285, 229.506, 229.727, 229.947, + 230.075, 230.388, 230.609, 230.841, 231.062, 231.282, 231.503, 231.724, 231.956, 232.165, 232.292, 232.618, + 232.838, 233.059, 233.186, 233.500, 233.744, 233.953, 234.173, 234.394, 234.626, 234.847, 235.056, 235.276, + 235.497, 235.729, 235.938, 236.170, 236.391, 236.611, 236.832, 237.064, 237.273, 237.505, 237.726, 237.946, + 238.074, 238.388, 238.608, 238.829, 239.061, 239.293, 239.502, 239.723, 239.851, 239.990, 240.187, 240.396, + 240.617, 240.837, 241.058, 241.290, 241.511, 241.731, 242.393, 242.649, 242.858, 243.078, 243.287, 243.519, + 243.659, 244.065, 244.402, 244.645, 244.843, 245.098, 245.284, 245.412, 245.841, 246.062, 246.201, 246.410, + 246.631, 246.840, 247.095, 247.397, 247.652, 247.966, 248.186, 248.848, + }, + snares = { + 0.012, 0.197, 0.522, 0.859, 1.080, 1.300, 1.521, 1.741, 1.974, 2.299, 2.635, 2.856, + 3.077, 3.297, 3.518, 3.646, 4.075, 4.412, 4.632, 4.853, 5.074, 5.294, 5.422, 5.851, + 6.188, 6.409, 6.641, 6.850, 7.070, 7.523, 7.964, 8.185, 8.406, 8.847, 9.079, 9.300, + 9.741, 9.973, 10.182, 10.623, 10.751, 11.076, 11.517, 11.749, 11.958, 12.399, 12.527, 12.852, + 13.293, 13.514, 13.746, 14.187, 14.629, 15.070, 15.302, 15.523, 15.859, 16.184, 16.405, 16.742, + 17.078, 17.299, 17.740, 18.181, 18.530, 18.855, 19.075, 19.412, 19.749, 19.958, 20.306, 20.631, + 20.852, 21.304, 21.734, 22.082, 22.407, 22.628, 22.965, 23.301, 23.522, 23.963, 24.184, 24.404, + 24.845, 25.298, 25.739, 25.960, 26.180, 26.633, 26.854, 27.074, 27.411, 27.957, 28.410, 28.851, + 29.187, 29.524, 29.733, 30.186, 30.407, 30.627, 31.068, 31.300, 31.509, 31.962, 32.403, 32.856, + 33.077, 33.297, 33.739, 33.959, 34.180, 34.528, 34.853, 35.074, 35.515, 35.956, 36.304, 36.525, + 36.850, 37.187, 37.407, 37.732, 38.185, 38.406, 38.626, 39.068, 39.520, 39.857, 40.194, 40.403, + 40.856, 41.076, 41.297, 41.633, 41.854, 42.179, 42.632, 43.073, 43.410, 43.746, 43.955, 44.408, + 44.629, 44.849, 45.198, 45.523, 45.743, 46.184, 46.626, 47.078, 47.299, 47.520, 47.961, 48.193, + 48.402, 48.855, 49.075, 49.296, 49.749, 50.178, 50.631, 50.852, 51.072, 51.409, 51.746, 51.955, + 52.303, 52.628, 52.849, 53.290, 53.731, 54.184, 54.416, 54.625, 55.078, 55.298, 55.519, 55.856, + 56.076, 56.401, 56.854, 57.644, 57.853, 58.061, 58.630, 59.617, 59.745, 60.407, 60.976, 61.196, + 61.510, 62.183, 63.077, 63.414, 63.739, 63.971, 64.540, 64.737, 65.190, 65.736, 66.630, 66.966, + 67.303, 67.512, 68.406, 69.079, 69.300, 69.741, 70.182, 70.415, 70.635, 70.856, 71.076, 71.517, + 71.866, 72.191, 72.400, 72.632, 72.853, 73.073, 73.294, 73.642, 73.967, 74.188, 74.629, 74.966, + 75.407, 75.743, 75.964, 76.301, 76.637, 76.858, 77.195, 77.415, 77.740, 78.182, 78.623, 78.971, + 79.296, 79.517, 79.749, 79.970, 80.190, 80.411, 80.747, 81.084, 81.293, 81.746, 82.083, 82.524, + 82.849, 83.069, 83.302, 83.522, 83.743, 83.963, 84.300, 84.637, 84.857, 85.299, 85.740, 86.192, + 86.413, 86.634, 87.075, 87.307, 87.516, 87.969, 88.189, 88.410, 88.851, 89.188, 89.525, 89.745, + 89.966, 90.186, 90.627, 91.069, 91.417, 91.742, 91.963, 92.404, 92.752, 93.298, 93.530, 93.739, + 94.192, 94.412, 94.633, 94.854, 95.074, 95.306, 95.515, 95.968, 96.409, 96.850, 97.083, 97.292, + 97.744, 97.965, 98.186, 98.627, 98.963, 99.521, 99.962, 100.182, 100.403, 100.635, 100.844, 101.297, + 101.518, 101.738, 102.179, 102.412, 102.632, 103.073, 103.294, 103.515, 103.967, 104.188, 104.409, 104.850, + 105.082, 105.291, 105.744, 105.964, 106.185, 106.626, 107.067, 107.520, 107.741, 107.961, 108.402, 108.635, + 108.844, 109.296, 109.517, 109.738, 110.190, 110.631, 111.073, 111.293, 111.514, 111.967, 112.187, 112.408, + 112.849, 113.081, 113.302, 113.743, 114.184, 114.625, 114.858, 115.066, 115.415, 115.740, 115.960, 116.402, + 116.634, 116.843, 117.296, 117.737, 118.190, 118.410, 118.631, 119.072, 119.293, 119.513, 119.966, 120.186, + 120.407, 120.848, 121.080, 121.289, 121.742, 121.963, 122.183, 122.625, 122.857, 123.077, 123.414, 123.739, + 123.960, 124.413, 124.854, 125.295, 125.515, 125.736, 126.189, 126.409, 126.630, 126.967, 127.303, 127.512, + 127.861, 128.627, 129.080, 129.300, 129.753, 129.974, 130.194, 130.531, 131.077, 131.518, 132.075, 132.307, + 133.294, 134.409, 134.629, 135.070, 135.407, 135.744, 135.964, 136.185, 136.417, 136.626, 136.858, 137.195, + 137.416, 137.741, 137.961, 138.194, 138.414, 138.635, 138.971, 139.192, 139.413, 139.633, 139.865, 140.411, + 140.748, 140.968, 141.189, 141.526, 141.746, 142.187, 142.629, 143.070, 143.302, 143.523, 143.964, 144.196, + 144.405, 144.858, 145.078, 145.299, 145.740, 146.181, 146.634, 146.855, 147.075, 147.516, 147.749, 147.958, + 148.410, 148.631, 148.852, 149.072, 149.293, 149.745, 150.187, 150.407, 150.628, 151.069, 151.301, 151.522, + 151.963, 152.184, 152.404, 152.857, 153.298, 153.739, 153.972, 154.180, 154.633, 154.854, 155.074, 155.527, + 155.736, 155.957, 156.410, 156.851, 157.304, 157.524, 157.733, 158.081, 158.418, 158.627, 159.080, 159.300, + 159.521, 159.962, 160.183, 160.403, 160.740, 161.077, 161.297, 161.634, 161.959, 162.180, 162.633, 162.853, + 163.074, 163.515, 163.747, 163.968, 164.409, 164.629, 164.850, 165.187, 165.523, 165.744, 166.185, 166.406, + 166.626, 167.079, 167.520, 167.962, 168.182, 168.403, 168.856, 169.076, 169.297, 169.622, 169.854, 170.075, + 170.527, 170.852, 171.073, 171.410, 171.746, 171.967, 172.408, 172.629, 172.849, 173.186, 173.523, 173.743, + 174.184, 174.417, 174.626, 174.962, 175.299, 175.520, 175.961, 176.181, 176.402, 176.855, 177.075, 177.296, + 177.737, 177.969, 178.178, 178.527, 178.852, 179.072, 179.409, 179.746, 179.955, 180.303, 180.628, 180.849, + 181.301, 181.743, 182.079, 182.404, 182.625, 183.078, 183.298, 183.519, 183.960, 184.181, 184.413, 184.633, + 184.854, 185.295, 185.632, 185.969, 186.178, 186.410, 186.630, 186.851, 187.072, 187.408, 187.745, 187.954, + 188.407, 188.627, 188.848, 189.185, 189.521, 189.742, 189.962, 190.183, 190.415, 190.624, 190.973, 191.298, + 191.518, 191.855, 192.401, 192.737, 193.074, 193.295, 193.631, 193.968, 194.188, 194.630, 194.862, 195.071, + 195.524, 195.953, 196.301, 196.627, 196.847, 197.079, 197.300, 197.521, 197.741, 198.194, 198.415, 198.635, + 198.972, 199.413, 199.750, 199.970, 200.191, 200.411, 200.748, 201.085, 201.294, 201.747, 201.967, 202.188, + 202.629, 202.966, 203.523, 203.743, 203.964, 204.405, 204.626, 204.846, 205.195, 205.740, 206.182, 206.518, + 207.076, 207.296, 207.517, 207.970, 208.190, 208.411, 208.631, 208.852, 209.084, 209.293, 209.525, 209.746, + 209.966, 210.187, 210.628, 210.860, 211.069, 211.522, 211.743, 211.963, 212.405, 212.625, 212.846, 213.078, + 213.299, 213.740, 214.192, 214.413, 214.622, 214.970, 215.295, 215.516, 215.969, 216.189, 216.410, 216.851, + 217.292, 217.629, 217.966, 218.186, 218.627, 218.848, 219.069, 219.521, 219.742, 219.963, 220.183, 220.404, + 220.845, 221.193, 221.518, 221.739, 222.076, 222.401, 222.621, 222.970, 223.295, 223.515, 223.747, 223.968, + 224.409, 224.746, 225.083, 225.292, 225.744, 225.965, 226.186, 226.522, 226.743, 227.080, 227.300, 227.521, + 227.962, 228.403, 228.624, 228.844, 229.297, 229.518, 229.738, 230.075, 230.412, 230.621, 231.073, 231.515, + 231.851, 232.188, 232.409, 232.745, 233.070, 233.291, 233.628, 233.964, 234.185, 234.417, 234.626, 234.963, + 235.416, 235.741, 235.961, 236.414, 236.623, 236.844, 237.192, 237.517, 237.738, 237.970, 238.179, 238.620, + 238.968, 239.189, 239.514, 239.967, 240.187, 240.408, 240.744, 241.081, 241.290, 241.743, 242.300, 242.637, + 242.858, 243.078, 243.299, 243.519, 243.740, 244.077, 244.413, 244.634, 244.854, 245.075, 245.296, 245.528, + 245.853, 246.190, 246.410, 246.631, 246.851, 247.072, 247.304, 247.629, 248.407, 248.628, 248.848, + }, + hats = { + 0.012, 0.197, 0.418, 0.522, 0.615, 0.755, 1.091, 1.173, 1.312, 1.649, 1.974, 2.310, + 2.531, 2.612, 2.868, 3.088, 3.193, 3.286, 3.413, 3.506, 3.750, 4.075, 4.180, 4.307, + 4.644, 4.865, 5.062, 5.201, 5.526, 5.608, 5.863, 5.944, 6.084, 6.165, 6.583, 7.070, + 7.523, 7.755, 7.964, 8.197, 8.406, 8.638, 8.847, 9.079, 9.300, 9.532, 9.741, 9.973, + 10.182, 10.426, 10.635, 10.855, 11.076, 11.517, 11.749, 11.958, 12.202, 12.411, 12.632, 12.852, + 13.293, 13.514, 13.746, 14.187, 14.524, 14.629, 14.965, 15.081, 15.302, 15.418, 15.523, 15.859, + 15.964, 16.184, 16.300, 16.405, 16.742, 16.858, 17.078, 17.194, 17.299, 17.752, 18.077, 18.181, + 18.518, 18.634, 18.855, 18.971, 19.075, 19.412, 19.516, 19.644, 19.749, 19.865, 19.958, 20.294, + 20.410, 20.526, 20.631, 20.747, 20.852, 20.991, 21.304, 21.629, 21.734, 22.082, 22.187, 22.407, + 22.523, 22.628, 22.965, 23.081, 23.197, 23.301, 23.522, 23.754, 23.859, 23.963, 24.091, 24.184, + 24.300, 24.404, 24.857, 25.194, 25.298, 25.635, 25.751, 25.972, 26.076, 26.180, 26.517, 26.633, + 26.749, 26.854, 26.970, 27.074, 27.411, 27.527, 27.957, 28.410, 28.862, 29.083, 29.187, 29.304, + 29.524, 29.745, 29.965, 30.081, 30.186, 30.302, 30.407, 30.523, 30.627, 30.964, 31.080, 31.196, + 31.300, 31.521, 31.962, 32.194, 32.299, 32.403, 32.752, 32.856, 32.972, 33.077, 33.193, 33.297, + 33.634, 33.739, 33.866, 33.959, 34.180, 34.528, 34.633, 34.749, 34.853, 35.074, 35.515, 35.747, + 35.852, 35.968, 36.304, 36.409, 36.525, 36.629, 36.746, 36.850, 37.187, 37.303, 37.419, 37.523, + 37.640, 37.732, 38.081, 38.185, 38.313, 38.406, 38.522, 38.626, 39.079, 39.195, 39.404, 39.520, + 39.857, 39.973, 40.078, 40.194, 40.298, 40.403, 40.635, 40.739, 40.856, 40.972, 41.076, 41.192, + 41.297, 41.633, 41.749, 41.866, 42.191, 42.632, 43.085, 43.410, 43.526, 43.642, 43.746, 43.862, + 43.967, 44.199, 44.304, 44.408, 44.524, 44.629, 44.745, 44.849, 45.186, 45.302, 45.418, 45.523, + 45.743, 46.184, 46.521, 46.626, 46.962, 47.078, 47.195, 47.299, 47.520, 47.752, 47.856, 47.961, + 48.089, 48.193, 48.414, 48.750, 48.855, 48.971, 49.075, 49.308, 49.540, 49.749, 49.969, 50.074, + 50.178, 50.527, 50.631, 50.747, 50.852, 51.072, 51.304, 51.409, 51.525, 51.641, 51.746, 51.862, + 51.966, 52.303, 52.407, 52.535, 52.628, 52.744, 52.849, 53.301, 53.522, 53.626, 53.743, 54.079, + 54.184, 54.300, 54.416, 54.520, 54.625, 54.857, 54.973, 55.078, 55.194, 55.298, 55.414, 55.519, + 55.856, 55.972, 56.088, 56.308, 56.413, 56.854, 56.947, 57.075, 57.307, 58.073, 58.630, 58.712, + 59.640, 59.757, 59.861, 60.407, 60.999, 61.196, 61.301, 61.626, 62.195, 62.288, 63.077, 63.193, + 63.414, 63.739, 63.866, 63.971, 64.760, 64.842, 65.086, 65.202, 65.747, 66.084, 66.212, 66.525, + 66.630, 66.757, 67.082, 67.210, 67.303, 67.442, 67.535, 68.011, 68.209, 68.313, 68.418, 69.114, + 69.300, 69.381, 69.753, 70.194, 70.531, 70.751, 70.856, 71.088, 71.413, 71.517, 71.866, 71.970, + 72.086, 72.191, 72.307, 72.411, 72.644, 72.748, 72.853, 73.073, 73.189, 73.294, 73.630, 73.747, + 73.863, 73.967, 74.188, 74.629, 74.861, 74.966, 75.070, 75.407, 75.523, 75.639, 75.743, 75.964, + 76.196, 76.301, 76.405, 76.626, 76.858, 77.183, 77.299, 77.415, 77.520, 77.636, 77.740, 77.973, + 78.182, 78.414, 78.518, 78.623, 78.971, 79.076, 79.192, 79.296, 79.412, 79.517, 79.749, 79.853, + 79.970, 80.086, 80.190, 80.411, 80.747, 80.852, 80.968, 81.084, 81.293, 81.746, 81.966, 82.071, + 82.187, 82.524, 82.628, 82.744, 82.860, 83.081, 83.302, 83.418, 83.522, 83.638, 83.743, 83.963, + 84.300, 84.416, 84.532, 84.637, 84.753, 84.857, 85.299, 85.531, 85.647, 85.751, 86.192, 86.309, + 86.413, 86.518, 86.634, 86.866, 87.075, 87.307, 87.412, 87.528, 87.853, 87.969, 88.085, 88.201, + 88.305, 88.410, 88.851, 88.967, 89.083, 89.188, 89.304, 89.525, 89.745, 89.966, 90.186, 90.419, + 90.523, 90.639, 90.744, 90.860, 90.976, 91.069, 91.405, 91.521, 91.858, 91.963, 92.404, 92.636, + 92.740, 92.857, 93.089, 93.298, 93.414, 93.530, 93.751, 93.983, 94.087, 94.192, 94.412, 94.528, + 94.645, 94.865, 94.970, 95.086, 95.306, 95.527, 95.747, 95.864, 95.968, 96.084, 96.189, 96.305, + 96.409, 96.641, 96.862, 96.978, 97.083, 97.303, 97.524, 97.640, 97.744, 97.965, 98.186, 98.522, + 98.638, 98.743, 98.859, 98.975, 99.080, 99.300, 99.521, 99.974, 100.194, 100.299, 100.415, 100.635, + 100.856, 101.076, 101.193, 101.297, 101.413, 101.518, 101.634, 101.738, 102.075, 102.191, 102.412, 102.632, + 102.864, 102.969, 103.085, 103.306, 103.410, 103.515, 103.851, 103.967, 104.188, 104.304, 104.409, 104.641, + 104.745, 104.861, 105.070, 105.186, 105.291, 105.628, 105.744, 105.964, 106.185, 106.417, 106.522, 106.638, + 106.858, 106.963, 107.067, 107.416, 107.520, 107.741, 107.961, 108.193, 108.298, 108.414, 108.635, 108.855, + 109.192, 109.296, 109.412, 109.517, 109.738, 109.970, 110.074, 110.190, 110.411, 110.527, 110.631, 110.852, + 110.968, 111.084, 111.293, 111.514, 111.746, 111.851, 111.967, 112.187, 112.408, 112.640, 112.744, 112.849, + 112.977, 113.081, 113.186, 113.302, 113.743, 113.987, 114.196, 114.521, 114.637, 114.858, 114.974, 115.078, + 115.403, 115.519, 115.740, 115.960, 116.193, 116.297, 116.413, 116.634, 116.854, 117.191, 117.307, 117.412, + 117.528, 117.632, 117.737, 117.969, 118.073, 118.190, 118.306, 118.410, 118.526, 118.631, 118.863, 118.967, + 119.072, 119.200, 119.304, 119.409, 119.513, 119.861, 119.966, 120.186, 120.407, 120.639, 120.860, 121.080, + 121.185, 121.289, 121.638, 121.754, 121.963, 122.079, 122.183, 122.416, 122.636, 122.857, 123.066, 123.530, + 123.739, 123.960, 124.192, 124.413, 124.633, 124.738, 124.854, 125.190, 125.306, 125.515, 125.736, 126.084, + 126.189, 126.305, 126.409, 126.630, 126.967, 127.083, 127.303, 127.524, 127.745, 127.861, 128.070, 129.811, + 130.380, 131.088, 131.529, 132.261, 132.365, 133.306, 133.410, 133.933, 134.049, 134.177, 134.478, 135.082, + 135.744, 135.848, 135.976, 136.313, 136.429, 136.533, 136.638, 136.754, 136.870, 137.207, 137.300, 137.416, + 137.532, 137.868, 138.077, 138.194, 138.426, 138.646, 139.088, 139.529, 139.726, 139.981, 140.411, 140.957, + 141.073, 141.201, 141.305, 141.537, 141.816, 142.199, 142.536, 142.629, 142.861, 143.081, 143.302, 143.523, + 143.755, 143.975, 144.184, 144.405, 144.637, 144.742, 144.858, 145.078, 145.194, 145.299, 145.531, 145.752, + 145.972, 146.077, 146.181, 146.634, 146.855, 147.075, 147.307, 147.528, 147.737, 147.958, 148.410, 148.526, + 148.631, 148.852, 149.084, 149.188, 149.293, 149.525, 149.641, 149.734, 150.082, 150.187, 150.407, 150.523, + 150.628, 150.860, 150.965, 151.081, 151.301, 151.417, 151.522, 151.859, 151.963, 152.079, 152.184, 152.404, + 152.636, 152.857, 152.961, 153.078, 153.194, 153.298, 153.635, 153.751, 153.960, 154.076, 154.180, 154.424, + 154.633, 154.749, 154.854, 154.970, 155.074, 155.411, 155.527, 155.736, 155.957, 156.305, 156.410, 156.642, + 156.851, 157.187, 157.304, 157.420, 157.524, 157.733, 157.977, 158.081, 158.186, 158.302, 158.407, 158.627, + 158.964, 159.080, 159.196, 159.300, 159.417, 159.521, 159.962, 160.299, 160.403, 160.740, 160.856, 160.972, + 161.077, 161.193, 161.297, 161.634, 161.750, 161.971, 162.075, 162.180, 162.528, 162.633, 162.749, 162.853, + 162.969, 163.074, 163.527, 163.747, 163.852, 163.956, 164.188, 164.304, 164.409, 164.629, 164.746, 164.850, + 165.187, 165.303, 165.523, 165.628, 165.744, 165.976, 166.081, 166.185, 166.301, 166.406, 166.522, 166.626, + 167.079, 167.404, 167.520, 167.857, 167.973, 168.182, 168.298, 168.403, 168.635, 168.751, 168.856, 168.972, + 169.076, 169.192, 169.297, 169.529, 169.633, 169.749, 169.854, 170.075, 170.191, 170.411, 170.527, 170.632, + 171.073, 171.410, 171.526, 171.746, 171.967, 172.304, 172.408, 172.629, 172.745, 172.849, 173.186, 173.302, + 173.418, 173.523, 173.639, 173.743, 174.080, 174.184, 174.521, 174.626, 174.858, 174.974, 175.078, 175.195, + 175.299, 175.415, 175.520, 175.752, 175.856, 175.972, 176.089, 176.193, 176.298, 176.402, 176.739, 176.855, + 176.971, 177.075, 177.191, 177.296, 177.749, 177.969, 178.085, 178.178, 178.527, 178.631, 178.747, 178.852, + 179.072, 179.304, 179.409, 179.525, 179.641, 179.746, 179.862, 179.966, 180.198, 180.303, 180.419, 180.524, + 180.628, 180.744, 180.849, 181.301, 181.638, 181.743, 182.079, 182.184, 182.311, 182.404, 182.625, 182.973, + 183.078, 183.194, 183.298, 183.519, 183.856, 183.972, 184.088, 184.181, 184.401, 184.633, 184.854, 185.191, + 185.295, 185.632, 185.748, 185.864, 185.969, 186.189, 186.410, 186.526, 186.630, 186.746, 186.851, 187.072, + 187.304, 187.408, 187.524, 187.640, 187.745, 187.861, 187.966, 188.407, 188.523, 188.639, 188.743, 188.848, + 189.080, 189.185, 189.301, 189.417, 189.521, 189.637, 189.742, 190.079, 190.195, 190.311, 190.415, 190.636, + 190.973, 191.077, 191.193, 191.298, 191.414, 191.518, 191.855, 191.971, 192.192, 192.296, 192.412, 192.633, + 192.749, 192.853, 192.969, 193.074, 193.190, 193.295, 193.527, 193.631, 193.747, 193.968, 194.188, 194.409, + 194.525, 194.641, 194.746, 194.862, 194.966, 195.071, 195.419, 195.524, 195.628, 195.860, 195.965, 196.197, + 196.301, 196.418, 196.522, 196.638, 196.847, 197.195, 197.300, 197.416, 197.521, 197.741, 198.078, 198.194, + 198.298, 198.415, 198.519, 198.635, 198.751, 198.856, 198.972, 199.076, 199.308, 199.413, 199.529, 199.750, + 199.866, 199.970, 200.086, 200.191, 200.307, 200.411, 200.760, 200.864, 200.969, 201.085, 201.189, 201.305, + 201.526, 201.642, 201.747, 201.967, 202.083, 202.188, 202.641, 202.966, 203.070, 203.302, 203.418, 203.523, + 203.639, 203.743, 203.860, 203.964, 204.196, 204.301, 204.417, 204.637, 204.754, 204.846, 205.195, 205.299, + 205.415, 205.636, 205.740, 206.182, 206.414, 206.518, 206.634, 206.971, 207.087, 207.192, 207.296, 207.424, + 207.517, 207.865, 207.970, 208.202, 208.306, 208.411, 208.643, 208.747, 208.863, 208.968, 209.305, 209.525, + 209.641, 209.746, 209.966, 210.083, 210.187, 210.524, 210.640, 210.860, 210.965, 211.069, 211.418, 211.522, + 211.743, 211.859, 211.963, 212.300, 212.416, 212.637, 212.857, 213.194, 213.299, 213.519, 213.635, 213.740, + 214.076, 214.192, 214.413, 214.634, 214.970, 215.075, 215.191, 215.295, 215.412, 215.516, 215.853, 215.969, + 216.085, 216.189, 216.305, 216.410, 216.631, 216.851, 217.083, 217.188, 217.292, 217.629, 217.745, 217.861, + 217.966, 218.082, 218.186, 218.523, 218.639, 218.744, 218.848, 218.964, 219.080, 219.417, 219.521, 219.638, + 219.742, 219.858, 219.963, 220.195, 220.415, 220.636, 220.740, 220.845, 221.193, 221.309, 221.414, 221.518, + 221.634, 221.739, 222.076, 222.192, 222.308, 222.412, 222.528, 222.633, 222.970, 223.074, 223.295, 223.411, + 223.515, 223.747, 223.968, 224.200, 224.305, 224.409, 224.746, 224.850, 224.967, 225.083, 225.187, 225.292, + 225.628, 225.744, 225.860, 225.965, 226.081, 226.186, 226.418, 226.522, 226.638, 226.754, 226.847, 227.080, + 227.196, 227.416, 227.521, 227.857, 227.962, 228.299, 228.415, 228.635, 228.740, 228.856, 229.193, 229.309, + 229.518, 229.738, 230.075, 230.191, 230.307, 230.412, 230.632, 230.853, 231.085, 231.306, 231.410, 231.526, + 231.747, 231.851, 231.967, 232.083, 232.188, 232.304, 232.409, 232.745, 232.861, 232.977, 233.070, 233.302, + 233.639, 233.744, 233.860, 233.964, 234.080, 234.185, 234.417, 234.638, 234.858, 234.963, 235.079, 235.416, + 235.532, 235.636, 235.741, 235.961, 236.193, 236.298, 236.635, 236.855, 237.192, 237.308, 237.412, 237.517, + 237.738, 237.970, 238.190, 238.411, 238.527, 238.631, 238.968, 239.084, 239.293, 239.514, 239.862, 239.967, + 240.083, 240.187, 240.408, 240.744, 240.861, 241.070, 241.302, 241.522, 241.755, 241.905, 242.521, 242.869, + 242.974, 243.090, 243.206, 243.426, 243.531, 243.751, 243.984, 244.193, 244.309, 244.413, 244.645, 244.866, + 245.191, 245.528, 245.864, 246.422, 246.642, 246.863, 247.304, 247.525, 247.641, 247.861, 248.407, 248.628, + 248.848, 248.999, + }, + kick = [[ZVSQbYURPcunidZWTWTQOMKWUSPNLx0tnhdZsmgcYVSgcYUSPQxqkfbXUrlgbXU0unidZVnidZVStpkfaXTjeaWTQrvpjeaWimhcYVStnhdZVSuoidZWizrlgcYWTQOMKJQNLKIUlxqkfbXunidZVSmhcYVS+1unidZzsmhcYzsmhcYVXfaXTRO5xqkfbXURPNLJZxqkfbXUZVSQNh3vpjeadojeaWdjfbXURPbYVSQNQWTQOMM7yrlgcYrlgbXURdZVSQN3vpjeaWieZWTQw0smhcYoieZWTj1unidZrnidZVS2voieZWlfbXUR1unidZWrlgbYUR1tnhdZVmgcYVSPNLKIMa0tnhdZpqkfbXUZgbXURouoidZWqoieZWTxqkfbXUbXURPNZ4wqkfaXVSQNMSzsmgcYVSPNLKL6y6yrlgbYURPN1tnidZVSWTQOMK0/2voieZWTQOMkfbXURPZVSQOMny80tmhcYVSQNe3vpjeabXURPNUm/6yrlgbXURPNkklgbXUgcYVSPT1t/2voieZWTQPuojeaWTQTQOMKaz0tmhcYVSQNMenhdZVSQbXURPNpv1unidZVSQOMzsrlgcYUSPNLKk4/2voieZWTQOMVwpkfaZXURPMP2vwpjeaXTWTQOMNNLJIHaXUROML/27zsmgcYVSPNZeaWTQOSQNMKJi/2wpjeaWTROMLguoidZfbXURPNq7/2voieZWTQOMrlnhdZVjeaWTW4w1tnhdZVSQOMKjidZWTQaXUROb3/2voieZWTQOMRXURPTQVSPNLKv/2voieZWTQOMKl3vpjeaWTQOMKR/2voieZWTQOMKJIHGFEEDDCGNl//2voieZWTQOMkxrlfbXUUROMLJ5xqkfbXURPNLJgoieZWTRmgcYVSxqkfbXURPNLJIbkfaXTRQRPNLLo/2voieZWTQOMRqkfbXURWTQOMK+1unidZWXURPNYeaWTROYhcYVSy/2voieZWTQOMNflgbXURWUSPNL/2voieZWTQOMKJedZVSQbsmhcYX6yrlgbXURPNLJkfbXURPRRPNLKmlrwpkfaXTROMutxqkfbnidZVSQ/21unidZWSQOMKvpjeaWfaXTROis/2voieZWTQOOvojeaWTXgbXURwp/2voieZWTQOMvoieZWTbXURPO1x2uoieZWTQOMinkfbXUUfbXURf//2voieZWTQOMxrlfbXURVSQOMu/73vpjeaWTQOMyrlgbXUVSQOMP880tmhcYVSPNLihfaXUROcYVSQm/2voieZWTQOMKesmhcYVSPNLKIa5xqkfbXURPNLJmjeaWTQYYVSPOa0tnhdZVYVSPNPffaXTRWWTQOMd23vojeaWTQOMKloidZWTUkfbXUT1tnidZVSQOMKJagbYURPehcYVo76yrlgbXURPNLXWYUSPNLkfbXUS/2voieZWTQOMKcfbXURPUWTQOMv/2voieZWTQOMOfjeaWTQTjeaWTurqkfaXUROMLJyrnhdZVidZWTQm/2voieZWTQOMK90tnhdZaWTQON0tvojeaWTQOMKckoieZWcYUSPNL/4/2voieZWTQOMvpjeaWXgcYVSnxzsmhcYVSPNLKsmhcYVSSbXURP/2/2voieZWTQOM0smhcYZXURPNL//2voieZWTQOMKLJIHGFEEDDCDe//2voieZWTQOMKMKJHGFFEDDNVp/2voieZWTQOMKlgbXURPRPMLJIs/2voieZWTQOMZnidZWTfbXURPTvpjkfbXURPMLJjqkfbXUVWTROMj+1unidZWTQOMKZlgcYUSeaWTQOx6yrlgbXURPNLRYZVSQOMQPNLJ250smhcYVSPNLKhcYVSPNLPPNLKwwpjeaWTROMLJIXWTROMLUYURPs02vojeaWTQOMKjigbXURPYdZVSQox7zrlgcYUSPNjkgcYVSWTQOMKq/2voieZYVSPNPomhcYVSPURPNcqs/2voieZWTQO0tmhcYVSXXURPi6yyrlgbXURPNLvpjeaWTQVSPNLwt/2voieZWTQOPfkfbXURceaWTQ/2vpjeaWTQOMKMrlgbYURRQOMKM2/2voieZWTQOR0uoidZWTQOMKJ+/2voieZWWTROrroieZWTRPMLJI2/5xqkfbXURPNLXhcZVSTSPNLKpm4wpjeaXTROMLbkfaXUROOMLJI0tonidZVSVSPNLWYdZWTQRVSQNNk5xqkfbXURPNLKmhcYVSPTROMLg/2voieZWTQOMKfbXURPNTTQOMK74wpjfaXTROMLJlgcYUSPNVSQOYq4xqkfbXURPMLJXUTQOMKNeaWTt/2voieZWTQOMKlgcYVSPXieZWTX/3vpjeaWTQOMXmwpkfaXURPNLX6/2voieZWTQOMtnidZVSQcZVSQop/8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fbXURPNLJIqkkfbXUZZWTQO0voieaWTQROMLSdjeaWTTeaWTQVh5xqkfbXURPNLqksmgcYfhcYVSPzsmhcYVSPNLKISrlgbYUVdZVSQ6yrlgbYURPNLKprlgbXURWTQOMK0wqkfaXUROMLJewuoidZbXURPNcunidZWTQOMKJQ8zsmhcYoidZWT/2uoieZWTQOMK/2voieZcqkfbXUvptmhcYVSQNMK80smhcYVdZVSQkxtnidZVSQOMKo3vpjeaWhmhcYVvpwpjeaWTROMLR10tnhdZaXTROMzrvojeaWTQOMK2vojeaWfxqkfbyrlunidZVSQOMwwpkfaXUURPNLKtmwqkfbXURPNLMsmhcYVSZWTQOOtmsmgcYVSPNLKxzuoieZWaXTROim/2voieZWTQOMstmhcYVSPNLKIR1tnidZVTQOMKXmsmhcYVXURPNPs/2voieZWTQOMfbcYUSPjeaXTRp1toidZWTQOMKJpjeaWTQTZVSQOq0tmhcYVSQNLKYvvojeaWTTQOMh/2voieZWTQOMK0sqkfbXURPMLJe/2voieZWTQOMKzsmhcYVoieZWT2vojeaWTQOMKJotpjeaWTeaWTQOrlidZVSQOMKJH/2voieZghcYVSmxqkfbXURPNLJT6yrlgbYUhcYVSvo0smhcYVSPNL/2voieZWhcYVSQvotnhdZVSQNMK8zsmhcYVgbXURUuoieZWTQOMKJospkfaXTnkfbXUrlxqkfbXURPNLM/2voieZkfaXUR/23vpjeaWTQOM1unidZWXfbXURxq1unidZVSQOM1vpqkfbXURROMLip/2voieZWTQOMj/2voikfbXURPtyrlgbXURQOMKiqunidZWaWTQOty3vpjeaWTROMLnilfbXUWURPNLzspjeaWTROMLJItmhcYVSYVSPNP1wqkfbXUURPNLpkkfaXURdZVSQwyrlgbXURPNLJI0tmhcYVSSQNLP5zsmhcYVSPNLKasmhcYVShcYVSd1yrlgbXURPNLJzsqkfbXUgbXURPyrlgbXURPNLJI6xrlfbXidZWTQvojkfbXURPNLJ2voieZWTjgcYUnqk2voieZWTQOMrlsmhcYYlgbXUgyrnidZWTQOMKc2voieZWTfbXUR5x0smhcYVSPNL0tmhcYVSYWTROM3vrlgbXURPNLJvtojeaWUWTQOMRm+1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]], + snare = [[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]], + hat = [[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]], + bass = [[MTZbeefghfdddeghgdZUPMKJJJJJJJLOTYcdcaYZbddbWQLGEEINTZefdaVQMKIJNRWbedbWSNKJJMQUZcdbYVSQPPRTXbegfaVQMJIKOTYdgfedegijgdccceecYTPMKJJKLMMMMNQUYbcbabdgiieYRLFDFKQXehhfaVQLIHJNRWbccZUQMKIKOSXbddbWQKGDEIOUaefebVPJFEHOVchkifeddefdbabdffcYUQNLLLLMNNNOQTXcedbaZZbcbYTOJGEGLQXcfebXSNLJJLQVadecYTPLKKMQVZdfebYURPOPRWcjmnjdWRNLLQWcjnmjgdcdfedcbcefebWSOMKKKLLMMMMPTXacbZYYabcbXSNIFGINTZcdcYUQNKJKMQUYbbaVQLHFFKPVbfgeZTNIFEGLQWaeebXRMHGKRajookfdceghfdccdfgfbXTPNMMNQVbfiihfefdaZZadgfdXRLHFHMTbhkhcWRONMMNPTXbedaWSOLJKLOTZdedaWTQPPRVafijhcXRNKLQXfnsrmieddffdccdfhheaVQNLKLPTZfjjjhfffdbaabdfdZUNIFEJRbkrtogYQLJIJLNPRTSRPMKJIJKNQUWXVSOKHFFGJMRUWWUQMIFDHPaluvrlhinssqlgcaYXXUROMKKNRXeknmjgdbcdcccdefgdZTOJHINXiswumcSMJJKMOQSTTSQPNLKJLNSXcfebXSONNNPRVZceecYURPNPVdmuyuoljlopmjhhhhfbXRNKJJNSaiqtrokgfhhgeddeedaVQLIFINUdmrpjaSKIJJJJJKKJJIHGGFEEFHJKKJHFFFFFFEEDCCCCCBBBBCEIPWbefcaYXWVXafkptvvrlcTMKOYjrwtpicXUSQRTWaehiihbVQNPZlw572wpfYSNLNSYfkmnmjcUOKNXjv441wqidXRPPRUYbdfebWRNLRblv20xrjcVOKKNTYceedbVQLIINVdkqttrngZSPOQUXacecZUQLJNVelstspkeXQKKOUcimnnlfXQLINZlw24yribVQORYfovz0xsjaRLMUgqxvpfVONMMMPSXcgiheZTMHFHMSZfiihcXTPMMOSXbfgfbWQLHINVdkmkeYRMIGHJNRXacdbYUPKHKQYgmnlidYTPMLOSYdilmkfYRMKPamx12vneXQMKLQYhnrtsohaSNKNUbjoqnjcVRMKMPTYdfggcYSMIINTbjonjcVNJIJOVemsvwvogWOKLQYjrwywqibWTRSWaejmnmicUONQXirvvrlgbaZYZcfjnrtusnfWPNSdpx1yrkdYXWWYcgkorsqmfXQOQbmy673xrhaTOLNQUZcefebVQLKPamx563yrjdXSRTXcgjmnkgaUONUeow10xtnhYQLLPVadeecZUOJHJQaiopplheZVRQRUYcefecYUQNMSclsxwsnidWOKKNSYcfgecWQLIINXgnqqmidYSNLLQVadffcZUOKINXirxumdVOMKKMRYhpvwuphYRLKOVcjnnlicXSPMNRWchllidVOIGLWju1yqhXQMJHHJMQUXYZXUQMJJLOTYdfecYURPNNPSVYbcbZVRNLNUfpy1zriaUOLLNRYfjmnlhbWRNOSZglonkeYSNJIMRXcggfdYTNIEEFHIJJJJJKKLLKJIGGFFFEEDDCDFGHJJJKMNOPPPONNMNOOPPPNLJLPWflmjeYVUUVUUUVWYZabYUPLIKTepvyunfbYWVWYchmqtsqmeWQQUep053ytmeYSOOSYelprsqldVNLPYjptqkeYTPMLMQVaehhgcWQLHIPYhnnibTMJGEEHKNQSSTSQMJHGJPUZfillkgZRMLMQWbdffbWQLIJPXelqssrmgXPKJLPVYbcbZUPLJKQYeilliebWRNMMPTXaccbYTOKJNTbfhdZUQOMLKKNQVYbbaXTOLJKOTXZaYWUQNLIILQUZcedbXSNKJLRXdhheZUOMKIJNSXcfggdZUPLLPUafigfcXTPMKLPUZdffebWRMJKPXfmmjfbZbehihgfffedaWTQOOQTXacbZWTQNLIJMQVaeedbXSNKIJMRWabZUPKGEFIPWdjmnmicUNIILRYhnsurlcVOLMQVbfgfdZTOJGJPXflmidWQMLKKNRWbeggeYTMIIMWhrwzxtngZSPOSYdiklieYRLIJPXirwxvqkbTMIHJNQUWXXVSOKIJOWeknmkfaVQNMPSWZbcbYTOKHINXgnrqnjhcYTPNOQSUWYYWSNKHIMSXbeedbZVQMKMPTXbeeeaVQLIKSZhlnlifaVOJHIMRWadedaVQLKLPUZbccaWSOKIIKNPSUWXWTPKHIOWfjjeZTPNMKKLQUZdfebXRNJJLQVbddbXTOMKKLOSWbdfebXSNKJNTaegdZUSQPOMNQTXbddcZWTQOOQSVYbcbaWSOLKMPTXacdbYTOKIMUdkoleXRONOOQSVYbdddaXUROOSXdgheaWSOMKJKORWZccaXSNJJMTckonjcWSPOOPRVZcfgebXSNJHKQXdhgdaXUSSRRSUVXZZYYWTQNLMSZgmpnkeYUQOPSVYbegfeZUQNNRYekljfaVSRQRUXbfiiieYSNJINWhs010wqkfaURRRTUVWVUQMIGGKRZgiheaXWWVUUUVXaehhgcXSOPSZgnrtspkfbWVWZbeghhgdaXVTUXacfhhhgeaXVWaejnqqokeXQMLNUbinpokhcZWUUWYaddedaVPKHILRWbeggfdaXVVYbeillkhbUNIGKUhsvtmeZZabbZXXYZbcbZVSPOPUZehifaVSPOOORUYbeffcYUPMKMUcjnoibVRONNOQTWZbcbZVROMMPUZegfdaXUSQPPRWZdggfbWRMJJQajopjbURQSTTVXadghgdZVRONPVbfgfaVRPONOPSVYcfggdZUOJIJMQWabbYVRQRRTWaflpstpjbSLJLQXdhjhdYVTUVZdhmqtrnhaSMIHKSajorpnlkllkjhfefffdYSMHGJQajpoleYSPNLLNRWbfhheZTOJJNUdkomhbUQMKJJLNQSTUTROLIHILQWbcbZVROMKKNSXdhjkhcWQLJLQXdikieZWUTTUVWXYZaaZVQLIIMSYdgjjigcZVVWZdhjllkgaTNJKPWdjnppolgbWVZekpssrojbTNKLQXdhjjigfcZXYbeikmljgZTMHINXgmlgaVTVYZYWVWYbegebXQLILQXdhgebXURPONQVZdhihfaVQMJLQXeijhdZWUUTTUXadghgdZUPMMPVbgiigdZWUSSUXcfjlkhcWQLJLSahkkeYTRRTUVVVWWWXWVTQPOPSXbefdZVSQQRSTTTTSQPPOONLJMTclrqkdWSPPPQSVYabbaZWTPKIKPWeilifbYWWWVVVWYZbaZXURPNNOQSVWWUSQPOOOPQRSUVVWXXXYYYYYXXXXXXXXXXYYYXXWXXYZZZaZZZZZZZZabbcccbbaaaaaaaZZZZZZaaaaaabbccddccbaZZZZabbccbaYWVVVVVVVVVVWXYZaZZYYYYYYYZZZaaaaZZZZZYYXXXXXXYYYZZYYYZZabcddeeeeeddddddddddddddddddddeeeeddcccccccdddccdhouz0ysolklllmmllllllllllkkjiiiiiiihhggghhhhiiiiiiihhggffeeeeeefffeedcccccdddddddddddccbbbccbbaaabbbbbbbbabhow13ysnjjjkkkkjjjjjjjjjihhhgfffffeefgghiiiiiiiihggffhlsy32ysmiiijkkkkkkjkmptvvsojhghhhhhhiiiimsxyxsmhggggikqvywqhZTRRRRRRSSSSSSSTTUUUTTTTTTTTTUUUUUUVVVWWWWWWWWWWWWWVVVVWWWWWWWWXWWWVVVVVVVVVWWWWWXXXXXXWWWXXXYYYYYZhpx572vpkiijkkjjjjiiiiiiijjiihhhhiiiiiiiiiiiiiiiihhggjouz1ztnhedeeeeffeeddgknonjhjnqqoidaaabdhouz1yqjfcbccehkllhcYVUUVVVVWWWXXXXXXXXXXXWWXXXYYYZZZZZZaabbcccbbaZZacefedcbceffgfffgggggfffffeeeeffgggfffffffgghhihhggghjlnonljhgffffffffffggghhhiijjjkjhhgffgghijjkllkkkkkkkkknqssrqonmljikorsqpqsx11vpnoswyxwxz0zwpkmquvvtttx1yutvy00unfaYZZZacfilopoligfgiouy01zvrmhdbadgkoqroicVOKKLQVbiorroibVTTWadhkljeYSNJJOUagnrtusmhcYXZcfknppnligffimrw121ytrponoooopprssssqpnmmmljjjjkmooonnoprttqlfYSQTalu010xwvvvurmhbWWYchlprrpopommmllmmmkihijloqqpnkiedhnuxxskedfilmligffgggffgiklosuvuojhhjmonljhhhhhijklmmnquwxuohedfhjjiihiijkmnoolhiknrsojggimqrrpmkiiijklnooooqrrpkeaXXYZacegijjjkmortsrrsqpmiffhlprqpnmlmllkkkllkknqturjbUQNMMOSWadghhijjjigedceeddcabdfffgikmnnnmmmnmllmptvvtokhfedefhknoomjfcZYZdhlptuutrokgefgilopmhbUNKLQZksxyvojgdcefghikmnlgbWROPVbhmsuwyzxvrnjhggikllllmnooqtwz11yuqolkkklmnprstuuutrponmllllllllklmnopppqrrplfccdjqvxyyxvvutokfaWVYbehihfddfhknrtvwxwutrqqqrsttsrqpquy21xqjgilqtsqnkihghikmoppprttsokfgjosutqnkihhiiijkjjlptutoidcdeedcbbdefgghijkkjkmopplhggkostspnljiijjklmllnpqrpkeaYYZacdfhjllmnoqtutuwxvupjghlptutrpnkjjjlnqrqopruwvqjfdegijjjkklkjiijjlklorstqkhgjnsuutqnmlkkklmprrrtuuvvtqmiebZacfilopnkhfdddfjnqstrolhebbcfimqsspkdWPMNRYgpw0220ywvuronmoqpmigegjmpstvxyywslfaYadhlopnkgcZYZdkrx01ywuutsrpoopqrssqonmmmnpqqpnkjjjigfgilostuvvvuutrrsstuttttuuutsttuvxyyyvrkfceglopqqqqpnkjklortttsqniedjqxzwpjgjnruutssrrqpnmlkkknrwyyuoiffhijkkklmmkkkkklllqv011tniiloqnkhggijjlmoprqqtwxwrlhgjostqnkhggghiiiihgjouwxrjeehmqqqponoonnmmmmllortsqkebcfilllkjiiihgffeeegjnqrpnlklnnmjfbXVUVXaehjlkjjlnppnmllmonkhcXUSTWbgklkhglpuxxtpmkjihjmpsvwvrmieaZbeilnppnkheaWWbgmrwxwrlfaWVbjry22yvqomljiklmnppmjgeddfhmprsrrrssrokijlpstsnidZWVYdlsy00wrmhdYYbgmswxxvusqpnmnopprqqqrrqnlllmpqqqonmlllmqux010wsplgdegjosuvvusrpnmnprtvvvuttroljhhijkllkkllnrw142wpjfhkllihghijjiiiiihilpstqlgcbdgiiihgffffghiklllptwwunhegjlmkjijkmnnooooonoswyzunjijnppnkhffggghhiihhlrwxwphcdglpnmkihiijklmnnlmqtvwslfdehlnnljhggghiijkjjlpuwxtojjlnnlkjjknnmmnooomjknqqqkebcgkmmlllmopnlkihgffinopnicZWTRPQVciorrplfYSNMQXfmstsojcUOKMTZfjlljhaUNJIQcnv0zvrlgaUQRUYdgihfbXTPNPUbgkllkheZUPPRVZcefgecZWTSXelsxwsohcXTRTXchlmmlhdYURRVbgloqpmibUPQUcjqssrojbTMILTdmtxxvqleXTUahntwwusmgZTRUbjrvxuqjdXRPTYelopolgaVPMOVdkqpnieaXURQSXcgkkjgdZVRRWdkrspkgaWSOMPWelpqolgaTNJLScmttqjeZYXWVWYadggfdaYVTSWcjptrokgecaYYbfjmomkgbWQMMSdpxzxpibYVUSTUWYbccbaYWUSUZglqplfbXUTRPRVZehihfbWQMIJNTZehgecZWTRQSWafjkjhdYTPPTZgnqrojdWPKGIOVcjlljgbUOJJNVelppnhcXSPNQVbglnnlgbWROPWensvtqlfZTOMRYflpqqojcUNJKUfouxuqnhcWSQSVZegihfbXSONQXfkpqpolgZTORWdjnooojdXQLMSbjrwwupjdWSQTYcgjkjhdZUQORXelrttqlgZTPRXdjprsrnhZRLJNVdkqttrmgZTRTZekoqqqojeZUTXdkpsspmhcWRSVchnpomhcVQLLRbmtyupjebXURRVZdhjjihfcYVUYdjnpmjgbXTPPTagmoomieYRMJNVgqwvqkeaXVSRTWZdeeecbYWTSXfnuwrkeaZZZYYadgjkjheZUOMOWhryxtldYWUTSTVYcefedbYVTRVckqtrmhcXTPMNSZgmpnkgbVPLKPbmvxungZXUSQPSUYbccbZVQMJLRZhnmjeZWUSQPRVafiigeaWQLHIMTZeffeaXTPLLQVchmmkhbWRNLNUagkmlifaVPMMRXejmnmjeXQKJNWhpuvtokeYTPPTYchjkkhdXRNMRZhmqplhcWQNMQWchkmmlgZSMIMWit141vohcXTUYdinqrsplfZTQUahntttpkeXQNRYfmrrqojcVOJJQZjrxywtmgZTRUZekpsttrnicYXZdinruurmgZTTWbglnoolhbUPPXhrwxrkcXUSQPSWbfijhecZWUTVcjpsrlgcYWTSTWafjkjheaVRNMSbkqspjeaXVTRRUXbefedbYWTRSYelpplgbYYXXYadgjkjgdZVRNLQYiptrleaXWUSSUXadfedbYVSQPTahlnkhcYVQMJKPUZdfedbYUQNNRXcffdZWUTSQPRVagkmlieZUQNOSWZddcaXTPLIIMRXchihfaVRNKNRWaeedbYUQNLLPTXadedcZVRONPTZdghgdZVRMLMQVZcdedaWRLJKQYgnqpmhdYURPQSVYabbaYVSPNOTYeijheaWSOLKMPTWZbcbYTPKLQYhosrnieaXTRSUYchjkkgdZVRRVaejmmlidXSNMRXekoonlgaTNLNVckopnjfcZVSTWaejllkieaWSRTVZdghhfcXTONPTYdijjieZTNKNVempojeaZZYXWXZbcefecaWSQQTYfjkieZVSPNLMQUYcdedbYUQNNUdlppkfaYXWUTTVZcegecZVSPOQWdikieaWSQOMNQVZdfedaXTPMLQYglolgbYWVTSSVYcghhfbYUROPVciklhcYUROLKMRWbegfdaWSONPVcikjgbXTRPOORVZceedcZWSPORXdghfbXURPNLMPTXaccbaXTQOORXdhhgcZXXXXWVUUTTTTSSRQQRSTUVWXXXYYZaabaaZYXXXWWWVUUTSRRRRRRRRRSSSSRRRRRRRRSTUVWWXXXXXXYYZZaabcdefffecbaZZabcccccccbaZZabccbbbbceeedcbaZYYYYZZZaabcdeeffffeeddccddeeffedcbbbbbbaZYYYZZYYYXYZaabaZYYXXXWVUUVWWWWWVVVUTRQONMMLLLMMOPQRRSSSSRRQRSTTTSSRRRQQQQQQRSTUVXYYZZZZYYXXXWWVVUUTTTTUUUVVWXYZabcdefgggfedcbbbbbbbaabbaZXWUTSSTUVYZabcdeghijkkkkllkkjjiihgfdbZYXWVUTTTTTUUVVVVVVVVVVWWXYYYYXXWWWXXYZZaaaZZZZZZabcdeeedcbbaaaaaZZZZYYXWUUWYacdeeefeedbaaZYXWVVUTSSRSSTUUUUVVVVWWWWXXXXXWWVUUTTTTUUUUTTSRQPPPQQRRRRRRRSTUVWXXXXXYYYYYYYZabbccccbZYXWWWWWWXXYZbbccbbaZYWWWXYZZZYXWWVVVVVVWWWWWWWVVVVWWWWWWVUUTSSSSTUVVWWWWVVUUVVVVVVVVWXYYYYXWWVUUUUUUUUUUTTTTTTTSRPNMLLMNOPRSTUUVUUUUUVVVUSRQPPQRSTUUUVWXYYZZZYXWVUUUVWXYZZZZaaaaZYWVVVWXYabddeeeedcbaYYZZZZZZabdedbZXUTRQQSTVWWVVVVWXYabbbbaabcdeffecaZXWVVUTTSSRSSTUUVVUTSRQQRSTVWYYYXXXYYZYXVUTTSSTUVXYYYXXWVVUUVVVVUUTTUUUUTSRPOPTcjoqpmjhhhfdbcdfikkjhgfffghjklkjhgggggggikmoqqpmjgedglptvtpljiiihhhilmnnmljihgfgjmoomkihhiihijkmpqqpnligfgkpuwuqnkllljhhjlnpnkigeefffhjkkkjjklmllklnprttsqnljhghjklmllmnoomjhghhjkjjjjjjhgikmnnjhfggfebbbdgkmmkhebachouywrlgfhjkkkjjijjjiiijkklmnnonkihhhihgffgiklkigfefghklmmjgffhjlmnopponlkkkklkjkmnnlhcaZZaaZZbdfhjjihgffedefghgfeghkmonlkihghjkmnonmjihggggggghhgebaZabdeeffgggiloqqmifddfgfcYUQNMNSXbfhgffgikjheaYYabcaXSOKLOTYeghhhjosvwxvtsromllllkjjklmnnnlmoqrsrpmlkjhgggffeedddddeeejotxzyxvtsqonnnmkihikmnonmnquwyywvtrqpnooonmmmprssrpnptx01ytpkjhgedcdegikjgedcehkoqrrronmlihghknruvuqmigefhlqtvvusrqonljjjjklmnnnmlllmprrrrqonmkigffggijllmlkiikpvxxtmfccdegggggghgfdbaaadjqw0ztmhedeeeddefgihfcZXWXbhnrvurmjhgffedcdegijjjjjjilqvyzwrolllljiijklmmkifdcdgmrvwurmjihhgfdddfgijgecaaadgkorsqnljiihfeefgijjhfdcccejoqttpmjhfedddeeghjjjihgggkqvyxtmgdccdddfhkpsutplgcZfnu2640xsolifeefffhjnqssqomknrvx0zwsqnlkklmmkjgdZWTRRUZfmrttspljgedefghjjkllkkjhgjnruxxvtqnkhfhjkllkjjjihgfgntz330xussqnkhggghkljhfeegkqwz0zxtrqpmkihhijkmmjhfdbcflqrtrollljihhijklnmljhgffhlrx000yvuvtqolkjjjlmmlkjihmsy12yrkgeddcbabcdffdccbcfipuyzvogbZYZbaabcehjjhfdcbchntwxtmgdccdddcccdefgggfgggkosuupjfccccccdfgijjhfcbaaekqvywrmjhhgfdccdfhihfdbbbdiotvvrmiggggfdddegiigdbZYZchotxwslgddfhihdZVROORUYcefhjloqolifdegijigdZVRQRVZdfeginsxzywsoljhhjklllmprssqolknrtvwtqnkifeegilmnnnmljhfddgkorsqmkihhhiiihhhiklllkjjmquwxvtrpnljiihhhijlnmliecdksy21wsommljheeefgjkigedccfjopqpolkkjhfeeefhjlmlkkjiilnppqssssrolihhiklnonljihhkosuvvurpomkigghjlmnmkigffhmsxyxrlfdccccccccdeddddeghjosssokgffffedcdegikkhfcbbdksx00tlfdaacccdeffggfedcccekquwvqligfedcccdfgiigfedcdhntxzvoheddfffddcdefedbaabdhmpqqmjggfedbabdfjmmkhdaYZdinsutqlifeeffghijkkjhfdddeipvxzvqlihfedcdefhihgecbbdfjqw11zvsonnlihhgeefhjllljhghnsxz0xuroliggijjkjiebYVTTWcjqwyxtpmkjhhiiigffhjjjigdcgkosvusqomkjjklljiiikllkihkqwz0yuqponmkiijklnppomljhhkoqrrpmkkkjighikmpqolhebbbdjpsuupljhgfdcdegjkmljgedbceimoonkhggfedccbbbdfhijiihjpvzyvnhcccdcbabcdefffffffgjotwxtoifccdccddefhgedbaabdhmprrmheddefeccddfghggfedccgknomhdcbefggghijjjhfedddegknpqnjfcabbaabcegihgfdccdeimqpnidZYabccbcefhjjhecbZcgmrvwsmhdcceffdaXUQPQSVYcdfghiiihgffgghhhgdZVRPQTXadeegkosuvuspnjgeeeeddegjlmmljhjoswyywusqollmmmmlkkigecbaejpvyzwtpnljhhhhhgffghiiihggjmpqrqomlkiijkllkjjjkjigeehnruusoljihgfdddddeeffggfedgjmopnlkkjigefgghjjhfecbbbekptvuronmlkihffffghijjjiihjnqrrpnkjihfdcbbcdfggggfefjpuxwrjdabcdecbabceffeeeefimqtvsnhdcbcddcdefhihgfedceipvzzwoheefhihfeeeeedcbbcdgjnprrojgedeggfeffghgfdcaabfmuz1zslhggijigfedeffeeefgikpsttqkfcbbcdcdfhjmnmjgecabfkpturlgcabddddefghhgffeeeeimprqlgcbceffeddefgfedddefimrx0zwsnjigeefgggffgijihfdeinqsrpnlkkjiijkkjkklljheccgmsyzxurnmkigggggfefhiihgecejostspnkjigghiiihhhhhhfdcflrxzwsplkjhfedddegijjjhgghkpuvtsqonnmkihjkllljhggffghkpsuutqponljihhhhhijlllkiggknrsspnllkihgghiijkkkjhfdgmty0wphbYYZaaaacdfggedccceinswwtmgdddfgffgghjjhfdbaaeksx1yslgeffgfedddeeecbbcdegknpqokhfeeffdefhiklkhfdccdipv00xohcbbdeddddeffdcccdfimsx0zuojggijjhhhijkkigfdddhnswxvnhcaabdeecaYWVVWYadfgghghhfdbaZacdddcbbZYXXYZbcdehmruuurnkjhghijjihhjklkifeglqtutqmkjihgijkkkkkmnlifcdjry33zuqmljihiiihgfgijjjgeehmprrpnkjhgeeghhhiikllkifeintyzwtqmmkheccdefgggggggffgknoppnlkkjihhhiiiiihgfeeegkoqssrrrrpnljjjkkkkkkjihhghmqtuusqpomkhfeeffghhhgfddipw00umeaZaccbabbdfgfeccccejotwwqjfccdfgfgghijjhfedbcgnuz2yqicZZaccccddefedcbcddhntxzwpjfeehhggghijigedbbcejpuxvqkgeegggecbbbddcccccdglprspjcZZaceeeeghijjigeddfkry21wqkiiiihedccccccccccccdgjlmljhgghhhhhijkkjhfeeefkqw2751xsoljgfghhhhhhjjjigdcfkqtvusqonljiiihgghjlnmjgefkqwzywsokjhgghihggghijigdbdiptvurmkjihgghgghhjklljhffkqx22ytokigecbcdeghiiihggfgjoqqppnmmmkigggghhhhgfedddhlqttsqonomkhfeeefgghiiihgghmruutqnlkigedefghiiihgeddiovz0vngdbceeccdegijiihhhggkoruupkgddefeefhjklkjhgfedhntxzvngdccefeeeefggffffffgkortuqkgeefhihhhhijjhgfedeiouxzwpjgfgijigedccdeeeefghkosttpjfeefggfgijlmljgdaZZdjquwuphcZZZcddcaZXXWXYadfhijjiigdaZYZbdeeeefggedccdefimsy10ywrnligfhijjjjkllkihffjosvwvusqpmllmnnmkklmmkigfhmsxyxuqnkjhhiijihghijjjhfdglqtwvtqomljiijihhhiklkifeglrwzxtqnlljhfeefghjjjihgefimsvvtqnlkjgeeeghjkkjihfeeflqvxwsnkjkjjiijklmnnljigfghjmooonllmnmljjjjklmmkigeegnu121umgedefffffghihgfffggiknpqplgecdefeeffgggfeeeefhnty01vngedeghggffghgfeeeefglquxwrjebbceeeeefghhffeffhlrx130tmheeeeeeffggggfeeeefkptwxtnjgffggffffghhhgffefiou032woiedegggggghhgffeeefhlortrnigeeffffffgggffffeefjpuzyuohaWRMLOTagknnmicVOKNWhsyxsmeYUPKKOVcinoolgaTNLPYiswvrmdYSMJMTZgklllkhcWRQUdowwunfXTOKKOVcjmnnjeYRLINUfpxyvrkdXRMLPVaehhgfcXSONRYgmnnljfbWQNNSXdhklkicWQMNTcmtvurnhbVPMOTZejjjifbVPNQVdlqqolfaVQMNSYeillkjeYRLLRbmvxvpibXSPNOSXbfgfdaWRNLRalv20vnfZTPMLPVbgklkieZTONSdny34wogZSPNOSXbeffdbXTPMPYis01xpibVRONPTYcghhfcXSOMPalw25yribUPMLPTYceedbYUQNOUeowyvogaVQMKMRWbgiihfbVQLNTbksvsplhcYURSVaglmmmlicWSRVbltxxwtojdYVWZfknonnmidXTRUcmstsmfXSMJJOUZfhjkifYRKIMVhqvtpibWRMJKPVchlmlhcVPKKRakrtrniaWRLKOTZfijjifbWQNQXiszxtmfZWSOPSYflnnnjdXRLKQZktyxupjcXQMNSYdhjjigcWPMMRZiopolhcYTNMNSYdhjkjgbVPMPWfouusoidXSNMPUZehiiheZUPMOSZehjigcYUPNPUZfjkkkidXRMNVgqxwsldXTPMMPVafiihdZUPMMTdovzwqjcXSNLNRXchjkjhcXRMNTepz21ungZTONPUZeghgfcZURPUdow21vohbUPMMQVaehhgfcXSONTdoz44xpgYSOMNSYdhjigdYTOKMUfqxzvogaUPLKMRWbfggebXSOMScnx43xpfYRNLLPUZeggecYUPMMRcnx11umeXRMKMQWbghhgebWRNNQXgoqpmgaUQLILQXejlmlidWPKLScouvtojeaUOMOTagkmmlhbUOLMVhsyzvpiaVPJJOVdjmnmkhcWQNQZktzxslcWSNKNSZgmnnmhbVOKMUeovxurmfaUNKMRWcfggfdYTNMPWfnrrpmhcXRMNRXdjlnnlhbUONSZhosqolhcXRNOSXdhkkkkgbUQPRXfkllieYUQLLPVbhjkkifaUOLPZku0xrjcVRNLMQWbfhhfbXSOLOYjt02yrkdXSOMOTYeillkhcWQNQZku22yrkcWQNORWbfggfdaWSPOUdnv0yskdXROMNSWbfhihfcXSPRZju241tldWRNMNRVbeghgdZUPMRbmv10vohbVQMLOUafjjihdYSNLPWensurojeYTQQUahnqqpolgaUTVagquvtsnicXSSVbhmonmljeYTTWepxzxskcVPLKOTahmnnmicUNJLTeptuqkdYTOLLQXdilnmkfZSMLNWgpttpkeYTNKLQXdijkkjhcWRPTcntvsnfZUPKJOVchllkjeYSMKOWgpuurnibXQLKOTafiiiheYSNLOUchlkjheaVPMOTYeikllidXRNPVdlrtspmgcWQMOTZfikkjhcWQOPUckoookfaVQMNRXdjllljgaTOMSdovyunfZUQNLLORUWYXVTQONPTckruuphbVRONNOQTVWXXWUQOLKQXflqokeaWSQPRUYcfhiheaWSQRYhpwzvohaVSRRTWZcfggecYTPNQXhpuuqjbVRNLMORVaceecZVRPPVdmrvsngbXSQOOQTWYaaZYVROMOUeowzxqiaUQOPRVZdghhgdZVSRVclsyyuohbWTQQUckrwupjdZYYYbfjmlhaSMJIIIHGGFEEEEEEEEEEEEDCCBBCCDDDDDEEFGHIHGEDCBBBCDEFFFFFFFFFEEEEEEEEEEEEEEEEEEFEEDCCBBBBDEFFGFEDCBBBBCCDEEEEEFFFEEEEFFFFEEDCCCCCBBBAABBCDEEEEEEEEEEEDCBBBBCCDEEFFEEEEEEEEEEEEEEDDDDDDDEEEEEDDCBBBBCDEFFFFEDCBBBBCDEEFEEEEFFFEEEEEFFEEEDDDDEEEEEEEEEEEFEEEEEFFFEDCCBBBCDFGGGFFEEDDDDDDEEFFFFFFFEEEEFFFFFFFFFEEFFGGHHGGGFFFFFGHIJJJJIHHGGGGGGGGFFFFFFFFFFFFFFFEEEEEEEEEFFFFEEEEEDDEEEFFFGGGFFFFFFFFGFFFEEEEFFFFFFEEEDDDDCCCCDDEEDDCBCEINSUUROLJJJJJIIIHGEDCBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]], + level = [[LQVXZabbbbbccdddcZWTQNMLLLMMOPSVYacccbaaZZYWUSQPOPRTVXYYWUSPMLLNQUYZaZYVSOMMNQTXZaaZXVTRQRSTWXYYYWTRPOOPRUWYZZaabbcccccdedcaXUQNLKKKLMMOQSVYZabbbbbbbaYWTQOOPSVXZaaYVSOMMNPTWZbbaYVRONNQTYbdddbYVSQPPQSVXYZYXWUTTTVXacdeddcccbbbbbcdcbZWTRONMMNNOPQTVYbcccbaZZYYXWVUTSSTVWYYYXVTQNLMNQUYabbaXUQNNOQUXabcbZXUSQPRUXbdedcZVSRQSVYbdfeecbaaaaaaabbaZXUROMLKLMNNOPRUWYZaaaaaZZYXVUSQPQRTVWXXWURPMMMORUXZZZYWUSRRSVYcdeecaWTQPPRUYbdedbZWTSWbjt0442wqlheeeefgghgfdaXVUWbiqw00yuplhfddcccccbZXVTRVaiqz352vmdVPNORUYaccbZXTQPQVcltz0zvngaURRTVYaccbYWTQRVclu032yrlgbZZabcdeedbYUROQTZiqvyzwsnjgedcbaaaZYWTRPQTaisz451ulbTONORUXYZZYWTQNQUblw2661umeXTRSTVWXYXWUSRQSXfnu01zwtrqqqomjgedbaYVSPQUblv38861vqmjiiihhhgfdbXURRWeox575xndUNMNPRUXXXWVSQNNRYit28961sjaURRRUWZabaZXVTTWbjsz351xsollllkkjigeaWSOMOTalu2664ytpmjjjihgfdcaXUSSTais0685yoeUOLMORTVVWWWVUTTXckt2685yphZTRPPPQQQRSTUVWYdjpw2553ysmhedfhknprrqnjdYYbhr16972wpidZXXYacdfgggfdbejqy69+72vngYVVWZejlnmkhcYYahqz6+962vohbYXWYacefgfecZadjrz5873wohYTRRTXbdeedbXTSWbju27883ysleaXVWYZabbaZYVWZelu1553yrkdXUTUYcfhihfcYVWahq05884xpibXWYcglorrpmhbXXcjt1874yqicYWWYadfggfcZVQRVdmy4773yrlfbZZabdeeedcaYXXcjs0775zpgYROPSWbehiigdZUTVbju2774zsleZXXYadfghgfdaXYbiq06882uldVSSUXdimopomhcYXckt28+84xphbXWWXacdefedcZZchox3773wnfXSRTXcinqrqolgZXZdmw47861wrmhfeegjmoqpomiedfksz6995zslfbbcdgiklmlkhcYZcis1574ysmgcaabdgikmmljgdbdhpy59+82wohZWVWYcfhihfcYWXbis06+961ungaXXYadgijkjifcdhnu26862wpiaWTTUYbdeecaWUUYgqz6+960tmgbYXXYZbbbbZYVTVahqz5772wohZTRRSWaceedaXTSWclw48972vohbXVVXaceffdbYTTVbku1540umfaXXZbfilnmlidYUWajt37971vngaXXZbfikkjheaWVXdmv3872vmcVQOQSWadfffcZVRSXfp06983wpicYXXYZabbbbaZXWZfmv3786yriaUSTVZfjmnnlidXWYdmx49960tmeZWWXZcefffecaYaeks168840vronnmljigfeedcbacgmt05763ytqnlkjihhgfeeddccejov15640vrnlkkkkkkkkkkjhfeglsz68960unhcbbdfikmnnmkheehnu27+/9741xtrqpqstuvvuspoorv1589851yvuttttttttssrponnptx14530wsolkjjkkkjjihgfefgkqw1453ytmfbZZaehkmmmjheccfkqx133zuoibXWYbhmoqqpoljiknsy3653xqjdZXYafimoqqqponnptx24541xurppppqrrrqpomkiilpv16874zuokihhijmoqsssrpnllosx130vogZUSSTWacegfebYVSVais2674yqibVTSTVXZbccbZXVUWcjs0552xsnkjkmoqtvwxwuspmmnsx379852yurqpppqrrsrrqponoqtx25662ytokiijlnqrtttsrpppruy257752zvrommmoqstttrolklotz4774ztniedegjmpqrrrqommorw167752yuqnmmnoqrssssrqqrux1578750wqmifdcbbbcbbZWTSWclv4784xqibXWXaehjlmlkihggjnt0588740wsqonnnoooonmlkkmpuz367630wspnnnoqrstttsrqqsuy145530xurpnnnnpqrsrqomlkmquz3442zvspoooopqqqqqpomlmpty36640vspnnnoprrsrqonkiikosy2553zuqmkjijklmnnnmljjjmrx2563ytokhggghjklmmlkjhhkou169961wqmjijklnoopoonmlkmqv15863xsoljklmoqrsssrpnlmptz489852yvsrqqpqqrssssqonnquz48873ytpnmnprsttsqnkhefhms04652xsojhggghijjkkjihgghkouy121yvsonmnopqrssrpnlklotz58851vojeccdgjmoonkgcYWZelu1563ztmfaXXYbfikkkjigfgjov16760tlgbZacfilopqqqponoqtx157752ytpmllmpqssssqommmosx1342zwsommlmnppppnkgbYWYdlsy11ytngbYYacgjlllkigeegjov0331xrmgcbcfinqstsrolihjot0578631yxwvtttttttsrpnnpsx26+/+8641zxvtttuvvvusqnllotz58973zurqqstvxyz0zyxvsrsvz378851wrnljjknprtttrpnmmnrw0342yuronmmnpqsttsrpmjikou067740wspnmlkkklmmnmmkjjmpuz46630vrommmoqtvxxwtqmiijnt03552yuqnmnpruwxxwuqlgddejry378630wtrqqqrrrqqpommmpty379851wqmjhhikmoqqqomkihjnty3541wqlgedegijlmmljgdcejpx38873yuqnmmnoqssttrqonmorv046640vqmjhhhhiiiiiiiiilosx257751xuqoooprstutspmiggimsy2331xtpmllmortuutrniddeipx25751wsolkkllmnonmljgffintz3430xvttttssssrrqpomllmqv057741wrnkkkmnpqrrqqponmorv04652zvromlkklnoonliebabgmu15640vqkgeeegiklmnmljhhjnsy3551xsnkjjjjklmmmlkigefint04653zuqnlkkkkjigfeedddfkpw2663ytojhghijlmmmmlkihgimry4553yuqnkkjjkllmmlkjhggilpuyzzxuqnljjiihgggfffffgghhhhhhhggggggffedcbbbcdefghiijjjjjjjjiiiihiiijkkllllllllkjiiiiiijjjjjjjjjjjiiiiijkkkllkkjihgfeefgiijjjjihggfffgghhggfedcccccddeefghiijjjklmmmmljhggghijklllkkjjiihhgfffffghhhhhhhhhhggggffhkoswzzyvrolkjkkkkkllllkkjjjjjkklllmllkkjjjjjjijjjkkkjjiiiiihhhhhhggggggffgghhiiiiihhgggggghhhhhgggggggggghjnsw022yurnllllmnnnnnmmlkkkklmmnnonnmllkkkkkjjkklmnoprsuwyzzxuroljiijkllmnortvwwvsqnlkkklmnoppruwz10zvspmlmoruxzzwsmhdaZabcddeeeddcbbabcdeefffffffffeeddccbccdddedddddddddccccddeeffffeedddccdddeeffggghgggfffeeffffgimrv0220wsomklmnnoonnmlkjjjjkklmmmmmmllkkkkkjjjjklmnoprux011zwsokhffgghjjklnoqrrrrssuvvtqnkjhiknqtwwvsoliggimptwxurmifdddddddddddddddccddefghiiiiihhhhhhhiiiiiiiiknruwwurokiggghhiiiiiiiihhhhhhhhgghhiijjjjjkklllllkklmptwyyxurnljiiiiiiiiiiihhhhjmpsuvusqnlkjjjiiiiiijjkkmnpsvxyywusqonmlmmnoppqrstttrqqqrstuvvvvtrqpppqrrrrrsrsuvy0220xtpnlkkkklllllllkjkmqv04552ytokhggikmnnnmkigefhjmruwxxurmifddfikmnmljheeegkqvy00zxtqnkjjjlmnoppoonnnpsvy010yvsomllllmmllkkllmnpswz00xupmkjjkklmnnnnnlkiggimrx022zwtronmljhfeddfhjkmpswz221zxusqooooopppponljhiknsx01zwsqonnnnnmmllkkjjjjmquy231ytplihiiijklmnnonnmmnqux01yupkhffgghjkllmmmmlklmptx00yvronmnnoonnnnnoooppqtwz120wrmifddegiklmmmmmnnoqtwz11zvspnmlllkjjjjjjjjiijloswyyvqkeaXXYZbeghjjkkkkklorvxzyvrnljjjkklmmmmmllmmmorux0221yuqnkjijjkkklkkjihhjmrw011zwtqnkjiiklmmmkjhfeeilqvz0ywsnjgffgiklnnmljgdcdglrwz010ywusqponnooppqqppoprux0121yurnlkkklllmmmmnnoqswz222zwsoljjjjklllmmnnnmlklosvy00yvtromljigeedefhhjlorwz2321ywvtsrrrrrqqqqpponoqtwz0zxurpooonnmlkjjjjkklnptw0231xtpnmmmmmmmmmmmlllllorvz11xsnkgfgghijllmmmlkkjmptx232zvspoooppqppoooooooopsvy01yuqmigfffgijklmmmnnnpsvz2320wtqpnoonmmllkkkklllnpswz10xtpmlkkllmnoooonnmlmnptxz0yvtqppqqqqppoonnnnnnopqstvwwwuroljhhhijkkkkkjhhilotxzzyvrokhgfgiklmnmligcbbdhnswyzzxvtqponmmmlllkihghkotx1220xuqligfghklmnmljhffilrw010yvsqonmllllllllkkjknqv0343yupligggghjlmnopppoopruxz0zxusponnnnnoppqqqpnlllnrvxyxvtrpnmllklnooponmjhilpv01zwsomllmnnnnnnnmlkjjknsw1441wrmigghiknopponmkjikoty242ysokihiiiijjklllkkkloswz11zvrommmmlkjjiijjiihghimptwxuqnljjklmmnnnnmmkjihilptxxxuqmjihiijklllkjigfedgjnrvwvtqomkjihgggfggghhgghjmpsuutrponllkjiihhhhiiiihjloty110xtoljijklmnonnljhffgimquwvurojfcbbdhkmoonlifddfjotxzzxuqnkjijklmnnmkjhffgjmquwwvusqomkkjjkmmmljhfccdhlrwz0zwsnieccdfjlnoonnmlmnpruwwwurpnlkkjjkllllkjihhiknrvyzzxuqmjhgfhjkmoooonllmnquxyzywusqomljiiiiiiiiiijnrvz20wsnjhhghhhijkkkjigffgkpuxyxuplhfeffghjklmmlkkjjlptx00zuqmjhhiijkmnoonmlkkknquxzzxurommlmlkkjjiiiihhhknsx132ytokiijkklmmnnnnmlkkmptx01zvrnkjijjjjjkkkllkkjjlosvxxwtrpnllkkklmnooonmmmnptx010xtpmkjjkllnooonmkihgilpty10zvqlgdcdfjnpqqpmjgcdfjovy0zxtpkgdccehijkjigdaYZchovyzzwrmhdaaacfhjjjhfcaabfkquxxwuqlgdaZacfghhhgecabdjovz10xtnjdbabcfhjkjihebabejpuwxwtplgdccdgjmmmlifcYXYciqvz0yvqlgcbcfjnpqqpnkhedeintxz0xtokecdehlooomjgcZYaekrwzyvqlgcbabdgijkkjigeccejouyzyuqkgbabdhloppolifcZYchouzywsniecabbcfghggebZXXafmuy11xtokgdeghknnnmkhgebcgkry231wqkfcbccefhijjigecbcglrx00yuplhfefghjkkjihedbbcfkquwwtqlhdbabdgkmoonligdcfiotxzywsojfccdfilmmljhecaacglrwyywsnidbbdfilmnnmjhdbcejpuxyxupkfcabdfjlnnnlifbZbejqwyywtokgdccdfijklkjheddfjotwyxvsokgedegjmooonkhdbbdhnswxxurlhdbbcfikllkjgeccdhntx00yuqlheefgjmnnnmkhecbdhmsvxywsnidbacfilmnmljhfefhlrvyzyvrmieddfhlmnmkifcZYbgmuy0yupkfcbbcegiiiihgfdbdgkpvyzxuqlhedefilnonmjgebacgmsx0zvrmhdcbcdfhiihhfedbcejotxyxuqligeffhikkkjigecacflqwzzwrmhdaabdfijkkkigecbdhmsx00xtokfccdfimnnmkhfcabejpvz0zuoidZYZabeghhhgecbabfkqw0zwsojfdddfhjkkjigecaZaejotxyxvrmifdegilnoonlifdcehmrwxxvsnjfcbcdhkmnnmkiecbeintxzyvqlgbZZadgjkllkigcbdfkqvyzxtpkgdccdfijlmlkhebZaejpvyzyuqkfbabdgjmnnnlifeegkqvy0zwrnjeddegklmmljgebaadintxzyvrmhcaaceikmnnmljgfgimrvyzyvsojfeefjlnonmkhdabekry01ytnhcYYZbdgijjjhgeccfiotyzyvrmhebbcehjkkkigdbaadjpv01yuoidaZZbcfhiihgedcbcglqvxxvsnjgeefghjkjihebZWWYdjrwzyvpkfbZZacehiiihfecbbeimsvwvsnieaYYZbdfgggfdcaZaeiouwwupjdZVVWZchklmljhebbcglqtvtplgbYWWXadgijjjhfcaacglrvxwuqlgcZYZbdfhhhhfdbZZcgmruvurnjebZZZbdfghhgecZYadiosvvtrmiebaabdghijihfdbacfjnrssqnjfbZYYZbcefghgecbbdhmrvwusojfcaabcfhjjjigfccdfjpsuwtqmhdaabdfjkllkigdaabejptuurnjgcbbcegjkllkigdccfinsuvtqlhcZYYabeghihgebYWYcipwyxuqlhebccdfhhhhgfdcabdhmruwurmhdaZZabdffggfedcbcfkqvyzwrmiecbcdfhjjjihfdbbcfjortsqmjfcbbcdfhiihhgedddfimqtvtqmjfdddefhijkjigfdbcfimrttrokgdZYZZbegghgfdcaadhmrvwvsnidaYYabeghihhfedbceimruvtqmieaZZacfghihhgfdbceiouxyxtpkhedcbZYXWVVVWWWWXXYYZZaaaaaaaaaaZYXWWWXYYZZZYXWVUTTSSRRRSSUVWWWWVUUTTTUVWWXXXXXXXXXXXYYYYZZZZaaaaaaaaaaaaaaaaabcdddccbaabbbaaaaZZZZaabbbccbbbaaaabbccccbaaZZZZaZZZZZZabbbaaZYXWVWXZbdeeedcbaaZZZZZaaabbbbbbbbbbbaaZYXXXXXXXYYYYXXWVUTTTUUUVVVVVVVVVVVUUTTUVWYZaaaaYXVUSRRQQRRSTUVWXXYYYXXXYYZbbccccbaaZZZZYYYXXXXXWWWWXYZabbaaaaaabbccdddeeeddccbaaZYXWVUUUTTTTSSSRRRSSSSTTTTTTSTTTTTUUUUVWXXYYZZYYYXXXYYZabbbaZYXXWXXYYZYYXVUTSTVXadeffeedcccbbcccccbaaZYXXXYZZZaaaaaaaaaaZZZZZZabbbbaaaaabbaaZYXXWXYYZaaaZYYXXXYZabccccbaaaaaabbbbbbaaaZZZZZZZZaaabcddeeffffeedddcccbbbaaaaabbcddddcbaZYYZZaabbaaZYXWWWXXYYZZabccddcbaZYYYabefggggfffeeedcbaaaaabbbbbaaZYXWWWWWXYZZabbbbbaZZYXXXXXXXYYZZaaaaaaaaaaabbbcbbbaaZZYYYYYYYYZZaabccccbbaabbccdddccbbaaaZZZaabbbbbaaZaabcdeeedccbbbbbcccccbbbcccbbbbaaZZYYXXXWWWWVVWWXYYYZZZZZaaaaaZZZYZZZZZZZZZYYYXYZZabcccccccccbbbbcddeedcbabehmqtutrpmkjiijjjklllkkjiijkmorrrpnljihghhijkllllljihijmpsttspmjihhijlmnnnnmkkjjknpsuutroljiiijklmnnnnmlkjjkmorttsqnljiiiijkllllkihgghkmpsttrpmkjijjkklmnnnmlkjijknqsttrpmkjihhhiijjjjjiiijkmpsttrolifedddefghijjihfffilptutroljiiijjjjjjjiiiiijlosvyzyvspmkjjjjjkkkllkjjiikmqtvutqmjihijkmnoooonmlllmoqtuvurnkhfeefghhijkkkjjiijlnqsttqnkjiijklmoopponmmllmoqsttsqnljihhhgfffghhiijjkloruvvtpmjhhhhhhhgfffffhhjkmpsuutqmjgeddefghhhhhggfghkosvyyxuromkjjjjkklllkkkkjlnqtwxwuromjiiiiiiihhggfeefhkoswxxvtqnlkkklmmllkkjjijkmpsvwxvurpommnopqrqqqppponoqsuxyywsplifeeeffgggggfedefjnqtutroligfghiklnoonmkhgghkosvwvtqnlihhhhiijjjjjjijkmosuuutqomkiihhhiiiiiiihhiknswyyvrmifeefgijjjjigfdcbdglquwwuqmigeefgghijiihfdbbcglquxxvrmifdddefghiiiihhggiknrtutroljhhhijklllkjhgeegjmruvvuqnjhgghiklmmmlkjhffgimpsttspnljiijklnnooonmkiiilosvxxurnkhgghjklmmmlkjhhhknruwvtqmjhgghhjkmnooonljijmqvyzywtpmkigggghijklmmmkklnquxxxvspmjijjkmmmljhecaZbfkpuxxwtokgdccdfhjkllkjihhiknsvwxvspmjhhhiknooonmkjiikosx010xuqnkjihggffffeedccdglquxzxuroljhggffggghggfdcehlqvxywsokheddefghhhhgfdddgkpuyzzyvsqomllkjiihhgffedfjotz11zupkgdcccccdddeddcbcfjotxywtojgdccdefhijjjhgeddgkqvz0ytojfcccccdddddeeeeegimqtvvtpligeefghijjjihgfeefjnswzyvqmifdddefghhgfedcbceimruutqnjheddefgijjjigecbdhmsxzzxtojgeedccbZZZZabcdegjnqtutqmjgfffffggffffffffgjnrwyzyvsoligghhjkklllllkkkmptxzywtokifefghkmnnnmkigfgjnrvxxvsokgedefghiijjiihggjlptwxwuromjiiiijjjkkkjjihilotx01yvqmigffeeffffffecbbcfjosuuspmjgeddddefggghhhghjmptwxxwtqnkigggghhihhgfeeehkpsuvuspnkihhhhjklllkigedfimrvwvsojgdbbccdeeffffffefhkoruvtqmjgeddefgijkkkjheefhmrvxxtpkgcaaabceffgffeeddfjnswyxvrnjgeeeefghhhhgfeefhlqvyzxtojfccdfhikllkjhfdcdfjosuvtqnljgffffhjkkkjigedfimsxzzxtplihhijlnooonmljihilptwyxuroliiiiijjjjihfeddfimqvxxxuqnljihiijjkkkjjigghkotxzywurolkjjjkkkkjhgecbbdhmswyxvsnjgeefghijjjjjihffhkptwxwuromkjjkklmllkjihgfgknswzzxuqmjihgghhijjkkkjiiikortvuspmkihhhhhijjjihfdccgkqvzzxuqmifeeeefgghhgfecdfinsvxwuqnkhgfeeeeeffffeedehlqvyywsokhfeeeeeffgggffedehlquxxvrnjfedeeffgfffffeddfjnsxyxtpkgdcbbccdeeffffeddfimruvtqmifeefgghiiihgfeedegknrturnjfcbbcdeghhihhffddehlptutrnjgeddefgijkkkjihghjnrvyzxuplifeeeddcaaZZZaaacfimprrqomljjjjjkjjhgfedccdgjoswxxvsoligfffghiiiiiihggimqvy0zxurolkkllnooonmkjhfgilptwxwtqmjgeeeefggggfffeegimpsttrpmkjiiiijjiihhgggeefhlprssqnkigfffffffeeeeeeefhknqrqpnlihgffffggggffeeddehkpsuutroljhggfffeeffffffghjmprsrpmjhfedddeeeeeeedccdgjosutrnjgfeeeefffffffeeddfhlprsrolhfeddeefgggggfeeccfimruutplhfedeeefffffedcbbdgkpsuuspligeefghijjjihgecdfinsvwvsokhfeeedddddeeeeeegimquwwurmifedefhiklkkjhfdccehlpssrokgdbbcdefghggfdcbbcfjossspmigeddddddefffffedegjmqtuuspmjgfeeffffeedddddfhlptuusoligeeffgiiiiihhfedegknrssqnkhfddddeffffffffeegjmqtutqnkigggghhihgffeddcdfjnrttspmjgeeeefgggffeeedegjnruvusoligeeffghhhhgffeefhlptvwvtqnkhggffggggggfggfgilosuutqnkhgffgghhhhhgfecdehlquvtqmiecccdeghhhggeedcdgkotvvtplheccdfgikllkigfdcehmswzxuqlgedcdddeeeddcbbbcehlpstspmigedefgijkkjjhgfdehkotvvuqmifedeffghhhgfedccehlptvuspligffghijjkkjigfeegjnsvwvsnjgddddeeffeedccccehkosuusplifedeefghiiihhgfghknqtvvtrnligfggghhggffffffgjmquvusolifeeefghhiiiihhffhkoswwvsokheddefhiiiiihhggghknqssromjhggggghhhhggggfefhkostusqmjhfeedeeeedddccdegjmqstspmjgeddefggggffedccegkostutqomkihggggggggffeeegjmqtuuspmkihggfffffeeedcbcfjotwxuqlhdccdefghhhgfedccehlptutrniecbcdefghhhhhgfeegjnrvwuqlhdcbccdddddddddccdgkotwxvsokigghijklllkigfddfhlpsutrnjgfeeeffffffeedcccehlprsqnkhfdeeffffffeedccbdglqvyywrnjgfeeeefggggfeedddfimqssrolihfffgghiiihggfffhjnruvvtroliggggghggffeeeddfilptttroljhfgghhihhhgggfeehjnruvtrnkheeeffhhhhgffeddfhlqtuusokiffffghhhhhgggfffgjnruvvtpmifdcccdddeedddcdfimruwxvrnkhfeeefgggfedccbcegkosttrpmkiggffeeeeeeeeedegjnqtutqnkifeeefgghhhgffdcdfimqrrpmigeddeffggghggffeegilorsrplhdcabdegjklllkigffgkotxywsnjfdcdeefffffeedddfilpsutrnkgfffgiijkkkjihfeefimrvxvtpkhgffffffeddcbbaacfjosuvtqmigeeefghijjigfdaZbdhmruusplheccccddedddddddegjnqstspmifeddefghhhhgfeedfilptwwvtqmkhgfffghhhhggffefhkosuvusoljhgghijkjjihgfefgjnsvxwuqmjgfeeffggfffffeeegjnswwwurnljjiijjjjiihhgfeegilprsrpmkigffeeffffeeeedfhjnruvvsokgdcbbcdfgggfedcbbdgjnqqqolhfeddeefggggfedcdehkpsuutqnkigffeeefffffedcbdfkostspmifdcddeffffffeeddefhknqqpnjgecbccdeeeeedccbcehlpstsplhecbcdfghhggffedcdfhlorsrokhdcbbcdeffgffedcccehlpstrokgdcccdefffffeedddegkosttrokifeeefffgfffeedddfhkostsplheccceefffffedddcdfiloqqpmjgecccccdddcccccccdgjnsuvtqmhdZYYZbdfghgfdaWWXbipuxwsnhcXUTTVYbeghhgebYXYcgnqssokfaVTSTWadfghgfcZWWZelrvvtoicWSRRTXbeghhfdaVTUXbimpqpmieZVVVWZcdeedbaYVXaekruutpkfbXVVVXacdeeecZWUVYcjorsrplhdZXWWYacdeedbZXYaekruvurmgbWSSTWaeghhgebXTTVagostsplgcaYZacefgfedbZWWZdiotutqmgbXVUUWYbdeffedbYYadiotuuqlfaWUUVXZcddcbZWTRSXeltyzwsmfYUTTVYbdfffdbZWVXagnsvvsnicYVUVXZcdedcbZXVWZflrwwuqkeZVUUWYbdfggfdbXVVYciptutqlgcYXXYadfghhgfdbYachouwwuqlhdZYYacgiijigecZYZbgmrttrmidZWVWXacdfffedaXWYciosusokfaXVVWXacegggecZXXZdhnpqplhcYUTTUWZcdeedbYUUVaiqw0zvqkdYVTUWadghihfcYUUVZfmqstrnjeZWWXYcegggfdbYWYbfmsuutojeaWVVVXZbdeedcZWVWZdkoqrqnifaXWWXZbcddcbaYWXZchnqrqnidZUSTUXcfhihgebXUVYdkquuroidZXWYadfghgfdbZXYbglruutpkeaWUUWXacdefedcaYYadiorsrnjeaWUUVWZbcddbZXUUXciqvyxupicXTSTVYbdeeecaYUUWagosuurmhcXVVWZcegggfdbZXZdiouxxvqleZXVWXZcefggfdbXWXchotvvsojeaXXYacfgggfecbZZbflrwxwtnhbVSSUXaegggfdaXVVYdjquvtqlgbYXXYacfghhgebXTUXdkruvtplhdaYYYZbdfffedaXVXaflqssqlhbWSRRTXadeffdbYVVXdlsy1ytnhaVTSUWaegiihebXUUWagnqssokgbXVVWXbdeffdbZVVYbgnrsrqlhdZXWXYacefffdcYUVWagnqsrplhdYVUVWZcdeeedbZWYaflruusnhaWSSTVYceffedaXUTWahpuwvsnhcZXXZbdefedcZXUSUZfmuxxuqkeaWVVWXacefffecZXYbflqtsqmhcXUTUWYbdddcaYVSTWcjrwywtnhbWTTUWZbddedcaYVXafmtxxvqkeZUSTUWZbddecbZXWYdjpvxwtpjeZXVVWYacdddcaXUVXciquwwsnhcYVVWZcfijjigebYYbfmtxywtoieaWWYadgijjigeaZZcgmruvtpkfaWVVXZceghgfdaWVWagntvvrnidZXWXYacdeeecbYVVXbgmqrqnjfaVTSTVYbdeeedbYYZcipuxyupkeYVUTVYceffedaXTSTWbhmopolhcYUTTVYbdeeecaYWXaekqtutqlgdZXXXZbdffffdaXUVXbioqrrojgcXVVVXadefedbZWWXbgmrstrmgbWSTVXcfhhhgebXTTWaiqtvspkfaXVVVWXXXXWUTRQQTYelrutrmhbYVUUUUUUUUUTSQPQSXcinppmicXSRRTVYbcddcaYVSTVagnrsrnicXTSTUXZbcccaYWUSTXciorqojdYTQQQRTWXYYYXVTRSVagnsutqlfaVTSTUWYYZYYWVTRSVagnrsrnibWRQRTWacdedcaYWVWZekpssqmhcXUUWafloqpnjfbZYZcgkoqqnjdXTQPOONNMMLLKJJIHHGGGFFGGHIJJKKKKLLLLLKJIHHGHHIJKKKKJJIHIIJKLMMMMLLKJIIIJJKKKKJJJIJJJKKLLLKKJJIIIJJKKKKKKKKKKKKKLLMMMMLLLKKJJJJJJJJKKLLLMLLLLLLLLKKJJJJJKLMMMMMLLLLLMMMNNNNMLKKKKKKLLLLLLKJIHHHIJKLMMLLKJIIHIIJJJJJJJJJJJJJKKLLLLKJIHGFEEEEFFGHIJKKKKKKKJJJIIHGGHHIJJJJJJJJIIIIJJKLLLKKJJIIHHIIJJJJIHHGFFGGHIJJJJIHHGGGHHIJKKKKJJJJJJKKLLLLKJIGGFEEEEEFFGHHIJJJJJJJJIIHGGFFFGHIIJJJIIHGGGGHIIJJJJIHGGGHJKMNNNMLKJJKKLLMNNNMLJIHHLQXfnrsqmhaVSQPOOMLJHFEDCBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAA]], + bright = [[HIJHGFFFFFFGIKLMMMOQTVWVVWYabaXTPMMNOONLJHGIMQXdhheYRKHFFGILPTVUSQONOPQRSSSSRPNMLLMLMOQTVWTPLIFFGILQWacbWQKHEEEEEDDDEFHJKMNNOQRTVVVVWZdecZUPNNNNLJHFEFHNUbhkjdXPJGFFGKOSVWUSQPPQRRSTUWVUSQMMMNPTXcgjheXQJFEFINSYcebWQJECBCDEEFFGHJKMNNNOQTVYZXWWWYYWSPMLMNONMKIHIKNSXcecXSNIHGGJMQUYXVTQPQRSSTUWXWURPNMNNMNPRUVURMHECDFJOTXYWTOIFDCCDEEEFFGHJLMOOPQSVXZYYXXYYXUROMMNNMKIGFGILSZgmnjcUNIHHHJMQTUTROLLLMOQUYbdcaXUSSUVVWYZddcaXUTTTTVXadjmoqqrswz12223320xvttux148++741xxxyxvsoljiiiigebZYacfikljfYSNMNPSUWXXYYXXWVUVWXZeimpstuwxyxvspnmkjgcXTQRSVbfjjhaTMIGHHHGIKOSVVVTSRSUWbgkosttvutqnjgecccbaYVUWYchlnnlfYRMKLOQSTUVXXXWUSRRTVYcfghijlosvxyxtojeaWRPOQUZbehiheaWRMLJGEDEINRTVUSQQSTWadegikmprqnjeZVSPMKIGGJNSXacddZUNJGILORSUUVVVUTSRQRTVaefghhjmqtwxxuqkfaVRNKJMQUbhmqpkeYTRRPMJIHJMOPQQOPRTWaeghjkloqrqnicXUROMLJILQVaeghgeZTNJJKORUZflrx1355421zywuromkloruwvtpmjijjjjhghijmopppqqsvy245530wrmheehmsz4861vpkkmoqstuutsqnicYWXZdhjlmmjgdbadgijkjhgebZYXaejlmnmllllkklmmlmmnomjeXRPRUafknrtspkfdeiknnljhfdcbacgkopoomkkmlmnoqqrssrqnjdWSSUZgmptutrmgcabehiihggfdbbacfjmlnmlkmmnorttuvvurpmjhhhimsy4884yrlgfhmpsutrokfYSQUaktuurojjiikmopppoonkgcVQPSXemqsttqlifehmqrspligdcbacfjprrrojhgfgjlnopppomjeXRPQUbjorttsmieccgkmomkhebaYXYaeillmljiiiikoqsttsrpmicVRPQVchmqsusnidbdfhihfdcbbZYYaejnqrqnlllmoqtx0232yuromlllmptwz1zwrlheehjmnmljgcWQOQWfmmlkjikmkkmnoooonmjgbWPOOSXehkmonkgcZYacdeeeddbaYYYcgllnonmnnmllnnopqqpnjfZTPPQUZeimqrplhdbeikmmlkkjhfdcdfilnoomkkjjkmoqrssrqolgaURTXfmruwxvrmgcbegjlmlkjgedceintvusokjklnprsssttsrpmkjjkmrx37+72voifgkorstqnkfaTPOSajppqmifhhikorssssrojdWPLLPWfnswwurligfinprrokgecccdgkorqqomijiijnqrsrqpnlhdXRPQUahkopqplheeglpqqnjfdaZYXZcgjklmlkkkjjmoqrrrrpnjeYTRSWcjnqrqnkjjmptvxy023320yuqlheccdfghijlnprstvxz0zyvsokhedegjnqstsrsux02321zwtpmkjjlnopqqomlkkklmnooonlieZUSSVZeilnmjfaXVVWXXXVVXZbcbaZZZZZZabdghijlopqqpommlifaXVWZdfgikmkiebZceghhgfffffeegiklmkjjjklmoqrtwy0yvpjbVSSVZejlnoolifbZadgijjihgdbYXYadeccccehkmprstvwxxvspligfeefhijllkhebZadfhhhfedbYWUUWZcdccbbdfilorttuutrojeYURQSUWZadgihfdabfkopnkhedcbabejnomkhfeiknqtwy01220xtngcbdhnsuuuroiebZadedbZXWXYYXWWXYZZZZZadfhjklnonnnkhdZUSQRTXaceeedZWTTUZdgfdbZYXXWVVVWWWVWWXbfilnmmnoqrqomkihfcbceiloomiebZZcfiklllkgbWQOPTXZYYZaejmnpqpqsttspkfZTPOPTXbdeeeecaXXYbeggfeeeedbabfilihgfehklnruvwwwvspmgbWVVXbfghjkljgcYXYacdddddeeeddefhfedbadgikmoopqrsqnidXSQPSVaegikkifbYWYacdbaZZZaaZYZbdcbZYXafjnprrssttsqnmllkjhghknpqokgeccfjlnmlihfcXTRSWbfedcbbehknqrsrqonkieZUQPQVafiklmkhebachklkhdbaZZYYaceecZXWWZdhkortttsrpnlieZVVXbfjkllljgebcfikkgdbZZZYWXadggecbbcgikmpqqpomljheaVRRUYdijklkieYUUWcjoppnkhecbbdhlprspligegikllmmmmmljhgeddeefgiklmnoprtvxyz00zxurnkjkmprrqokjjlnqtuuuspnkheaXVWZekoqssqnjfcdgilljhgfeedbbdhkmljhffhjlortvwwvurpmjgdccdgiijjjigeaYZabbaZZacddbbceghfdcbcgjlnopqppnligdZWSTVafknoppnkgdbdgjlkhfcbbbbbbdfijjjihikmpsuvwxyzywspmjihhhkoqrrplhecceffeeddeebXTUWbfhedcbdghjloppomkjiheaVTSVZeikmnnkhdbacgiigecbaaZXXYacdbZZZadhknoqrrqqpnmkheZWVXZcfghjjhfcbbegfdaYYYZZYXYbeffcbabchjloqrrqonljhdZVSSVZdhiihfcXTRTYejmkhebaZZZacgknqqpmlklnprttutroljjjijjknruwwvtqlhdaZZabbbbbaXUSQQUYabaaabdgijlllmnoomieZURPRUZdfhjkjhdZYZdgihecbaaaZXXYabbZZZadhkmpqppponnlifbXTSTXbfgijigebXWXYaZXWVVXZaZaceggdcbbdghijkkkkkkjhfbWSOORWchkmmligdaZabddcaYXYYZYYZcgkmnmkijlnprsssssrqonljiiijmrtvusojhfffhihgedefebXUVYdikjigffhjlorstsrrpnjfaVTUXbfhjkmlifbaaeikkhfdcbbaZadhlnnligghkosvxzzzyxwurokgefhkmoppolifeehkmmkjhhgfecceiloppnkihiloruwxxxwurnjhffhjlmnopomiecdhnsuwwurokhgfhjmorttrolkknqssssrrqolifdcbcccddfhjkmnqux1221zxusqppnmlkjjigfffefdbaZYYZYXWVVVWVUUTTUUTSSRQQQPPPPPPPPPOOOPOONNNNOOOOOPPPPOOOOOOOOOOPPPOONOPRVaflqtuvvvuutqnkiggfdcbaabaZZZZZYWVVVWWVUSRQQQPOOOOOOONNMMNNNNOOPPOOOOOPPPPPPPQPOOOOPQPPPPQRRRRQQQQPONNNOQTWZdghijjjjjihfecbbaYWVVVVVUTTTUVUUUVVWWVTRQPPPPPPPPQQQQQQRRQQQPPPPPPPQRSSRQPPPPPOOOPPPPQRSTUUTSRRQQQPOONPRUXacfhjklllkkigfeeeecbZXXXWUUUUUUTSRRRSRQPOOOONMMMNPSVXadfghiklllifcaaacddeedccbcfhhfbWRPPPQSWZbccccdhklkigeefimptwyyyywurpmlljihhhhhfdddegfedccdecbaaabcbZZZZZaZYYYZYXWVUUUUUUUUUVUTTSSTSSRRRRRRRRRRSTTSSSRRRQPPOOORUXZcegilnnnmljhgfgghhhhgfcZWWYbeffeeeffdbYXYZbccddccaZYYadegiknpomhdbbdeffffedcdefhijjjklmopomkihhfeefhkllkiggilptwxyyxwutsrrsqomkjjjihghijkigfeeeedddefggffeffgfffghjlnnnnmlkihhgggfeeeeecbaabbcbaZZZaaYYYZacccbbaabcdefhjmoqrrsssrqpooomjhfeeeedfhkosvxz011zwusqqpomlkjjjjiiiijjlmnpqqpomllmnoomkihghhihhhhijjjklmnnmmllkkkkkkllkjklnprstssrqoonmmmnnmlkjjjjllmnoopppomkihfffhjmprsrqnkhdbcdfffcaYYZbbcdegiknoonmmmlllkjjiihhggfdccceghhhhhgfeccddeeedefhijihhhhgedcdeikmorsssqnkhfedccdehjlmnoomjfcbcfghdYWWZfknonmljhgfffhjlnppoonmmljihgggghiiiijjjigfeefgffffghhigedddefeeefhklnoqrqpomljigfcbaacdeefghgfeeegiigbYWWXbdefgggfeefghjklmoonmkjihhggfddcddeeefgggfeefhihgfffghhgfgghgdbabdgkmoqrrpnljihhfcZXXZcegijlmkihhjnqsrqomlkjjijklllkihggilnqrsrqpmkjhhiiijiiiggghhihfddfgijihhiijifffghihgggikmnoonmmlkjihgedcefilnoopoliebacfhgdZWUVYacddegikmmmmllkkkjihggffeeedcbbbdfgghhhgfdccegggfefgijjjihhhfeeefilnopqomkjhgfeedddeefghikmmkhdaacefeaWVWZglopomkiggghhjllmnnnnnnmkjihhhgfeeeeeeeddccdfhiiiihhhggeeeghihfeefhkmorssrpmjhhgedbabcefghijjhfedehjkkigeddeefffeedddddegilnoonmkjhggedcbabcdeddedcbbbdfijihffghiihggggedccefijjjjkkkkjjihfcZWWYZceefghhgfeefhhfdbcdfjmmmmmmlkihgfhkmoponljihgggggfeeddccdfhjlnnpqsuwxyzzywusrqpqppppoonoqrtttsrqpnkjiiijjjkmpsutrnjfddeegffdddefhijkklkjigggijklmmmnooomlkihgffffghijjigeddefgggffggggeddegijjjjklnqtvwvtrqomkjhhhhiiihgffghhgedeghhhfdceghjjiiiiiijkklnoprsrrqonmkjihgfeeeefhkmmljgfgjkllkihhihfbaacehggffgiloqtttsqnmkkjjihhhjklllkjhggghjlljihhhijjiijjjjhgghhjkmnpppnmllmmllkjijlmmmkjjiiiijkmnmkigfddcbabcddbYXYaeknprtttsrqomkgcXUVXchkkmmnonnmmmmmllkjjjjihgfedbXWXYchklnnnmmlkkjihhijihgebZadfhihffgijjjiijifbXTUYdilmnnmmmnnnnnoooonmlklkklmnopqqqnkigfgiiiihffffghiiijjjjjihhijklmmllkjjiihgffgikmnonnmkigeeefgfeeeeeeeeegiklllllkklmnoonmkjihhiijklmnnnnnnnmljhgfghhiijjjkkjihhhiiiiijkllllkjjjkkkllllllklllllkjhfdddfikkkjiiiheZUTUXaZWWWXbgjloqrqpnmlkjjjjihhiijkkjigfeegikkkihhhhhhhijkkjhgggikllmnnmlkjiiihfdbabdfhiiiihecbaceedbZYZbdeeefggfdaabcehjloqrpnlkihgecZYZbdghhhhggecdhkoomheddfghhjlmmkhfefhkmnnnnmkjjkkllkjiijjhgdddegjmoruwy0121yuronmnoqsvwwtqnlklmnortuutqnjfdcdglqtvvtpkgdbdeghhggfeddccdgiklkkjijkkkmmmoqrstrokdWTTVbgkmnnlhdYVVXZbbbbccdecbcdfghgggghjkklmnprttspmidZXZbhouxwurnhecabceeeeedddcbbdfggfffghkkkkkllnpqpnkgdbaabfimopnlidbaabehjlmmlkhcXUUVYbbaabcfhhjmprtuuurokfZUTVZgnqrrpnjfcZZcecZWVVXacbbdgjmmlkkjjllmoppponnljhfZVTTVZgjllljgdbZZbedcYWWYbedcdehjjgdcbcfhjlmmmmmmljhfbWTSUZgnrsrqnjfcZYYYYWWXYZbbaaacdeecccdgkklkjkmorsqmhdaZadgkoqrsqnjeaZadhloqrqnjdXTSVZeffffgikkkklmpstutpmgbVTSVbinsutqlgbYYabccaZZacccaacegfcbbcfklmmmnoqrtssplgbXXaekprssrokhdbdfikkjjjiiigfghjklkkjijkkklmnpqrrqomjebZadiosvvuqmgcaacgijigfeeedefgijigggghklmmmlmnprrpmiebabdhmpssrokgdccfilmonmljhcYWWYababcegjjjkkmmoprrpnjeZVVYdjprrqnkgdbabefffedccddeegijjihghhjklmoppponmmlkhdYXYbgmpqqpnifcabeghgedddeeeefgiihgfefgijkmoqssssqolhcYWWZflpsssplheddgjmnmlkjiiiiijmopqqpnmkllnoqrsttspmjhgghjlnqtutrpnnpsvxy0232zwtpoooqsuxyxuqnllmnoqsuwwurnjebbdglruvurnjfbZaceggedcccbbabdgijjjjjjkllmmnoqstsqnidYWXaeloqqpnjeaXWYbcdbbbbcccbbdgijjigfgijklmnoprrqpmjfbZZbflrvwvtpkfbZZbdedbbbcdedefhkkhfedeilmnnnmnoponlifdcceilprrqokgcaZcgjnoponmkgbZYZcffedddfhjlnpqqqqpomlhdYWXaflpqqolhebabeijjhecbcdcddfhjjiggfgikmopqqqppomlifaWXbfmsttsqmhebcejnolifddefghknppnjihgjlnpqstuuvuspmjebZZbejmoqrrqpnmmnonljhedeeddfilmnlkjjlnpqsuwyyzyxvtroliggimpstusqomkklmnppponljfZYZcgjhffgimnmmnortvvvtrokfaZaekpsttrpnmlllmmlifdccdcbcegjkjgfegkoqrsstvwxxvtsnjdZWXaeilnoonmkijklkjhfdeffedegikjihhhkmnoqrsuvwxvsolhdbaceimpqppnljiijllkheccdeeeegjlkjhhhjnpqsuvxxyyxvtroljhghknqttspnkjjklmmmllkjheZZadhkjhgfhkmopqsuvwwvtrojfaXXZcgkmnonmkjijlmmkigggghgghjkkjgggiknpqrrttuutrpnjgbXXYafjklmmmlkjkmopnkigfhhhhhiklljjijjmnoprtuwxxxvtplfbZbeinpqqqqpoooquwvtqnkjjjjjkmnnmmnpqsssstwz12321zywusrsuw012zvqkggiknooooppqqqqpnkigfeedbZYWVVUTTTTTTSSSTTTSQPNNNMMMMMMNNMMMMNMLJJIHHIHHHHGGFEEEEFFEEEEEEEDDCCCCCBBAAAAAAAABBCBBBBBBBAAAAABBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCDDDDDDDDEEEEEDCBAAAAAAAAABCEHJKKKKJJJIIHGFFFEEEDDDEEEDDDCCCCCCCCCCBBCCDDDCCBBBBBBBBCDDEDDDDCCBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCDFGIKKKKJJJIIIHGFEDDDCCCCBBBBBBBCCCCCCCCDDDDDDEDDCCCCCCCCCCCCBBBBBAAAAABBBBBBAABBBBCCBBAAAAAAAAAAAAAAAAAABEGJMPQQQQQQRRQPPOOOONNNOPQRRQQPONNNNNNNOOOONNOOOOOOOOOOOOOPPPPQQRSTTSRQPPOOOOPQRRQQQQQQPPPPQRRQPOONNNNOPQRRRRRSSSRQPOONNNNNMMMMNNOOPQQQPPPPPPPOOONNNNNOQRRRQQQRSSSRRRSSTSSSSSSRRQQQQQQQQRSSRQPONNNNOOOOOOPPQQQQPPPPQQPPPQRTUVVVUUTSRQPOONNNNOPQQRRSSTTTSQPPOPPPPPPOOOOOPQQRSSSSTTTTSSSSTTSRQPONNNNNOPPPPPPQQRQPPOOOOOOOOOOOOPPQQQRRRRQQQQQQRRRRRRRRRRRRQQQQQQRRSTTUVVWWWWXWXXWVVVVVVWWWVUUTTTTTTTTUTTUVVWWVUTSRRRRRTVXZabccbbaaaaabbdefghijkllmmnprtuutrqonljihghijjihggilnpqssrrqonmmljfcZYZcefhiklnnmmmnmkgdbbcdffghjkigdcdgjmopqqqpomkjjjigcaYYZacdfikmmllmnmlhdbacdghhjklkjgfegilmnoooonmmmmmljgedcefghikmoppppppolheccdeefgikkifddegkmoqrsssrponmljigfeeffghijjjjjklmmljihijigcZZacecbbcfilmnpqrqpnmllkjgcZXWYZabdgiklkklmmkgcbbcfggffgggebaacgknoppppoonmnnnlidaYYZabdgjmnnnnppokebYZabccdfhgebYYbeilnoqrsrpnllmmmjfbYYZabcehjkjkkmmmjfcabdhknoppoliedefiklmopppomkihhijklnoponlkjiihgghjlmmlkkjigecbdgiiggghjmnnopppomkihhgfdcbbcegghijiigfgikjhebZabdeffikmljgfehklnopqrqoljhfedcaaabdeeffghhgghjmnmjfcabdghiknppomllmnoooppppponljigedddegijkmnnmljjjkmmkhfddeghhijkkihgghjmopqqqpomkjihhiijjklmlkihhgfffhknoonljiihfddehklkjjijlnoprttsrpnlkjihfefghjjjjkkjihiknpolhfdefghiklmmjhghhknprtutrokigfffedccbcdeefghhgffgikkifdbbcdccdehiihijkmnoopqqpomkjihgecaZZbdeghjkjjhghjlmkheddefgghjllkhgghjmonopqqpomjhfdcbcdfijigfefgijlnqrtuutsrppnmljjjkkjjjjkmnopqqpomkihfecbbbehjkkjjiigffhjmljebYZbcddddffdccegknoooonnlkigedbaWVUVWZcdeghggfefgigeZVTVYcghijkkhdccdhloppqponljhgfedaXWWWZcegikllkiijmnmgaWUVZdfhknpokfdcfjnopppomkhecbaabcdefhhhhhhfecaadgjlmlkjigfbZZbehhcbacejmnpqrqonlkjjifaXWWZcfggijkjihhjlliebZYcfhjkllkhcbbdglnopqqpnligfeddaXWWXaeffgggggghjlmkgbZXXadfgikkjfcccejmopqrqoljhgfedZWUTVYcefggggffgiknlgaYXbglmmllljfbZZbfknooonljhedccefhhhggffffgffffffghiiiihhfebYXYbefcZYZcinpqsttsqnljiheaVUUXbeffghhiihhjllhdZWUWZbcdeghifccdeinooponmkigecbaYVVWXZdddeghiihijlmjfZWUWZbdefhkljgffgjnopppoonmljihfdZWUVWZbcdfhijiggghheZVSSVYbcdfikifdeeinppqqpomkhfdbaabdegijkkkjigfdccfikmlkjihgeaZacfifcccejnprtutrpmkjihebWUTUYbefghiiihhikmlhdaYYbeffgghgebaacfjlmnnnmljhgghgfbYWWXadefijkjjikmoolgcZXYZabcfiklkkllmoonnnmlkihgggfeaYYbekprsssqoljjlosvtplifeeeefhkmnmlkjklmnopqqomjhgfgghjkmmljhffefghiknqstuspmkjiiiijjjjjjklnnnooooonmljhfdbZYYbeghhhhhgfefhjjgcZXWYbdeefggebZZadhlmnnoonljhgfecaYYacehhhhiihgfgilmieZVUWadffgghgcccdflnppppponlkhgedaWVVWafhijkkjihggikjgbXVVYbcdegjkhfedeilmmnnnnmljhfffghgghikkjihgffeddfhijihfeddcbcehkkheedgkmnpqqqpnljihhfdaYXYadffggggggikmnlgdaabfghhhggebZbehmpqrstspmigfeedbYWWYadeeeghhhhhjmoojeaWVYbdfgijjgcbcehnopqrrqpmljhfdbYVUUWadfhijjihhijmmjdYWVZeijlmnmjeddejoqrrqpomjigeeefhjjiiijjjihgedddehjkkjigfedbZaceedbaacgjlnopppnljgecaXVUUVZcefhijjihhilmmidZXYbeeeefggecaabfjlmnmmlkjihgggebZZZcfijklmmlkhggiifbXUUXbeghijjgbZYZdjnpqpnmljjihgecaXXXaeijklmmlkihikljfaYXaehiijkkjecbcelprtsrpomlkjihgffefgiijjjjihfeefhijjihggfcZXXYbedaZachmopponlihgggggdaYWXaegiklnnljhhhjheZXWXbfghghhheaYYYdjnpqqpolkihfddbaZZacfjlmnoonligggfdZXWXafikkjigcZWWYbfklmnnmlkihfedbZWUVXbfijklllkhghjllgcaachlmlkjhfbXWWXaeeeeeeedaXYaejnponmkjigggghjlortwyz110xvtssuvwxwwusrpppqrttsrqomkjigfffgilmnnmmlkkjjlnnlgcZZbdfgghhiiihhhikmoprrrqpnmljjigfefgjlmmnnnljhghjklkjhggghiijklmljjiijlnoppponlkjjjjihghhjkllllmmmljjkllkiecbdfhijkmoonnmllnopqrsssrpnljjjjkkklmopqpomigggiklmmkjiiihgfghjmmjhggilnqrsqomljjihgdbabcfijklmmkjhhjmoomhecceijkllkkiggggikmnppqqonmkhgfeddddfhjklmmmkjiijkkjhgffghiiijklkkjjklnpqrsqpnljiihgfeddegjlnnoonljhhjlnnlhfeegijklmmmmjihhjmnpqqqpomkjhhgghhhijjkkkkkjihggijkkkjihhfdbbdfijihgghkmopqponlkjiiihffghilmmmnnmljikmpolfbYZbdeefgijjihhhknpqqqponmlkjhhgddefgjkkkklllkiggggggggghhhijjlmljihhjlnpqrrqpomlkjihhgghiklmlkjjihgfgijjhdaZacehijkllkjihiknprtutsqonlkjjjkllmmnnnlkjheddegjlllkjigfcaZacfhggghjmoqsttsqnliihhhgfeddfhjkmnmlkjkmpqolhffhjlllkkjihghijklmnnnnmkihgeddcbbcdgijkkkkkihijmoomjhfffhijjjiiiiijjlnpruvvusqonmmmlkjiijklmmnnmljjkmnonkhgffghiijjkkjhhgggiijlmmmmkjjklmonnmmmmlllkklnpsvxz0zzxvuutuuuuuvvwxxvusrrrsstttspmlkklmnoqstuvutqomlnprrrpmkihhhijlmnonnnmmnopqrsssrqnljihhhijlnpqqppnkjijlnppnljihhiijlnqrttsqpooopqqqqrrpomkjjlmoqstutrqomllmoqqpmjhhhijkloqsrpnmlnoqqrsssssrqoljhghijlnnnmmnnmlkklnnnmlkihgdZYZadijiijjknoqrssrqomkjhgffffgikmoqrrpnljklnoonljihhijklmmllkllmnopqstttromkiiihgfgikmmnnoomljijklljhgfghjklmopokhfefknprtvvutrponljfcbbdhlorrrqoljiikmnnnmmmllkjklmmljiiilnprtvxxwusqnmllllllkjijklmmlkklmoppponlifbXXYbglmnnoopqrsttssrpoliggghjlnqrssrqomlkklnonljihikllkllmmlkjjjkmnpqrrqonljgfeeeghjlmnooonnmmmmmnlkigffffghikmopqqpppppqstuvvtsqnmlkllmopqrrrrrqponoqssrpnlklmnopqrsrrponnoqrsttsqomkjijjklmnopqrqponljiggfggggghhgfcbaacdbYacgmqrrrrrrqpnljhgedbcegjkkkkkkkjiijkjgdZYYbdfggijjjgggikopqqrrqpnljhgfedbabdgijjjjjigfeddcXTRSVaeggfgggeZYZbfmooopponmkigfedbZabeimnnooonliiijjifdcdgjnprrrroljiijlnpqqqpomkihggijkkkklmnnnmmlkklnpsuwyyxwtpmjjlpuz21yvrpooprtvxzzyvrnhcZZbhmqssrqomjhhjloppnkhhhggghjlmlljijlmnopqtx120vqkfcaabejosttsqmjgeehkmmligfefghjmprrrpmlllnpqqrtvxxurokgdccfkquvvtqmigeegjmnnljihhhhhjmpqqoliijkmoqsux01yuqlhgghkpv042ysmgddegikmmlkjigebbbdgjlllklmnpqrstvwxwtqlfZVUWbinqrpnmjgfghjmomlihghhhjlptusplihikmoprrsttrpmiebZYZcgmqrqolhfdddgjmlkhfddeefgilnoomkjklmortuvwwvspmhdYVUWcjqtusqnjhfghjlljhgeeefffhjlllljijlnprtvwwxwsokheefghjmsxzxvpjhgghknqttspnjfcZZchlpqrqqppppqrsuwxwtqmgbWTUYekprrqolihghjlmmljhhhihghjlnnlkjikmnnpqsux0zxtojebZZbglqtutrplhdbbeiklkigfeeeegjmprsqnmlkmopqsuvvurokgdbcdhmsvwwurmjhgghkkkjhfffffghjmooomkklnprsuwyz10vrolkkkjlpu043ztmhffgjlnppnjhfcaabejpssrolklnprtuvwwwtplicYWVXcimpqpnliffgilnljgedefffhjnsvtqnjijlmoprtvxyvrnjebZYaflquusrokifefilnmkgeccdddfhjkkjhghjlmoppqrssqokhdYURSXemrsrnkifdbbcegfdbZZbdeeegikllkiggfedehnu1562wrmjijkmpsvwwurpnnnnprtwzzyvtokhefjpv020wsomnnoqrsuvutqmhcZXYdjptvuspmjhhjmprrqnkjihhhiloqqpnkjklmmnoqsvxxvrnidaXYbgmruusqmigddegjkjhfededddfjnrtvtrqqqrsttvwxwvrokgcaabglquutrpkigfgjmmljgeeffgggiklmmlkklmortx02330vrolkklmptx11ytpigffgjnqssrpmifdbdgmswwuqmlkmoqsuvwxwurojdXVVZgnsutrpnkihjmqstpkgedeefilptuspmiiklnpsuwyyxurolgdbacfkorrpmjfddfjnqqpmjhgggghilnoonljjlnprstuwyzyvsokfbZaelrvvtqmigffgikkkifeddddefhknopnlkklnqtuwxyyxvrnigffgilotutrojhffhkosuvutqoiebZbfloqqqppqqqqrsstttrqnjdYVUXdlruusqmjhghkopqokhfghijkklmmljihhjklnprtvxxwtqnjfdbdhntxxwtplifeegjlllkjijjiiijmopqponnnopqqrtuvusqokgdaabgmqssqoligffgjlkjigggggffgjlnnnmlmnopqstwy0zxsokihijlqv1651vpigghilorttrqpnnopruxywtolihhjmqtvwwwusqmhcYYbipwz0yvsnjffhlppoligghiiilosutrpmkmnoqsvy13430vqkebabgmty0zwtojfefimpoljhiklmnpruwwuromlklnqsuxxyyxurnhdbbekrw0zxuqmkkkmoqqolihijklmnooomkiiijklnpsvy00yvqmigghknprsrpnkhhjosx14565420zzzywutstuuuvwxwtnidbaaZXVTSTUWZdhkljeZUSRSTUWYacbYWTQQQRRSVYbaZXUSTUVWYcfijgbWRPPQRUYbfhfbYURRRRQPOOOPOOONOPPQRUWYaaZabdfebXSOOOOONMLLLMOSWbeeaVPKIIIIIIJJKKJIIJKMNOPQQPONMMMMOQRVadhfcWQKIHILOUaehfaVPKIHHGHHHHHHHIIJJKKMNPQRRUXbfgeZTOMLLLKJIHGGIKPUZaZUPLJIIIIJKMOONLKJJKKKKLMPQQPNLKLLMOQSUUSPMJIHIIJMQUWWUQMIGFEEFFGGHHHHHHHHIJLNPRTUWYacdbWSNKJJIIHHGGHILPTVWTPLIGGHIJNRVXXUROLKLMORTUWaeksz20vngaYZdhmsy11ytpnnqtutqnkjlotx12331xpicZXadeeeefghijjjklmmmllkkkkjjkkllkjiihgaT]], + note = [[DDEEEEEEEEEAAAAAAAAAHHHHHKKKKKKKAAAAAAAAAEEEEDDDDDDDDDEEEEEEHHHHHCCCCCCCCCHHHAAAAAAAAHHHHHHHHCCCCCCKKKKKKKCCDDDEDEEECCAAAAAAAAAHHHHHKKKKKKKAAAAAAAHCCCEHHHHHHHHHCEEEEEEHHHHHFFFFFFFFFHHHEDDDDDDDDFFFFFFFDDDDDDDDDDDDDDDEEEDDDDEEAAAAAAAAAAHHHHHKKKKKKAAAAAAAAADDDDDDDDDDDDDDDDEEEHHHHHCCCCCCCCCCHAAAAAAAAAAACCCCCCCCCCEEKKKKKKKKEEEHHHAACDEAAAAAAAAAAHHHHHKKKKKKKAAAAAAACCCCHHHHHHHHHHCCCCHHHHHHHCCCCAAAAFFFFHHHHFFFFFAAAACCCHHHHKKKCCCDDDCHHHHHHEEEEAAAAAAAAAAAAAAAAAKKKKKAAAAAAAAEEEHHDDDDDDDDDDHHHHHHHAADCCCCCCCCCAAAAAAAAHHAHHHCHHHHCCCCCCKKKKKKCCEEAAAEEEEEEAAAAAAAAAAAAAAAAKKKKAAAAAAAAAAAAACHHHHHHHHCDCAAAAHHHHHAAFFFFFAAHHHAFFFDDDDEFFFFFFFEEJJDDDDDDDDDEEEEEEECCCCDAAAAAAAAAAAAAEEKKKKKAAAAAAAAHHHHEDDDDDDDDDCCCCCCAAEHECCCCCCCCCAAHHHHHHHHHHHCCHHCCCCCCEHKKKKKKKKCEEEHHHEEEEEAAAAAAAAAAHHEAAAJKKAAAAAAAAAEEEDHHHHHHHHHHHHCHHAHHHHHAAFAAAAFFFFHHHHHFFFFFAACCCCCHHHKKKCCCCFFAAHDHHHHDDDDHHHHDDDDDDDEDDDHHHHHHEHHHHHHHHDDDDDHHHHHDHHDDDDDDDDHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAFFFFFFFFFFFFFFCFFFFFFFFFFFFFFFFFFFFFFFFFFFCCFFFFFFFFHHHHKKKKKFFFFHHHHCHHHHHKKFFGFFFFFFFFFFFFFKKCCCFFFFFFFFFFFFFFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDHHHHHHHHHHHHHHHHHDDHHHHHHHHHHHHHHHHHHHHHFFFFFHHHHHHCCCCHJJJJFFCFFFHHHHHHHHHHCFFFCCFFFHHHHHHDDDDDDDKKDDDDDDDDDCDDDDDDDDDDCCCKKKDDDDDDDDDDDDDDDDDDDDHHDDDDDDDDDDDHHHDDDDDDDDDDDDDDDDDHDDDDDHHHHHDDDDDDDDHDHHHHHDDDDDDHHDDDDHHHHHHHDDDDDDDDDDDDDDDDDDDDDDDDDDDCCFFFFFFCCCFFCFFFCCCCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFKCCCCCCFFFFFCCHJFHDKFFFKFFFFFFFFFFFFFFFFFFFFFFCFCCCFFFFFFFHHHHHHHHHHHHHHHHHHHHHHHHHHDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDHHHHHHHHHDDHHHHHHHHHHHHDDHHHHHHHHHHHHFFCCFFFHHHHHHHHHHHFFFFFFCCCHHHHHHHHFKKFFFFFFFFFFEEHHHHHHHHHDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAHHHHEDDCBHHHHHHDDHHHHHHDDDDDDDHHHHHHHHHHHHHHHHHHHHHHAAAAAAAAAAAAHHHHHHHHHHHHHFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEFFFFFFFFFFFFFFCCCCCCCCCCCCCCCCCCCCCHHHCCKKKKKKKKKKKKKKKKKKCCFFFFFFFHHHHHHHHHHHHHHHFFFFFFFFFFFFFHHHHHHHHHHHHHHHAAAAAAAAAAAAAAHHHHHDDCAAAAHHHHHHHHHAAHHHHHHHHHHDCHHHHHHHHHHHHHHHHHHHHHHHFFFFFCCAAAHHHHHHHHHCDDDDDDDAAAAAHHHHHHHHDDDDDDAAAAAAAHHHHHHHKKKKKKHHHHHHHDDDDDDHHHHHHHHKKKKKHHHHHHHHHHHHHHHAAAAAAKKKKKKAAAAAAAHHHHHHHDDDDDDDDHHHHDDDDDDDDDCCCCCCKKKKKKAAAAAAAAAAAAAAAAAAAAAKKKKKDHHHHDAAAAAAAAAAAAAAAAAAAAAAKKKKKKAAAAAAAKKKKKKKHHHHHHHKKKKKHHHHHHHHFFFFFFHHHHHHHHDDDDDHHHHHHHHFFFFFDDDDDDDDDCCCCCDDDDDDDFFFFFFHHHHHHHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKKKKKKKKKKKKKKKKKKKKKKKKKKKHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHBCCCDHHHHHHKKLLAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDHHHHHHHHHHHHHHHHDDAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCCCCCCCCCCCCCCCFFFFCCCCCCCKKKKKKKKKKKKKKKKKFFFFKKFFFFFFFFFFFFFFFFFFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHFFHHDDDDDDKKKKKKKHHHHHHHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDHHHHDDAAADDDDDDDDHHHHHHHAAAAADDDDDDDDHHHHHHHHAAAADDDDDDDHHHHHHHHAAAAAAAHHAAHHHHHHHHHAAAAAAADDDDDDHHHHHHHAAAAAADDDDDDDHHHHHHHKKKKKKFFFFFFFHHHHHHHKKKKKKFFFFFFFHHHHHHHKKKKKKKCCCCCCKKKKKKKKKKKKKKCCCCCCCFFFFFFFDDDDDCCCCCCCKKKKKKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKKKKKKKKKKKKKKKKKKKKKKKKKKHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHKHHHHHHHHDCBAAAAAAAAAAAAAAAAAAHHHHHHHHHAAAAAFFFFFAKKKKKHHHHHHHFFFFFFFHHHHHHHHHHHHHDDDDDDDDCCCCCCCAAAADDDDDDDDDCCCCCCAAHHAADDDDDDDAAAAAAAHHHHHHHAAAAAAAFFFFFFFKKKKKAAAAAAAFFFFFFFHHHHHHAAAAAAADDDDDDDCCCCCCAAAAAAADDDDDDDCCCCCCCHHHHHHHAAAAAAAAAAAHHHHHHHHHHHHAAAAFFFFFFKKKKKKKAAAAAAFFFFFFHHHHHHHHHHHHHDDDDDDDDCCCCCCCAAAAADDDDDDDDCCCCCCAAAAAHHKKKKKKAAAAAAAHHHHHHHAAAAAAAFFFFFFKKKKKKAAAAAAAFFFFFFFHHHHHHHAAAAAADDDDDDDCCCCCCCAAAAAADDDDDDDCCCCCCCHHHHHHHAAAAAAAAAAAAHHHHHHHHAAAAAAFFFFFFFFKKKKKKAAAAAAFFFFFFFHHHHHHHHHHHHDDDDDDDDDCCCCCAAAAAADDDDDDDDCCCCCCCHHHHHHKKKKKKKAAAAAAHHHHHHHHAAAAAAFFFFFFKKKKKKKAAAAAAFFFFFFFFHHHHHHAAAAAAADDDDDDDCCCCCCAAAAAADDDDDDDDCCCCCCHHHHHHHAAAAAAAAAAAAHHHHHHHHHHHHHHAAFFFFFFKKKKKKAAHAAAAFFFFFAHHHHHHHHHHHHHDDDDDDDDCCCCCCAAAAAADDDDDDDDCCCCCCHHHHHHHKKKKKKKAAHHHHHHHHHHHHHHHHAAFFFFFFFKKKKKKAHHHHHFFFFFFHHHHHHHHAAAAAHDDDDDDDCCCCCCAAAAAAADDDDDDDDCCCCCHHHHHHHHHHHHHHHKKKKKKAAAADDAAAAAAAADDDDDDDDDDDHHHHHHHHKKKKKKKAAADDHHHHHDDHHHHHHHKKKKKKKKKFFFFDDDDDDDDCCCCCCKKKKKKKHHHHHHKKKKKKKKAAAAAAAAAAAAAAFFFFFFFFFFFHHHHHHHHHHHHHHHHAFFFHHHHHFHHHHHHHHHDDDDDDDHHHHHHFFFFFFFFDDDDDCCCCCCCHHHHHHHKKKKKKHAAHHHHHAAAAAAAAAAHHHHHHHHHHHHHHHHFKKKKKHHHHHHHHHHHHHHHHHHHHKKKKKKKFFFFFFDDDDDDDCCCCCCCKKKKKKFFFFFFFFHHHHHHHHHHHHHHHHHHHHCCCHHHHHHHHHHHHHHHHHHHHHHKKKKKKKHHHHHHHCCCCCCKKKKKKKDDDDDDKKKKKKKFFFFFFFHHHHHHHHHHHHHHKKKKKKHHAAAAAAAAAAAHHDDDDKKDDDDHHHHHHHHHKKKKKKHAAADDHHHHHDHHHHHHHHKKKKKKKKFFFFFDDDDDDDDCCCCCKKFKKKKKHHHHHHKKKKKKKKAAAAAAAAAAAAAACCCCCCCACCCHHHHHHHHHHHHHHHHFFFHHHHHHHHHHHHHHHDDDDDDDHHHHHFFFFFFFFFDDDDDCCCCCCCHHHHHHHHKKKKKKHAAAHHAAAAAAAHHHHHHHHHHHHHHHHHHHHHKKKKKHHHHHHHHHHHHHHHHHHHHHKKKKKKKFFFFFFDDDDDDDCCCCCCCKKKKKKHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHCCCCHHAAHHAHHHHHHHAAAAHHHHHHHHHHAAAAAAACCCCCCAAAAHHHKKKKKKHHHHHHAAAAAAAAAAADDDDAAAAAADDDDDDDDCCCCCKDDDDDDDDDDDDDDDDDDDAAADDAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCKKKKKKKKKKKKFFFAAAAKKKFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCCCCCFFFFFFCCFFFFFFFFFFFFCCCCCFFFFFFFCCFFFFFFFFFFFCHHHHHHDDHHHHHHHHHHHCCCCCCCCCACAAHHHHHHHDDDHHHHHHDDDDDDDDDDDDDAAAAAHHHAHHHAAAAAAAAAAAAAAADHHHHHHHHHHHDDDDDAAAHHHHHHHHHHHHHHHHHHAAAAAAHHHHHHHHCHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDDDDDDDDDDDKKKDDDDDDDDDKKKDDDDDDDDDDDDKKDDDDDDDDDDDDDDDDDDDDDDDDCKKKKKKDDDDDDDDDDDDDADDDDADDDDDDDDDDDDDAADDDDDDDDDDDDDDDDDDDDDADDDDDDDDDDDDDAADDDDDDDDDCCCKCCKCCCCFFFFFFFFAAAAAAFFFFFFFFFFFFFFFFFFCFFCCFFFFFFFFFFFFFFCCCFFFFFFFFFFFFFFCCFFFFFFFFFFFFFFFFFFAAAAAAAKKKKKKKKKKKKKHHHHHHHHHDHHHHHHHHHHHHHHHHHHHHHHHDDAAHHHAAAAHAAAAAAAAAAAAAHHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDAAAAAAKKKDDAAAHHHHDDDDDDDKKKKKKKKKKKKKKDDDDDKKKKKKKKKDDDDDDDDDDDCCCCCCCCKKKKKKAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDDDDDDDDDDDDDDDDDKKCCJJDDDDDDKKKKKKKKKHHHHHHAAAAAAACCCCKKHHHHHHCCCCCCCCCHHCCCDDDDDDCCCCCCCDDDDDDDCCCCCCCDDDDDDFCCCCCCCKKKKKHHHHHHHHHHHHHHHHHHHHHHHHAAAAAAAAAAAAAAAAAAAAAAHHHHAAAAAAAAAAAAAAAAAAAAAKKDDDDDDAAHHHHHHHDDDDDDHHHHHHCCCCCCCDDDDDDDHHHHHHCCCCCCCDDDDDDDAAAAAACCCCCCCDDDDDDDFFFFFFHHHHHHHDDDDDDDFFFFFFHHHHHHHJJJJJJJFFFFFFFHHHHHHHKKKKKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKKHHDDDDDHHHHHHHHHHHHHHHHHHHCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDDDFCCCCCCCCFKKKKKHHHHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHHAAAAAFFHHHHHHHHFFACCCCCCCAAAACCCCCCCHHHHHHHHHHHHHHDDDDDDDDDDDDDDHHHDAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDKKKKKKKKKKKKKKHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDHAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDKKFFFKKKKKKFFFFFFFFFFFFFFFHHHHHHHHHHHHHDDDDDDDDDDDDDDHHHHHHHAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDDKKKKKKKKKKKKHHHHHHHCCHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDHHHHHAAAAAHHHHHHHHHHHHHHHHHHHDDDHHHHHHHDDDDDDDDDDDDDDDKKKKKKKKKKKKAAAAAAAAAAAAAAHHHHHHHHHHHHHDDDDDDDDDDDDDDDHADDDAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDDKKKKKKKKKKKDDDDDDDDDDDDDDDHHHHHHHHHHHHDDDDDDDDDDDDDDHHAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDKKKKKKKKKKKKFFFFFFFFFFFFFFAAAAAAAAAAAAADDDDDDDDDDDDDDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHHHAAEEDDDDDDDDDHHHHHHEEAAAACCCCCCCCHHHHHHHHHHHHHHCCCHHHHHHHHHKKKKKKHHCCCHHHHHHHHHHHHHHHHHEEEEEKKKKKKHHHHHHHHHHEEHHHHHHHHHHHEEEEHEEEEEFFFFFFFFFHHHFFKKKKKKFFFFFFFFFFFFFFDDDDDDDDDDDDDDDDDDDDHHHHHHHHDDDDDDKKKKKKHHHHHHHHIIIDDDDDDDDDDDIIIIIDDDDDDDCCCCCDDDDDDDDAAAAAADDDDDDDDDDDDDDFKKKKFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFKKKKKFFKKKKKFFKKKKKKKKKKKKKKKKKKKKKKKKFFAAFFFFCCCCCFFFFKKKKKKKKHHHHHHHHHHKKKKHHAAAAAAAAAAAAAHHAAAHHAAAAAKKKKKKKAAAAAAAHHHHHHHDDDDDDHHHHHHHHHHHHHHCCCCCCCHHHHHHHHHAAAAHCCCCCHHHHHHHHKKKKKKHHHHHHHHHHHHHHHHHHHHHHHHHHHKKKKKHHHHAAAAHHHHHHHHHHHHHHHAAAAHHHHHHHFFFFFFFFAHHHHHKFFFDFFFFFFFFFFFFFFDDDDDDDDDDDDDDDDDDDDDDDDAAAAKKKKKKKKKKKKAAAAAAADDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCDDDDDKHHHHHHHHCCCCCCDDDDDDKKKKKKKKKKKFFKKKKKKKKHHHHHHKKKKKKKKKKKKKKAAAAAAAFFFFFFHHHHHHHHFFKKKKKKKFFAAHHHAAAAAHHHHKKKFFFFHHHHCCHHHHHHHCCCCFFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCFFKDDDDDDDDCCCCCCCCCCCCCCCFFFFKKKFKKKKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFHHHHHHHHHFFFFFFFFFFFFFFFDDDDDDDDDDDDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDHHHHHHHHAAHHHDDHHHHHHHHHHHHAAAAAHHHHHHHHHHHHHHHHDDDDDHHHHHHHHHHHHHHHHHHAAHHHHHHHHHHHHHHHFFFFFFKKKKKKFFCCCFFFFFFFFFFKKKKCCCCCCCFFFFFFFFFFFFFFCCCCCCCFFFFFFFCCCCCFFKKKKKKKKFFFFFKKKKKKKKFFFFFFFFFFFFHHHHHHHHHHHDDDDDDDDHHHHHHHHHAAAADDDDDDDDHHHHHHHAAAAADDDDDDDHHHHHHHHHHHHHDDDDDDDHHHHHHHHHDDDHHHHHHHHHHHHHHHHHHHHHHHAHHHHHHHHHHDHHHHHHHHAAAAAHDCCDDDHHHHHHHHAAAAADDDDDDDDDHHHHHHHHHHDDDDDDDDDDDHHHHHHHHHHHHHHHHHDDDDDDDHHHHHHHHHAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDAHHHHHHHHHHCCHHHHDDDDHHHHHHHHHHHHHHHHHHAAAHHHHHHHHHHHHHHFFFFFFFFFKKKFFCCCCCCFFFFFFFKKKKKKKCCJCCFFFFFFFFFKKKKKCCCCCCCFFFFFFFKKKKKKCCCCCCCFCCCCCFKKKKKKFFFFFFFFFFFFFHHHHHHHHHHHHHHHDDDDDHHHHHHHHHHHHHDDDDDDDHHHHHHHHAAAAADDDDDDDDHHHHHHHHHHHHDDDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHAHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDCHHHHHHHHHHHHHDDDDDDDCCCCCCCHHHAADDDDDDDDHHHHHHHHAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDAAAAAKKKKKKKKHHHHHFFFFFFHHHHHHHHHHHHHHDDDDDDDCCCCCCDHHHHDDDDDDDDDCDDDDDDHHHHHCCKKKKKAAAAAAAHHHHHHHAAAAAAAAFFFFFFKKKKKKAAAAAAAFFFFFFFHHHHHHAAAAAAAADDDDDCCCCCCCCAAAAADDDDDDDCCCCCCCCCCCCCHHHHHHHHHHHHHHHHHHHHHHHHHHHHAAAFFAFKKKKKHHHHHHHFFFFFFAHHHHHHHHHHHHHHHHHHHDCCCCCCCHHHHHHDDDDDDDCCCCCCCCHHHHHHKKKKKKAAAAAAHHHHHHHHAAAAAAAAFFFAAAAKKKKKAAAAAAAFFFFFFHHHHHHHAAAAAAADDDDDDDCCCCCAAAAAHHDDDDDDDCCCCCCCHHHHHHHDDDDHHHHHHDHHHHHHHHHHHHHHHADDDDDKKKKKKKKDDDDDFFFFFFFHHHHHHHHHHHHHHDDDDDDDCCCCCCHHHDHHDDDDDDDDCCCCCCCHHHAAAKKKKKKAAAAAAAHHHHHHHAAAAAAFFFFFFFKKKKKKKAAAAAAAFFFFFFFHHHHHHAAAAAAAFFFDDDCCCCCCCCAAAAADDDDDDDCCCCCCCCCCCCCCHHHHHHHHHHHHHHHHHHHHHHHHHHHFFFFFAAKKKFFHHHHHHHAAFFFFFHHHHHHHHHHHHHHHHHHHHCCCCCCHHHHHHHDDDKKKCCHHCCCCCCAHHHKKKKKKHHHHHHHHHHHHHHHHHHHHHAAAFFAAKKKKFHHHHHHHHHAAAAHHHHHHHHHHHHHHHHHHDDDDCCCCCCCHHHHHHDDDDDDDCCCCCHHHHHHHHHHHHHHHKKKKKKAAAADDAAAAAAAAHHDDDDDDHHHHHHHHHHHHKKKKKKHAAAAHHHHHHHHHHHHHHKKKKKKKKKAFFFKDDDDDDDDDCCCCCKKKKKKHHHHHHHHKKKKKKAAAAFAAAAAAAAAAAAAAAAAAAAHHHHHHHHHAAAAAAAAAFFHHHHHHHAAAAAAAADDDDDDDHHHHHHFFFFFFFDDDDDDDCCCCCCHHHHHHHKKKKKKHHHHHHHHAAAAAAAAAAAAAAFFFCHHHHHHHHHKKKKKFHAAHHHHHHHHHHHHHHHHHKKKKKKHHHHFFKKDDDDDCCCCCCCCKKKFFFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDHHHHHHHDDDDDDKKKKKKKKKKDDDDDKKKKFFFDFFFFFHHHHHHHHHHHHHHKHHKKAAAAADDAAAAAAAAAADDDDKKKDDHHHHHHHHKKKKKKKAAAAAHHHHHHHHHHHHHHKKKKKKKKKKKFFKDDDDDDDDDCCCCKKKKKKKHHHHHHHKKKKKKKAAAAFAAAAAAAAAAAAFAAAAAAAHHHHHHHHHAAAAAAAAAAAHHHHHHHAAAAAAAADDDDDDKKKHHHFFFFFFFFDDDDDDCCCCCCCCHHHHHHKKKKKKHHHHHHAAAAAAAAAAAAHFAAAAAAHHHHHHHHHKKKKAAAAAAHHHHHHHHHHHHHHHHKKKKKFFFKFFFFDDDDDDCCCCCCCKKFFKKHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHKKKKKKHHHHHHHHHHHKKHHHDDDDDDDDDDDDDDDDDCCCCCCCCCCKDDDDHHDDDDDDDDDDDDDAAADDDDDDDDDAAADDDDDDDDDDDDDAADAAADDDAADAAAAADDDAAAAAAAAAACCKKKKKCCCCCAAAAAAAADDDDDAAAAAAAAAAAAAFFCFFFFFFFFFFFFCCCCCCCCCCCCCCFFCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCAADDDDDDDDDDDDHHHHHCCCCCCCCCAADCCCCCCCCDDDDDDDDDDDDDDDDDDDDDADDDAAAAAAAAAAADDAAAAAAAAAAAAADDDHHHAAAADDDDDAAAAAADDDAAAAAAAAAHHHHDAAAACCCCCCCCCCCCCCCHHHHHCCCCCCCHHHHHHHHHHAAAHKKKDDAAAAAAAAAKKCCCCCCCCCCDDDDCCCCCCCCCDDDDDDDDDDDAADDDDDDDCCCCCKKKCDCDDDDAADDDDDDDDDDDDDDDDDDDDDAAADDDDDDDADDADDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDDDDDCCKKCCCCCKKKCFCCKKKKADDDDDAAAAAADCCFFFFFFCCCFFFFFFFFFFCCFFFFFFFFFFFFFFFFFFFFCFFFFFFFFCHHHHHHFFFFFFFFDDDDDDKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKDDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHAAAAAAAAHHAAAAAKKKKKHHHHHHHDDDDDDKKKKKKKKKKKKKKKAAAAAHHHHHHHHHAHHHHHAAAAHHHHKKKCCCFFKKKKKDDDDFFFFFDHHHHHHHHHHDDDHHHHHHHHAHHAAHHHHHHHHCCCCFFKKDDDDKCCCCCCCFFFFFFFHHHHHHAAKAAAAAHHHHAAFKKKKKKKKKAAKKKKKKKKKCCCCCCCKKKKKAAAHHHHHFKKAAFFFCCCCHHHHHHHHHAHHHHKKKKKKKKKKKKKHHHAAAHHHHHHHHHCCHHHHHHHHHHHHHHHHFFFFFFFHHHHHHFFFFFFHHHHHHHHHHHHHHHHHHHHHHHHAAAHHHHHHHHCCCCCCDDDDDDDCCCCCCCCFFFFFHHHHHHHHCHHHHHHHHHHHKKKKKKKKKKDDKKKKKDDDDCCCCCCKKKFCCHHHHHHHHHDDCDDDDDDDDDAKKKAAAAAAAAKKKKKKKKKKKKKKKHAAAAAHHHHHHHHHHDHHHHHHHHHHHKKKKKKFFKKKFFHDDDDFFFFFHHHHHHHHHHHFKHHHHHHAAAAHHDDHHHHHHHHHAAKAACDDDDDCCCCCCCCFFFFAAAAHHHHAAAKKKKHAAAAAAKKKKKKKKKKKFKKKKKKKKKCCCCCCCCFFFFFFAHHHHHHAFFFFFFFFFCCCCHHCCCCFAAAKKKKKKKKKKKKKKAAAAAAAHHHHHHHHHCCHHHHAAAAAHHHHHHHFFFFFFFFHHHHHFFFFFHHHHHHHHHHHFFHHHHHHHHHHHHCHHHHHHHHHHCCCFFFDDDDDDCCCCCCCCFFFFHHHHHHHHHACHHHCAAAAAAAKKKKKKKKKAAACDDDDDDDCCCCCCCCKKKFKAAAHHHAAAHHHHCCCCCCAAAAAAAAAAAAAAAKKKKKKKKKKKKKKAAAAAAHHHHHHHHAAAAAAAAAAAAAAAAAKKKKKKKKKKKAAAKKKKKKHHHHAAAAAAKHHHHHHHAHHHHHHHHHHHHHHHHHFFFFFDDDDDDDCCCCCCCCKKKKKKAAAAAAAAAAAAAAAAAAAAKKKKKKKKKKKKKKDDDDDCCCCCCCKKKKKKKAAAAAAAAAKCCCCCCCCCHHHHHHHHHAAAAKKKKKKKKKKKKKKKAAAAAAHHHHHHHHHCHHHAAAAAAHHHHHHHHKKKKAAAHHHHHKKKKKKHHHHHHAAAAAKKAHHHAAAAAAAAAAAHHHHHHHHHAAAHHDDDDDDCCCCCCCCKKKKKHAAAAAAAAAAAAAAAAAAAAKKKKKKKKKKKKKKKDDDDCCCCCCCCCKKKKKAAAAAAAAACDDDDDDCCCAAAAAAAAAAAAAKKKKKKKKKKKKKKKAAAAAAHHHHHHHHAAAAAAAAAAAAAAAAAAKKKKKKKKKKHDDKKKKKKKAAAAAAAAAKKDDKAAAHAAAAAAHDDHHHHHHHHHKCCCCDDDDDDDCCCCCCCCKKKKKAAAAAAAAACAAAAAAAAAAKKKKKKKKCCCCCKKDDDDDCCCCCCCKKKKKKKAAAAAAACCCCCCCCCCCHHHHHHHHHAAAAAAKKKKKKKKKKKKKAAAAAAHHHHHHHHHHHHHHHHAAAHHAAHHHHAKKKKKKKHHHHHHKKKKAHHAHHHHHHHAAAAAAAHHHHAAAHHHHHHHHHHHHCAAAAKDDDDDDDCCCCCCCHHHHHAAAAAAAAHHHHHHHAAAAAAKKKKKKKHAAAACDDDDDDCCCCCCCKKKKKKAAAAAAAAAAKKKHHAACCAAAAAAAAAAHHHHHAHAAAAAAAAAAAAAAAAAAAHHHHHHKKKKKAAAAAAAAAEEEEEDDDDDDDCEEEEEEEEEEEACCCCCCCCCEEEEAAAAAAACCCCCCCCCCAHHHKKKKKKKAAAAAACCCEEEHAAAAAAAAHHHHHKKKKKKKAAAAAAHHHHHHHHHHHHHHHEHHHHHHHHAAEEFFFFFFFHHHHCEEDDDDEFFFFFFFHHHHHHHDDDDDDHHEEEEHHHHHHHHHHHHHHHHHDDDDFFFFFHHHHHHHHHHHHHHHDDDDDDDCHHEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHCCCHHHHHHHHHFFFFHHHHHHHHHHCCEEHHHHHHHHHHHHHHHFFFFFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHAAAAAHHHHHHHHHHAACCCCCKKKKCCCCCFFAAAAAHHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEEEAAAAAAAAAAFFF]], + noteClear = [[AAFHJIIJJIHFJNQUVTLFMQRQPCIVadcMEKSUYbZRJFGHGNYjz01xaQHHGFEADMNMCNdgdbZWRCFKJGIKNOQQMIITWXXQJCDCBAADSYabYIFGEEDDDDDDBBDTWVSRQOIGLKHDBOWcbTJIMOTUSNCCDCCEOiryyxfSFDEFGECGHGFDELVYbcYSIGGFCMTYbclkQao22wkJDBAAAOpy678ymQHCDCCGHFCBCINSSSTTQMJKMKAFUZbaVHOTSRUXTNGFEFHWgxz1ynRIFEBBACHKJCIZfiikhdODDGFCDILMNOMHRVWWVMEAFFEFCJYbecKCBCABEBAAAAACNQRSTXXOHLNNFAPXghhSEHILOQPJCDDDFPcz586oZMEEDCFHOQPOLEGKHEQSMVneTciQGEKTXWJUSHTRHXbbUBFFKPHNTIAABHJIEAAAAABAFIMLKFCBCBAAAAACCDEBFJMOPIBAACCEHOUbegaEAAHKLJEDCABACHJJMOPMAGQUaXSPQNMJHFDEILGAABDAAACJLMQNBBAAABACCDDBAACDKNPQQKFIJKJHADJIEBPRROPQNFEEEFDIYcelqdQAAAACAAAABFFBGRVTTPKGAAAAEFFPRSSINUddaXGAAAAAJckomlWLAADHIBAAAAAAAAEIPRPNJAABBAAAAAAAFHLOQTSDAAAAAAMSYabZRACEDAAAAAABCAGQRSSRPAAAACCBIKJEEEDEGGHJFAABAAAACLMMMHAAABAAAAADFFCBEGJKKIAAABCAAAAABCACKMKJHFBAAAACOYnsvuiXOAAAAAAAACGEAAAAHQMKROHKdcLFBKRRNIJDMSQNQUJNbQLgiRIKGDACACKLKNOIFCAABCDDCBAAAAAACAABAACEEEFFDAACCGGPTTOKHHAAAAAACGFCBECDJKJJIFCCGEFIGFEDBDFCAABDFDAACEKJAABFIRRLIGCBDFBAAAABEGKQRPLHCEMQRNLKLLKNOLCDIIFECDDLOECEFEBBCCAAGIHGKLIAAAGGDFEAAAALPSJHIKJJIJFDDDEAAEGKJIHFDGMPQBCKMNQRSSONJLSUUUVXVMJHPWXRSWaXXeeUQMMPVVOMNOQOJHLSSUSODFLMMJHHJKNOQRVXYWTSLLUZPHHHKLPOMLKIGEFDBJPVTLAADEEDAADGGIGABCADACEBBACFFACJLJAAAABAAACBEGIIAADJPPLDIRSPNEABFFEJIJNNKRDEGJIHIHBABEEDEDEJMPRROLIIIJIKNRSSNIDEINRUXXUOLKIMKHJLJFHKLMLFDFOdTJEFCDHJJQQJICCCDEGHJHIIIOQNKCEGHHEEFGJPUHJMLIJHHGRcqraLIIHEEFFECBFGEDEKMNHABGNNRRECBAABDCDDCKFEKORQRRPHKabSRSSPPPJIKQRRSRNFEHNNFCAEIKHDCCDGNKECAAGAAAACBDAAACSYPIIKKKKLMSURMMGBAAADCDEFHMNMFKRPNOORSRRONMLMMJGHFEEVbRGJNROMLPQONPRQQLKRUVSOLLKIFHJHHKMMIILKHKOPQWYWTKHHMRSROQQNMMLEDJJILLJJJLPLEDCEFEFBFJKMQMHBAAFCEHGECCECACGLIBBBBAAACEEEEFKKFAAFIJJKOOQMainw3///+/7542vtv37///////udlquttxvrrssusrtuuutvwwx02fRNfhecbaXadiieZFAJOFKNPIEFIFGFDDDFLLLMJGGABFHGKRROQRYl5+++////////pWbegfejp6//+ukx9+9///////3dt5////79+////69/++/////20+7tp32wlrzs3xjdcaXbcaXUOSXUagu5//8rotwxtlQKFFFFDEHGKPSYimpruvx9///8qaJIHGHILMNNKScnruxyy07+//5dZpqponlosrmfTu5863203+///2dVYgjjilopnljgVOTehNELNDFMLFEGMPLFBCDTXILNOMMKDBACFJGEGJJIDAABFGHFEGHKJJDAABFFCAAHOPPOIHRVZaOIMUZceWLNVaeZTcnnoqnTexyuobXjxy1tciqtrroSTjyxmaZkt46vgTdlsrZSu5///vfOUXVTTgtusrqruwwyzmcb167yOLbyzocLSbdeeXnx///6nq/////vQHKMNWet0332vkqz78hPLaehfJTt138/0tux3//dPGFGFDABNSSGADFEDADFFFHISbqv1///zqpoqslbgt5//ib/////ehxywvsbe////qXdqtrkboy3243iRj6/+qo1/////gc242em+////vajptsbUl////6mVZfifSdtvy1yeZv01zqSh////ujtwvuvvuuvvyzyy3882yz5////7uty00yzywuuvvvz3564rooqty133427+8vs09//qjfilkit5////yTgrqonpsuwyz0zz1+//501577whm//////+/////+74335+//////83//////////////////////+/////////////////////86/////scMMKKIIHDDOPLDAAESTBGOORMNZhqwx01011017722689974369/+2xzywtroifcZTUev021dROYbimVKIJJJIHLMHPOTeiprsqpw8////2UHNLGEFKHACRcqx2+/5023310ee9///////////9643358///////vutrsuutv24zngt4+/7vXRIGHHGFECEHLMMMQXSdkw0zxxz6////3naPKSQEDGFFHTsyyz2449////9l4///////////////////////////////////////////////////////////////////////////////ocRdcQRWdlmkTXkq13zUdvxvtfTfz023xuv05//0xxxwttrt+////spuvutu0530yurloooqrrttx1840688++538///0sonnlmpr5////olorsplkklmssnMFJKLGAGHDKNMchknomeJNRRQJFILOPRLZz7//8cZrroppYPNPQOOYixzyqXippotuZamxy0vTSRUVRVkmhgfaVfu//2jTcmrsmaXvy12paVry61RVw101zaZy6++4WOmx93mWhstoeUv/////yYionkcjuz03rZo4///qXow179teZkruyeWmt+//tqsw2zfSj////kXMdgecSMOXaWRbkuuuqgiz///hk585675335875569///944/////5xyzzz122598789////+4244///6////////////546uldZp8///nVimmkkigdbehkhhijortqotsqpnan2188yx1////wuusttty6/////1wz012210z04747////6110x1547/////+7+///1y0zutwpo2////neQKLNPMIGEEBABFIJLHDJGbkmksxyyz3432145pamrttrbWUSVXXVTRVZYSHNadaWIQVUVUPRbhnogUq4+983vaUTSSKNjs135xmkoonjWKPONOMbo230yhYZijgcOINNOTRYlvtspfclqrsjYelprtlahnrtvodoz8+ykXfkkhRRovxwtan/////pb29//zTguvxseXn11yujq4//8wUkw45qbo3///yiw8///rahnoppcNdhiiigeZWVUUZjurppdUROMQRWVSkpqlRZvyyshJNQQRROZhnngVOszxxvogdcWVOLYpssseUVYZaYNEPQPMISfutssnUTffecTIOPPRQNdr21wmgqw011rm09//0mpy2891pp7//4ZX+/8zmQex021vew////kUo961wWYdecXRViwyzypfo10xobZkutqUY2///0iUltvvjTYpw47nXVmkllkgTONNJQYeffgdLKLJKMLVfrrsqkPSefcVMJMMMONZgjkleVgprqpngWTNMMFRknprqbPVYabXELPNMKLXhoomiROXccdZIPUZZVPVfnkjcSiorqpdZz566ylXlqstmbPmqpmVLXorrnSRiklkfQdx2571UbsrpiZTYbceXKWenpohVZhqtvjIRXYXKNfkotujVcjljfNQdgorsWOeeffgbWPNLLLZfhfggWTTRPPNHIQZbdZKIQRROIJMLKLKJSVXWTKMlqqrngYSPMNILViknmcVQSTVUIGOONLHTcklljdORTUYYUEILMNKFOXcbXRJLKLLRVnrqongWLKJKKLIUacddSMWbcYRBFJJLMKJScdaWLWfjklgLKLJIJGEJNPPMIEILKLGDIIJJJEESWaaQJEGHIHDBCGHGHJNSVVVVQLGKOTREKPOKFDOUYZaYRFEHGDCBEFGIFGPcfhigVPWckldQGIFIIPXdcXDCZdfdZZVLTglvukMGNTVTMUchikdDCDJNKDRUVVWXSEMWYZOLaekmlTJLOOJCAEMOWYRLGCCBAACCOTMFRYbccggURSTTWWPJFDEALZdaUDHOSSOOQOINVfihXLOUXWRIWflqqgXJKNQQJMXZimkNUcbdeaIGNQQNEPTUUabTPRWaecQHBFGCBFHHHIPUfilnpbPCGUadLKSQMKQXcfcTOSVXXWabNPVfmtlHIIIJKIFKUWXTLAAFIMKFJLOQSNKTYZaVPJOThnfZXYYaaYYZcegfSMNPOOQUVWVSOKEFKNPNHAFOPRMTckpoaJUZelmXIILMJKLNWYcedJGIMPQOSYfhfaTIPYZZWLOUbdhhZYZbbdbMHSVWTOEGMMJCGSWZbcTMKKKJEDCFHKJJQWeedeXNGRXggPDIJGOKWccXQBEWaeefdWIQcgnkZFGJIKHLYhqsnbFHJHJHFNNPTVUMGLPTVKPbfknnTKLQQLHSYdbeeRKHCDFHDBBCCGGJOSUUZaaaXYZYULGHFEITdfbTIJOTTRROIFVgsudRIPPTUNVhmrvwcSRTTQNFLafindKTfgihbIMSTUQHLTWTLMPTVZaYTLHFGHNPSSPPQSYhikmlUKJQcgdIMQQLLQdioptpdddghhdKIPglodHILOTOHEKUWXRJGGHJMKFKORRLFKQTaccbcegihZWVWVZcaXWWWYZUSOOOQPKJIJLKHIKNONJFCGQUQLSYXSSQRZdgkjPOQRQOMFLPRTQKGJONLMKBFMNOLITWTQKIGHJMNKDCGJKNMKJLMJKJFFHKMNKFDFJJIFEHGGHEBCILLLLKLSUUUNPOSSRRTWaYTONMQdhgaWRSPPSaXPPSTVTPQTRTYWUUUXadZKILPRTRSUXXULGMONIKOPSUWXVLKKJIIFAADFHJHCCCCFFCEKSRSPLKLPPRRYaXWWRPSVTVWVTSWZaaQNQPWacZZXUZdZRKRQVUVchihcUJGLNORRPSWVWVMBFKKLKKEELPTOJKNRSJAGLNTVMDAAABCACFGIKHRRMLMNLJJKLRSROOPOIJIEFOPNIHGGGGGHEGKOPQPMMOIGIIIHJNNLLMONMMHGMNLKHHFOVaaUUUXWWXQMMLLJGAABEEDEHHIJJEBCGQRRPORTUUQIBDIIFHKORRSTOLIJMTVONTVWXXRNJKJMMGDDDHJICDCBDCBINUXbYSGFFGJJKNRSROKSYbVRQMFIQSTJDDFLMLCADGLNNIILMKJHFHIIIHGGOZYVSNNPLMQMIJOOPVVWWUUSNKMQUUWTRMKMJRROLJNRUSPIFHHJKJJLVXLDMMLNOLKOPJFECBGILKHAEJKKFFJKLNNKDDEKMNHBFJNPKILNMSUNJILSSSPOTWXcbORSSVWTQPLKOPHHILOVXTQMHJKIMQWacVMDFHIJEACEJJJFDILQTKBDHJOQKDAAAAAEEBBACEJKIHHKJJMSTRMLIJJKPRPPSLKKMPPQSSUSPKIHIJHGJJMSXTPQQNNONOSWXXXXVUSSTRRSTUYdbZadhgccccdgifdcZZaXQPSYagdTSVUTMGGLPNNNOPQSRPLLQRPONOQWYabWSQVXXWMHJLNONIILLNRQHINOMJIBABDDCBFFHJKGCHJNPLEDDEILPQQPPRTNEDEDEDKQXXcecMHDFHGHQVWUTSHMPYbdaLNTVUQKKNQVYdehjmnpjaRONNNRUackpsfWEGIJGCCFGHIGCBEHKJABDDFECMRaaYRHfq1350kFIPQQPMPXghhXLLPKGHFLWXWVLUjlmpsibRORRUTSghklibjxz11sXcedbaUbipsxuVSTPOOLKMQSUYVHKTXZLIUXWWZWRLKKKLLKKMOONOOPNKMNOPTVXYSPOTUUTQPMKJMPVVQPRUUPOQTYZaaZWXXXXddNFBBFGFFFHFEKOUUEBBBADGECHNSRNGJOSXYSSZeecWNDFLLKFIQWacaQPTVXYPHFKNSTECIKNLIGLZaZYVHLYXZYSUeopssaXiuribMRdqrocQZhfeYQJQXZaSGMRRQOJFajmnhWIKOVYPFQfhjlmfbcZXYceggfhlnjfjmnkjmw0560qmbXWUTUUVVZcebZYdjfSPOSSVWabaeghitz47/tiababdhjolSXWDFAEIIGMRXXcfdbaedYVPPRRRNGRailonnruy261toqrrsrqsvz23xqiecdhjkijkmqrwxz65qmkklv31zyyxwspsx1892ttrqponsw16+zbQHJHDIRSUWWTMJNSXZJHSSLQWbccacdeegiilnnighjllggjtw3yifhgeefjkklnpnjkorvskedfhjnnppmostw8///2qhcbbejjosv14pgeiieedbcegkkilvz651pmmp20shhkkkkjrz687yomljjhjpsu15ricbaabghjifilihiknmiYXZacehgfcfkjYWVUTURHFGGIHGKOIDMYabbPGFFDFHJJGDDDEGGDGKRTTPINPNLLMPSTUURPSaikmooklppqpeILGFHKMNPRQNPYlppqtrtvusvvocbZUUUVbeghdTcortsogfmpstnUbfbSVZddefgdKOSYaYUQQRVUUXYZaaaaafjmnnSHMMPSUVWhmomNEISUVVSTVZbfeYjssrvxz22004yhghghheeiopndRWXXWWYaglophVJLKQSONdghfcWclnnoohdacikhOJZcddedbXVXVOfkpsvvrtz673oJPWUROOPQTYWVf0469/wonqnorrstpnoonorrqnTahiebcims014yaRUTPRVadebZVNXeooogYOONPacbbccccbYbhqrYMPRUXWWXdhjliMJQPNMLNONMKOTjonpxytmptrmgJGHJKIHRXcefYNafkmmjglrwz1lWVUQMMSUSSUUSFLSVaZUTUXXZYKKOTTTSPRUXYVMfny5+6xms455qbGFGIIGILMOPMWdijklgddebXYYZbcebaacjmoniPYlpqnjdgux35wTSMOSTVURQTWSkrwz00upsvy1xlPZcaaZbjnpmeTZefbYWXbptvsQLONMMNQQQPOKNhmmhhlideggjlgVVXYZaZejprkXJSVaaXYajosrWGJNOOPQSRPPRSSZlnotrcXVYaZSNPPPSVVSSSUWSLaekoqljou23pZTXXXXVVZaZYcgffgjllcZaZWXacdffmppkmtuy0rnkhhjkklntw1zttmihkllmopruuqqw03xtx00141xuvwxvuu0214sjglkiilov04//ypdbcfgjjjkjjjjkqu2xnflqquvskmpnpsvz2350rgfipqmlz79//2ukjhhjkhcZbhkecgijhfghiktrXXdtvpnjfaWVWWSRQSWabbZVUXaYLJMNKQUTVYaXSLGGHIUflqqmlbRMOPPPKHJNROETdjklfYFHMOQRTbdeedbWUTWWQPOONPRRNSXbdaGJQQTUVSOOOMMSgjmmlmlZRSTUQKVaijfVbggfgjiZSPRSXdx24573vWLKLOLMOQPPMXl24662ujHJGELNUcbXVTXbfilnmkihheViptuwtlZYXXYYYabaaWPJSTQQTRLNNNOKFNRSUUMITVWYXPJIIIKWx36532yfPKJLLFKMSWedUUWRRSNLMLNPQKWYXTTKKXbfffaZabbbYIKVXZaWUROOMPTUUVWYYXXYZadedbZZZWURPUWXZXPSTVWUSOORTWVVTTVUXZZUPHEFEEFIPRKMRTUUVPIafgaQVcihiifUQMJAAKWYacddaKHLKGHQTTRRSRNNNPRSSXXWWWXULMJIHCMaaceYSaehmkXTSQOLMKJUosoeLPSUWYWQQPRTTOZoxwvhQTVUVYYZZXadZSNUYYYPLMRQOPMGSZccaJRbcbefWUVTQRUZbYXabaVWXWWWSVacbPFVXXceeZVWVSTcm35311tjPPLLMRXbaZZWLXtz54iSFKLMLDDIONLOgpwvtvsaSQSSJPputtwumTMNSWVQNNNQYXVNLMOLEFMMNPUWWXYZTKSXXZYSMUcddaVow0y00veXTSUUUVXWXWQKafghhYUSQMNHIVYZXWRNRTWVTIOZbbYTMPUVXXVKHHKNMRVXWVUSGJPVWVQNSTQONNSSSTTRMdlppoXLIKOONJJaistlbQJMRSMMLQSXTDKQRQYbXTLKTaTLRQQdcUfmhYfaPmqkfTLKehRRTKdhggheccefhkhcbcdfhjjnqw10iYVWYZbdehjnniecbdhfdfihgjkjjlpqplikortpiffXWWXYgkoquhYMOSUZaabbZchhgfgmpmjhhkolUYcccdccfopqohUQPRRSUZbegnkifbWVXZZZZbbXVUUVXXXWZaYXYbcfdddbXYegkkbFAIJKJJMRYZWRPTXaZUTVXYYYWRLMVXWSOHIJLLFFVZbaYXYYYabaZaghjkfbZdgklbYWXXbeffgghiifdinrrlfgghmlifgilmjgknqrqkfdgjheelprvytjTTVZaceggglnomosxwtmlllnomikonomhilrvwsnooonmlilnrusmgffillkkmnoqokknuwsdZYXYaQXgnnpqqrtwy30mlkgcYWXbikkhZNPUUTWXUSSSSRSUUUTSQOOQYdXMIRSRQOOMNORSRPNNOUWTVdgjmkaYWUTVXYZcdedZQQXchdVWZdedcaadiknnmpstumhVQLMOTWcgnqnRUbfhiklllmqrpoprrtuuuuoqvnamy0231utxyyvsssuvxvsppvzzqhYcebXWWejoqssvuvwwqnonljfUWhjmspjnvx30oTRURUVWfnvulWimmffqtpqsokZVSQUceghjklnnScjigggggbZabbbYTVgfWWbklvsaZdcabbcdfefkmiiijkliiicbdaWVWfklhinpuxrkeXWYaXWejmuvibSTVUVWUSSTceYVZenokZXadfaTcjrtwvttx11wuxzz232z037///5uqrqooquwwwx02/////53029/81w2589779////9886552z3+///7vvwvutswzz01yx20wxxuu02//xngcbdhgcSNLOPOOSUWZWSWZadjcHBDFKLMOMRSZegecYXWQFMPQQWdnmlsuphYZclnXNUXXWTRWeflokWSVaffZTOJIMLRUWdfjicdehkjbEESXabVVahmqaQNNOLLPRSTWbbVQIKGEFPXddbYNXjoqnjcbYVVYTRVVVWYSRUVWZUNRWXVNJMQWntodUMMUWXVYaZdeVQMMRYWPSaeornPOWaffdVSKIIJKMQXZYUOWfosvmRJJJKKLbdcbbWQTYcglaPJMQRQLSYXcfXUfuuuvgaZccZWQairsvlWZWUTTSNKLMLMSehghljbaachqngcehkmdTPRVZSPORSOJEJXejuwfVKLMSSIEHGGFCVeklmjdOORSQLUcionnkVKMOQPMMMMJIHQgkuz1fTHHFHJOOMMMNNKMLKPRQRYnptrUQTSTadYTILMNSbefgijgbZeimlgUQONNONSUUVabejijleXQEEFEUdosvyyhaVXXZbQKKNPMIUahksuocZWXYZXRNGEHFOSVbfhbbdfghYONRSRTROUWXabLKMNMMOJGQUdhZQJSVXWNGFAAFJIPUZaheTUYcfeYXebaaUNZgklndWVYZaVNPcfjkWNKJPXZRLRTVccQQcgknlbehghlbLSYZabZPNQPOPQNOTVSMSYformbNJFIKGHTXacaMSgjorrXLTVTTRahkijjhQXlntqVQPXZVOZhlopmcVXYYVTURQSRPOPXZdehfbVXfjnkcLKSUNHGMMSVRSUVVUWYbegirqXSIIHHGDGMNGDDQWccdaUIECEHFGSVaaWPJORQQMHJMMOQFMelnokLFKIIOTNIGFHIHFPYXYYQNLPRaaWTRLMPROJGJJMPWWSQOIIIJLMOJDADEIJGKVYZZVPIHJJLDADEFECLTbdgmkRMKKLQOELYcfeWORTTQMLHHFGHKQYYabVNPPPPTPIGKJFGEDQVYbYLUlomlfNRVVZaWRdrtumZLLMSfdKGJMOOMQXegdWOQTYadYQSdkjhUPipsqkPHIOTUOKRdinkSJMQPNLIRXZZWRUZabaaWKECFHFGIJLNONNSWUTURUdeknjbSQUcfUKFIIHIEBHKOOLKTegedXFKNMIIILUjnrrjUUWXYSIKNLNNJHNRTVRKIJIKLIISSTTULGIIKMNKHPOPQMFLTVZYIMXpqrkTbilkidPSjkljYGEJLLHEGIMNNJEQYiliXPTbggWJKckondUfmoljTLRWYZaZWbfiicJOYWNOKWfiiljbNQSSRROMUacgYIIJFDGGIIIIINSYZZXWRMLPUURFABCDEDJTcbWUHABGHECCHJIHJHKUepprmTMJKKKFBEFHKMJILSTNFHJEEFLIOSSSSLGEJLPTKDHJJHLHJVbghYMWgfknfHMLMMMLZhqsnZNWUQSXTHJLQRNHQTUWZXQXgmpmXQQYikhQVoqmkbCGNMQSUbitvvqOCGHINNIOSabWSUUYYadZQSXYYSLNPNORROLJKKILSglrsfWQQTadRKGHHIJDCCEFEFFMWZadXGHLNRPITahiokbWacdbTOOOOOKHLOQRTLHKOQNMGELLEFFBFKLIMPLJFDGIHDKXZbVGMSbdeWTXbccebTTUWWUNRSKFIIFLOLIGDLchlnkZNLMJIHMTgikmfaWWZedSTQMLPOCFOOMJHABILQPJJORTXRKHIKKHEGIILOPOVXWUUQLRRQQRLJOPMGHNSbdffZIFBDFFFBBIHFLUYbcdhdLIMQRQNELTSJDMVYbZWTVUSQSSLSbcfhiTLEGHHGLSZXUTPMKLNTVKGPQQRTIPadddYFKdhkdRHJIFCIPbgijjcTLKFEEHLNMMKJTbceiiXSMSXbZOJBAAADXfljbSNTVVXZUMOYjmkaDCGPTVQRVYeheVNTYYXVPLRRRPFFNRVVVMISSSSLENZaYYVTScgljQKJJFCDGGEFEAGbipqrpfIGPPPLGKOOKQXcnojfXeksqkhYPNSVZZKHIFEJIEDHMONHNSUUZbWGEHGGJIUchjmlffhjhffknplijhdefjoslYVaceaVWaadeaYejkkjcYSRUVRNHADMLVcgggcOLLKKKJJafjkiSKQSTadUKVVNIIMLKMSTNGFVXWWZbdcYSQOMLMMMHHMSROHGQVegllfTSIGOMIIGCCCENbeeffYGNRSSQKLTWNDLSYZVQKRTTUVWUGOYbfhfQMLKKKJNUccZVMJKPRWUCIMLNXVPXghhdTHRbeiWJXZSNJKQeimpiYTTPHGHJNPMGFRXbcdfgXRJKNSVVSKEDFMfjnmdRMPQSTXUNOVhkgTEGHNRJNegfaZTORXZYXNIQRXabQKPScecLHNMPPNIQXVUSMUbeeieMGHFABABDFFFDKfnuuuiVBJRQNGLUZTLTahsuxxeYbigcaXRQVZcYLJBAFRRDIQSSOIFKOOTUOCGKKMIIafhjmjggijjgddcdfffebaaglicZYXadbYWVYcffghhiifWZddfdTUYehkgfkossiQRXcbVOQWadcaUXaYVSPCEJLONDGMTTSRMLLPOJHHHHGIMNKJMOPOLFFEFIGEJMPQQPMGEDCFDBAAFHKORWXUUVVSOMRRTU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]], +} diff --git a/demos/insertCoin/video/plasma.mp4 b/demos/insertCoin/video/plasma.mp4 new file mode 100644 index 000000000..246b95e60 --- /dev/null +++ b/demos/insertCoin/video/plasma.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:182ffed903dac337d7aefcde9d04dec8b38821d58cf76de8e71c094cc223d4b9 +size 1318603 diff --git a/demos/insertCoin/video/tunnel.mp4 b/demos/insertCoin/video/tunnel.mp4 new file mode 100644 index 000000000..51c0077b6 --- /dev/null +++ b/demos/insertCoin/video/tunnel.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9da9c5350ad5155f48625774df8ab631f541c9ee06f8023e97499370c067a8d +size 4631231 diff --git a/demos/kit.lua b/demos/kit.lua new file mode 100644 index 000000000..11d7e093c --- /dev/null +++ b/demos/kit.lua @@ -0,0 +1,657 @@ +-- The demo kit: what the three demos share. A demo loads it with dofile(DIR .. "../kit.lua") and +-- gets back one table. +-- +-- Time is the music's. K.time() is where the listener is in the track: musicGetPosition while the +-- demo plays, or a clock that moves exactly one frame a frame when DEMO_CAPTURE asks for a capture +-- (see util/demoCapture.sh), so a captured frame lands on the music added afterwards. Everything +-- else is read off that time: beats and bars from the beat list util/demoSync.py wrote, the drums, +-- the bass, the loudness and the brightness as envelopes from 0 to 1, and the drum hits as lists. +-- +-- A demo is a list of scenes, each with the bars it spans: { from = 17, to = 33, enter = fn, draw = +-- fn, leave = fn }. K.run calls enter once as the scene starts, draw every frame it is on with the +-- time, the bar, and how far through it is from 0 to 1, and leave once as it ends. Scenes may +-- overlap, and are drawn in list order. + +local K = {} + +local ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +local ENVELOPES = { "kick", "snare", "hat", "bass", "level", "bright", "noteClear" } +local HIT_LISTS = { "kicks", "snares", "hats" } +local LEVELS = 63 +local PIXEL_PNG = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\x0b\x49\x44\x41\x54\x78\x9c\x63\xf8\x0f\x04\x00\x09\xfb\x03\xfd\xfb\x5e\x6b\x2b\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82" +local FONT_FILE = "Singe/FreeSansBold.ttf" +local TAIL = 2 -- Seconds the demo runs on after the music ends + +local sync = nil +local music = nil +local fonts = {} +local widths = {} +local pixel = nil +local startTicks = nil +local lastTime = 0 +local lastTicks = 0 +local frames = 0 +local stats = { second = 0, frames = 0, worst = 0, last = 0 } + +K.W = 640 +K.H = 480 + + +-- The fractional bar at time t, counting from 1: bar 1 starts on the beat the sync data names. +function K.bar(t) + return (K.beat(t) - (sync.barStart - 1)) / 4 + 1 +end + + +-- When bar b starts; fractional bars land between beats. +function K.barTime(b) + return K.beatTime((b - 1) * 4 + (sync.barStart - 1)) +end + + +-- The fractional beat at time t, counting the first beat of the list as 0. Before the first beat +-- and after the last the spacing of the nearest two carries on. +function K.beat(t) + local beats = sync.beats + local n = #beats + local lo = 1 + local hi = n + + if t <= beats[1] then + return (t - beats[1]) / (beats[2] - beats[1]) + end + if t >= beats[n] then + return n - 1 + (t - beats[n]) / (beats[n] - beats[n - 1]) + end + while hi - lo > 1 do + local mid = (lo + hi) // 2 + + if beats[mid] <= t then + lo = mid + else + hi = mid + end + end + return lo - 1 + (t - beats[lo]) / (beats[hi] - beats[lo]) +end + + +-- When fractional beat i falls. +function K.beatTime(i) + local beats = sync.beats + local n = #beats + local whole = math.floor(i) + local part = i - whole + + if whole < 0 then + return beats[1] + i * (beats[2] - beats[1]) + end + if whole >= n - 1 then + return beats[n] + (i - (n - 1)) * (beats[n] - beats[n - 1]) + end + return beats[whole + 1] + part * (beats[whole + 2] - beats[whole + 1]) +end + + +-- Vector bobs: count balls on a shape that changes every two bars (a ring, a helix, a sphere, a +-- flower), turned in 3D and drawn back to front at the size their distance gives them, each tinted +-- round the colour wheel. sprite is a white shaded ball; spread scales the shape; size is a ball's +-- radius in pixels at the shape's middle distance. +local BOB_DEPTH = 5 + +local function bobShape(kind, i, count) + local k = (i - 1) / count + local a = k * 2 * math.pi + + if kind == 0 then + return math.cos(a) * 1.6, math.sin(a * 3) * 0.3, math.sin(a) * 1.6 + elseif kind == 1 then + return math.cos(a * 3) * 1.0, (k - 0.5) * 3.2, math.sin(a * 3) * 1.0 + elseif kind == 2 then + local phi = math.acos(1 - 2 * (i - 0.5) / count) + local theta = math.pi * (1 + math.sqrt(5)) * i + + return math.cos(theta) * math.sin(phi) * 1.5, math.cos(phi) * 1.5, math.sin(theta) * math.sin(phi) * 1.5 + end + local r = 1 + 0.5 * math.sin(a * 5) + + return math.cos(a) * r * 1.4, math.sin(a) * r * 1.4, math.sin(a * 5) * 0.4 +end + + +function K.bobs(t, bar, sprite, count, spread, size, cx, cy) + local shape = math.floor((bar - 1) / 2) % 4 + local next = (shape + 1) % 4 + local morph = K.smooth(0.75, 1.0, ((bar - 1) / 2) % 1) + local ay = t * 0.9 + local ax = t * 0.5 + local pts = {} + local pump = 1 + 0.25 * K.decay("kicks", t, 8) + + for i = 1, count do + local x1, y1, z1 = bobShape(shape, i, count) + local x2, y2, z2 = bobShape(next, i, count) + local x = K.lerp(x1, x2, morph) * spread * pump + local y = K.lerp(y1, y2, morph) * spread * pump + local z = K.lerp(z1, z2, morph) * spread * pump + local x3 = x * math.cos(ay) + z * math.sin(ay) + local z3 = -x * math.sin(ay) + z * math.cos(ay) + local y3 = y * math.cos(ax) - z3 * math.sin(ax) + local z4 = y * math.sin(ax) + z3 * math.cos(ax) + + pts[i] = { x = x3, y = y3, z = z4 + BOB_DEPTH, i = i } + end + table.sort(pts, function(a, b) return a.z > b.z end) + for _, p in ipairs(pts) do + local s = BOB_DEPTH / p.z + local r = size * s + local px = cx + p.x * s * 60 + local py = cy + p.y * s * 60 + local cr, cg, cb = K.hue(p.i / count + t * 0.1) + + spriteSetTint(sprite, cr, cg, cb) + spriteDraw(sprite, math.floor(px - r), math.floor(py - r), math.floor(px + r), math.floor(py + r)) + end + spriteSetTint(sprite, 255, 255, 255) +end + + +-- A filled rectangle, corners inclusive, in any colour and alpha: the kit's one-pixel sprite +-- stretched and tinted. blend is a SPRITE_ constant, alpha by default. +function K.box(x1, y1, x2, y2, r, g, b, a, blend) + if x2 < x1 or y2 < y1 then + return + end + spriteSetTint(pixel, r, g, b) + spriteSetAlpha(pixel, a or 255) + spriteSetBlend(pixel, blend or SPRITE_ALPHA) + spriteDraw(pixel, math.floor(x1), math.floor(y1), math.floor(x2), math.floor(y2)) +end + + +-- A chrome material: metal, polished to roughness, tinted r, g, b. It needs a sky to reflect. +function K.chrome(r, g, b, roughness) + local m = materialNew() + + materialSetColor(m, r, g, b) + materialSetMetallic(m, 1) + materialSetRoughness(m, roughness) + return m +end + + +function K.clamp(v, lo, hi) + if v < lo then + return lo + end + if v > hi then + return hi + end + return v +end + + +-- How long ago the most recent hit in a list ("kicks", "snares", "hats") was at time t; huge when +-- there has been none. An effect fed exp(-age * k) flashes on every hit and dies away. +function K.decay(list, t, k) + return math.exp(-K.hitAge(list, t) * k) +end + + +function K.ease(t) + t = K.clamp(t, 0, 1) + return t * t * (3 - 2 * t) +end + + +function K.easeIn(t) + t = K.clamp(t, 0, 1) + return t * t * t +end + + +function K.easeInOut(a, b, t) + return a + (b - a) * (0.5 - math.cos(K.clamp(t, 0, 1) * math.pi) / 2) +end + + +function K.easeOut(t) + t = 1 - K.clamp(t, 0, 1) + return 1 - t * t * t +end + + +-- An envelope's value at time t, 0 to 1: "kick", "snare", "hat", "bass", "level", "bright", or +-- "noteClear". +function K.env(name, t) + local curve = sync[name] + local f = t * sync.rate + local i = math.floor(f) + + if i < 0 then + return curve[1] + end + if i >= #curve - 1 then + return curve[#curve] + end + return curve[i + 1] + (f - i) * (curve[i + 2] - curve[i + 1]) +end + + +-- The whole screen in one colour: a flash, a fade, or a tint. +function K.flash(r, g, b, a, blend) + K.box(0, 0, K.W - 1, K.H - 1, r, g, b, a, blend) +end + + +-- Coloured glass: see-through by alpha, polished, drawn after everything solid. +function K.glass(r, g, b, alpha) + local m = materialNew() + + materialSetColor(m, r, g, b, alpha or 90) + materialSetBlend(m, true) + materialSetRoughness(m, 0.05) + return m +end + + +-- Seconds since the most recent hit in a list at time t. +function K.hitAge(list, t) + local hits = sync[list] + local lo = 0 + local hi = #hits + 1 + + while hi - lo > 1 do + local mid = (lo + hi) // 2 + + if hits[mid] <= t then + lo = mid + else + hi = mid + end + end + if lo == 0 then + return math.huge + end + return t - hits[lo] +end + + +-- How many hits in a list fall after t0 and up to t1: what a frame's worth of time held. +function K.hitCount(list, t0, t1) + local count = 0 + + for _, h in ipairs(sync[list]) do + if h > t1 then + break + end + if h > t0 then + count = count + 1 + end + end + return count +end + + +-- A full-bright colour from a hue, 0 to 1 round the wheel. +function K.hue(h) + local f = (h % 1) * 6 + local i = math.floor(f) + local p = f - i + local c = ({ { 1, p, 0 }, { 1 - p, 1, 0 }, { 0, 1, p }, { 0, 1 - p, 1 }, { p, 0, 1 }, { 1, 0, 1 - p } })[i + 1] + + return math.floor(c[1] * 255), math.floor(c[2] * 255), math.floor(c[3] * 255) +end + + +function K.lerp(a, b, t) + return a + (b - a) * t +end + + +-- Reads the demo's sync data and its music, makes the overlay, and loads the kit's own pixel. +-- Envelopes become arrays of numbers from 0 to 1 here, once. +function K.load(dir, width, height) + local value = {} + + K.W = width or K.W + K.H = height or K.H + overlaySetResolution(K.W, K.H) + for i = 1, #ALPHABET do + value[ALPHABET:byte(i)] = (i - 1) / LEVELS + end + sync = dofile(dir .. "sync.lua") + for _, name in ipairs(ENVELOPES) do + local text = sync[name] + local curve = {} + + for i = 1, #text do + curve[i] = value[text:byte(i)] + end + sync[name] = curve + end + local notes = {} + + for i = 1, #sync.note do + notes[i] = math.floor(value[sync.note:byte(i)] * LEVELS + 0.5) + end + sync.note = notes + for _, name in ipairs(HIT_LISTS) do + sync[name] = sync[name] or {} + end + K.duration = sync.duration + if not DEMO_CAPTURE then + music = musicLoad(dir .. "music.mp3") + end + pixel = spriteLoadData(PIXEL_PNG) + return sync +end + + +-- The strongest pitch class at time t (0 is C) and how clearly it stands out, 0 to 1. +function K.note(t) + local i = K.clamp(math.floor(t * sync.rate) + 1, 1, #sync.note) + + return sync.note[i], sync.noteClear[i] +end + + +-- Every mesh node under a model instance gets the material. +function K.paint(node, material) + nodeSetMaterial(node, material) + for _, child in ipairs(nodeGetChildren(node)) do + K.paint(child, material) + end +end + + +-- Starts the music and the clock, and takes over onOverlayUpdate to run the scenes. Under +-- DEMO_CAPTURE = { from = seconds, to = seconds, every = frames } nothing plays: the clock starts +-- at from and moves by the frame (run Singe with --deterministic), every frame (or every "every"th) +-- is saved as frameNNNNNN.png, and the demo quits at to. +function K.run(scenes) + local active = {} + + if DEMO_CAPTURE then + debugPrint(string.format("DEMO capture from %.3f to %.3f", DEMO_CAPTURE.from, DEMO_CAPTURE.to)) + else + musicPlay(music) + end + function onOverlayUpdate() + local t = K.time() + local bar = K.bar(t) + + frames = frames + 1 + if DEMO_STATS then + K.stats(t, bar) + end + colorBackground(0, 0, 0, 0) + overlayClear() + for i, scene in ipairs(scenes) do + local on = bar >= scene.from and bar < scene.to + + if on and not active[i] then + active[i] = true + if scene.enter then + scene.enter(t) + end + elseif not on and active[i] then + active[i] = false + if scene.leave then + scene.leave(t) + end + end + if on and scene.draw then + scene.draw(t, bar, (bar - scene.from) / (scene.to - scene.from)) + end + end + if DEMO_CAPTURE then + if frames % (DEMO_CAPTURE.every or 1) == 0 then + singeScreenshot(string.format("frame%06d", frames)) + end + if t >= DEMO_CAPTURE.to then + debugPrint(string.format("DEMO captured %d frames", frames)) + singeQuit() + end + elseif t >= sync.duration + TAIL then + singeQuit() + end + return OVERLAY_UPDATED + end +end + + +-- Under DEMO_STATS, once a second: frames drawn in the last second, and the longest gap between two. +function K.stats(t, bar) + local now = singeGetTicks() + + if stats.last > 0 then + stats.worst = math.max(stats.worst, now - stats.last) + end + stats.last = now + stats.frames = stats.frames + 1 + if now - stats.second >= 1000 then + debugPrint(string.format("DEMO t %6.2f bar %6.2f %3d fps worst %3d ms", t, bar, stats.frames, stats.worst)) + stats.second = now + stats.frames = 0 + stats.worst = 0 + end +end + + +-- A flat quad that exactly fills the camera's view at distance d (oversize makes it larger, to stay +-- covering while it turns): for a video over, or as, the whole picture in 3D, where it can turn and +-- glow. What comes back is a pivot on the camera's axis with the quad stood up under it, so the +-- pivot's roll, nodeSetRotation(q, 0, 0, angle), turns the quad in its own plane. It starts hidden. +function K.screenQuad(camera, fov, material, d, oversize) + local h = 2 * d * math.tan(math.rad(fov / 2)) * (oversize or 1) + local pivot = nodeNew(camera) + local quad = nodeNew(pivot) + + nodeSetPosition(pivot, 0, 0, -d) + nodeSetMesh(quad, meshPlane(h * K.W / K.H, h), material) + nodeSetRotation(quad, 90, 0, 0) + nodeSetVisible(pivot, false) + return pivot +end + + +-- A sine scroller: each letter a sprite made once in the font, coloured by where it is on the +-- screen, riding a wave of amplitude amp. It enters from the right at t0 and runs at speed pixels +-- a second. +local glyphs = {} + +function K.scroller(t, font, text, y, amp, speed, t0) + local x = K.W - (t - t0) * speed + + for i = 1, #text do + local key = font .. text:sub(i, i) + local g = glyphs[key] + + if not g then + fontSelect(font) + colorForeground(255, 255, 255, 255) + fontQuality(FONT_QUALITY_BLENDED) + local s = fontToSprite(text:sub(i, i)) + + g = { sprite = s, w = spriteGetWidth(s) } + glyphs[key] = g + end + if x > K.W then + break + end + if x + g.w > 0 then + local r, gg, b = K.hue(x / K.W * 0.5 + t * 0.2) + + spriteSetTint(g.sprite, r, gg, b) + spriteDraw(g.sprite, math.floor(x), math.floor(y + math.sin(x * 0.018 + t * 4) * amp)) + end + x = x + g.w + end +end + + +function K.smooth(edge0, edge1, x) + return K.ease((x - edge0) / (edge1 - edge0)) +end + + +-- A full-screen flash that fires on every hit in a list and dies away at rate k: a = 0 is off. +function K.strobe(t, list, k, r, g, b, a) + local v = K.decay(list, t, k) + + if v > 0.02 and (a or 255) > 0 then + K.flash(r, g, b, math.floor((a or 255) * v)) + end +end + + +-- How wide text is in the bundled font at a point size, in pixels; measured once and remembered. +function K.textWidth(text, size) + local key = size .. ":" .. text + local w = widths[key] + + if not w then + local font = fonts[size] + + if not font then + font = fontLoad(FONT_FILE, size) + fonts[size] = font + end + fontSelect(font) + local sprite = fontToSprite(text) + + w = spriteGetWidth(sprite) + widths[key] = w + spriteUnload(sprite) + end + return w +end + + +-- Text in the bundled font at a point size, in a colour, left, centred ("center"), or right +-- aligned on x. +function K.text(x, y, text, size, r, g, b, align) + local font = fonts[size] + + if not font then + font = fontLoad(FONT_FILE, size) + fonts[size] = font + end + fontSelect(font) + fontQuality(FONT_QUALITY_BLENDED) + colorForeground(r, g, b, 255) + if align then + local w = K.textWidth(text, size) + + fontSelect(font) + if align == "center" then + x = x - w // 2 + else + x = x - w + end + end + fontPrint(math.floor(x), math.floor(y), text) +end + + +-- Where the listener is in the music, in seconds. It never runs backwards, which a mixer +-- position read just after a buffer moved can otherwise do by a millisecond, and once the music has +-- ended it runs on with the clock. +function K.time() + local now = singeGetTicks() + local t = 0 + + startTicks = startTicks or now + if DEMO_CAPTURE then + t = DEMO_CAPTURE.from + (now - startTicks) / 1000 + else + t = musicGetPosition(music) + if t < 0 then + t = (lastTime > 0) and (lastTime + (now - lastTicks) / 1000) or 0 + end + end + lastTime = math.max(lastTime, t) + lastTicks = now + return lastTime +end + + +-- A (2, 3) torus knot as a tube, built vertex by vertex for meshNew: the curve, a frame along it, and a ring +-- of vertices round each point. +function K.torusKnot(radius, tube, segments, sides) + local positions = {} + local normals = {} + local uvs = {} + local indices = {} + + local function curve(phi) + local r = radius * (1 + 0.42 * math.cos(3 * phi)) + + return r * math.cos(2 * phi), r * math.sin(2 * phi), radius * 0.42 * math.sin(3 * phi) + end + + for i = 0, segments - 1 do + local phi = i / segments * 2 * math.pi + local px, py, pz = curve(phi) + local qx, qy, qz = curve(phi + 0.01) + local tx = qx - px + local ty = qy - py + local tz = qz - pz + local tl = math.sqrt(tx * tx + ty * ty + tz * tz) + + tx = tx / tl + ty = ty / tl + tz = tz / tl + -- A normal that never lines up with the tangent: the knot never runs straight up the z axis. + local nx = ty * 1 - tz * 0 + local ny = tz * 0 - tx * 1 + local nz = tx * 0 - ty * 0 + local nl = math.sqrt(nx * nx + ny * ny + nz * nz) + 1e-9 + + nx = nx / nl + ny = ny / nl + nz = nz / nl + local bx = ty * nz - tz * ny + local by = tz * nx - tx * nz + local bz = tx * ny - ty * nx + + for j = 0, sides - 1 do + local a = j / sides * 2 * math.pi + local cx = math.cos(a) * nx + math.sin(a) * bx + local cy = math.cos(a) * ny + math.sin(a) * by + local cz = math.cos(a) * nz + math.sin(a) * bz + + positions[#positions + 1] = px + cx * tube + positions[#positions + 1] = py + cy * tube + positions[#positions + 1] = pz + cz * tube + normals[#normals + 1] = cx + normals[#normals + 1] = cy + normals[#normals + 1] = cz + uvs[#uvs + 1] = i / segments + uvs[#uvs + 1] = j / sides + end + end + for i = 0, segments - 1 do + local i2 = (i + 1) % segments + + for j = 0, sides - 1 do + local j2 = (j + 1) % sides + local a = i * sides + j + 1 + local b = i2 * sides + j + 1 + local c = i2 * sides + j2 + 1 + local d = i * sides + j2 + 1 + + indices[#indices + 1] = a + indices[#indices + 1] = b + indices[#indices + 1] = c + indices[#indices + 1] = a + indices[#indices + 1] = c + indices[#indices + 1] = d + end + end + return meshNew(positions, normals, uvs, indices) +end + + +return K diff --git a/demos/mirrorball/art/bob.png b/demos/mirrorball/art/bob.png new file mode 100644 index 000000000..76b5f0234 --- /dev/null +++ b/demos/mirrorball/art/bob.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ace021ff6910172a706b7dc675d34841f7fb9f6356eba68d1c3fbd36da345ca0 +size 2708 diff --git a/demos/mirrorball/art/boing.png b/demos/mirrorball/art/boing.png new file mode 100644 index 000000000..5ed3ba99e --- /dev/null +++ b/demos/mirrorball/art/boing.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c60bf072b89ccd24d13d932dadcd6c69ee438f199c763e904ac820081211e803 +size 480 diff --git a/demos/mirrorball/art/club.png b/demos/mirrorball/art/club.png new file mode 100644 index 000000000..a7020698a --- /dev/null +++ b/demos/mirrorball/art/club.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a353971808520f2be7b95411b1c70cfd98476ec8fa8cdaf6e321f20bf51725e0 +size 97233 diff --git a/demos/mirrorball/art/copper.png b/demos/mirrorball/art/copper.png new file mode 100644 index 000000000..3ca7b5047 --- /dev/null +++ b/demos/mirrorball/art/copper.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:77e3b195fa9d656885aa7bc95fa22866d5e40e3373efdf07db9df308e7a7454e +size 188 diff --git a/demos/mirrorball/art/glow.png b/demos/mirrorball/art/glow.png new file mode 100644 index 000000000..88dadee9d --- /dev/null +++ b/demos/mirrorball/art/glow.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8589f0a42d8d118a65bf39dcc1e42139e3659dba62ad36bcfc95d498ff79736e +size 4093 diff --git a/demos/mirrorball/art/logo.png b/demos/mirrorball/art/logo.png new file mode 100644 index 000000000..1eebd8607 --- /dev/null +++ b/demos/mirrorball/art/logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a67f837a6a236e3a1171f62becb774c083f7464b4ef65fe79eb2ee0ffecfd8ec +size 89232 diff --git a/demos/mirrorball/art/roto.png b/demos/mirrorball/art/roto.png new file mode 100644 index 000000000..3c0c8cb72 --- /dev/null +++ b/demos/mirrorball/art/roto.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:41f829d5edb4a7c8717b11e77afebb1bb5d0e0204d7da6c939793e20d88ffba1 +size 806 diff --git a/demos/mirrorball/art/singe.png b/demos/mirrorball/art/singe.png new file mode 100644 index 000000000..98e7a408e --- /dev/null +++ b/demos/mirrorball/art/singe.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e4caf4e7dbebd81bf0042331f2bdfbc5075759f97c1ead0d6e9aeea4030e039 +size 66896 diff --git a/demos/mirrorball/art/sparkle.png b/demos/mirrorball/art/sparkle.png new file mode 100644 index 000000000..eed95ecfa --- /dev/null +++ b/demos/mirrorball/art/sparkle.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb5f3a0b27869593ad7ba5800cb6eda7404acf7d9f07c111b79ea5a42510cca7 +size 1527 diff --git a/demos/mirrorball/art/tile.png b/demos/mirrorball/art/tile.png new file mode 100644 index 000000000..f3aa5f3d4 --- /dev/null +++ b/demos/mirrorball/art/tile.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:90982c9f1c447a225ceaa39290ef2c44d2af8e57f3d3449915f2eff9dd4d4ca7 +size 1501 diff --git a/demos/mirrorball/art/twister.png b/demos/mirrorball/art/twister.png new file mode 100644 index 000000000..039a0c607 --- /dev/null +++ b/demos/mirrorball/art/twister.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7cf559ac8309c625646b8b5eaa075baa4dc3967f8956fb26959651d2bbda136 +size 1003 diff --git a/demos/mirrorball/games.dat b/demos/mirrorball/games.dat new file mode 100644 index 000000000..67acce6a4 --- /dev/null +++ b/demos/mirrorball/games.dat @@ -0,0 +1,12 @@ +-- Mirrorball: a demo for Singe, to "Vintage Funky Groove" by miiira. +GAMES = { + { + TITLE = "Mirrorball", + SCRIPT = "mirrorball/mirrorball.singe", + CANVAS_X = 640, + CANVAS_Y = 480, + RESOLUTION_X = 1024, + RESOLUTION_Y = 768, + REQUIRES = { "SCENE", "POST", "SHADOWS" } + } +} diff --git a/demos/mirrorball/mirrorball.singe b/demos/mirrorball/mirrorball.singe new file mode 100644 index 000000000..9d90b0ffc --- /dev/null +++ b/demos/mirrorball/mirrorball.singe @@ -0,0 +1,949 @@ +-- Mirrorball: a demo for Singe, to "Vintage Funky Groove" by miiira. +-- +-- A night in a nineties club, in eight-bar phrases as the song is built: a choppy intro, the ball +-- coming down over a lit floor, the oldschool effects the dance parties ran on (copper bars, a +-- rotozoomer, a twister, vector bobs, glenz glass, a bouncing checkered ball), a laser show, a +-- breakdown in the dark, and a finale in which the ball shatters on the last downbeat. +-- +-- The song speeds up as it goes, from about 111 to 117 beats a minute, so nothing here assumes a +-- tempo: bars and beats come from the beat list in sync.lua, and everything that lands on a beat +-- lands where the drummer put it. +dofile("Singe/Framework.singe") +local K = dofile(DIR .. "../kit.lua") + +local W = 640 +local H = 480 +local FOV = 60 +local TILES = 12 -- The dance floor is TILES by TILES +local TILE = 2 -- World units across a tile +local BALL_Y = 6.2 -- Where the ball hangs +local BALL_R = 1.45 +local FACET = 0.2 +local SPARKLES = 70 -- Points of light the ball throws on the walls +local LASERS = 9 +local RAIN_MAX = 70 -- Balls that fall on the snares in the boing scene +local TWIST_R = 92 -- The twister's half width, in pixels +local TWIST_ROW = 2 -- Screen rows each slice of the twister covers +local DISCO = { { 255, 40, 80 }, { 255, 160, 20 }, { 255, 240, 60 }, { 60, 255, 120 }, { 40, 200, 255 }, { 160, 60, 255 } } + +local sync = K.load(DIR, W, H) +local art = {} +local video = {} +local world = {} +local lastT = 0 + +local SCROLL_TEXT = " MIRRORBALL ... A SINGE DEMO ... THIS GROOVE SPEEDS UP AS IT GOES, AND EVERY FLASH, EVERY CUT AND EVERY BOUNCE FOLLOWS IT, BEAT BY BEAT, BECAUSE THE BEATS WERE READ OUT OF THE MUSIC ... COPPER BARS, A ROTOZOOMER, A TWISTER DRAWN ONE SCANLINE AT A TIME, GLENZ GLASS AND A BOUNCING BALL: THE OLD TRICKS, ON A NEW ENGINE ... GREETINGS TO EVERYONE WHO EVER CARRIED A COMPUTER TO A PARTY ... " + + +-- Loading -------------------------------------------------------------------------------------------- + +local function loadArt() + for _, name in ipairs({ "logo", "singe", "twister", "copper", "bob", "glow", "sparkle" }) do + art[name] = spriteLoad(DIR .. "art/" .. name .. ".png") + end + spriteQuality(art.logo, RENDER_SMOOTH) + spriteQuality(art.singe, RENDER_SMOOTH) + art.font = fontLoad("Singe/FreeSansBold.ttf", 44) + video.plasma = videoLoad(DIR .. "video/plasma.mp4") + video.tunnel = videoLoad(DIR .. "video/tunnel.mp4") + video.tunnelFrames = videoGetFrameCount(video.tunnel) + videoSetVolume(video.plasma, 0, 0) + videoSetVolume(video.tunnel, 0, 0) +end + + +-- The world -------------------------------------------------------------------------------------------- + +local function buildFloor() + local tileImage = spriteLoad(DIR .. "art/tile.png") + local mesh = meshBox(TILE * 0.96, 0.2, TILE * 0.96) + + world.tiles = {} + for i = 1, TILES do + for j = 1, TILES do + local m = materialNew() + local n = nodeNew() + + materialSetColor(m, 40, 30, 50) + materialSetEmissiveMap(m, tileImage) + materialSetRoughness(m, 0.2) + materialSetMetallic(m, 0.3) + nodeSetMesh(n, mesh, m) + nodeSetPosition(n, (i - TILES / 2 - 0.5) * TILE, -0.1, (j - TILES / 2 - 0.5) * TILE) + world.tiles[#world.tiles + 1] = { node = n, material = m, i = i, j = j } + end + end + -- One static body under them all for whatever falls, and walls round the edge to keep it on. + world.floorBody = nodeNew() + nodeSetPosition(world.floorBody, 0, -0.2, 0) + bodyNew(world.floorBody, BODY_STATIC, SHAPE_BOX, TILES * TILE, 0.2, TILES * TILE) + local half = TILES * TILE / 2 + + for _, wall in ipairs({ { half, 0, 0.5, TILES * TILE }, { -half, 0, 0.5, TILES * TILE }, { 0, half, TILES * TILE, 0.5 }, { 0, -half, TILES * TILE, 0.5 } }) do + local n = nodeNew() + + nodeSetPosition(n, wall[1], 2, wall[2]) + bodyNew(n, BODY_STATIC, SHAPE_BOX, wall[3], 4, wall[4]) + end +end + + +-- The ball: facets in rings of latitude round a dark core, all one mesh and one material so they +-- draw in one call, on a pivot that turns. Each facet faces out from the centre. +local FACET_GROUPS = 4 + +local function buildBall() + local mesh = meshBox(FACET * 0.92, FACET * 0.92, 0.04) + + -- Facets in four groups, each its own material, so each group can catch the light in turn: a + -- real ball's facets flash as they come round to a lamp. Four materials still draw in four calls. + world.facetMaterials = {} + for g = 1, FACET_GROUPS do + world.facetMaterials[g] = K.chrome(200 + g * 10, 205 + g * 8, 225, 0.06 + g * 0.03) + end + world.ball = nodeNew() + world.facets = {} + local rings = math.floor(math.pi * BALL_R / FACET) + + for r = 1, rings - 1 do + local lat = -math.pi / 2 + r / rings * math.pi + local count = math.max(4, math.floor(2 * math.pi * BALL_R * math.cos(lat) / FACET)) + + for c = 0, count - 1 do + local lon = (c + (r % 2) * 0.5) / count * 2 * math.pi + local f = nodeNew(world.ball) + local x = math.cos(lat) * math.cos(lon) * BALL_R + local y = math.sin(lat) * BALL_R + local z = math.cos(lat) * math.sin(lon) * BALL_R + + nodeSetMesh(f, mesh, world.facetMaterials[math.random(1, FACET_GROUPS)]) + nodeSetPosition(f, x, y, z) + nodeLookAt(f, 0, 0, 0) + world.facets[#world.facets + 1] = { node = f, x = x, y = y, z = z } + end + end + local core = materialNew() + + materialSetColor(core, 10, 10, 14) + world.core = nodeNew(world.ball) + nodeSetMesh(world.core, meshSphere(BALL_R - 0.03, 24), core) + local rope = materialNew() + + materialSetColor(rope, 30, 30, 34) + world.rope = nodeNew() + nodeSetMesh(world.rope, meshCylinder(0.03, 12, 6), rope) + nodeSetPosition(world.ball, 0, BALL_Y, 0) + + -- The light the ball throws: sparkles on a great sphere round it, turning with it. + world.sparkleRing = nodeNew() + nodeSetPosition(world.sparkleRing, 0, BALL_Y, 0) + world.sparkles = {} + for i = 1, SPARKLES do + local phi = math.acos(1 - 2 * (i - 0.5) / SPARKLES) * 0.75 + local theta = math.pi * (1 + math.sqrt(5)) * i + local n = nodeNew(world.sparkleRing) + + nodeSetSprite(n, art.sparkle, 1.8, false) + nodeSetBillboard(n, BILLBOARD_ALL) + nodeSetPosition(n, math.cos(theta) * math.sin(phi + 0.6) * 16, -math.cos(phi + 0.6) * 9, math.sin(theta) * math.sin(phi + 0.6) * 16) + world.sparkles[i] = n + end +end + + +local function buildLights() + world.spots = {} + for i = 1, 4 do + local l = lightNew(LIGHT_SPOT) + local c = DISCO[i + 1] + + lightSetColor(l, c[1], c[2], c[3]) + lightSetIntensity(l, 0) + lightSetRange(l, 60) + lightSetCone(l, 10, 18) + world.spots[i] = l + end + world.ballSpot = lightNew(LIGHT_SPOT) + nodeSetPosition(world.ballSpot, 0, 14, 8) + nodeLookAt(world.ballSpot, 0, BALL_Y, 0) + lightSetColor(world.ballSpot, 255, 250, 240) + lightSetIntensity(world.ballSpot, 0) + lightSetCone(world.ballSpot, 5, 9) + world.sun = lightNew(LIGHT_DIRECTIONAL) + nodeSetPosition(world.sun, 4, 10, 6) + nodeLookAt(world.sun, 0, 0, 0) + lightSetIntensity(world.sun, 0) + lightSetShadow(world.sun, true) +end + + +-- Lasers: thin bright rods fanning out from a point high on the back wall. +local function buildLasers() + local m = materialNew() + + materialSetColor(m, 0, 0, 0) + materialSetEmissive(m, 60, 255, 90) + world.laserMaterial = m + world.laserFan = nodeNew() + nodeSetPosition(world.laserFan, 0, 9, -16) + world.lasers = {} + for i = 1, LASERS do + local arm = nodeNew(world.laserFan) + local rod = nodeNew(arm) + + nodeSetMesh(rod, meshBox(0.1, 0.1, 40), m) + nodeSetPosition(rod, 0, 0, 20) + world.lasers[i] = arm + end +end + + +-- Glenz vectors: a glass octahedron inside a glass cube, both faceted, turning against each other. +local function octahedron(r) + local v = { { r, 0, 0 }, { -r, 0, 0 }, { 0, r, 0 }, { 0, -r, 0 }, { 0, 0, r }, { 0, 0, -r } } + local faces = { { 1, 3, 5 }, { 5, 3, 2 }, { 2, 3, 6 }, { 6, 3, 1 }, { 5, 4, 1 }, { 2, 4, 5 }, { 6, 4, 2 }, { 1, 4, 6 } } + local positions = {} + local normals = {} + local indices = {} + + for _, f in ipairs(faces) do + local a = v[f[1]] + local b = v[f[2]] + local c = v[f[3]] + local nx = (a[1] + b[1] + c[1]) / 3 + local ny = (a[2] + b[2] + c[2]) / 3 + local nz = (a[3] + b[3] + c[3]) / 3 + local l = math.sqrt(nx * nx + ny * ny + nz * nz) + + for _, p in ipairs({ a, b, c }) do + positions[#positions + 1] = p[1] + positions[#positions + 1] = p[2] + positions[#positions + 1] = p[3] + normals[#normals + 1] = nx / l + normals[#normals + 1] = ny / l + normals[#normals + 1] = nz / l + indices[#indices + 1] = #positions / 3 + end + end + return meshNew(positions, normals, nil, indices) +end + + +local function buildGlenz() + world.glenz = nodeNew() + world.glenzOuter = nodeNew(world.glenz) + world.glenzInner = nodeNew(world.glenz) + local outer = K.glass(255, 60, 200, 110) + local inner = K.glass(60, 220, 255, 150) + + materialSetDoubleSided(outer, true) + materialSetEmissive(outer, 70, 12, 60) + materialSetEmissive(inner, 12, 60, 75) + nodeSetMesh(world.glenzOuter, meshBox(2.4, 2.4, 2.4), outer) + nodeSetMesh(world.glenzInner, octahedron(1.25), inner) +end + + +-- The boing ball, and the balls that rain on the snares. +local function buildBoing() + local skin = materialNew() + + materialSetTexture(skin, spriteLoad(DIR .. "art/boing.png")) + materialSetRoughness(skin, 0.35) + world.boing = nodeNew() + nodeSetMesh(world.boing, meshSphere(1.6, 32), skin) + world.rainMesh = meshSphere(0.32, 16) + world.rainMaterials = {} + for i, c in ipairs(DISCO) do + local m = materialNew() + + materialSetColor(m, c[1], c[2], c[3]) + materialSetMetallic(m, 0.4) + materialSetRoughness(m, 0.2) + world.rainMaterials[i] = m + end + world.rain = {} +end + + +-- Screens for the 2D-in-3D effects: the rotozoomer, the tunnel, and a kaleidoscope of four mirrored +-- copies of the plasma. +local function buildScreens() + local roto = materialNew() + + materialSetTexture(roto, spriteLoad(DIR .. "art/roto.png")) + materialSetUnlit(roto, true) + materialSetDoubleSided(roto, true) + materialSetFilter(roto, FILTER_NEAREST) + world.rotoMaterial = roto + world.roto = K.screenQuad(world.camera, FOV, roto, 2, 2.2) + local tunnel = materialNew() + + materialSetVideo(tunnel, video.tunnel) + materialSetUnlit(tunnel, true) + materialSetDoubleSided(tunnel, true) + world.tunnel = K.screenQuad(world.camera, FOV, tunnel, 60, 1.8) + world.kaleido = nodeNew(world.camera) + nodeSetPosition(world.kaleido, 0, 0, -2) + local h = 2 * 2 * math.tan(math.rad(FOV / 2)) + local w = h * W / H + + for _, q in ipairs({ { -1, 1, 1, 1 }, { 1, 1, -1, 1 }, { -1, -1, 1, -1 }, { 1, -1, -1, -1 } }) do + local m = materialNew() + local n = nodeNew(world.kaleido) + + materialSetVideo(m, video.plasma) + materialSetUnlit(m, true) + materialSetDoubleSided(m, true) + materialSetTiling(m, q[3], q[4]) + nodeSetMesh(n, meshPlane(w / 2, h / 2), m) + nodeSetPosition(n, q[1] * w / 4, q[2] * h / 4, 0) + nodeSetRotation(n, 90, 0, 0) + end +end + + +local function buildWorld() + sceneEnable(true) + sceneSetSky(DIR .. "art/club.png") + sceneSetSkyIntensity(1.0) + sceneSetAmbient(20, 16, 30) + sceneSetBloom(0.7, 0.55) + world.camera = nodeNew() + cameraSet(world.camera) + cameraSetPerspective(FOV, 0.1, 400) + buildFloor() + buildBall() + buildLights() + buildLasers() + buildGlenz() + buildBoing() + buildScreens() +end + + +-- What is shown -------------------------------------------------------------------------------------- + +local function setVisible(list, on) + for _, n in ipairs(list) do + nodeSetVisible(n, on) + end +end + + +local function hideAll() + for _, tile in ipairs(world.tiles) do + nodeSetVisible(tile.node, false) + end + setVisible({ world.ball, world.rope, world.sparkleRing, world.laserFan, world.glenz, world.boing, world.roto, world.tunnel, world.kaleido }, false) + for _, l in ipairs(world.spots) do + lightSetIntensity(l, 0) + end + lightSetIntensity(world.ballSpot, 0) + lightSetIntensity(world.sun, 0) + sceneSetFog() + sceneSetSkyIntensity(1.0) +end + + +local function showClub(withBall) + for _, tile in ipairs(world.tiles) do + nodeSetVisible(tile.node, true) + end + setVisible({ world.ball, world.rope, world.sparkleRing }, withBall ~= false) +end + + +-- The club in motion ---------------------------------------------------------------------------------- + +-- The ball turns, hangs at height y, and its sparkles turn with it, twinkling on the hats. +local function ballSpin(t, y, speed, sparkle) + local spin = t * (speed or 30) + + nodeSetPosition(world.ball, 0, y, 0) + nodeSetRotation(world.ball, 0, spin, 0) + nodeSetPosition(world.rope, 0, y + 6, 0) + nodeSetPosition(world.sparkleRing, 0, y, 0) + nodeSetRotation(world.sparkleRing, 0, spin, 0) + local s = (sparkle or 1) * (0.6 + 0.6 * K.env("hat", t)) + + for g, m in ipairs(world.facetMaterials) do + local v = (sparkle or 1) * (40 + 215 * math.max(0, math.sin(t * 9 + g * 1.7)) ^ 6 + 60 * K.decay("kicks", t, 8)) + + materialSetEmissive(m, math.floor(math.min(255, v)), math.floor(math.min(255, v)), math.floor(math.min(255, v * 1.05))) + end + nodeSetScale(world.sparkleRing, 1) + for i, n in ipairs(world.sparkles) do + nodeSetScale(n, s * (0.5 + 0.5 * math.sin(t * 7 + i * 2.3))) + end + lightSetIntensity(world.ballSpot, 60 * (sparkle or 1)) +end + + +-- The spotlights sweep the room on circles of their own, flaring on the kicks. +local function spots(t, level) + local flare = 1 + 1.5 * K.decay("kicks", t, 6) + + for i, l in ipairs(world.spots) do + local a = t * 0.7 + i * math.pi / 2 + + nodeSetPosition(l, math.cos(i * 1.57) * 10, 11, math.sin(i * 1.57) * 10) + nodeLookAt(l, math.cos(a) * 6, 0, math.sin(a) * 6) + lightSetIntensity(l, 120 * level * flare) + end +end + + +-- The floor's patterns, one per phrase: a checker that swaps on every beat, ripples from the middle +-- on the kicks, diagonal waves, and a scatter that changes every beat. level dims it all. +local function floor(t, pattern, level) + local b = K.beat(t) + local whole = math.floor(b) + local ripple = K.hitAge("kicks", t) * 14 + local colour = DISCO[whole % #DISCO + 1] + + for _, tile in ipairs(world.tiles) do + local i = tile.i + local j = tile.j + local v = 0 + + if pattern == 0 then + v = ((i + j + whole) % 2 == 0) and 1 or 0.08 + elseif pattern == 1 then + local d = math.sqrt((i - TILES / 2 - 0.5) ^ 2 + (j - TILES / 2 - 0.5) ^ 2) * TILE + v = math.max(0.06, math.exp(-math.abs(d - ripple) * 0.9)) + elseif pattern == 2 then + v = 0.5 + 0.5 * math.sin((i + j) * 0.8 - t * 6) + else + v = (((i * 7 + j * 13 + whole * 31) % 17) < 6) and 1 or 0.05 + end + local c = colour + + if pattern == 2 or pattern == 1 then + c = DISCO[(i + j + whole) % #DISCO + 1] + end + v = v * level + materialSetEmissive(tile.material, math.floor(c[1] * v), math.floor(c[2] * v), math.floor(c[3] * v)) + end +end + + +local function lasers(t, level) + for i, arm in ipairs(world.lasers) do + local spread = (i - (LASERS + 1) / 2) / LASERS + local sweep = math.sin(t * 1.3) * 25 + spread * (60 + 30 * math.sin(t * 0.7)) + + nodeSetRotation(arm, 0, sweep, -10 + 12 * math.sin(t * 0.9 + i)) + end + local v = math.floor(255 * level * (0.6 + 0.4 * K.decay("snares", t, 8))) + + materialSetEmissive(world.laserMaterial, v // 4, v, v // 3) +end + + +local function orbit(t, radius, height, speed, lookY, phase) + local a = t * speed + (phase or 0) + + nodeSetPosition(world.camera, math.cos(a) * radius, height, math.sin(a) * radius) + nodeLookAt(world.camera, 0, lookY, 0) +end + + +-- 2D effects -------------------------------------------------------------------------------------------- + +-- Copper bars: count bars swinging up and down, coloured by hue, each a gradient strip stretched. +local function copperBars(t, count, y0, amp, hueShift, alpha) + for i = 1, count do + local y = y0 + math.sin(t * 2.1 + i * 0.55) * amp + local r, g, b = K.hue(i / count * 0.6 + hueShift) + + spriteSetTint(art.copper, r, g, b) + spriteSetAlpha(art.copper, alpha or 255) + spriteDraw(art.copper, 0, math.floor(y), W - 1, math.floor(y) + 23) + end + spriteSetTint(art.copper, 255, 255, 255) + spriteSetAlpha(art.copper, 255) +end + + +-- The twister: a square bar turning about the vertical, its turn varying down the screen. Each +-- scanline shows the faces whose edges come round in order there, each face one row of its texture +-- stretched between its two edges and shaded by how squarely it faces the viewer. +local function twister(t, cx) + local faceW = 64 + + for y = 0, H - 1, TWIST_ROW do + local a = t * 1.6 + math.sin(y * 0.011 + t * 1.2) * 2.2 + math.sin(t * 0.5) * y * 0.004 + local row = math.floor(y + t * 60) % 64 + local x = {} + local wobble = math.sin(y * 0.02 + t * 2) * 30 + + for e = 0, 4 do + x[e] = cx + wobble + math.sin(a + e * math.pi / 2) * TWIST_R + end + for e = 0, 3 do + if x[e + 1] > x[e] + 0.5 then + local shade = math.floor(80 + 175 * math.sin(math.min(math.pi, (x[e + 1] - x[e]) / (2 * TWIST_R) * math.pi * 0.72))) + + spriteSetTint(art.twister, shade, shade, shade) + spriteDrawGrid(art.twister, math.floor(x[e]), y, e * faceW, row, faceW, 1, math.floor(x[e + 1]), y + TWIST_ROW - 1) + end + end + end + spriteSetTint(art.twister, 255, 255, 255) +end + + +-- The title, a letter at a time: each falls from above, lands on its beat, and bounces lower each +-- beat after. +local TITLE = "MIRRORBALL" + +local function titleDrop(t, firstBeat, beatsApart, y) + local b = K.beat(t) + local widths = {} + local total = 0 + + for i = 1, #TITLE do + widths[i] = K.textWidth(TITLE:sub(i, i), 72) + 4 + total = total + widths[i] + end + local x = W / 2 - total / 2 + + for i = 1, #TITLE do + local land = firstBeat + (i - 1) * beatsApart + local since = b - land + + if since > -1 then + local lift = 0 + + if since < 0 then + lift = (since * since) * 300 + else + local bounce = since % 1 + local height = 60 * math.exp(-math.floor(since) * 0.8) + + lift = 4 * height * bounce * (1 - bounce) + end + local r, g, bb = K.hue(i / #TITLE + t * 0.05) + + K.text(x + widths[i] / 2, y - lift, TITLE:sub(i, i), 72, r, g, bb, "center") + end + x = x + widths[i] + end +end + + +-- The shatter ------------------------------------------------------------------------------------------- + +-- Every facet leaves the ball: put where it is in the world, given a body, and thrown outward and +-- up with a spin. +local function shatter(t) + local spin = math.rad(t * world.lastSpin) + local c = math.cos(spin) + local s = math.sin(spin) + local by = world.lastBallY + + nodeSetVisible(world.core, false) + nodeSetVisible(world.rope, false) + for _, f in ipairs(world.facets) do + -- The ball turned about y by spin; the facet's place in the room follows. + local x = f.x * c + f.z * s + local z = -f.x * s + f.z * c + + nodeSetParent(f.node, 0) + nodeSetPosition(f.node, x, by + f.y, z) + nodeLookAt(f.node, 0, by, 0) + bodyNew(f.node, BODY_DYNAMIC, SHAPE_BOX, FACET, FACET, 0.04) + bodySetMass(f.node, 0.05) + bodySetBounce(f.node, 0.35) + local out = 3 + math.random() * 5 + + bodySetVelocity(f.node, x / BALL_R * out, (f.y / BALL_R) * out + 3, z / BALL_R * out) + bodySetAngularVelocity(f.node, (math.random() - 0.5) * 20, (math.random() - 0.5) * 20, (math.random() - 0.5) * 20) + end + world.shattered = true +end + + +-- The scenes ------------------------------------------------------------------------------------------- + +local SCENES = { + -- Bars 1 to 8: the choppy intro. Copper bars light only while the band plays, so the gaps in + -- the groove are black; the title drops in a letter every two beats. + { + from = 0, to = 9, + enter = function(t) + hideAll() + end, + draw = function(t, bar, k) + K.flash(0, 0, 0, 255) + local gate = K.clamp((K.env("level", t) - 0.15) * 2.5, 0, 1) + + copperBars(t, 10, 210, 170, t * 0.05, math.floor(255 * gate)) + titleDrop(t, K.beat(K.barTime(2)), 2, 230) + if bar >= 7 then + local w = spriteGetWidth(art.singe) * 0.5 + + spriteSetAlpha(art.singe, math.floor(255 * K.smooth(7, 7.5, bar))) + spriteDraw(art.singe, math.floor(W / 2 - w / 2), 330, math.floor(W / 2 + w / 2), 330 + spriteGetHeight(art.singe) // 2) + spriteSetAlpha(art.singe, 255) + K.text(W / 2, 312, "PRESENTED WITH", 18, 200, 180, 140, "center") + end + K.strobe(t, "kicks", 16, 255, 220, 160, 40) + if bar > 8.75 then + K.flash(255, 255, 255, math.floor(255 * K.smooth(8.75, 9, bar))) + end + end, + }, + -- Bars 9 to 16: the club. The ball comes down over the floor, the spots sweep, the floor + -- checker swaps on every beat, and the title settles at the bottom. + { + from = 9, to = 17, + enter = function(t) + hideAll() + showClub(true) + end, + draw = function(t, bar, k) + local drop = K.easeOut((bar - 9) / 2) + + ballSpin(t, K.lerp(16, BALL_Y, drop), 30, drop) + orbit(t, 13 - 3 * k, 2.5 + 2 * k, 0.12, 3.5 + 1.5 * drop) + spots(t, drop) + floor(t, 0, 0.3 + 0.7 * drop) + if bar >= 13 then + local a = math.floor(255 * K.smooth(13, 13.5, bar)) + local w = spriteGetWidth(art.logo) * 0.85 + local h = spriteGetHeight(art.logo) * 0.85 + + spriteSetAlpha(art.logo, a) + spriteDraw(art.logo, math.floor(W / 2 - w / 2), math.floor(H - 20 - h), math.floor(W / 2 + w / 2), H - 20) + spriteSetAlpha(art.logo, 255) + end + K.flash(255, 255, 255, math.floor(255 * (1 - K.smooth(9, 9.25, bar)))) + end, + }, + -- Bars 17 to 24: the lead comes in, and the rotozoomer with it: the floor's own disco tile, on a + -- screen that turns and zooms, under copper bars coloured by the note being played and the + -- scroller. + { + from = 17, to = 25, + enter = function(t) + hideAll() + nodeSetVisible(world.roto, true) + end, + draw = function(t, bar, k) + nodeSetPosition(world.camera, 0, 0, 0) + nodeLookAt(world.camera, 0, 0, -1) + local zoom = 4 + 3 * math.sin(t * 0.6) + 2 * K.decay("kicks", t, 7) + + materialSetTiling(world.rotoMaterial, zoom * W / H, zoom) + nodeSetRotation(world.roto, 0, 0, t * 30 + math.sin(t * 0.8) * 40) + local note, clear = K.note(t) + + copperBars(t, 6, 40, 30, note / 12, math.floor(120 + 135 * clear)) + K.scroller(t, art.font, SCROLL_TEXT, H - 80, 22, 180, K.barTime(17)) + K.flash(255, 255, 255, math.floor(255 * (1 - K.smooth(17, 17.2, bar)))) + end, + }, + -- Bars 25 to 32: a kaleidoscope of the plasma, four mirrored copies, under vector bobs that take + -- a new shape every two bars. + { + from = 25, to = 33, + enter = function(t) + hideAll() + nodeSetVisible(world.kaleido, true) + videoPlay(video.plasma) + end, + draw = function(t, bar, k) + nodeSetPosition(world.camera, 0, 0, 0) + nodeLookAt(world.camera, 0, 0, -1) + nodeSetRotation(world.kaleido, 0, 0, math.sin(t * 0.4) * 20) + nodeSetScale(world.kaleido, 1.15 + 0.1 * K.decay("kicks", t, 6)) + K.bobs(t, bar, art.bob, 56, 1.4, 21, W / 2, H / 2) + K.flash(255, 255, 255, math.floor(255 * (1 - K.smooth(25, 25.2, bar)))) + end, + }, + -- Bars 33 to 40: the chop comes back, and the picture cuts on every beat between the club's + -- corners; the gaps in the groove go black. + { + from = 33, to = 41, + enter = function(t) + hideAll() + showClub(true) + nodeSetVisible(world.laserFan, true) + end, + draw = function(t, bar, k) + local beat = math.floor(K.beat(t)) + local shots = { + { 0, 1.5, 10, 0, 5, 0 }, { 9, 9, 9, 0, 3, 0 }, { 0, 13, 0.1, 0, 0, 0 }, { -3, 6.5, 3, 0, 6.2, 0 }, + { 12, 1, -4, 0, 4, 0 }, { 0, 4, -11, 0, 5, 0 }, { -9, 2, 6, 0, 6, 0 }, { 3, 5.5, 2.5, 0, 6.2, 0 }, + } + local s = shots[beat % #shots + 1] + + nodeSetPosition(world.camera, s[1], s[2], s[3]) + nodeLookAt(world.camera, s[4], s[5], s[6]) + ballSpin(t, BALL_Y, 40, 1) + spots(t, 1) + lasers(t, 0.8) + floor(t, 3, 1) + local gate = K.clamp((K.env("level", t) - 0.12) * 3, 0, 1) + + K.flash(0, 0, 0, math.floor(255 * (1 - gate))) + K.flash(255, 255, 255, math.floor(160 * math.exp(-(K.beat(t) % 1) * 14))) + end, + }, + -- Bars 41 to 48: the twister over copper bars, drawn one scanline at a time. + { + from = 41, to = 49, + enter = function(t) + hideAll() + end, + draw = function(t, bar, k) + K.flash(14, 4, 22, 255) + copperBars(t, 14, 220, 200, t * 0.03, 200) + twister(t, W / 2 + math.sin(t * 0.7) * 120) + K.scroller(t, art.font, SCROLL_TEXT, 30, 14, 200, K.barTime(41) - 40) + K.strobe(t, "kicks", 14, 255, 255, 255, 50) + K.flash(255, 255, 255, math.floor(255 * (1 - K.smooth(41, 41.2, bar)))) + end, + }, + -- Bars 49 to 56: the boing ball, bouncing on every beat and crossing the room every bar, while + -- a ball drops from the ceiling on every snare and piles up on the floor. + { + from = 49, to = 57, + enter = function(t) + hideAll() + showClub(false) + nodeSetVisible(world.boing, true) + lightSetIntensity(world.sun, 3) + end, + draw = function(t, bar, k) + local b = K.beat(t) + local hop = b % 1 + local across = math.sin((bar - 49) * math.pi) + + nodeSetPosition(world.boing, across * 8, 1.6 + 4 * 4 * hop * (1 - hop) * 1.4, 2) + nodeSetRotation(world.boing, 20, t * 120, 0) + orbit(t, 12, 4, 0.08, 2.5, 1.2) + floor(t, 1, 0.8) + spots(t, 0.6) + if K.hitCount("snares", lastT, t) > 0 and #world.rain < RAIN_MAX then + local n = nodeNew() + + nodeSetMesh(n, world.rainMesh, world.rainMaterials[#world.rain % #world.rainMaterials + 1]) + nodeSetPosition(n, (math.random() - 0.5) * 16, 14, (math.random() - 0.5) * 10 - 2) + bodyNew(n, BODY_DYNAMIC, SHAPE_SPHERE, 0.32) + bodySetMass(n, 0.5) + bodySetBounce(n, 0.7) + world.rain[#world.rain + 1] = n + end + K.flash(255, 255, 255, math.floor(255 * (1 - K.smooth(49, 49.2, bar)))) + end, + leave = function(t) + for _, n in ipairs(world.rain) do + bodyDelete(n) + nodeDelete(n) + end + world.rain = {} + end, + }, + -- Bars 57 to 64: glenz glass in the tunnel, the tunnel scrubbed by the kick. + { + from = 57, to = 65, + enter = function(t) + hideAll() + nodeSetVisible(world.tunnel, true) + nodeSetVisible(world.glenz, true) + world.tunnelPhase = 0 + world.tunnelLast = t + sceneSetSkyIntensity(1.5) + lightSetIntensity(world.sun, 5) + end, + draw = function(t, bar, k) + nodeSetPosition(world.camera, 0, 0, 0) + nodeLookAt(world.camera, 0, 0, -1) + world.tunnelPhase = (world.tunnelPhase + (t - world.tunnelLast) * (0.5 + 1.5 * K.decay("kicks", t, 5))) % 1 + world.tunnelLast = t + videoSeek(video.tunnel, math.floor(world.tunnelPhase * video.tunnelFrames)) + nodeSetRotation(world.tunnel, 0, 0, -t * 20) + local pump = 1 + 0.2 * K.decay("kicks", t, 8) + + nodeSetPosition(world.glenz, 0, 0, -6) + nodeSetScale(world.glenz, pump) + nodeSetRotation(world.glenzOuter, t * 37, t * 53, t * 19) + nodeSetRotation(world.glenzInner, -t * 61, t * 29, -t * 43) + K.flash(255, 255, 255, math.floor(255 * (1 - K.smooth(57, 57.2, bar)))) + end, + }, + -- Bars 65 to 72: the laser show, in a haze, the camera moving through the beams. + { + from = 65, to = 73, + enter = function(t) + hideAll() + showClub(true) + nodeSetVisible(world.laserFan, true) + sceneSetFog(16, 8, 30, 6, 70) + end, + draw = function(t, bar, k) + orbit(t, 12, 2 + math.sin(t * 0.4) * 1.5, -0.15, 5) + ballSpin(t, BALL_Y, 45, 1) + spots(t, 0.8) + lasers(t, 1) + floor(t, 2, 0.7) + K.strobe(t, "snares", 20, 255, 255, 255, 60) + end, + }, + -- Bars 73 to 80: the plasma flat on the screen, the Singe logo rotozoomed over it, a ring of bobs. + { + from = 73, to = 81, + enter = function(t) + hideAll() + videoPlay(video.plasma) + end, + draw = function(t, bar, k) + videoDraw(video.plasma, 0, 0, W - 1, H - 1) + local punch = 1 + 0.3 * K.decay("kicks", t, 8) + + for i = 1, 12 do + local a = i / 12 * 2 * math.pi + t + local r = 190 * punch + local cr, cg, cb = K.hue(i / 12 + t * 0.1) + + spriteSetTint(art.bob, cr, cg, cb) + spriteDraw(art.bob, math.floor(W / 2 + math.cos(a) * r - 18), math.floor(H / 2 + math.sin(a) * r * 0.8 - 18), math.floor(W / 2 + math.cos(a) * r + 18), math.floor(H / 2 + math.sin(a) * r * 0.8 + 18)) + end + spriteSetTint(art.bob, 255, 255, 255) + spriteRotateAndScale(art.singe, math.sin(t * 0.9) * 35, (1 + 0.4 * math.sin(t * 1.1)) * punch) + spriteDraw(art.singe, W // 2, H // 2, true) + K.flash(255, 255, 255, math.floor(255 * (1 - K.smooth(73, 73.2, bar)))) + end, + leave = function(t) + spriteRotateAndScale(art.singe, 0, 1) + end, + }, + -- Bars 81 to 88: the breakdown. The kick is gone; the club is dark but for the ball and its + -- sparkles, turning slowly. When the bass returns at bar 85 the floor comes back a tile a beat. + { + from = 81, to = 89, + enter = function(t) + hideAll() + showClub(true) + end, + draw = function(t, bar, k) + orbit(t, 9, 3 + k * 2, 0.06, BALL_Y) + ballSpin(t, BALL_Y, 12, 0.8 + 0.4 * k) + sceneSetSkyIntensity(0.4 + 0.6 * k) + local lit = (bar >= 85) and math.floor(K.beat(t) - K.beat(K.barTime(85))) * 9 or 0 + + for n, tile in ipairs(world.tiles) do + local on = ((n * 37) % #world.tiles) < lit + local c = DISCO[n % #DISCO + 1] + local v = on and 0.8 or 0 + + materialSetEmissive(tile.material, math.floor(c[1] * v), math.floor(c[2] * v), math.floor(c[3] * v)) + end + end, + }, + -- Bars 89 to 96: the build. Everything comes back on, the camera climbs, and the beat strobes. + { + from = 89, to = 97, + enter = function(t) + hideAll() + showClub(true) + nodeSetVisible(world.laserFan, true) + end, + draw = function(t, bar, k) + orbit(t, 14 - 4 * k, 2 + 7 * k, 0.2, BALL_Y - 2 * k) + ballSpin(t, BALL_Y, 30 + 30 * k, 1) + spots(t, k) + lasers(t, k) + floor(t, math.floor((bar - 89) / 2) % 4, 0.4 + 0.6 * k) + K.flash(255, 255, 255, math.floor(110 * k * math.exp(-(K.beat(t) % 1) * 10))) + copperBars(t, 4, 10, 8, t * 0.1, math.floor(200 * k)) + copperBars(t, 4, H - 40, 8, t * 0.1 + 0.5, math.floor(200 * k)) + end, + }, + -- Bars 97 to 112: the party, then everything at once. The floor changes pattern every phrase, + -- the bobs and the scroller come up over the club, and in the last phrase the camera spins. + { + from = 97, to = 113, + enter = function(t) + hideAll() + showClub(true) + nodeSetVisible(world.laserFan, true) + end, + draw = function(t, bar, k) + local final = bar >= 105 + + if final then + orbit(t, 9 + 3 * math.sin(t * 0.5), 2 + 2 * math.sin(t * 0.3), 0.45, BALL_Y - 1) + else + orbit(t, 13, 3.5, 0.18, BALL_Y - 1.5) + end + ballSpin(t, BALL_Y, final and 70 or 40, 1) + spots(t, 1) + lasers(t, 1) + floor(t, math.floor((bar - 97) / 2) % 4, 1) + sceneSetBloom(0.7, 0.55 + (final and 0.4 or 0.2) * K.decay("kicks", t, 7)) + K.bobs(t, bar, art.bob, 36, 0.9, 13, W / 2, 150) + K.scroller(t, art.font, " GREETINGS TO EVERYONE ON THE DANCE FLOOR ... KEEP IT FUNKY ... MIRRORBALL ... A SINGE DEMO ... ", H - 70, 16, 190, K.barTime(97)) + K.strobe(t, "kicks", 18, 255, 255, 255, final and 50 or 25) + if bar > 112.5 then + K.flash(255, 255, 255, math.floor(200 * K.smooth(112.5, 113, bar))) + end + end, + }, + -- Bar 113 on: the last downbeat. The ball shatters, its facets rain onto the floor, the lights + -- go down, and the credits come up. + { + from = 113, to = 200, + enter = function(t) + hideAll() + showClub(true) + world.lastSpin = 70 + world.lastBallY = BALL_Y + shatter(t) + world.endCamera = t + end, + draw = function(t, bar, k) + local p = t - K.barTime(113) + + orbit(world.endCamera + p * 0.3, 13 + p * 0.5, 3 + p * 0.25, 0.2, 2) + lightSetIntensity(world.ballSpot, 0) + sceneSetSkyIntensity(math.max(0.25, 1 - p * 0.12)) + floor(t, 1, math.max(0, 1 - p * 0.15)) + for i, l in ipairs(world.spots) do + lightSetIntensity(l, math.max(0, 120 - p * 25)) + end + K.flash(255, 255, 255, math.floor(255 * math.exp(-p * 3))) + local lines = { + { "MIRRORBALL", 56, 255, 200, 90 }, + { "music \"Vintage Funky Groove\" by miiira", 26, 255, 255, 255 }, + { "code and art Claude", 26, 255, 255, 255 }, + { "engine Singe", 26, 255, 255, 255 }, + } + local y = 90 + + for i, line in ipairs(lines) do + local a = K.smooth(1.5 + i * 0.4, 2.1 + i * 0.4, p) * (1 - K.smooth(K.duration - K.barTime(113) - 1, K.duration - K.barTime(113) + 1, p)) + + if a > 0 then + K.text(W / 2, y, line[1], line[2], math.floor(line[3] * a), math.floor(line[4] * a), math.floor(line[5] * a), "center") + end + y = y + line[2] + 22 + end + end, + }, + -- The time at the end of each frame, for "what happened since last frame". + { + from = -10, to = 1000, + draw = function(t, bar, k) + lastT = t + end, + }, +} + +loadArt() +buildWorld() +hideAll() +K.run(SCENES) diff --git a/demos/mirrorball/music.mp3 b/demos/mirrorball/music.mp3 new file mode 100644 index 000000000..97e06bd30 --- /dev/null +++ b/demos/mirrorball/music.mp3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc6c875acb922ece44175a185e0744f9fab257df21bf400b1df7338f3b7364dd +size 7837440 diff --git a/demos/mirrorball/sync.lua b/demos/mirrorball/sync.lua new file mode 100644 index 000000000..136ce5a40 --- /dev/null +++ b/demos/mirrorball/sync.lua @@ -0,0 +1,301 @@ +-- Written by util/demoSync.py from music.mp3: what the demo synchronises to. Times are seconds of +-- music; envelopes are 60 samples a second, one character each, 0 to 63 in the base64 alphabet. +return { + duration = 244.920, + rate = 60, + barStart = 2, -- The beat (counting from 1) that begins the first whole bar + beats = { + 0.2474, 0.7858, 1.3246, 1.8631, 2.4016, 2.9400, 3.4781, 4.0161, 4.5540, 5.0929, 5.6307, 6.1688, + 6.7060, 7.2438, 7.7812, 8.3191, 8.8565, 9.3945, 9.9318, 10.4693, 11.0064, 11.5439, 12.0812, 12.6189, + 13.1563, 13.6940, 14.2316, 14.7693, 15.3062, 15.8439, 16.3808, 16.9181, 17.4553, 17.9931, 18.5300, 19.0673, + 19.6045, 20.1419, 20.6787, 21.2159, 21.7527, 22.2894, 22.8264, 23.3629, 23.8991, 24.4363, 24.9727, 25.5095, + 26.0460, 26.5828, 27.1189, 27.6551, 28.1912, 28.7277, 29.2636, 29.7997, 30.3355, 30.8714, 31.4081, 31.9440, + 32.4794, 33.0155, 33.5508, 34.0864, 34.6218, 35.1579, 35.6932, 36.2286, 36.7642, 37.3000, 37.8352, 38.3706, + 38.9061, 39.4423, 39.9779, 40.5127, 41.0474, 41.5837, 42.1188, 42.6542, 43.1895, 43.7252, 44.2601, 44.7950, + 45.3298, 45.8652, 46.3998, 46.9345, 47.4691, 48.0038, 48.5381, 49.0726, 49.6070, 50.1416, 50.6750, 51.2092, + 51.7434, 52.2777, 52.8111, 53.3446, 53.8785, 54.4124, 54.9454, 55.4790, 56.0128, 56.5467, 57.0808, 57.6147, + 58.1484, 58.6819, 59.2155, 59.7490, 60.2824, 60.8158, 61.3490, 61.8824, 62.4158, 62.9491, 63.4823, 64.0157, + 64.5489, 65.0818, 65.6150, 66.1477, 66.6802, 67.2129, 67.7454, 68.2784, 68.8113, 69.3442, 69.8767, 70.4090, + 70.9421, 71.4748, 72.0070, 72.5391, 73.0717, 73.6040, 74.1362, 74.6680, 75.2004, 75.7329, 76.2651, 76.7976, + 77.3298, 77.8623, 78.3942, 78.9262, 79.4587, 79.9907, 80.5224, 81.0549, 81.5881, 82.1206, 82.6530, 83.1851, + 83.7175, 84.2495, 84.7807, 85.3120, 85.8437, 86.3750, 86.9060, 87.4371, 87.9686, 88.4998, 89.0304, 89.5619, + 90.0927, 90.6227, 91.1527, 91.6833, 92.2141, 92.7446, 93.2749, 93.8054, 94.3362, 94.8667, 95.3970, 95.9273, + 96.4579, 96.9877, 97.5175, 98.0476, 98.5778, 99.1079, 99.6377, 100.1673, 100.6964, 101.2253, 101.7541, 102.2824, + 102.8110, 103.3392, 103.8673, 104.3950, 104.9228, 105.4504, 105.9783, 106.5062, 107.0334, 107.5603, 108.0868, 108.6132, + 109.1396, 109.6655, 110.1910, 110.7163, 111.2417, 111.7670, 112.2917, 112.8162, 113.3409, 113.8650, 114.3887, 114.9120, + 115.4353, 115.9586, 116.4815, 117.0045, 117.5278, 118.0508, 118.5741, 119.0972, 119.6207, 120.1443, 120.6671, 121.1902, + 121.7132, 122.2362, 122.7589, 123.2821, 123.8059, 124.3285, 124.8513, 125.3738, 125.8960, 126.4181, 126.9399, 127.4613, + 127.9831, 128.5044, 129.0253, 129.5463, 130.0673, 130.5883, 131.1086, 131.6290, 132.1492, 132.6687, 133.1886, 133.7082, + 134.2279, 134.7480, 135.2673, 135.7871, 136.3071, 136.8270, 137.3464, 137.8656, 138.3851, 138.9048, 139.4242, 139.9441, + 140.4642, 140.9839, 141.5033, 142.0228, 142.5422, 143.0616, 143.5806, 144.1001, 144.6199, 145.1391, 145.6583, 146.1776, + 146.6972, 147.2164, 147.7356, 148.2548, 148.7740, 149.2930, 149.8124, 150.3318, 150.8513, 151.3714, 151.8911, 152.4107, + 152.9302, 153.4498, 153.9696, 154.4888, 155.0084, 155.5283, 156.0483, 156.5681, 157.0885, 157.6082, 158.1282, 158.6476, + 159.1675, 159.6869, 160.2061, 160.7253, 161.2447, 161.7640, 162.2832, 162.8021, 163.3220, 163.8415, 164.3607, 164.8796, + 165.3986, 165.9170, 166.4374, 166.9563, 167.4758, 167.9945, 168.5146, 169.0341, 169.5533, 170.0722, 170.5917, 171.1109, + 171.6301, 172.1481, 172.6667, 173.1853, 173.7039, 174.2224, 174.7407, 175.2574, 175.7749, 176.2920, 176.8095, 177.3257, + 177.8421, 178.3593, 178.8765, 179.3928, 179.9091, 180.4255, 180.9425, 181.4590, 181.9762, 182.4933, 183.0103, 183.5268, + 184.0436, 184.5604, 185.0767, 185.5928, 186.1091, 186.6254, 187.1411, 187.6565, 188.1723, 188.6879, 189.2030, 189.7180, + 190.2332, 190.7473, 191.2612, 191.7750, 192.2892, 192.8028, 193.3165, 193.8304, 194.3445, 194.8584, 195.3720, 195.8856, + 196.3995, 196.9127, 197.4260, 197.9394, 198.4533, 198.9663, 199.4794, 199.9924, 200.5057, 201.0184, 201.5313, 202.0438, + 202.5567, 203.0694, 203.5818, 204.0942, 204.6069, 205.1191, 205.6313, 206.1435, 206.6561, 207.1678, 207.6800, 208.1922, + 208.7045, 209.2164, 209.7284, 210.2405, 210.7530, 211.2652, 211.7773, 212.2893, 212.8017, 213.3137, 213.8257, 214.3378, + 214.8501, 215.3619, 215.8739, 216.3858, 216.8976, 217.4095, 217.9212, 218.4324, 218.9460, 219.4581, 219.9701, 220.4822, + 220.9943, 221.5064, 222.0184, 222.5305, 223.0426, 223.5547, 224.0667, 224.5788, 225.0909, 225.6029, 226.1150, 226.6271, + 227.1392, 227.6512, 228.1633, 228.6754, 229.1875, 229.6995, 230.2116, 230.7237, 231.2358, 231.7478, 232.2599, 232.7720, + 233.2840, 233.7961, 234.3082, 234.8203, 235.3323, 235.8444, 236.3565, 236.8686, 237.3806, 237.8927, 238.4048, 238.9169, + 239.4289, 239.9410, 240.4531, 240.9651, 241.4772, 241.9893, 242.5014, 243.0134, 243.5255, 244.0376, 244.5497, + }, + kicks = { + 0.209, 0.720, 1.289, 1.567, 1.823, 2.368, 2.810, 3.437, 3.692, 3.959, 4.516, 4.957, + 5.596, 5.851, 6.130, 6.664, 7.117, 7.744, 8.011, 8.278, 8.824, 9.358, 9.880, 10.159, + 10.437, 10.971, 11.413, 12.051, 12.225, 12.562, 13.131, 13.572, 14.083, 14.211, 14.466, 14.605, + 14.733, 15.267, 15.464, 15.732, 16.231, 16.358, 16.625, 16.858, 17.392, 17.868, 18.402, 18.692, + 19.040, 19.563, 19.760, 19.992, 20.143, 20.550, 20.793, 21.177, 21.711, 22.129, 22.268, 22.698, + 23.057, 23.336, 23.870, 24.137, 24.311, 24.857, 25.205, 25.472, 26.018, 26.424, 26.564, 26.993, + 27.353, 27.620, 28.154, 28.700, 29.118, 29.489, 29.768, 30.302, 30.732, 31.393, 31.544, 31.904, + 32.450, 32.868, 33.530, 33.692, 34.040, 34.482, 34.621, 34.842, 35.016, 35.561, 35.840, 36.188, + 36.699, 37.175, 37.814, 37.976, 38.336, 38.870, 39.404, 39.950, 40.124, 40.472, 40.925, 41.471, + 41.993, 42.272, 42.620, 43.166, 43.433, 43.572, 43.700, 44.118, 44.385, 44.745, 45.302, 45.569, + 45.708, 45.836, 46.254, 46.382, 46.521, 46.649, 46.928, 47.415, 47.856, 48.402, 48.565, 48.774, + 49.064, 49.563, 49.842, 49.969, 50.097, 50.515, 50.654, 50.817, 51.200, 51.572, 51.711, 52.129, + 52.280, 52.651, 52.802, 53.034, 53.267, 53.859, 54.079, 54.381, 54.799, 55.078, 55.426, 55.914, + 56.111, 56.517, 56.924, 57.051, 57.214, 57.597, 58.003, 58.259, 58.549, 59.083, 59.211, 59.350, + 59.687, 60.256, 60.523, 60.778, 61.289, 61.486, 61.858, 62.288, 62.798, 63.344, 63.611, 64.006, + 64.517, 64.807, 65.039, 65.573, 65.747, 66.096, 66.548, 67.071, 67.709, 67.872, 68.255, 68.638, + 68.778, 68.963, 69.184, 69.312, 69.869, 69.997, 70.391, 70.809, 71.076, 71.355, 71.866, 72.144, + 72.516, 73.038, 73.317, 73.572, 74.002, 74.246, 74.374, 74.641, 75.059, 75.186, 75.442, 75.697, + 76.382, 76.510, 76.765, 77.206, 77.566, 77.822, 78.356, 78.507, 78.750, 78.890, 79.424, 79.679, + 79.958, 80.387, 80.515, 80.643, 80.991, 81.258, 81.456, 81.734, 81.978, 82.640, 82.779, 83.151, + 83.673, 83.882, 84.079, 84.207, 84.753, 84.904, 85.299, 85.693, 85.833, 86.076, 86.332, 86.843, + 87.133, 87.388, 87.679, 87.934, 88.375, 88.747, 89.002, 89.246, 89.525, 89.792, 90.059, 90.593, + 91.103, 91.359, 91.649, 91.905, 92.137, 92.427, 92.613, 93.228, 93.484, 93.785, 93.971, 94.273, + 94.540, 94.819, 95.364, 95.608, 95.875, 96.142, 96.421, 96.665, 96.955, 97.466, 97.733, 98.023, + 98.418, 98.545, 98.731, 99.056, 99.602, 99.834, 100.124, 100.659, 100.844, 101.169, 101.715, 101.947, + 102.249, 102.795, 103.027, 103.189, 103.816, 104.083, 104.350, 104.885, 105.175, 105.302, 105.941, 106.208, + 106.463, 106.998, 107.183, 107.497, 108.042, 108.321, 108.565, 109.099, 109.389, 109.621, 110.155, 110.283, + 110.411, 110.666, 110.945, 111.200, 111.456, 111.607, 111.746, 112.164, 112.524, 112.803, 113.209, 113.569, + 113.836, 114.254, 114.381, 114.602, 114.869, 115.392, 115.914, 116.146, 116.669, 116.878, 117.493, 117.760, + 118.015, 118.445, 118.805, 119.049, 119.467, 119.594, 119.873, 120.094, 120.628, 120.790, 121.150, 121.556, + 121.684, 121.940, 122.137, 122.601, 122.973, 123.240, 123.658, 124.285, 125.063, 125.341, 125.759, 126.131, + 126.386, 126.804, 127.141, 127.420, 127.849, 128.221, 128.453, 129.231, 129.533, 129.672, 129.927, 130.299, + 130.554, 130.984, 131.228, 131.599, 132.005, 132.609, 133.166, 133.387, 133.689, 134.060, 134.200, 134.455, + 134.594, 135.152, 135.488, 135.732, 135.883, 136.162, 136.533, 136.673, 137.323, 137.474, 137.822, 138.228, + 138.356, 138.612, 138.762, 139.297, 139.540, 139.877, 140.307, 140.690, 140.829, 141.340, 141.723, 141.978, + 142.385, 142.512, 142.768, 143.023, 143.546, 143.778, 144.057, 144.475, 144.846, 145.090, 145.473, 145.612, + 145.752, 146.135, 146.657, 146.913, 147.180, 147.551, 147.691, 147.830, 147.958, 148.213, 148.747, 148.991, + 149.246, 149.629, 149.769, 149.908, 150.291, 150.825, 151.057, 151.336, 151.603, 151.731, 151.975, 152.102, + 152.369, 152.880, 153.147, 153.298, 153.681, 153.809, 153.937, 154.076, 154.436, 154.982, 155.225, 155.481, + 155.887, 156.015, 156.143, 156.270, 156.526, 157.037, 157.304, 157.547, 157.838, 157.965, 158.221, 158.604, + 159.138, 159.347, 159.626, 159.916, 160.183, 160.415, 160.682, 160.949, 161.193, 161.355, 161.739, 162.122, + 162.377, 162.505, 162.749, 163.294, 163.538, 163.805, 164.200, 164.339, 164.583, 164.838, 165.373, 165.593, + 165.872, 166.150, 166.278, 166.417, 166.661, 166.905, 167.439, 167.695, 167.927, 168.345, 168.484, 168.612, + 168.960, 169.494, 169.784, 170.028, 170.167, 170.562, 170.829, 171.061, 171.340, 171.781, 172.106, 172.397, + 172.629, 172.803, 173.128, 173.441, 174.080, 174.684, 174.951, 175.195, 175.729, 175.949, 176.181, 176.762, + 177.017, 177.168, 177.540, 177.795, 177.958, 178.213, 178.852, 179.107, 179.351, 179.873, 180.175, 180.384, + 180.907, 181.150, 181.418, 181.940, 182.370, 182.973, 183.217, 183.484, 184.018, 184.529, 185.051, 185.284, + 185.562, 185.957, 186.085, 186.340, 186.491, 186.851, 187.095, 187.246, 187.385, 187.606, 187.873, 188.000, + 188.383, 188.662, 188.894, 189.138, 189.301, 189.603, 189.928, 190.113, 190.427, 190.682, 190.961, 191.205, + 191.472, 191.727, 192.006, 192.145, 192.505, 192.737, 193.004, 193.248, 193.550, 193.782, 194.049, 194.258, + 194.560, 194.815, 195.315, 195.454, 195.582, 195.849, 196.104, 196.267, 196.615, 196.882, 197.103, 197.381, + 197.637, 197.892, 198.136, 198.310, 198.670, 198.914, 199.169, 199.343, 199.587, 199.947, 200.202, 200.330, + 200.469, 200.713, 200.969, 201.224, 201.468, 201.654, 201.967, 202.246, 202.490, 202.652, 203.012, 203.523, + 203.813, 204.045, 204.312, 204.591, 204.823, 205.090, 205.334, 205.578, 205.706, 205.845, 206.089, 206.333, + 206.507, 206.867, 207.110, 207.377, 207.633, 207.888, 208.155, 208.387, 208.666, 208.898, 209.165, 209.409, + 209.665, 209.932, 210.199, 210.442, 210.686, 210.965, 211.209, 211.464, 211.720, 211.847, 211.987, 212.242, + 212.497, 212.672, 213.020, 213.275, 213.519, 213.751, 214.030, 214.274, 214.541, 214.831, 215.052, 215.284, + 215.574, 215.980, 216.340, 216.561, 216.712, 217.083, 217.350, 217.629, 217.861, 218.140, 218.384, 218.813, + 219.150, 219.394, 219.905, 220.067, 220.427, 220.822, 221.193, 221.460, 221.693, 221.948, 222.227, 222.482, + 222.970, 223.237, 223.399, 223.747, 224.003, 224.142, 224.270, 224.525, 224.769, 225.036, 225.268, 225.535, + 225.779, 226.069, 226.197, 226.569, 226.801, 227.056, 227.323, 227.567, 227.846, 228.066, 228.345, 228.600, + 228.856, 229.007, 229.158, 229.552, 229.878, 230.121, 230.307, 230.644, 230.876, 231.143, 231.584, 231.921, + 232.083, 232.443, 232.687, 232.943, 233.419, 233.697, 233.976, 234.220, 234.487, 234.626, 234.998, 235.241, + 235.485, 235.683, 236.414, 236.577, 236.762, 237.169, 237.436, 237.772, 238.388, 239.038, 239.189, 239.479, + 239.700, 240.083, 240.257, 240.466, 240.605, 240.988, 241.116, 241.348, 241.476, 241.940, 242.068, 242.242, + 242.834, 243.310, 243.508, 244.564, 244.703, 244.831, + }, + snares = { + 0.197, 0.755, 1.300, 1.834, 2.368, 2.810, 3.204, 3.437, 3.704, 3.982, 4.261, 4.516, + 4.795, 4.946, 5.492, 5.863, 6.130, 6.409, 6.676, 7.210, 7.639, 8.022, 8.290, 8.557, + 8.707, 9.253, 9.520, 9.660, 9.799, 10.170, 10.437, 10.971, 11.505, 11.807, 11.947, 12.318, + 12.585, 12.864, 13.119, 13.398, 13.665, 13.944, 14.199, 14.466, 14.733, 15.012, 15.267, 15.801, + 16.091, 16.242, 16.614, 16.881, 17.160, 17.415, 17.961, 18.239, 18.506, 19.040, 19.470, 20.108, + 20.271, 20.538, 20.910, 21.177, 21.711, 21.989, 22.152, 22.419, 22.790, 23.069, 23.324, 23.766, + 24.149, 24.404, 24.567, 24.834, 25.205, 25.472, 25.913, 26.540, 26.831, 27.086, 27.353, 27.620, + 28.050, 28.700, 28.979, 29.118, 29.501, 29.756, 30.302, 30.592, 30.732, 31.370, 31.649, 31.904, + 32.438, 32.984, 33.251, 33.518, 33.785, 34.052, 34.331, 34.482, 34.876, 35.120, 35.666, 35.921, + 36.200, 36.722, 37.001, 37.164, 37.454, 37.698, 38.069, 38.336, 38.603, 38.870, 39.300, 39.695, + 39.834, 40.217, 40.484, 40.751, 41.006, 41.552, 41.842, 41.982, 42.353, 42.620, 42.910, 43.154, + 43.584, 43.828, 44.222, 44.501, 44.756, 45.035, 45.291, 45.708, 45.836, 45.976, 46.359, 46.637, + 46.893, 47.171, 47.427, 47.856, 48.112, 48.506, 48.774, 49.041, 49.308, 49.563, 49.981, 50.248, + 50.643, 50.910, 51.177, 51.711, 52.245, 52.512, 52.779, 53.058, 53.313, 53.580, 53.743, 54.277, + 54.660, 54.799, 55.182, 55.449, 55.867, 56.517, 56.808, 56.935, 57.318, 57.574, 57.853, 58.003, + 58.642, 58.805, 58.932, 59.072, 59.455, 59.710, 60.140, 60.534, 60.674, 61.324, 61.846, 62.276, + 62.682, 62.914, 63.449, 63.727, 63.983, 64.401, 64.946, 65.480, 65.863, 66.107, 66.525, 66.932, + 67.059, 67.454, 67.605, 68.243, 68.673, 69.300, 69.590, 69.846, 70.368, 70.798, 71.065, 71.436, + 71.703, 71.970, 72.249, 72.504, 72.934, 73.201, 73.572, 73.839, 74.002, 74.629, 75.047, 75.442, + 75.581, 75.964, 76.220, 76.510, 76.754, 77.183, 77.717, 78.100, 78.356, 78.890, 79.308, 79.586, + 79.958, 80.225, 80.480, 80.771, 81.014, 81.444, 81.711, 81.839, 82.083, 82.361, 82.617, 82.895, + 83.139, 83.418, 83.569, 83.952, 84.207, 84.486, 84.741, 84.904, 85.171, 85.542, 85.693, 85.960, + 86.227, 86.634, 86.866, 87.040, 87.400, 87.667, 87.934, 88.108, 88.364, 88.758, 88.990, 89.525, + 89.803, 90.059, 90.244, 90.593, 90.871, 91.115, 91.289, 91.638, 91.928, 92.079, 92.473, 92.613, + 92.996, 93.228, 93.518, 93.774, 94.192, 94.830, 95.132, 95.364, 95.631, 95.887, 96.305, 96.665, + 96.955, 97.489, 97.686, 98.011, 98.406, 98.545, 98.754, 99.080, 99.347, 99.602, 100.136, 100.508, + 100.659, 100.833, 101.193, 101.483, 101.715, 102.249, 102.655, 102.783, 103.039, 103.189, 103.828, 104.350, + 104.641, 104.885, 105.175, 105.419, 105.697, 105.941, 106.231, 106.463, 106.742, 106.998, 107.276, 107.520, + 107.810, 108.054, 108.321, 108.577, 108.994, 109.389, 109.633, 109.900, 110.155, 110.306, 110.562, 110.945, + 111.119, 111.351, 111.479, 111.618, 112.001, 112.257, 112.779, 113.058, 113.197, 113.580, 113.824, 114.103, + 114.347, 114.869, 115.392, 115.670, 115.926, 116.193, 116.436, 116.599, 116.971, 117.238, 117.388, 117.760, + 118.015, 118.282, 118.538, 118.817, 119.060, 119.223, 119.467, 119.861, 120.105, 120.372, 120.628, 121.150, + 121.568, 121.951, 122.195, 122.474, 122.717, 122.996, 123.240, 123.774, 124.053, 124.180, 124.563, 124.819, + 124.981, 125.341, 125.608, 125.748, 126.131, 126.386, 126.897, 127.420, 127.687, 127.837, 128.093, 128.221, + 128.476, 128.743, 128.998, 129.265, 129.509, 129.776, 129.916, 130.299, 130.438, 131.065, 131.344, 131.587, + 131.866, 132.110, 132.389, 132.528, 133.155, 133.422, 133.677, 133.933, 134.188, 134.467, 134.711, 135.233, + 135.500, 135.744, 136.011, 136.278, 136.684, 136.940, 137.311, 137.590, 137.822, 138.089, 138.344, 138.762, + 139.018, 139.378, 139.656, 139.900, 140.179, 140.434, 140.829, 141.084, 141.224, 141.468, 141.746, 141.978, + 142.257, 142.512, 142.907, 143.163, 143.290, 143.546, 143.813, 144.057, 144.463, 144.718, 144.846, 144.985, + 145.392, 145.624, 145.903, 146.135, 146.657, 146.936, 147.180, 147.702, 148.225, 148.735, 149.002, 149.153, + 149.537, 149.780, 150.047, 150.291, 150.570, 150.814, 151.092, 151.336, 151.859, 152.126, 152.369, 152.903, + 153.414, 153.693, 153.937, 154.204, 154.448, 154.970, 155.249, 155.492, 155.899, 156.294, 156.526, 157.048, + 157.327, 157.571, 157.849, 158.093, 158.360, 158.604, 158.883, 159.126, 159.393, 159.649, 160.171, 160.438, + 160.694, 160.949, 161.088, 161.216, 161.355, 161.727, 162.006, 162.249, 162.760, 163.178, 163.550, 163.805, + 164.328, 164.838, 165.105, 165.361, 165.616, 165.872, 166.162, 166.406, 166.917, 167.335, 167.706, 167.962, + 168.229, 168.472, 168.751, 168.995, 169.401, 169.784, 170.028, 170.574, 170.806, 171.061, 171.212, 171.595, + 171.735, 172.071, 172.640, 172.780, 173.151, 173.511, 174.173, 174.707, 174.928, 175.229, 175.613, 175.752, + 176.251, 176.506, 176.774, 176.913, 177.168, 177.435, 177.807, 177.946, 178.074, 178.202, 178.840, 179.351, + 179.873, 180.384, 180.663, 180.802, 181.174, 181.418, 181.685, 181.940, 182.207, 182.370, 182.729, 182.880, + 183.229, 183.484, 183.763, 184.007, 184.424, 184.796, 184.935, 185.307, 185.551, 185.829, 185.957, 186.085, + 186.224, 186.479, 187.106, 187.617, 188.024, 188.407, 188.651, 188.929, 189.161, 189.336, 189.672, 189.951, + 190.090, 190.462, 190.613, 190.973, 191.216, 191.727, 192.145, 192.517, 192.760, 193.027, 193.283, 193.434, + 193.794, 194.061, 194.200, 194.572, 194.815, 195.094, 195.338, 195.500, 195.849, 196.255, 196.638, 196.870, + 197.149, 197.393, 197.904, 198.171, 198.310, 198.682, 198.821, 199.204, 199.436, 199.947, 200.226, 200.365, + 200.737, 200.980, 201.247, 201.491, 202.002, 202.257, 202.397, 202.524, 202.664, 203.035, 203.302, 203.546, + 204.057, 204.463, 204.835, 205.079, 205.346, 205.589, 205.752, 206.100, 206.507, 206.890, 207.134, 207.401, + 207.644, 208.155, 208.562, 208.933, 209.177, 209.444, 209.688, 210.199, 210.605, 210.977, 211.116, 211.499, + 211.743, 212.254, 212.521, 212.648, 213.031, 213.275, 213.542, 213.786, 214.065, 214.297, 214.819, 215.075, + 215.214, 215.586, 215.841, 216.340, 216.607, 216.758, 217.130, 217.374, 217.629, 217.884, 218.395, 218.651, + 218.918, 219.057, 219.417, 219.928, 220.079, 220.439, 220.706, 220.961, 221.228, 221.460, 221.971, 222.238, + 222.482, 222.749, 223.004, 223.271, 223.504, 223.782, 224.015, 224.293, 224.525, 224.804, 225.048, 225.454, + 225.698, 226.058, 226.337, 226.569, 226.847, 227.091, 227.590, 227.776, 228.101, 228.391, 228.612, 228.902, + 229.123, 229.541, 229.773, 230.145, 230.423, 230.655, 230.922, 231.178, 231.584, 231.840, 232.188, 232.467, + 232.687, 232.966, 233.210, 233.477, 233.720, 233.860, 234.231, 234.382, 234.742, 234.998, 235.253, 235.508, + 235.764, 236.309, 236.751, 238.550, 238.887, 239.607, 239.816, 240.013, 240.199, 240.350, 240.756, 240.895, + 241.302, 241.476, 241.662, 242.068, 242.231, 242.440, + }, + hats = { + 0.221, 0.755, 1.300, 1.579, 1.846, 2.101, 2.368, 2.647, 2.914, 3.181, 3.448, 3.715, + 3.982, 4.261, 4.516, 4.795, 5.062, 5.329, 5.596, 5.875, 6.130, 6.409, 6.676, 6.954, + 7.210, 7.488, 7.744, 8.022, 8.290, 8.557, 8.824, 9.091, 9.358, 9.636, 9.892, 10.170, + 10.437, 10.716, 10.971, 11.238, 11.505, 11.784, 12.051, 12.318, 12.585, 12.852, 13.119, 13.398, + 13.665, 13.932, 14.199, 14.466, 14.733, 15.012, 15.267, 15.546, 15.813, 16.080, 16.347, 16.614, + 16.881, 17.160, 17.427, 17.972, 18.506, 18.773, 19.040, 19.307, 19.563, 19.841, 20.108, 20.376, + 20.643, 20.921, 21.177, 21.455, 21.722, 21.989, 22.256, 22.535, 22.790, 23.069, 23.336, 23.603, + 23.859, 24.137, 24.404, 24.671, 24.938, 25.217, 25.472, 25.751, 26.006, 26.285, 26.552, 26.819, + 27.086, 27.353, 27.620, 27.899, 28.154, 28.433, 28.700, 28.979, 29.234, 29.513, 29.768, 30.047, + 30.302, 30.581, 30.836, 31.115, 31.370, 31.649, 31.916, 32.183, 32.438, 32.729, 32.984, 33.251, + 33.518, 33.785, 34.052, 34.319, 34.586, 34.865, 35.120, 35.677, 35.933, 36.200, 36.467, 36.722, + 37.001, 37.268, 37.535, 37.802, 38.069, 38.336, 38.615, 38.870, 39.149, 39.404, 39.683, 39.938, + 40.217, 40.472, 40.751, 41.006, 41.297, 41.552, 41.831, 42.086, 42.353, 42.620, 42.899, 43.154, + 43.433, 43.688, 43.967, 44.222, 44.501, 44.756, 45.035, 45.291, 45.569, 45.836, 46.103, 46.359, + 46.637, 46.904, 47.171, 47.427, 47.705, 47.972, 48.251, 48.506, 48.785, 49.041, 49.308, 49.575, + 49.853, 50.109, 50.387, 50.643, 50.921, 51.177, 51.455, 51.711, 51.989, 52.245, 52.524, 52.779, + 53.046, 53.313, 53.592, 53.847, 54.126, 54.381, 54.648, 54.904, 55.182, 55.449, 55.716, 55.983, + 56.250, 56.517, 56.796, 57.040, 57.318, 57.574, 57.853, 58.108, 58.387, 58.642, 58.921, 59.176, + 59.455, 59.710, 59.989, 60.244, 60.523, 60.778, 61.324, 61.591, 61.846, 62.125, 62.380, 62.659, + 62.914, 63.181, 63.449, 63.716, 63.983, 64.250, 64.505, 64.784, 65.039, 65.318, 65.573, 65.852, + 66.107, 66.386, 66.641, 66.920, 67.175, 67.454, 67.709, 67.988, 68.243, 68.510, 68.778, 69.056, + 69.312, 69.590, 69.846, 70.124, 70.368, 70.647, 70.902, 71.181, 71.436, 71.715, 71.970, 72.249, + 72.504, 72.771, 73.038, 73.317, 73.572, 73.851, 74.095, 74.374, 74.629, 74.908, 75.163, 75.442, + 75.697, 75.976, 76.220, 76.510, 76.754, 77.032, 77.288, 77.578, 77.822, 78.100, 78.356, 78.634, + 78.890, 79.168, 79.424, 79.702, 79.958, 80.237, 80.492, 80.771, 81.026, 81.293, 81.548, 81.827, + 82.083, 82.361, 82.617, 82.895, 83.139, 83.418, 83.673, 83.952, 84.207, 84.486, 84.741, 85.020, + 85.275, 85.705, 85.821, 85.960, 86.088, 86.227, 86.622, 86.750, 86.877, 87.144, 87.284, 87.400, + 87.551, 87.679, 87.806, 87.934, 88.213, 88.340, 88.468, 88.607, 88.747, 88.874, 88.990, 89.269, + 89.397, 89.525, 89.675, 89.792, 89.931, 90.047, 90.326, 90.465, 90.581, 90.732, 90.860, 90.987, + 91.115, 91.394, 91.521, 91.649, 91.800, 91.916, 92.056, 92.172, 92.450, 92.590, 92.706, 92.857, + 92.984, 93.112, 93.228, 93.507, 93.646, 93.762, 93.913, 94.041, 94.180, 94.296, 94.575, 94.714, + 94.830, 94.981, 95.109, 95.237, 95.353, 95.631, 95.771, 95.887, 96.038, 96.165, 96.293, 96.421, + 96.700, 96.839, 96.955, 97.106, 97.222, 97.361, 97.477, 97.756, 97.895, 98.011, 98.162, 98.278, + 98.418, 98.534, 98.813, 98.952, 99.068, 99.219, 99.347, 99.474, 99.602, 99.881, 100.008, 100.124, + 100.275, 100.403, 100.531, 100.659, 100.937, 101.065, 101.181, 101.343, 101.460, 101.587, 101.715, 101.994, + 102.121, 102.249, 102.516, 102.667, 102.783, 102.922, 103.050, 103.189, 103.735, 103.840, 104.107, 104.234, + 104.362, 104.501, 104.629, 104.768, 104.885, 105.163, 105.291, 105.407, 105.558, 105.686, 105.825, 105.941, + 106.220, 106.347, 106.463, 106.614, 106.742, 106.881, 106.998, 107.265, 107.404, 107.520, 108.054, 108.321, + 108.460, 108.577, 108.716, 108.844, 108.983, 109.099, 109.378, 109.517, 109.633, 109.900, 110.155, 110.306, + 110.446, 110.562, 110.957, 111.212, 111.363, 111.491, 111.618, 111.804, 112.268, 112.536, 112.663, 112.791, + 113.058, 113.186, 113.302, 113.580, 113.720, 113.824, 114.103, 114.231, 114.347, 114.625, 114.765, 114.881, + 115.148, 115.287, 115.403, 115.670, 115.810, 115.926, 116.193, 116.320, 116.448, 116.715, 116.854, 116.971, + 117.238, 117.377, 117.493, 117.760, 117.899, 118.015, 118.282, 118.422, 118.538, 118.817, 118.944, 119.060, + 119.327, 119.467, 119.583, 119.861, 119.989, 120.105, 120.372, 120.523, 120.628, 120.906, 121.034, 121.150, + 121.429, 121.568, 121.673, 121.951, 122.091, 122.195, 122.474, 122.613, 122.717, 122.996, 123.135, 123.240, + 123.519, 123.658, 123.762, 124.041, 124.180, 124.296, 124.563, 124.703, 124.819, 125.086, 125.225, 125.330, + 125.608, 125.748, 125.852, 126.131, 126.270, 126.386, 126.653, 126.793, 126.909, 127.176, 127.315, 127.431, + 127.687, 127.837, 127.965, 128.104, 128.221, 128.464, 128.998, 129.265, 129.405, 129.509, 129.776, 129.916, + 130.032, 130.299, 130.438, 130.554, 130.821, 131.065, 131.344, 131.587, 131.866, 131.994, 132.110, 132.377, + 132.528, 132.632, 132.899, 133.039, 133.155, 133.422, 133.666, 133.933, 134.072, 134.188, 134.455, 134.711, + 134.978, 135.117, 135.221, 135.500, 135.639, 135.744, 136.011, 136.150, 136.266, 136.533, 136.684, 136.789, + 136.940, 137.056, 137.195, 137.311, 137.578, 137.718, 137.822, 138.089, 138.240, 138.344, 138.623, 138.751, + 138.867, 139.018, 139.134, 139.273, 139.389, 139.656, 139.900, 140.167, 140.307, 140.423, 140.690, 140.829, + 140.945, 141.212, 141.351, 141.468, 141.735, 141.978, 142.245, 142.385, 142.501, 142.768, 142.907, 143.023, + 143.174, 143.279, 143.430, 143.546, 143.673, 143.813, 143.940, 144.068, 144.335, 144.475, 144.591, 144.730, + 144.846, 144.985, 145.101, 145.380, 145.624, 145.891, 146.019, 146.135, 146.286, 146.402, 146.541, 146.657, + 146.924, 147.064, 147.180, 147.331, 147.447, 147.586, 147.691, 147.969, 148.108, 148.213, 148.364, 148.492, + 148.619, 148.735, 149.014, 149.142, 149.258, 149.409, 149.525, 149.664, 149.780, 150.047, 150.187, 150.291, + 150.454, 150.570, 150.698, 150.814, 151.081, 151.220, 151.336, 151.487, 151.603, 151.742, 151.859, 152.126, + 152.265, 152.369, 152.520, 152.636, 152.776, 152.892, 153.159, 153.298, 153.414, 153.565, 153.681, 153.821, + 153.937, 154.204, 154.343, 154.448, 154.610, 154.726, 154.854, 154.970, 155.249, 155.376, 155.492, 155.643, + 155.759, 155.899, 156.015, 156.282, 156.421, 156.526, 156.677, 156.804, 156.944, 157.048, 157.315, 157.455, + 157.571, 157.722, 157.838, 157.977, 158.093, 158.360, 158.499, 158.604, 158.766, 158.871, 159.010, 159.126, + 159.393, 159.533, 159.649, 159.800, 159.916, 160.055, 160.171, 160.438, 160.578, 160.682, 160.833, 160.949, + 161.100, 161.216, 161.355, 161.472, 161.611, 161.727, 162.133, 162.249, 162.516, 162.644, 162.760, 162.911, + 163.027, 163.167, 163.283, 163.550, 163.689, 163.805, 163.944, 164.072, 164.200, 164.316, 164.595, 164.722, + 164.838, 165.105, 165.245, 165.361, 165.628, 165.767, 165.872, 166.150, 166.278, 166.394, 166.661, 166.801, + 166.917, 167.068, 167.184, 167.323, 167.439, 167.706, 167.845, 167.950, 168.217, 168.356, 168.472, 168.751, + 168.879, 168.995, 169.262, 169.401, 169.506, 169.784, 169.924, 170.028, 170.562, 170.957, 171.073, 171.212, + 171.340, 171.479, 171.595, 171.735, 171.862, 171.990, 172.106, 172.640, 172.768, 172.896, 173.023, 173.151, + 173.291, 173.418, 173.546, 173.662, 173.813, 173.929, 174.068, 174.173, 174.707, 174.974, 175.102, 175.218, + 175.357, 175.485, 175.613, 175.740, 175.880, 176.007, 176.147, 176.251, 176.774, 176.924, 177.052, 177.168, + 177.296, 177.807, 177.958, 178.074, 178.213, 178.736, 178.840, 179.107, 179.246, 179.351, 179.513, 179.618, + 179.757, 179.873, 180.140, 180.280, 180.384, 180.535, 180.651, 180.791, 180.907, 181.185, 181.313, 181.429, + 181.580, 181.685, 181.824, 181.940, 182.207, 182.346, 182.462, 182.613, 182.718, 182.857, 182.973, 183.240, + 183.380, 183.496, 183.647, 183.751, 183.890, 184.007, 184.274, 184.424, 184.529, 184.680, 184.796, 184.935, + 185.040, 185.307, 185.562, 185.829, 185.969, 186.085, 186.224, 186.352, 186.491, 186.607, 187.118, 187.269, + 187.373, 187.513, 187.617, 187.780, 187.884, 188.024, 188.140, 188.407, 188.534, 188.651, 188.801, 188.918, + 189.057, 189.161, 189.428, 189.568, 189.684, 189.835, 189.939, 190.079, 190.195, 190.462, 190.601, 190.705, + 190.856, 190.973, 191.112, 191.216, 191.495, 191.623, 191.739, 191.890, 192.006, 192.134, 192.250, 192.517, + 192.656, 192.760, 192.911, 193.027, 193.167, 193.271, 193.550, 193.678, 193.794, 193.945, 194.061, 194.188, + 194.305, 194.572, 194.711, 194.827, 194.966, 195.094, 195.222, 195.338, 195.605, 195.733, 195.849, 196.000, + 196.116, 196.243, 196.360, 196.627, 196.766, 196.870, 197.021, 197.137, 197.277, 197.393, 197.660, 197.788, + 197.904, 198.055, 198.171, 198.298, 198.415, 198.682, 198.821, 198.925, 199.076, 199.192, 199.320, 199.448, + 199.703, 199.843, 199.959, 200.110, 200.214, 200.353, 200.469, 200.737, 200.864, 200.980, 201.131, 201.247, + 201.375, 201.491, 201.758, 201.898, 202.002, 202.153, 202.257, 202.408, 202.536, 202.664, 202.791, 202.919, + 203.035, 203.546, 203.813, 203.952, 204.057, 204.208, 204.324, 204.463, 204.568, 204.835, 204.974, 205.079, + 205.230, 205.346, 205.485, 205.589, 205.752, 205.857, 205.996, 206.100, 206.263, 206.367, 206.507, 206.623, + 206.890, 207.018, 207.134, 207.273, 207.389, 207.528, 207.644, 207.911, 208.039, 208.155, 208.306, 208.422, + 208.550, 208.666, 208.933, 209.061, 209.177, 209.328, 209.444, 209.583, 209.688, 209.955, 210.094, 210.199, + 210.350, 210.466, 210.605, 210.709, 210.988, 211.116, 211.220, 211.383, 211.487, 211.627, 211.743, 212.010, + 212.138, 212.254, 212.393, 212.521, 212.648, 212.764, 213.031, 213.171, 213.275, 213.426, 213.542, 213.670, + 213.786, 214.053, 214.192, 214.297, 214.448, 214.564, 214.703, 214.808, 215.075, 215.214, 215.319, 215.470, + 215.586, 215.725, 215.841, 215.992, 216.108, 216.236, 216.352, 216.491, 216.607, 216.747, 216.863, 217.130, + 217.269, 217.374, 217.525, 217.641, 217.768, 217.884, 218.151, 218.291, 218.395, 218.546, 218.651, 218.802, + 218.918, 219.069, 219.185, 219.312, 219.417, 219.823, 219.939, 220.195, 220.334, 220.439, 220.590, 220.706, + 220.845, 220.949, 221.100, 221.217, 221.356, 221.460, 221.611, 221.727, 221.867, 221.971, 222.238, 222.378, + 222.482, 222.633, 222.749, 222.888, 222.993, 223.144, 223.260, 223.399, 223.504, 223.655, 223.771, 223.898, + 224.015, 224.282, 224.421, 224.525, 224.676, 224.792, 224.932, 225.036, 225.303, 225.443, 225.547, 225.698, + 225.814, 225.953, 226.058, 226.325, 226.464, 226.569, 226.720, 226.836, 226.963, 227.080, 227.347, 227.486, + 227.590, 227.741, 227.857, 227.985, 228.101, 228.368, 228.496, 228.612, 228.763, 228.879, 229.007, 229.123, + 229.274, 229.390, 229.529, 229.634, 229.785, 229.901, 230.028, 230.145, 230.307, 230.412, 230.539, 230.655, + 230.806, 230.922, 231.050, 231.166, 231.433, 231.573, 231.677, 231.828, 231.933, 232.072, 232.188, 232.455, + 232.583, 232.699, 232.850, 232.954, 233.094, 233.210, 233.477, 233.616, 233.709, 233.860, 233.976, 234.115, + 234.231, 234.382, 234.498, 234.626, 234.742, 234.893, 234.998, 235.148, 235.253, 235.508, 235.659, 235.764, + 236.785, 238.353, 238.852, 238.933, 239.467, 239.618, 240.176, 240.350, 240.617, 240.907, 241.232, 241.488, + 242.010, 242.231, 242.474, 242.753, 243.821, 244.227, 244.576, 244.762, + }, + kick = [[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]], + snare = [[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]], + hat = [[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ZWTQOMKJIPxqlfbXURdaXTROU/2voieZWTQOMKJINtqkfbXURcYVSPNLrlgbXURPNVSQOMKJwpkfaXTRXdZWTQOu3vpjeaWTROMLJIHhtnidZVSSWTQOMK/2voieZWTQUROMLJ0vojeaWTQieZWTQO/2voieZWTQOMKJISunidZWTQZZVSQNT2uoidZWTQWTQOMK5xqkfbXURYXURPNLXWTQOMKJzsmhcYVSmhcYVSQPlhcYVSPVmgcYVSPNNNLKIHNabYURPNLPZVSQOMQWTQOMKJIaaWTQOMYWVSPNLKLcYVSPNOZVSQOMMOORQOMKJHTSQNLKKOROMLJIimhcYVSPNLRPNLKIbkfbXURPPjeaWTROpjeaWTROScYVSPNLunidZWTRhdZVSQe7zsmhcYVSPQOMKJNwunidZWTgbYURPNzsmgcYVSPZWTQOMKvojeaWTQefbXURP/5xqkfbXURRPNLJIgwpkfaXTYbXURPN/2voieZWTYYURPNLhunidZWTQlgcYUSP7zsmhcYVSROMLJISvojeaWTQigcYUSk/2voieZWYeaWTQOW1unidZVSidZVSQO/2voieZWTVSPNLKItpjeaWTQUfbXURP/2voieZWTZbXURPNosmgcYVShfbXURP/2voieZWTQSQNLKIysmhcYVSUidZVSQjzsmgcYVSYcYVSPNXyrlgbXUkoieZWT12uoidZWTQOMKJIHhtoidZWTQeaWTQOM/2voieZWTcYVSPNLxqkfbXURjieaWTT/2voieZWTQQOMKJMyyrlgbYUhcYVSPN6xrlfbXURfbXURPNwpkfaXURfjeaWTRx5xqkfbXURVSPNLKetnhdZVSYbXURPM1uoidZWTQbcYVSPNlqkfbXURTjeaWTQO/2voieZWTRPNLJIKqkfbXURPedZWTQWxrlfbXURSaXURPNRrlfbXURPojeaWTQ5xqkfbXURRPNLJIHtnidZVSQTZVSQNM5xqkfbXUUhcYVSPNotnhdZVSghcYVSP/2voieZWTQSQNMKJroidZWTQThcYVSPW8zsmhcYVWcYVSQNcwpkfaXUekfbXURgzsmgcYVSPQSPNLKcrlgcYUSPbYURPNLuoieZWTQOcYVSPNLxqkfbXURlhcYVSP5yrlgcYUSQSQOMKNyrlgbXURheaWTQO4wqkfaXURcYURPNLtoidZW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]], + bass = [[AAAAAAAAAAAAABCDGIKMNOOPPRSSROMKJKLMMMMLKKJJLNRUXZbcdefghhihhfdZVRNJHFECBBBBEHNSWXWSOJGDCBBBDGMTbioqssqnhaSLJMSXdhiijkkjifbWRMJGEDCBBAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBABBCCDDDDDDEEFGIJLMMLLLLKKKLMOONMJIIIJKLMQXeknkdUMHEDCCEIMTYeilmnlieXRLIJOWcfijhiklmmkgcWQLHDCBBAAAAAAAAAAAAAAABBBBBBAAAAAAAAAAAAABBCDEEEEEFHJLMOPQQQRRRRPNLLLMNONLJJJKLMNSYejlhaSMHEDDCDFINVdkquvurldVOJHLQWaefffgggfdZWRNJGDCBBAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBCDEEFFFFGHJKLNOOPPRTUUSOLJIJKLKJIHHHIIJMQWaebXQLGEDDDDEHMSZgknoppmhaSLJLRYdhhhhiijjigdZTOKGECBBBBBBBBBBAABBBCCCCCCBBBBBAABBBBBBABBBCCCCDFGILNQSUVWYacdcYTQOPRUWXWUROMLLMNQUYcebWQLHEDCCFIOVchknnonkfYRLLOVdimnnnpponkhdYSNIFDCBBBBAAAAABBCDEFFFGGGGFFFFFEEEFGGHGFFGHJKJIKMORUVWXZbccdeeedZWUTTVVUSPMKKLMNPVbhkkfXQMKIIIHHKOUcimquurngXPKJNUbhjjiikmoonlieZUOKGFDCBBBBBBAABBBBBCCCCCCCCCCCCCCCCCBBBBCDEFFFFGHILOQSUVWYbeghfaVROOQRSSQPNMMMNPUZdedZTNKHGFFGHJOUbhnqssspkeXROPUaeghggilmnnkgcWQLHEDCBBBBBBBBBBBCDEFFFEEDDEFGGGFEEEEFEEEFHIJJJKMPSUVWXadgikmmlgaURPQSTSRPNMMMNOSXchmmibUPLKJJJILOTagikmljgbUOKKPWdjnnmllllmmlkgbVPJGDDCCBCCDDDDDDCCCCCDDDDDDDDDDCCCDDDDDEEFHHIIJKMOQSTVXZacdfggebZWVUUUTRQONMMMMOQTWZYWSOJHGGGGHKOUbimprsrmhZSMLQYhlomjhjlnoomkfZSMIFDDCCCCDDEEDCCCCCDDEEEEEEEEEEEEFFFEEDDDEGHHIJLMOQRRTUWXaegigcXSPPQRRQOMKKKKLOTYeijgbUPLJHGFFINUbinrstusleXPKMTbjnomkilmnmjgbXSOKIGFEEDDDCCCCBBBBCCDDEEEEDDDCCCCCCCCCCDEGIKLKKKMNPQRRSTUWZcefdaVSPONNLJHHHHHHHJLQVaccaUPLIGGGGIMSZglopoolgZTPLMQWaeffeefghhhheaUOJGEDCCCCCCDDDDCCCCDDDEEDDDDDCCDDEFFFFEEEEFGHHIKMORTUVWXYZbceecXTQPQTVVUSPNLKKMOTYcedaUOKHFFFFEHLRZgloqssrnhZRMOWhqvurmklmmljfcXSNJHFFEEEEFFFFEEDDDDEEFEEEDDDCCCCCCCCCCDEGIKKKKLOQTVXYZbehjlnonkeaWUTVWVUSQPOOOOPSWaddaVPKIGGHHIKPUbioruwtqldUOMPYgorrommoqqqpnicVOJFEDCBBBCDDDDDDDEFFGFFEDDDEEEEEDDDEEDDEFGIJJJIIJLMNOPQRTVXZbcbXUSSSUUUSQONNNOOPSXcffcXRMJGFFEGJOTXbfjmqroicTNNUfqz0xsnlllllkheYTNJGEEEDDDCCCCCCCDEFHIIIGEDCBBBBBBCCCCCBBCDDEEDEFGHJKMOQRSRRRRQONMMNPQRQPNMLLLLNTahmmgYQJHFFFFFHLRZfkpqrrqnidWRRXhsyzwrnmopqrplfYRLHEDCCBBCDEEEDDCDDEEEEDDDDDDDDDDDCCCCBCCEFGGGHIKLNNNNPRTWYaaZWSQQPPQQPNMLLLMNPSYfkmkfXRMJGGFFGJOTZflosvurmfWPNSbmvyxtpooqrssojbTMIFEDCCCDEFFFFEDDEFFGFFEDCCCBBBCDDDDDCCCDEFGGHIKLNNNNOQRSTVWWVSOLJKMOPQPNMLKKLNRVadcZTOJGFGGGHHKPWchmnopomhbUPNRakstsoliklmmjfaUOJGDCCBBBBBBBBBBBBBCCCCCCBBBBCCCCCCCCBBBCCDEFFGKOSWWVSQPQSTUUUSPOMMNOPPOMKJJJKLOUZdgeZTNJIHHGGGIMSZhpvy0xrjcUOMRaksvslgeehklkheYUQNNPQRROLIFEDDDEFGIIIIIIJLORTVWYZaaaaaaYWTQONNNNOQRTWZbcccbaZYWVVVWYZaaZXWWVUVXcjqtrlbSKIHHHHIJLQVcimqttrnjeaXYemu0zuojhikkjgbWRMKJJKLOQQQNKGEDDEFGHIJKMNQSUWXXXXVUSSSSTTTUUVWXXXURPONPRTTTSRQQPQRTVYabcbaZYYYbeimonjdWQLIGGGGIKPWdkprtuvurkcTQSbltvtokjlnponicVRRTYcdYSMHDCCCEIOWcggeYTPNNPSUVUTROLJGEDEGIKMMMNOPQRSUWYabbaaaZYURPOPRSSRPONOOPSXelqojaRLKKKJIGIOYju0454333220ywy0111ywwy02442vnfbZbeecWQLHEDCCEJQXdecXSPMMNOQTUUSPMJGEEEFGIJKLMOQSUVXYbefhjlnmlgbWTSUWXXVTRONLMQVbgifaUPMLLKIGINUdmtxz010zzzzyxz24430xvwz1220umdXUWaccXRKGDCCCEGKPUXYYVSPNNNOQSSQOMKHGFFGIKNPQQRRRSTUWYZbcfhklkhbXVUUVVURPONNNOSXejmjdWQMLKJJIILRajswzzyyzz00zxy0222zvtvy0221yrkebZbedZTNIFDDDEIOVcggdYTQOPQSUUTQNKHFEEEFHJKLLLNPRTUWXYacdfhklkgbWSQQRSTTSQOMLKNRXcggdYSNLKKKKKOUcmuxyyyyz03563001222yvrstuutqldWQMLMNOOONMLJHGFFFGHJJKKJJJJJKLLLKJIJKLNPPNMJHFFGGHJLNPSUVWXYZaZWTRQQRSSRQPQQRSTWbfhigcZYXWWWWWXbgmquvwwxz13441xz0212zwvxz011zvpjdZXXXXWVUTSSSTVWWUSPOOPRTUWXXXWVVVVVVVVWWWVVUTSRPONNOPRTVXadffcZWUUVWWWVUSRRRRRTYcghfaUQONNONOQUahotxyzz00000yutuvvwwsrstuvwuqjaRLGFFEEEEEFFFFEDDEEFGGGFEEDDDDDDDDDDDDCCCDEFFFFGHIJLNPSVXZaaZXVTQPQQTUUTQPNNNOPTXcghfaVPMLLLLKNSbkty2344443330y013541ywx02330tlbRJFCCBBBCDEEFEEDDDEFFFFEDDDDDDDDDDDDCCCDFHJLLKKKLNPRTWZdegghhgdZVRQPRSRQPNMMMNPTYeijgaSMIIIIIIMRaluy122110zzzxvx02340yvwy0110tlbS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sttuuttvyyxvrnmnpqrsssqleXPJGFFFFEEEDDDEGIKLKJHFDDDDDDDDEEFFGGGGGGFFFGJOSWYZacehijkkllkigcXSOLIHHGGFFFILPTVUROKIGFFFILRXejnpqrstttttssuyzzzxtsttuuvvvuuuuuusngdbbaZURRVafijkjjlnopqpoopqqqpnmlnoppqpptxywtmfaXWVWWXXXWVUSQNLJIHGFFEEEGKOSUVUSQOMKIHGHLPUZceeebXRMHFFIOTYaaYWVWWXXXWWVTROLJHFEEDDDDDDDEFHIKKJHGFEDDDDDEFGGFFEEEFFFFFINSXabaabdfgghhiklljgbVPLIGGGGGGHHJMOSVXZaZWSOLJJKNPSUVVUSQOLJIINTbhlmlklnpqrrrrrqomhbUOIGEEEEEDDDEFGHHHGFEEEEEEEEEEEEEEEFFEEEHNYkw341wrmlkjkklmmlkjhfbXRNJGEEGJNRWbehiifbWRNLMPTZfiloonlhcXTQSYhrz21yurqpooopppmicUNIEDDDDDEDDDEEFGGGFFEDCCCCCDEEFFFFFEEDDDGMVht2552zwxxyyyxwusrrrstuutpibSNNRajrvwvtqolgbVQOQVbhlooooopoomkotz6+752zxxwvvutssttuutrmfYRLIIMVgqz4430yxxyz0zzzzzyxvusstuttsqsw1640vrnprtvwwxwwvvvvvvvtrnjfbZbfijhbVPLJIGGGHMTbiorrstuuwwwwwz12zxtolmnnonkgaTNIFDDCCCCDDDDDDEGIKLLLJIHFFEDDDDEEEFEEEEEEEDDDEFHIKMPRTTUUUUSRONMMOQRRRQQPPOPRVZcdZUOJHFFFGHJPWdkoqqqrrsttuttw010ytpmmopppmhaSLHEDDCCDEEEEEFILPTVVVUUVXaeikkhbVPKHGGGGFFFFHQcoy2zuqnoqssttttsrqqqrssrqnjeZWYdimlfXPJHGGHGJNUckorrrstuuuuusrtvvutqmmnooookfYSNJGFDCCCDDDDDEGILNONLJHFEDDDCDDEEEEEEEFFFFFFGHKLLMMMOPRRSTUUUSQPPQRRPNLJIGGHKPWcfeaTNIGEEDEIOWemqtuvvwxyzzyvxz211wrmmmnoonjeYSMJIGFFFFGHHHHILPUYbdegiklmlljihfcYTOKHHHIIIIOYjqutqmmoopqrssrmieaYYXXWVUTTSTWafhhcVOJGGGGGHKPVdjoqssssrqqpootx000vqmnnoonlhbUOKGEDDDDEEEEDEFILOPPOLIGEDDDEEEFFGGGFFFFGGGGGGHJKMPRTVXYZaaZXURPMMLLLKKLMNOPRXdikjeWPLIGFFFHLRYgloqrstvwxxvvx0220wrooppppmhaUOJGFFFFGGHHHHHJMQWbfilnoqrtuvvuqleXQLIGGGGGGIOZlvzytomoqsuvvvvvusrrqqqolhcYUTWbgjkgaTNKIHGGHLQYgmprssttssrqpqvzzzwsnmnooomjeYRMHFEDDDDEEFFEFHKNQRQNJGEDDCCCCCDDEEEEEEDDDDCDEFHILNQSUVVWXYYYVROLJIIIIIJMPRTVYbdecXRMJIIIIIKPVdkqsttsssttttsvz000xtrsstuvtqmlkkkhbUQPSWYXTRRVafgdYSQRUYaYVTSUXcghgeaWTQOOQaku13zvrprsttsrrrrrsstttsqnjeaXWZdgjhbTMIGFFFFIMSahmprrsttttsqrux232ytppqstsqlfXQLIFEEDDDEEEEEFGIKMNMKHFEDDCCDDEEFEEDDCDDDDDFGIJLNOQTVXYabbaXUQONNOPOONOPPQQTWbgheYRKHGHIIJLOVcjptvwxyyzzzxwy0zywsnmnopqrqnicWRMKIHIJKKKJIJMQVaeghhijlnpstutrnicVPLJJKLMORZiquwvsrtvwyyyzzzyxwvvuutpmhcYUTTVYZXUQNLKJIHIKQWdjnopqrrrrssstw010ysnlmmopolgZSNJIIIIIIHHHGGGHIKMMMLKIHFFFFFFGGGHHHHHHIJKLLLMNOPQRTVXZabcddcZWUTTVWWVTQMJIKPVcffbVPKJIIIIJMRWdkpsuvvwxxxxwy0200wsooopqqqojdWRNMLLLJIHFFFFHLPTVUSOLJHHHHHIIIHGGFFFGHIKLMNOQRSUWXZbcefhjjjhebaZZaZZXWUTTSUYcggfaUOLJJIIJKNTahmrtuvxxyyxwwz2442xsonopppokfZUQNMMLKIIHGFFGJNSVWUQMJHHHHIIIIHGGFFEEEFGIJLMPRTUWYadfghhijkjfbVQMLKKKLMNOPPSWbfieZTNKKJJJJKRZhpwyzyyyxxyxwuxzzyxsomnoopnkgaUQNLKKJIHHGFFEGKORTSPMJHGGHIJKKJIHGGFFFFGGIJKMPSUWZbceedbabcedaVRONMNNNNOQRSTWbfiheXRMKJHHHHMSZgotwwwvutuvvwy1410vrmmnnmkieZUQNKJJJIIIHHGGHJOUYZYUOKHHHIJKKKKJJIHGGGFFFFFFHKMNQTVXacegilnmkihffcaYWVVUTTTXcgiifZTQQSXdhkkllnptvwwvuuvwwwwwxwvtqmlkkjhfdZadghieYSPQRTTTQNMMNPQPONOPQRRQPQTWZaYUQNNOOONKJJMPSUWWVUUUUUTSQPNLJIHHJMQTWXYXVUUTSRPNNNMMLJHIMQVYbcccaWSOKIIKMQTVWVUTSRQQRQPONMLKKLNOOPONMLLMPRTUTSQPPQRSTUUTRQONNNOONNMLJJKNRUWWWWXZbdddcbZWSPNKKLNPRUUTSRQQQRQPNLKJIIIHJLOSXadedbXTOLIHJMSXbcbbabdfgfebXTPMKIIIIIIHHHIJLORTTSQOMMMNNNOPSWchlopponmlkjknrtvuqonmmnnnnmkhdZWTRQRTVYaaaaceecaWROPPONLKKNQUXaceffdaVRNLMRYfkljfcaabcddcaWSPMLLLLLKKJJJKNSWXYWTPMKIGFFHKOSVZcfilmnopponprstspkiiiijjklmmkgcYVTTVXadffecccaZXURQQPONMKLPSVYaaaaZWSOLIJNVelpojeaYYYYZaaYVRNKIHHHHHIIIIJLMOPPQQRSSSSTTTUUTTUUUWWXYYYYYZdhkmmiebZZabbbbYVSPMKJJMPSVYYYWWXXXWUQNMLLLKIHKNRWacdeedaWSOLMQVaehgffffffecaXUSQONLKKKLMNNMLKLMNOQQQPPPQRSSTTUVWXYZacdefffcbcfillkjiilnpqsssqmhbVRQQTVXYXVTSRRSSSQPONLLJHHJMOSVYbdedaWRNJJMQWceeeddeffgggfcZUPLIHGGGGGGHHIJLMOPONLKIHHHIKOSWaehjklmmnooorvz01zuqonooooppnlhdZWUUVXZbdfeedcZXVTQQQPOONMMQTXadefffeaWRNMOUckoomifdeeefedbXTPLKKKKKKKKKKMPTXYXTPLKJKKLLLNQTXcfhjlmmmnnnnquxyxuolkjklmnoonlifcaXWWYZbcbaZZabbaWTRPONLJIKORVZcdffecXSNKKOWfmomhcZZaabbbabdffeaUPOQUXZXUSTXbeedZWVWWWWUUWZccbZXVWVVWWWVXdinqpjeaZYYZabccbZVROLLNPSVXYYXWWWVVTRPNNNMLJKMQUYacefgfcXTOMNUcjnpmjiiiiihhfebXTQMKJIIIIHHHHJMQTUURPNMMMMLLMNPSVXYZabbccdcbcejmppnljjkkkkjigdZUQNLLNOQSSSRPQRSUUSQNMKJIHHIKMPSVXYZYXURPMLNSahnoolihjjkkkkifbWQKHEDDDDEEEFHJKLMLJIHGGGGHJMQUZdhkmoppppomkjmpstsnjghhijklljeZTOLKJKKLLKJIIIIJKKJJJJJJIHGILPUZdgjkmmkgaUQRYiqttpkghijkmnnnmjeXRLHEDDDDDDEFHIKKKJIGFEDDEGKPVbfiklmnnnmnnotx231vqlklnnoppomhbUNJIJLMNNLKKMORTSQNKJHHGGGHLQVaeghijklmmmllpuz10uniggikklmmnnnnnmmnnnopqrrpmkigghhhgghhhiiiiihhggghggffeeilnmlhdaabbbbccddcaXTPLJHGGGGGGGGGHHGGGGGGGGGFFFFFGGGGGGFFFFFFFEEEEDDDDDEEFFGGGGGGHHHIIIIIIHHHHHHGGFFFFFFGGGGGFFEEEEEDDDDDDDGJOTWXYXXYbdeeeedcbZWSOLJHHHHHHHHHHIIHHHGGFFFEEEEEEEEEEEEEEFFFGGGHHHHHHHHHHHHHHHHHHIIIIIIIIIIJJKKKKKKLLLLLLKKJJIIHHHHGGGGGGGINVdkmlhdbcefghiiihhgecZUQMJHGGILQUZceffecYUOKIJLPTVXZabbbYUQNMNQTWYZabdeghijkkieYSNKIIIIIIIHHGGFEEDDDDDDDEEEEEDDDDDDDDDEEFFJPbny21uoiggghijkmnoonljhebWRNKKOTZehiihhggfcZWSRTWZdghhffeecaYZfox0zsmjknoonliijkkgaUOKJJIIHHLQXcgggffilnpqpoorsrpnlklnpqrromoruvupkgedddcbaYUQMIGFFFFFFGGGHJMOQPOMJHGFFEFFILPUYacdeeedZUSTYflnmifeffggecZUQLIFDCCCCCCCCBCCDEGGHGFEEDDEEEEEEEDDDDDEEFFFFGIKLNOOPPPPPPPPONLJIGGFFFFFGGHHIJLORRQNKHFEDDDFLRXdhiiiiihgcYUTYflonifdeghigeaUOKGDCCCCBBBBBBBBBBCDDDDDCCBBBBBBBBBBBBBCDDEEEEEFGHIKMNOPQQRRQOMKIHGGGFFFFGGHIJMPSSROKHFEDCDEJOUZefghiiigdYTSWcimnkhghiijhebVPKGDCBBBBBBBBBBBBCCDDDDDDCCCCCCBBBBBBBBBCDDEEFFGIKMNPRSTUUUUTRPMKIHHHIHGGFFEGIMPRRPMJHFEDDDFJOUafhjklllkhdYWagnrsojhhijjhdYTPNMMLJHHJNQTSQOPRTVUROKJLOPRRPOPRSTROKJKNQRRQRVbfhhebbcefgggggggggghhijkkkkkiihhggfdaYXXXZbccdfhjjkklllmmlllnpoomjijkllmllkjigedcbaZZbdfiiiijjkllllllllmmmmmlkjiiiiiihgffiorsrnigfgggfedcbaabbccccccccbZYYYYZaZYXWXXXYXWWXYbegijlllkjhgghhgecabcefgggggfecbbbaYWUUUWXXWXXZabccdefghhihfedddeeeffeeedfmty21yuttvvvvutsqqqrstuvwxyyywuqnmmnprromllnqsrppqruxyz0000zxvvvvuttssuwwwwwvuuuuuuutpmllmppnjgfgkosuwxyyxxvtrqqqstuvvwxxxwxz231vohdbcdddcbaZYYZacefggggfedeeeedcZXWWVVWWWXYYacdfgiijjihgijlmmifcaabcddccbaZaabcddccccbbbdgjmnmllllmmmlkjjjjjkkkkllllllptvwvqmjiijjkkjjjihhhhhhiiijjihggffggfdcbbbcefgijjkkklmnnnnmmorrqpmiggghhijkkjihhhhebYXYbfhihhhhihhhijjkkklllllkkkkklllljhjmrstqlgffghhhhhggfeeeefffggghhhhhhgfdbZXYYYZZXXXZbeghijkllkkjijigfdbbcefghihgfeddcbaWVVVXZbaZZZZbdefghiiijjhgfeeffggghhhgehnt0430xvwyz000zxvtsssstuvxyzzyvrmkjlpstropqtvwsommnruwxz1111zyxxxvutssvxyyyyyyyxxyyyxspnnnqrnjgddgjmpqstuutsqppqrsttuuvwvusuwzzztnhedeefffdbZXVWYabdeeeedcbcccdcaZYYYYYZZbccddddefghhhgggijjjigeeeeffgfeefgffdaXWXYZbbZZacdghhhhiiiijjhgfedeffghijllklotx10vpkhggghiiihgffghhijjjjjihhikklliebaZZaccdeghijjkllmmnnmpsvuspkfghhiijjkkjihhhgfbZYZaegghjjkkkjjjjjkkkjigggghiijjjjjijpuyzxpiecddeeeeeddcbaaabbbbbbbaabbccdcaYXXXYYXXXZadfgghhhgghhhjkihfcbcefghhggfedccccbaYYYZaaZZZabddefghhhhfdbaZabdfghiiiiiimrvyzyvuuvwwwwvvtrponoqrstttutsqnjhgggfedehkoonmmmorstssrrstuutsqnlmnorstuuutttsssssrpmlllnmjgedfilnopqrsssqonmmoqstuuuuusqruxzysleaZZZaaZXWUTTUVXYaabbbaZZabbaYVTQQRSUVWWWWXYabcddddccbbddddcZXXXYZaabZYXWVWWVUUUVXYYXYadhloppppoopppomkjiiklmmnnooopsvxyvqkgddeefffdcaZZabbccccccbaaaaZZYXUSSTVYbaaZZabdeffggggffimppnjfbbdeeeeeecbZYXXXVTSTWadddcbabcddefghhhgecbZYZabcdeffgfinrutojebcdeeeedbaZYZabccdddedcaaaaZZXUSRRSUWXWVVWXacdfghhiihhiihfdaZZbcdeeedcbaaZYYVSRQQSTUTSSSSTUVXZZaaaaaYYXXXYZaabbbbaZbhnrttqnnprssrqqonlllmoqrrrqqqpnkigffffcbbdhmpomkkkmprsssssssssttrpnmlmprsttsqonmnoppoljjikmmjfedfjnqrstttsromllmopqqqqponllptwyunhcZZaaaaZXWVUUVWXXYZaaaZYZZZYYVTQQQQRRRRRTVXacddeeeeeedeefeecaZZZaaaZYYZabaYURPQSUWWVVXaejmpqqqpnnnnnnmlklmnoppppppqrtvurnhcaaabccddccbaabbcdefffdbZZZacbaXVVVXZbZXWWXZbcccccddddeilllieaZabbcdeedcaZXWVTSRSTUWWVWYZbdefffeedddcbbbcdeeeeeeeeccgkmnmhcZZZabbcccdddcddddeefffedcbZYWTQNNPQTVVUUUVXabddeeffffefgfdcaYXYacddddbZYYXXWURQQSVXXXWVVVWXXYacefgfebZYYZaccddcbaZZbhotwxvtstvvwwwvurponoqtuvwvvusqolkjjjjhfefgknnmlllnqsttttssrrqrsrponmoqstuutrponnnppljhhhkmkjhhhjmnpqstuuutqnkjknqstttsrpmorwzzungbaZZZYXWVWWWYYZabccdcbZYYYYXWURRRSTVWWWXYZabbbbccdddcbcbbbaZYYZaaaaaZYXWWWWWUTTTTUTSUXbgknnmmmmmmmmkiiijlmmmlllmmmorvwyvpkgeefeedcbZYXXZacdfggggfdcaZYZYXUSQPQSUVYabcddeefgghhgfilmkjeaZacdddddccccbbZWSRSTWZaZYYYZZZZZabbbbccccccddefgghhhhhjoppmhbYYZaabbaZYXXXYaabbcccccbbbbZYVSPQSVZbcaZZabdfffgghhhhgghhfebZYYabcddddcbaaZYWURQQRTUUTUVWYabbccdddeecbbaaabaaaabcdccinqsusrrvwxxxxwusqpooprstuuvvvtrolkkjifcbdhmqqnlkkmquvwwxxwwvtttqnnllmpqrrssqponnoppnlkklnonkhggiloprsstttsqoooqsvwxxwwvtrsuy00vohdbbbbbZYXXXYYXWVVVVWXYXYYXWWVTQPPPQRRQQRSUWYZZaaaaaaaabbbbaZZYYZZaaaYXWVUTSRPPRSTUUVZfmtwvspnmmmmmlkjiikmpqrrrqqrqpqrrpnieaZZaaaaZXUQMIGFFFFFFFFGGGGGGGGGGGGGGGFFFFFFFFFFGGGGGGGGGGGGGGGGGGGGGHHHHHHHHGHHHIIJJKKKJJJJIIIIIHHGGGFFFGGHHHHHHHHHGGGGFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFFEEEEEEEFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDEEEEEDDDDEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]], + level = [[AAAAAAAABEIMRVWWWVUTTSSSSTTTSRPNMLLLLLLKKLOVdmu14330wtsrqqonljhfcYVSQONMMLNRWbhlnkhbVQMJHGFINTahmpppomkhdYTSWclv3441wsqomlieZUPMJGFFEDCCBBBGNVeottrnidZWVUTTUUTTRQNLIHGGGHHKSbkv3651xsomllkigcYUSPOOMMLLLMMORWcioqqnhaTNIGFHMSXdiklmmkifcXSOQWdnx110yvsqqpomjfZUPKHFEDCBBBAAGNUdloomhbUOJGEDCDDEFGGFFEEEEFGGGNVfpz320wsnlllkjifbXTQONNMMMNOOORWbhnpnkfYSNIGFEINUbimpqrqolhbWQQUbjtz10yurpnnmlifbVQLIFEDCBBAAAFLTbkoqpnjfcZYWVUTTSRQQONMKJIIHHKPZis05631xtrrqpokgbWSPNMLLLMMNOPSWafjkkhcWQLIGFHLQWchkmmmljigcXUTWcktz210wtqoonnljgcYUQLIGFEFGGFINTZgkljfaVQONNNNNMKJIHGFEEFGIJKLPWenv022zwtqponlieaXUTSTTTTRQPPQTYdjnqqnicWPLHFGINTafkmmnmljgdYTTXclu0220xurqpomkgbVQLIGFEDCBBBBGOWgpuvtpkfaYXWWWWWWVUTSQOMMLLMMOSajs0653zvrponmkifcZWUTTSRQPPOPQSXcinqqnjcWRNLKJLQVcjoqrrpnlicXSPTbku232zwsrqqpolidYSOKIGFDCBBBBFNWgqwyxtnfXRLIFEEFGHIIIHGFFFGHHIPXhs26640xsqqqqpnkfbXUSRQQQQPPPPTYdjprpmhbUPLJHHLQWdknprqqpnlidYYchox221yvrqqpomkfaVQLIHFEDCBBBBFNVeotusplgcaYXWWWWWWWVVUTSRQONNNSajs25530xtrqqpnlhdZWTSSRQQPPQRRVagmtvvtngaUOMKJOVfq17971voicYUPQVdlw1320xtrponmkhdYTOLIGFEDDDFINTbhosttroljhggghhiijjjjkkkkkjigfgkqx379641ywwvusqpnmlllkkjjihhghikmprrplgbVQNLJJMQVbhkmnonlkheYTUZgp05741xusrrqolhdXSNKHFEEEFGGGLRZiruvtpkeaXWVVVVVVVUTRQONLLLLLNTcmw49851xtrssrplhcXUSRRQPPOPPQTXdjpssrmhaUQNKJJMSXejnoopoljhdXUVbjt289652zyyyxxvtqomlllljheZTONOTajostspligfgghiiiihhhhhhhhggghikpv0699630xwwwvtqolihggggffffffgjmptwxwurnljhggghjmpsuvvvusqoljijou06++740wtsssrpmjhfeffffeddccdfimquvvsojeaXVUTTUVXZbdeefedcaXTTZgp079840wsrrqpnkfbXVUUUTSQQPPQTZekrutpkdWQMJIHJMSYfkopponljhdYVWcku38741xtsrqomieZTPLIHGGHHIJKNRXemrvvtrnkhfeddddeeeeeeedcaXVSRUbjt28863zvtssrpmjgfdefghiiihhhghjmpsuuqkeXRNKJIKPUahnpqrqpmkhbWUXdlv3542zwtssqpnkgbWRNJHFFFFGHHLQWdlprpnieaXWVVVVVVUUTTSQPONMLLKPXgpz4540wrpnonmkhdaXVTTSRRRQRRSVagmsvtqkeWRNJHHKQXfmruvvutqnicWWahpz5531yvuuvvutroligffedcZWSNKMRZiqvvtplgecbbcddefghhhhhggffeefjpw28+9630wvvvusromjigfeeeeffffgilosvwvsoligghhikmpruvwwvutsromklpuz587530xxxxxwusomkjiiihgfdaXVXaflruutplhfdeefffffeeedddddddddflry599740ywwwwuspmjhfecaYVTRPPPSYelrutpkdWRNKJIJOTZglnnoonljfbWUYemv242zwtrrrrqnjeZTQNLIHHGHIJJNSZhptutqmifdbZWTSRTVZcfghgfcZVRRVcmw3552zwuttttsrpmkihhhhhhhhhhikmpsuusqnkhgffffhjlortuuvuuttromorw17+9852zyyyxvtqnkihggggffedbcdgjosutsplhedcbccdddeeeeedccdddehmsz59962zvuuvvvtqlhbXTRPONMMMMORWcinqqmhbVPMJIIKOUahortuuspmhbWVahpz674zuqmmmmljhfdcdddedbYVQMJKQXfotvurnifdccccddeeeeeeddddeefglqx38+962zvutttsrpnkihgfffeddccdhlqvyxuogYRNKJKLPUagmqtuutsqomjhimsy4974zuqppppnlifcbaabbbaZXUQPRWdlrvuspkhedcccccccddeeeeeddcbachou16752zwtsrqpnligeddddeeddcbceinrvxwrleXRNLJIKOTYfknoopomlieZXbhpy6851xspoonmjgcaZZaaZWSNJGEEJRajsxywtpkgedcccbaYWUSPMKLMQVZcflqw278630xvvwwwvtqnkhgfeeeeeeeefhlptvwtoibVRPONNOTZgntwxxwutssrqrtwz3642zwuuvutqmjfdccbbYVQMIFDGLTclruurokgedddddcaYUROLKLNQUYbdhnt059962yvtuvvvutpmjgeeddcbaYVUWaekqsrojcWQNLJJLQVbinqrssrrrrqqrvy169852yusstsqnkgdcccbZWRMIFEGLTbkqtusqmifeeefeecaXTQMKKMPTXadgkqw279630xvvxxxwuspmkjihhhggffgilptwxwsmgZTQOMLMPUbjpuvutrqqqrrrtwz36630xusstsrpmjhgfedbXTOKHEDJPYhquwurnjgeefffdcZVROLKMPTXadfhlqw167520xwwyzzxvsokihggfedbYWTUYciossqlfYTPNLLMQWckquvuusrqrttuwy0378742zwvwwvuqnkhffffedbZVSOQTZgotvurojgeddddccdddeeedcaYURNPTaju04531zxwxxxwvtromkjiihhgfffegjmpstsqnjhfedddfilpsvwwwvvvwwwwxz1489741ywwwvvtrnjfdbaZZZYYYXYYcglquvurnjfdccccccccbbaaZYYYYYXXbgnu25420wtssssrpmhdaXWVVVUUUUUUYchmrsrnhbVSPPOPSXciosvxxxwvvuutuwy045431ywvvvutrokgebbbbbbbbaaadgkptusplgbYVUUTTTUUVVVVVVUUTTSSVdlt17640xtstttspmhdZWVUUTTSRRRTWchnsvsojcWSPONOQVahnsuvwvvuutsrsux158741yvtutsqmhbUPKHGFFFGHHIKOUbiorrokfaVTRRRQQQQPPOMKJJJKMMNRZhqy4520wtrsssrpmhdYUSRQPPOOOPRVagmqsqmgZTOMKKLNSYelqsuuutsrrqprtx157730xutttsqmhbVPLJGFGGIKNPRUYdjnqqnicXSPOOOOOOOPQRQQPOOPQRTYfnw37841xuttuuutspnlkjiihggffffhkmpssrplifdccccehlptwxyxwwwwwwvvx148++852ywvvvtroligedccddddeefhjmpstrpmifdccccccccdddddeeedcaYafls15630xusstttsqoligffffffeeffhknquvtrniebaabbehlpuxz11111100y01469+963zwvuutrpmjgfdccbbbbbbbbeimqtutqlhecbcccccbbbcccccbaZZZZcipw37630wtssssrqomjhfddccbbbbbcehknqrqolhecbaZacfimqtuvuutttttstwz257630xvtuttrolhecaZZZZZZabbdfimpstrolifccbbaZZZZZZZZYYYZZabbflrx4762zwtstttsqnjfbYWUTTTTUVWZchmrvwuqmifddedefhkortvvvvuutttttvy03541zwuuuutrolhecbbaZYXVTRRSWagmprrokgecccddccccdeeedcaYWVTWbjr168740xvuvvutspnkjihggffeeedehknrttrokhfddefgiloruwxxxwwvvvuuwz269+852yvtssrpnligfeeeeeeffgghkmpsuusqmjgfeeeeefffgfffeeeedddekqx4+/841yvvwwwvurokhfcbaaaabbbdfiloqpnjgcaZYYYYadgmqtvxxwwwwwwwz258//851xuttsrqnjgdbaaabcdefghiloqtuurokgedcddccbbaabbbbbbccddfjpv16741yvttuuusqoljhhgggfeedddfhlprtspkgcZYYZZadgjnqsuvvvuvvuttvx046630xutstsrpmifdaZZYXWWWXYYbdhlppomhdZXVVWWWWWVVVUUUUUVVWWWbgnv26640xtrrrrqpnkhfdbaZYYXXXXYbfjorspmgbXUTTTTVYchnrtuuutssssrtw037862yvrqqqpmjeYSNKHGGHIKNQRTYdiostrmgZURQRSSTTTTTTTTTTUUUVVXelt17963zwttuvvusqnkihfeddcccccegiloqrpmkhfeeeefgiloruvvvvvvvvuuwz158+740xutuutsqoligfeeffgghhhijlmoonlifcaZabcdddccccdddddddddfkqw38973zvsrssrrpoljihhggfeedddegjmqssqmiecaaaacdgkoruwxxxwwvvuvxz257852zvsrrrqolifdbaaaabbcdeehjmorsqojfaYWWXXXXXYYabccdcccdddglry589730xvvvvutqnkhfedcccbbccdfimpstsqmifdcddccegkostuuutssssrsvy269752yvuutsqolhdbYXXXYYZabbcdgjmopnjfaXVVWXXXYYZbcdeddcccddfinsy2541yusrrsssrpnkjihgggfeedcdfilprsqnjgdccccddfimpsvwwvvttsrsux047850vqnkkkiijklnonmjjikloonmmnpsvwvsqonmnnllklmorttttsrqpomlnrv16751xspnnmmmmmmmllkihgfeedcdgjosvwwurnkifecdegilnoppomkifdcgkqx3642ytpnmmmmmmmmlkigfedddeedehlpuyyxuromkihgffffggffeddddeefinsy3530wtpoopoppppqqpnkhfcaaZZbdhmqtvusqoljihfdcbcdfgijjjihgedeiov16740vrpopppoonljigfdcbaaaaZbeimqrrpmifdbbbabbbcdeeeeedcccbbekry59+740wtsssssrpnkhfdcbbbbbbcehlpsusplgcaZZZadfimprsuuuuvvvuuwz26+/951xutttttsqnkhdbZXXXYYZabehlpssqmiebaabbbaaZZZabbbbaZZabejqx38+841yvtuttsrpmjhfeeeeedcbbceimprspmiebZYYYadgkorttuuutuuuuvy0379863zwuttuuvwwwwvtrnkigfeeddfimruvwusrqqqrssstttsrqponmmmmmpty38974yrmifgghhhhhggfedcbbbbbbdgjmppomjgecbbbbbcdfijlmmlkigeccglsy453zuojhggghhhhgedbaYYZabccehknqssplhdbaZZZZZabcdddcbaZaabcgmsy4762ytpnnnooooonmkigecbbbcbcehlpsutrpmjhgedcddeghijiihhgffefjou05651xurqrrrrrrqpnjgdbZaabcdegilpsrqnjgdbaZZZabddeedddccccccdjpw399730wuuuuuutsqnkhebaZabbcdfilprtrplhecaZYYaehmpstuuuuuvvwwx0357863zwtssttttsqnkgdbZZabcdefhjmprrpmjfcaZZabcdeeeffeeeeeeeehmsy599730wutttttssrqolifdcbbcccfilpstrplhebaZZZcfjmqstuvvvvwwwvx0369+852yvuuuuvvwxxyxvsqnllllkklmnqssrrrrstuutsstuvwwutsrstuuuuw037++61vpkiiiiiiiiiihgfeddcbbdfimqttspmigeeeeeefghklnnnmkifeccgmtz675ztnifefffggggfedcccddeeefilortsqnkgedccbZZYYZacdddddddefioty353zvronnopppqppomjhfdcccccdfjnrtuusqoljigffffgiklllkjigfedhmsy47640wtsrrsrrrrqpoljgedccddegjmprrqnkhecbaZZZabcddedddddeffgkpv28+951wsqoopppqqrrqpomkigeddfimquvvtrolihfedefgjlnoqqqponljjlqv169740wsqpopppppomkifedcccddfilortrplhdaZYYXYYZZaabbaaaabccdhnu17+963zvutuuuvvwxxxwutrqomjhghkotwyxwvutssqoljijkmopprstuvtstwz48+/852zxwxwvvvvwxxwusolifcaachnty111zyxxxxxxyz0121zxvuuuuussux16+962yutstuuttsssstttttsrpnmmnoqrrolhebbbccefilpsuvvvvvvvvvwy0367641xusqqonlifcbZZZZaabccdegjlopomjgdbaaZZZZaabbbbbbbbccccgms069963zwutsrqomjhgfeeedddcccehknqqpmifcbaaaabdgjnqssssrrsssstwz25641yvrrqqpnlifdbaaaaaaZYXWYcgmsvxxwvvuuvutsqnkhfdcbbbabbbejqw37972yvsrsttutttssssssrrqonllmnprsqokhfddccdfhlortuuuuuuuuuux0379962yurrrqqomjhfdcccccdeeegiknqsspmidbZZZaabcdfghhhgfedcbadipw47751wrpopponliebYWVTSQONNNPUZfknnjfZTPNMMNPTYdimopqqqqqrqrtvz2564zuqmkllljgdZURPMKKKLNPRRUYciosuutsqqqqqponmllkihecaYVTRSWemv2541xtqpppppponljihggggggfghjmprrqmjfcaZZZabdgjmoqrrrrrqrqqtw04763zvrpoonmligdbaYYXXYYZaabdgjmpqoliebZZYYZZZZaaaZZZZZaaaadiov2552zvsqqrrqpnlifdbZYYYYYZZacfjmponjgcZXXWWXZcglpstuuuttssstw047973zvrqqqppnljgfdcbaZXWUUTVZejptvwxwvvuvvvvutqoljgeddcccccgmsy5652zvtssstttttsssrqponljhgghknpqpmifcaZZZZadgkoqsttstsssrstwy2443zwsqoonmkhfcaaaaaZZYXWVVXbglpqpmiebaabcdeeeeeedcbbbbbbcekqw37752yvttttssqolifdbZYXWVVVXbfjnpokfZUQPPQRTVZdiloppppppqqqsvy25640wtpooonooopqqokfcZYacdcdegjmooljhffggfeeefhknnnmkhfcaYafmt15642yvtsssssssssstsssrqpnllmnqsuurokheddddegilorstuvuuuuttux037873zvsqqqqoljgdcbbbbbbcccbdfimqsrokgcaZabcccddddccccbbbbcfkqw25520wsqqqqqpoliebZWTSQQQRRVaflqsrnhaUQOPQQSWagmruwxxwvvvuuwz1589730wrqpoomkhfcbaaZZYXXWWXaekqvxyyxwvuvvvwvvusqnkgdaZYYYaekqw2542zwtsssttuuvvvvuutsrpnkihikmoonkgcYWUTSTUXbgkoqrsssssssuwz25653zvrponmjhebZZYZZaaaZZYWXaeinqqolhdaZYZZabcdeffecbaZZabejou04552zwutuvvvtspmjigeeedcbaacehloonkfbWUSSSTVYchlprstttttsstwz378740vqnmllkigecbaZYYWVUTTSVZdinqpokgcaYYZaabccbaXVUTTUWYadinsy231zwtrrsttsrqomkjihhggffefhjlnonliebYWVUTUWZdinprstttttsrsvz37973zupnmkjhfdbZZYYYXXWWWVWYbfjmonlhdaZYZabbcccbZWTRRRTWZadjpv16530wssrsssrqnljhedbZXWUTTWafkoqrokfbXVUTTUYchnsvwwwuttsrqswz48862ytqonljhecaaaaaZZYYXWVWZdhnqrplhdaZZZabcdeedbYVTSTVYachnu17973zurpqqrrqpnligedccccbbcehkoqrplhcYVTSSSUYcinrtvvuutsrrsvy25762xtpmkjgdbZYYZabaaYXWVVUWZeinqpnkfcaZZaabbbbaZWUSRRSVXYchov27851xtqqrrrsssttrpmjfdbaZYYcipw341wpieddfgijkmoqrrrrqrssssux047862ytpnmlkkkmnppoligedefedglqx453ztokihhghijknonljgeeeffefjou1552xrmigggffeedddccdefhjklmnoqrrpmjhfddccbbcegjklmmljifdccglry320vpkhfefffeddccbbaaZZZZZbdhkoqqokgdaYYYZZabcdddccbaZYWVUYelt01zwrmjiijjjjjihhfedddefgghijlnppnjgcaYYXXXYacfikllkjhfdbZafls0330vrmkjkllkjhecaZYYYZZZZYZbeimppmieaYXXXYZcfimpqrqponmlkkmqv04651wsolllllkkjhfecccdfgiiiklnoqolifdcbbaabdfimopomkigfdbachnu032ytojgfffeedddddccbbaaZZYacfimmkhebZXWWWXZcfiklllkkkkkkklotx1441wrmjiiijkkkkjhfdccefijklmnnonljgecccccbcegjmnmkjgedbaYZdkry463ytnigfgggfedbaZYYYYYZZYZbegjlmkigdcbbbbcccddeddddddeeeehlqw2441vpjgddddddeeeecccdefhhhijkmnnmjgecbccbcdfhknoonmljhecZbgmt0442ytpmkkkkjhfdbaZYXXXWWWWYbehkmljgdaYXXXYadfilmmlkjiijjjkmrv0453ytpmlmnopqqpnlifddcefhhhjklnonlifcaZZYXXZbehklmmlkigecbciou1440vrmkkkllkkihfdbaZYYYYZZbehknomjgdZXWWVWZcgkopqqponnnmmorvz48862wromlmmmmmlkifeeefhkkllmnnnmkhecbabaZYacgjoqpomkhfdbYYchpx463ztnhfeedddcbaZYXXWWWWWWXadhkmmjfbXVUUVVXadhknooonnmmmmmoruy2420vrmkjjklmmmmlkigffghijjkllmnnligdbbbbaabdfilnnmmkihfdacgmsz330vqkhffffhjlnoomigedfhihghikmpqonljijjihhhhijjjigfeddddfjnsy231wrmigghiiiihgfeeefghiiijklmnonkhfdbbbaaabcfhjkkkkiigebbeipx3662ytomllllkjhfdbZYXXYYZZZcfilpqpmieaYXWWXZbehkllkkjijjjjlosw1440wsommmnnmlkjigfeeeeffffghikmnmkifccccccdegilmmlkjhfecbcflsz573ytokklmmmlkihfdaZYYYYYYZcfilmmkhdZXVUVWZcgjnoppppppqppopsvy241xsnjiijkllllkigedcccccccefhklljgdaYXXXXYZadgjklmmmmlkigilpv132zuqljjjkllmmljhfcaZYYYYZadfilllifcZXWVVVXadimoppponnnnnpsw04663ytomkkllmmlljhfedcccccbcdfhkllifcZXXXXXZbeiloponmmlmmmoquy2441wrmjhijkklmmmnmmmmmmnnopqstvvusqnljjjjjjkkllmlllkkjjjiilouz4651vqljijjkkkkkkjigedcbbbbccccccbaaaaaaaZYYXYYZaaaaZYYYYYYYYYXXYXYYYYZZZZZZYYYYXXXYYZaaaaZZZZZZYYXXXWWWWWWXYYZZZZaaZaZZbgmt0563ysnkjkllllkjihfedcccccccccbaaZYXWWWWWWWXYYZabccddcccbaZZYYYXXXXXXXXXYYYYYYYYYYYYYYYYYXXYYYZZYXXVVVVWXYZZZZZYYYYYYYYXYbhnu042ytpkjjjjkkjjjihgfedbbaZZabdfijkkjihfecaZZbcegggggfffedbbbdfhiiiihhiijjkkjihfdaYXWWWXYZZaaaaaZZYYXXXXWWXYZaaaaZZYYYYYYbhow39850vpmkkkmnpsuuuroligfedcegkostsqonmmmmlihgghjlmnoopqqqonosw1653yuqppqqqrstuutqlgaWUTTTVYcgkmnlkjklnpqpppqqrrpnmlmoqrrqstvz220wsolkjjjihgecaYXWWXXXXXYadfijigdZWUTTTTVXadgijkkjjjigedfjouzzxtpljiiihgebZXVVUUUUUUVVWYbeghgebYUSRRQQRSTUUUUTSTTUVVVWagnv110wsnljiihgfdbZYWVUTTTSSSTWZdgiifcYURQQQQSVZeilmlkjihgfdceintyyvrmigfffdcZWTRPONMLLMMMMPRVZeggdZUQMKKJKKMMNNNNMLKKKKLLMSZgovwvrnkiiijigebYVSQONMMMMMLNQUYdffcZVROMLKKMPTXcfhhhhhgfebYaejpvwurnjhgggebYVRPMLKKKLLLLLNQUYdffcZVRONNMMLLLLLLLKJIIHIIJKRYhqxyxtpljiiigfdaXVSPMKJJIIIILPUZehheaVPLJIHGJMRWcfhiiiiihgdbdinu120wqlhfedbZXWUUTRPPQSVZbbaaabdffebaZabdedccccddcaYXXYacccfjntz0yvrmjhhhhhiijjkkjjjjkkkklmoqssrolhecccddeffghijjjjjjkkklnruy10yuqmkkjkjjjihhgfeedefgijlnpqssrpnlkjjjkjkkkklkjjiihhhhhimqv031ysnigeedddddeeffffffeeddfhjlmmkhebZZabbccdcdddeefghihhgiloswzwtokgeeeeeeeeeedcbbaaabcegiklmkigecccdeeffgghiiihhhgggfgjosx12zwspmmmnnmmmmnnopppqqqqqqrstuutsqnlkjjkklmmmmmnoopqqqrqrtwy010xtronooooonnnnoonmmlkkklmopqrrqponnoopppppooooopppppqqrtvy1320uoidaZaabbcccccccccdddeegiknoomjgdbaabcbccccdddeeeffffhkosx11ytnhdaaaabccdddddddddeeefhjlnoonmkigggghhhhiijjiiiiiiiilorvz10xsojhghhhhhhhhhhihhhhhhijmnpqqolifdcddefghhiiiijjkkllllnruy12zvrmigffgghhiiiihgeeddefgilmopomkigffgghiijklllkkkjjjjjjmosvyzwsojgfeeefffgggggggffffegikmopnlhfccbdddeeedeeeffffgghhjmquy0zvrmigffffffeeedcbaZZZabcehjkmmljhfddefffgggghhhggggghghkoswz0ywtrppqrrqppoooonnooopqqqrsttutsrpnmmmnoponmkkklmoqrrsstvyz22zwtqooopqqqqqrrrrqponlkllmoqrrrqomlllmmmnmmmmmnooooppppprtwz21yuojfdbccccbbbbbbbccccccdegilmljhecaaabccdeeeedddccddeefjoty1zwrlgeccdefhjklljgfeefhihiijknnnllkkmnooopoooomlkjiijjkkmqtx2430wrnllkllllllmmmmmmllllllnoqsrqolihgffggghhijjjkkklmmmnpswz21yuqmjiiiijjklllkjihggfggikmoqqpomkiiijjjjjkkllllkkkkllloruy231wqlgedeeeeffffffeeeedddefhkmnnlifcaZZaabbccdeeeeeeeeeefjnsw0zwrmheddddddddccbaZZYYZacehjlnnmljihhiiiiiiiiiiiiiiijjkkloruxzxvtrpppppppponmmllmnnopppqrrrqomjhfeefhjkllmmmnnnnnnnnnpsvxzzxurommnnooooooooooonmlkkkkmnpqrqpomllmmmnnnmmmmmmnnnnnmnortxzywqkeZWWWWXXXYYYYXXXXXXYYZbdfijigcZVTTTUVWXYYZZYYYYYYYYYbfkpvxvsnhbYXXXXXXXXXWWVVUUVWXYbdgjmooonmlkkkkllllkkkkkkkllmmmorux00yupkgedddddddddddeeeeeeeghjkmmkifcaZZabbcccccddefgghhhhimquy0zuqlhdddddddcccbaaZZZZabcegikmmkigfdddeeeeddcccccccccddfjnswzzwrlgdbbbccbbbbbbbbbbbbbbcehjlnlieaXUUVWWWXXYZbcdddcccccfjotyzxtokgeeeeeeeeeeedbaZYYYZabdfhiihfecbbcddddddddddddddddeeimquxwtqollmmnmmmmllllllmnnnnnnnopppnmjhfffgikkllllmnnooooonnpsuxyyuqnkiijklllkkkllmmmmlkkkklnopqppoonnooooonnmmmmnnnnmmmlmoruxzyupkfcccccdddddccbbbaaaZZacehjkhebXUTUUVVVWWXYYZZaaaaaaaeinsxxupjeaYYYXYadfhifcZXWXZabcdfhkmnnnnmmmnmmlllmmmmmmllllkklorvyzxuqmjihhhggfffffefffggggghjkmnmligecccdeeeedddeeefffffghkoswyxtpjfbaaaabbccddddccbbcccegikmnmkigfffffffggghhiiiiiiiiilosw00yuojecccddefffffeedddddddfhjkkjfbXUTTVWWXYZacdeefeddcccfjnsxzxtojebaaaaaaabbccbaZYYYYacegijjihhgghiiiihggffggggggggfgjnrvzzxvtrqqrrsrrqponnoopqqqqqqqrrrrpnljggfghiijkklmnoopppppprtwyzywspnllmmmlllkklllllkkjijklnpqqqponmmnopppponmllmmnoooonoqtwz0yuojecbccccccccccccddeeefghikkjifdbZYYYYZZabcdeefeeeddcdhlqvywtokfcbaaZZZZZaabbaaZZaaabdfilmnmmlkjjjjjjjjkkklllllllllnqtwyxuqlheddeeeeedddddeffghhhhiijjjigecaZXWWWXYacegggggffeedgkoswwuqlhdcccbbbbbccccaZYYZacdfhjklljhfdccddeffffffeeeeefghhjmqtwzwsmhdbcdffffedeeeeeeeeedefghjjihebZZZabbbbbbcefgggffeeefimqvxxtpkgdcbbbbccddeddcbbabbcdfgikkkjhgffffffeeeeddcbbbbcdegjmqtuusqpnnoqrrsrqqonnnnooppqqrstuutrpmjgfefhjkllklmnopqqppoprtwz0zwsomjkkllllllllmnnnnmlllmnpqrrrqponnoooppooonnoopqqrrrrsuwy01ytoieccdefgijkkjhgeccccdeimquxyvqlfaYXXXXYZacdeeeddccccehmrwzzwsojgeeeegghiihfcbZZZaabehmrwzzxvspoonnnnnnnnnnnnoooppprtvxzyvrnjgghhhhgfdbZYYXXXWWWXXXYYYYXXXXXXXWWWWWWWWWWWWWWWWVVVVUUSRQPONNNMMMMMMMMMMMLLLLLMOPQQQPONMLKKKKJJJIHHHHHHHHIIIIIIHHHHGGGGGFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDEEEEEEEEEEEEEEEEEEEEFFFEEEEDDDDDDDDDDDDEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]], + bright = [[Tant06//1riZQQRQPOMKJIIIIHFDCBCDDEDDCBBCCDFMSZiqvz467899++++///////////////+743347+/////////93ytokifdaacgnv121vojebYUQNKIIJNYku3///////////82xurtx010wrnifcbcfkotx1452vmcURSWaeeecZWSNIEBAAAHUhs242xqjcWRPNKPUbjuz47+/83ysmgbYWWbffcWOHDABDEKQWaedbXRMHDBAAADObo0+//////+9741xvuvz37+////+966678///////2tiXMKPUZdgcZVRNJGDBBAENamy685zriaSOKHNUcmz268+/+71uoicbbceffbVNHDAABDKRZdgdZVRMIEBAAABKXjw7//////////72yuqtwz0zwsnjgdbbfkqw00xtojdZVRRUYbeecaWTPLHECBADLYlx572wngZUQNLPUblv058///70sldYWWXZbdaVPJEBAACJQXdhfcYTNIEBAAAAGPZly58//4wogYXadgkqv059+83wofXSXfpz9////80sjaUTXcgjkhcXQLHDBBBACObny73vlbTNLKKILQWfqw157762ytpkgfghkopkdUMFCAABDJOTYddbYSLFCAAAALYkx9//////82wpkjjlnoruxwurmifdccglqwzyvpibUOJFDIPVaffdaUOIDAAAAAKWit452wofXQMJGIOUepw04541uldWSQSVacggeYRKFCAABFKPUZcccaVOIEAAAAJViu7+////83ytolkjkmquz10yvspmkhlqw3//////1qeTJINRVYaZXUQLHDAAAAENZlw586zrgWOKIGLQWeouz4673ztldXUTWbgjkhZRJDAAABGNTZddcaWRLGCAAAAJWjv8/////+71voiffilqsuutrpmifdbcflrwyxsmfZTOKGEJPVafcZUPLGDAAAAFOalw11yrjbUOMKILPVdnrvz11yumeXTTWZcecZWSOJFCAABIPWchhgeZTNHCAAACLYkx7////3uiWKFFJPWdhiihfdcbaZXWVUUTTTTTUSQNKHFFHKOUafkptwxyz01367641zyy023210zyxwvuwy27++++741zzwvurnmjgcYXXaejopnkgddbYUOIECBBELYkw6///+6zrjdbdfilnpsvxxvsnifdcdioty0yuqleXSMIKOSWZZYWSOJFBAAAAEPbnx42vogYROLJJLPVemsx020vphbXWXbehjjhbTMGBAAABIOTYbaYXVSPNNNOPQTXchlnnkgcXURPNPSXdlquwxvrmiebaZaeinsvtqleYUQONNPRUXYXUROKHGFFFGHNUckpnjdYTPMJGGKQWfnsvyyuogYPKFEHMSYccYRLFBAAAACGLQVZZXTNHDBAAAAJUfq0ztkZRKIIIHJNTbjorttsrokhebaehloqpnkhebYVRMMPSXbbaXTOJECAAAAITepz1yskcWROMJKPUblty48873vmeYTTWaeijgcUMFCAAACIOTYbaXTPKGDBAAABObn0//94vlcVQPORVZflopqpnkigedbbeinsxyxuohYQIEBDIMSXabbaYVTRNKGEHNUbiihfcaZYXXXXZbfkrx2553xqhZSPQTYcgfbVPIDBAAADKQVabZVRMIEBAAAAIViu7/////3ulbRRTWahmqtwwuqmifdbbeiouxxuoicVPKGDJPVafedaVQKEBAAAAISdoz21umdWPMJHIMSaksx2564yrlgaWVUVWaZWQLFCAABCGMSXacbZXURPONOOOSXekqqokgbXTQOMNRVcjptvwuspmjhedfinqturnjfaWTSSSVYbdecZVQLHECCCDHMUcjnmhcVQMKIHGLRZjtx020wphYRKGFHLQXaaYSLGCAAAAGNUagfbXQLGCAAAADLWiv44xmaPIEDCCINUdmprtrplgcaXWWZdlu120tldXTRPPQUXacdaXTPLHECBABGNVciigcXSOLIFEHOWfqx15776zqhYTTWcimpokeVMGCAAAIQXejhfcYTNIDAAAAJTdnx13660rhXPKNRWdmruvvtplgcaYWaeinsutqmgaVQMKLQVagknrwz0zzyyxxz13577765420xwutssrtvxyywuqnkhfdcddfhiheZVRQPPQRTWZabZXUROLIFEEFHNUckrrnhaURPONNPTYelqtvvrmhcXVUVYdlsxxvrmgcYVTSTVXZabZWTQMJGFEEFKQZjswxtlcVQLIGJPWfqw15775zriaURSUXZcdaVPJDBAAADJOTYaZXUPKFDBAAAFMTbilkieaUQNLLPVbhoqrtusqmhebZXYadinqpmgZSOMMMNQTWYZYVRMIECAAAACHOWdiieWPJFDDCCHOWgrx15654xpgXOKMPUZddaVPKHFGHJNTYcffdaYVQLHDBAAHOWelljgcYVTQNLPTZgnqsuuspkfaXUTWbglppmhbVQMJIHIMRVZbaWRMHDBAAAAFMWfoqnfWOHFEEDFLScmvz24430uneWSUXdillicUNFCAAAFMTZefdaXSNHDBAAAJRZhppnkgcWSQQOSXciorsttrojeZVSPRVbjt06+5vlcTRTUXabccbYUPMJJKMNOPTZfknlhcZWUTSRQRUZhov0331wndVQMOTXbddZUOJECAAAAELSZegcXSMHEBAAABIPYhonlgaTPMMMRZflqsstttqlgbXUSRVbjt38/+2tjaSRSTUWXXYXUQNKIIKLMMPUZeiigcYTPMKHFJPWepuy2564xqjdYXZbdgjidWOHCBAAACIPUaeebXRLFCAAAAIPWelnlieZTQNLJNTYfnqsttqmhcXURQQWfpy7+91riYRRSTWYabaZUPMKJKMNONOSWbfigdZWTSRQQQTXciotwz1zvnfWQMORUZcecXSLFCAAACIOUZddaXTNIDBAAADKRaimmidXRMKIHKPVdmrvxxupjcXTRQPWfpz8/91riZSSTUVWXXYZYVROLJKLMMOSXbfhgdZUQMKIGHMSZjrx15651vmeXSQTWadffbWPJDBAAAFLSYdecYWTQONNNOQUafjllgbWQLHEDGLSZinquvvtqlgcaZZadhlnokgaUNJGEIPVaedaYWVTRPONLKLNSXcfhgebYWUTRQSVahosvwurmhaVQNMNRVZcbZTOJEBAAAEKQVaaYUQLHDBAAACISdntuofVNIFDDCHNWgquxwuqkfaWSQPRXdjprqkdUOIGEDIOTZecaWRMIEBAAACJSbkqqleWPKGFECIPXhsw0331wofXPKKMRXdfebWSNJHGFFJOUZefdbYVSPNMKKMQXfnrqlfZVUVXZacehnuy230wrlgcZXXagnu00xrlfaWTRQRUXabaXTPMIFDBAAAGPZjrrnfYSOMJHGIOWfqx14652vndVPNQVafjhdXQJEBAAADJOUZccZWQKFCAAABLYlx9/+70riZRMLRXenvxz00yvqlgcZXZfnw49/+3thWLGEKRXeiheaWRLGCAAAAITdp030ukbSNJHGJOUdnty37883tjaUQTYdhmmibTLEBAAAEMTagigbWQKECAAABLYkx8///6xndTOLPVbkuy13552xqhXPLPXhrz2zvogYSOLJLORUYacdgjklllmnortwyzyxvutsrpoooopqsuxyywtpligeddefghhfaWROLLKLMQVZcdcZUQMHEDCCFKVhsy0vndWSPPPOQUagpvy0ywqjbWQNMPWemtwsldVPKIHGLRXciihfcZVRNMLKLOVcjopmhcYVTSSRTWagmquwwvqkeYSPOPSVZbaYTOJFCBAAELRYdecYTOIECAAADJRbkqrogYSOLLMKPUZgptwyyxtleXRMKNUbkstqiaTOMNQRUXZbcbYVRPMLKJJJJNTagmmjeZURQOONPVbiqwyzxtohaTOKIKOTYdcYTMGDBAAADKQWbdbXSNIECAAABJUgqzyriZTOOOONPUbjsy121xrjcWSPOUbiryxsmeXQMKJIMQVaeedZTOIDBAAAAHQYisusnfXQMKJJOTZhorstsplhdaYWVWYacedaVPLHFDDDHNUafgeaYVSQPOOORWdjpstpkeZVUTTUXafkqvz0yvqkfbXWWZdimpqnjeXRMJHJNRVYabdgjlllllllnoqsttsrqqqpppooooopqsuvusokfdaaaabceedaWSPNLLLLPTYcgdaVRNJGEDCCHOYjswvqjcXUSTTTWZekrvz11yskdYUSUXdkrvvsmfZVTSRRUYbdfeaWRMGDAAAADJRajnmhbUOKGECEKRZiprstsqkfaWSRRSUXcedbXTQOMMNOSWacecZVSPMLJJJKPWfnuvrmgaWUTTTUXcgmsvxywsnhcZXWWYbfjmlkgdZXVUUUWYabcbXTPLIGFEEEGMTagjhcXSOMLJILPWdmswyyvrleZURPPRTXaaWRLFCBAAAEKRXdecZVSNIECAABGPaluxtlcWSQQSSUZekrvz231wpicXWVWcipwzytmfaWVVVXZceggeaVPJEBAAABFNVdjlidWQLHFDCIOWfptwyywrleaVUUVXadhheYRJEBAAAHPXejhcXRMHEBAAAJWiv8///93vogaYYbeiouy36884xqjdYYbflsxywrkdYVUUUWXZabaYVTQNLLKKKLPVbgjigbYVTSRQQTYdjptvwwtoicXUSRTVYbedZUOIFDBBBGNTYccYVRNJGDBAADMWhrxunfWRPOPQQTYelsx011xrlfZWTTVaejnmkgdaXWWXZbdeeedaYVSPNLKKKMRXchkifbYWTSRQRUYekpuwwvrmgcYWUTVXadecXSMIECBBDIPVadcaWSOJFCBABGQbmwzwogYTQQQQTWagntx01zunhbXUSTXbhmoolidZWVWXZbdeedbYUSOMJIIHILQXdhigcYURPOMLOSYfnrtuusoicXTQPQSWaeecWPIEBAAACKRXdgdZVQKGDBAABLWiu32xpfYTRRSSUYcjrx1453xqjcXUTVYdinnnkfaYWWWXZbcdedcZXUQNKIGFFKQXejjfbWSPONMNQWcjquxyyvqicVQNMNQUYcdbZVSQPPQSWaehkmnortuuvvvxxwvuuvxyxtqpprtusqonnpqqqnllmortrqpppqqokhghknpqomieccehmpstuutsssttuttstvxz0zywtqooopqponnnnmljiijkmnmiffilpqnkihhhgdaXUUWYbcZVUVYdjlmlkmpstrmihijnqsssqpnmlliffhknqqolklmmmlhfeedddbaYYZcfhhfcbcfhkjheehlppnifehmruvuqmkiihfcYYcglpnhcadioqoiebbdedbYVUVVXYUOLPVensronoqrtrnjhikptxz0ywuromifeimquvtpnnooqokfcbaabbaYYYZacbZWVYdioqnkjjmqtsoljjmquwyzyxurokfbXXZdggeYUSTVXUPPRVZdcaXTSSTUUSNKLRcnvxuokkmpqnhedfjquy00zywtqmhddgkotspnllmnnlhfffffeaXVUUXZaYVSTZflpnjghkputoiffhnsuvutsrrpnibVUWafjhebZZacbZXYbdghfcZYYZabaXTRUZehifccgkoroiecdglopqomkigecZWVYbgijgbZZbdgeZXXZaeedbabdffgeaXXaejmmkihjmopnjhhjlqsttsqnljhfcZYbfknnkhghlpsqnljjihfcaZaceffdZXYchnqpmihhkmmkhffhkosuwusrpomjfdfjotusplklnppmjgeeeeedcccdeffdaYZcfikihghknpoljhijmoqrqpnljihgedehjkjhedegjlkhfedddcbZYYZbcdbZYYdinqqmhfgikljgfgjnqtuusrqonljhfgjnqrrolklnppmhedcbbaZXXYZbbbYVTVYdikjhghjnoomihhjnruwwuspnkifdbbegijhebbbdddaXXYabcaYXXYZabaYVXagmqqnkiklopnkiijmqtwxvuusqpmjgilptvuqnlmnppmjhfeedcaYXYZaccaXVXaeikjgfgjmppmlllnqsuvvusromjfcbcehihfbZZbdecZYYacgijklnooppomkjjklllkkjkmpqrrqqqrttsqnkijklmkjijlorrqnmlmoqrpnliffgjmruxyzzzyxwvvuuutttuwyyxvsqppqsttsrponljgfhjlmlidcdgknmigfeghfbYVVXZbcYTQRWdlqrpnnprrrniggjntwzzywvusplfdgjmqqnkiijkkifddeeeecaYYacffebYYadgiigeehkopnjhgimqsttronljifbZadhlmjebcfkoojfcbbddbZWVUVVXVRNNQVdknmllmopqokhhjmruwywvtromjggjpvz0yuqpqsttpkhfedefgilquwyzywuttsssqpprtwzzxuqonnprstqpomlkifefhknnliffhknnljihhhgdbaabdfgdaXXagmppnmmortroliikosuwvtrqonlhfegkptutolmnprqkheccccdfjnrtuvvutsrrrrrqpopqrsuutsrqqrrrpnlklmoonmmlmmjedcehmpponlhffhlptvuttsssrqqqqrrrrtuuutqooooppomkjjjknnnljjjlmonlkjkloqpnkgdehlptuutstttttutrqommmnooommmnpruwyyywtqnkihhhhiihecabcedbZYZcefedcbaaZXVSSWckswxurponmkhdceimtwz00xtpjfaYZdhnstspnoqstrlgdccefgedaYWVTQNMQXekolgdfilongcbcgouy1441wpibVRRUYejljfdbccbXRQSXdjkjiggffecbZaekrxzzwtromljgddehlqrsromjgdbXWYcjqwzzwsqononlkjhgfdcaZYYYXXURQUYfklhcaaeimkfddfkrvy00zvqlfaXVVYcgiheaZZaccYUVWaegeaXUWWXYWRNPTbltvtoljijjgcacekrvy00zwtqnjgeeegiihfefhkmmihghikjigddddedYSPQXgqwwsoortwwrkijmtz37+//+62vogedfjpqmgaWWYbYUTUXbggeaYXWWWVRNOVfr289632yutqjijlnsuvvurpmkigdbacejnpqpooooonjhfffggfecbZZXVSNLOUbjonkihijlljihjmrw03442zvrnjgefhjkkgbZabefdZZacehfcZXWWXXXVTVclu120upmmmmkhfgjouy0110xvsojeaadiputqnlllmlgedcefecYWVUTUUSPMNSaiornihhijkfYYbfnx034542zuqjcYYZeikifbaabbZUSUYcgheaYYZbcccbaejpsvsokiijjjhddehmruutqmjgecZWVYdinrsrqpommkihhhhhgfecbbbbbZWVWbfkljfbZaceecabfkrx010yvsokhdaabehkjgbZZadcZWWXbfhfcYVTTTUURPRXgqy0yuqnlkljffgjovz2430wtpnkighjnrttrppppqpligfeffecbZZZZZXTQRVcjoolhffgiiebabemtz48+84ztngbZbdjopmhdaabcZTSUYbhhfdbaZaaZWSTWckty25530xvvwwvvutuwxxvsqoortvwurnljgfffeedaYXZabdegimprrrrrqqqqqqqonmmmmmmmmmnpsuwxxxvtrpnkjijkllidZXWYZZWVWYaccaYWUUUUUSQRXemtxwtqonmmjfdehlrvxyzywusqokihilptuusrrstsqmkhgfedbaYXXXYWURTXelrspmkkkkjfdcfjqw047983yrkfbZabehhgcaYYYYWSUWZdhgdcbbaaZXURTXemtvurnkjiiheefgkoqrqplifdaYWUVXcgjkjhghijjiiiiiigdaXVUUUUTRQRVaegfcXVVYabZWYafnuyz0xspljgdZXXZcfgdbZYZaaXWWYbefdaXVVVVVURRTYgpvwvrnkjiiifffhmswz210yvspnkiijloqomkhgghgfeffggfcZWUUUUUTRRTYfknnjfefhiiedegmtxz10xurnkhcYWXZdggebXWXYXUSUXaefdaYXWWXXVSRTZgpuvsommmmnjgfhkptwyywuromkihhilptvwvspnlkjihgeddcaYWUUVXXWUUWbfkmlihhhhhfccdhmsx010yuqnkfcYWWZcffdbZYYXWTSUXbfgcZWVVWXWVSSWdltxwtpljjjjhhhjntxz0zxurnligffilptwwvsqnlkjihgfeedbZXWWWYZXVWZdinpoljjkkifcbchouy00xurnkheZXXYbfhgdbZYZZVRSTWafdbZZZZaZYVRTXelttspmjiiiigfhjntxz0zxurnkhfddfimprrqpnmmkjigfeddcaYXWXYaZXWYchmpqnlklmnmifefjpvy11zwtpkhcYWYbfjjhdaYYYWTSTWaefebZYWWXYXWWZdjqttqmlklmnkgfgjpvy110xtplifddeintxzzwsqonmkjigfedbZXWVWYYXWXZekqtvvuuvwz121yuplhgfgkpssqkdYXZdhigcYYciossoljhghhhijlmoopoooortwxxuspopqssrolklorttsrrsttsqpppqrqponnprtuusplkjlortvxyzzywuttvxyxvtrqonmlmosx1442ywuuttromnprrokijmptroligggfdbaacdefcZZdjryzwqmmpstrmiilqw02210zzyvpicbekqtspmklmonkjihikjiggghiijhedeinuxwtokiiiigefinu02431yxvtrojhikmonkgegimomlkkmonkheccdeffbYXcjsz1ytrruxzwqnlnt0467420yvsngbadgkljfcceikkgffhjlkhecbdfhifaXaemtwtnhedeggeefkqz3662xtqonlgbZadkookgfhlnoifdehlkigedefhjgaWZeoy65zutvy33uokkny3798655674umgefmppkfddghhdXWXaeihfdbcdfhhdYXYekrspljijlliecehpx243ysnkjihfcbdhmpoljkorvtomkjjljigffhjlkhdcejqwyxtqrtx00uqonrw01zwsqonmkgdehntwvqmklnpojhgghlkhecbcehjgbXWZelppolkjjkjhefhlsy132zxvtsrpkhggilljgefhknnmlkkkkifdccegiifbaeksxzvqoorvyvpmkms057742100xskeZZcghhfeegikjgfffhihgeddefhifbYZbhmqpmkhhjkkhffinw15640vsrrqokhghkmljgefimomkkijkljhffgikmlhdfjqy43zvstvyyuqmmpv03431zyyxwsmhffhkkifefilmjecbcfihecZacfhgcXWYdjpqnieccegfcbdgnv1330vrponkfaXYchkjfddeimmhfdcdgffecdfhjjfYYbju5+71yyy174wqlimu159/++++92tkeadhlligefhjjhgfghjifbYYZcefdZXWZeknomifdefgebceiqy244zuqponlhecfimnmjhilpsrpmkjkkjhffhjlnlhfegkrvz10ywvvxz0yxvvwxxwspooqsuutssssroljjknolgddehlnpruwxyzzzyxxxyyxvtrppqqqqpoosw04751yvtsrokhghkmmlihjnrsrqonnnlifcbbdghgdaafnuyzuqopqssokjjnuz36521zzywqjdbcglmliffhkljfcbcfhigfffgiiheZYbgmqrokhhijkigfgjpuy10yusqomjgdcdgklkifghkllhgffgihgedcdefdaURTYgpvusrrtvxwspnnqv04541yvtsokgddgjkkhedgjlkeZYadiljigefgiihdZYbflpomkjknqpmiggkry3674zvroljfefimppmhfgilnlkkklmljgdccdfgfbWVahqxyvrpruxxtnkjmsz477544552xpjfgilmkgefgjkigffgikjhebabceebXWZelrsrmjjlpqpkhhlry35640yvrolhcbceilkifefhjheddegkllkkjjklmjebbfmstrkecehjkfbachouwxuronmkieaadiosrolklosrnjgfgilnquz2345543211122221111111124677530yyyxwtpnnqtvusposx11ztopuz33ysoorvywsnlnsxzxqkhjnsvtomnsz651vqpty0ztnlou164zursw01ysnjiikmpty234321112232110013432zxwz25652zxyzzxurpqtwzxuplmpsuupllouz1ytnlmqttsnkknsvxslhgjouurnnqw242wrnptvvsnkmry330uoorvyysnkjjmpsv0367875432355421z0246641ywxyyxurooqsuusqonqstspkiknprnjggjnrqnifehlnmidcfltzxtnklpuurmijov13zurrvy1xrlils0550vtvz250tokijmnqtwz12221zywwxy01zxxxyz0ywtstvxxwtqopruutqonnnmkgfgjouwwurolmorv0220zyyzyxxyz13323568+730wvvwxwtrqrtvwusrrtwyyvtsstvvusqnmmnprtuvwvutttwz24442223321zwuuvy257654431yurqsvwvsnihiknononnnomjgddfjklideks0873yuuy241vroquz356644551xrnou17+5zvtsuxupmkijljfcZadilmgYYckv673wttw02zrmklrz479877784yphcdiospjecfkqpjhffhmkifcbdfikeYchp0//+77778//830xwy379+////94xvvw19//////+83xtpmlmjgcYWYadfaTVckw9/95444674xsppt047+/////+70tpoqvzwpjhjouvroljknljgcbcfimhadhoz///+++++//61xusv047876641ytrtx39////////81wqkhjjjifefikmfXYdlx9//+9999971xvtv158+//////82ywwz461tlgfimmhgfehoruy345677898666679/830zz26753113442zvuvwy0zxvwx0232zxxz1341xtrrux1345666665432100zzzyxvtqppruwyzxvtsrponnpruvvspmmmnnliiiijljhfedfhijhefhlrwvrmkjkmmkgghkptwwvtrpnmjgedgkpssojhhjlmkhgghijigecdfijkhdeglptrnjikmpomjjkovz121ywutrokiikpuwwsnllmnnjgghikljhfefhijifceiouxtnjijmpnjhhjouy11zwusrokfddglqrpmiijmnnigfghklifdbcfhhfaXZekoplgdegjlifefipuwwurpnmljgcbcglqqnifehjjhdcceikjhecbcfhgeZXZekoojecegkmigfgkqvxxvspnmkhcaadioqpmiffhjjhgfgilljhffgikljebcfmsutojhilnnhfegltxz0yvtsqpmihilrxyvqmkloqolihhjmmlihggikjgdcdhotsojfehmonjiilqx000xvsrqnkfefjoturnlkklljgedeghhgeddfjllifehlrutpkggilmkgfgjpvyz0zwuspmjfgkpvywrmijknnjhfefijihgggikljgeehmrsqmjijmppljjkntxz11yvtrolhffimqrpkihijlkgggikmligdegkmnkgedgkopmjhikmonkjjlqvy00ywusrplihjntxyvqomnoolhfdegjjihggilnnjgginuxvqnlmoqpkiijntxz0zxvutrojhhkotusnjjjlnmiggghkljgecehlmkfcdgmrrnigfikmjeccflsvwwusqpnkhddhntz0wqljjlmjgeddfijjhhgikmmiedgmtxwqkihknolhgimrxyywtrqqomhddglqusnkjkmookhggillkighjmprpkijmqvvsnkmqvywqmkmqx1220xuromjgfhlsx0ytqopqrojhggikihfefilmmifegkqvxxvtrrtvwwutrrstsronoqtvwusqppnliggikmmiffgimqsvy011110zzyxxwvsrqpqqqqpooprtvwxvtrpmkjgghknqqokihknnlhfefikkhfddhlppnheeinqrnhefhjliddeinuvwvtrqpmjeZZdinrpkgddeggedegjmliebZbeikhbXXbiprpkfegjkjcYYcirwyyxvtsrplgddgmrtqlhfgjlicaZZdiihfeegjllgaZbhqywrmihjmmifefjpuxwvspmlljhedfimookgfffhhfccdehkhebZaeijidZaekqsojedfjmkhecekqtvusqpoomiebcfmqrohddgkmkebachmnkhcaadgfbWUYgptrjbYaflokhghkptuuspnnmljfccfjopnjedfjmmigfehllkhfeglqtpjfdflstqliimruslighmux03210ywsniginv351wssty1wqlhgjkjighjnsvuollpv583vplkossokjjnrvvvtqpoonliffgkoqokgeefhgddegimmkiggilnokecbfkrspmjijlnlihikosvvutrqppnjgfhmswwsnkjknoligfghjigedegjlkhegjqx0xrmklorqmigilquxxvsqppnkfcbflrtrmighjmlhfffimmkheehlprmfcehpuupiffilnkeccflvz231zxvtrniikotxwsmjkmqsolkjjnnljhhilnpoljjlosusoklmoqplihjmrvxxwtsrqomhfgjnrtrnkjjkmlihgghkjhfddfjllhcbdinqpkebcehjifefjosuutrpoonkfbZcgmppkfegjmmhbZadimljgefhkkhaVUZflolgdcehkjgedfkpstsqnmmllkgeehlqrplgfhkllihggjlljhffhknmjecdhmookedfjmokeddhowz00yxvuspjfgkqy30uolmqusmjgfiooomkjknrtpjgegovz231zyxwwusqpprttsronoqsutrpopqqnkhghjkhdccdhmpsuvwxyz00zzyyyxvtrqrtuutqoopruwxxwusrolihjnruvtojjkmnmifefhklkigfgjmmkfegkqttojhiknolhffhmqsusrqponmigfhkoqoliggikkhgfghjigdbbcgjljfbadhmnkgcdhloojihjovy010ywusplgghmrvtpkggjmomkighklkjhhhknonjiimsxyupkkmpssolkkmquuusqpopomiffgkopmifdegiheefhjmlifccdgjjgcbdinrpjfcdgklifegjptvusqonmljfdceimpnjgeeghhecdegklkhfegiklidbcglpqmheegikjfefimrsrpmkjihfcZZbfkoolhfffhihgghiklkigffghjjgfgkotvsnjijmnnjgfimswxxwttttsqlijlqturnkjlnqokjiijmljhgghkllifglqvyvplklnppmkjjmprrqonmmmljfeehlpqnjedehiigfegilmjgedfilljfdfkorqnhfgkmolgfgkrxyxvsqqrrplhfhkorplhghknmjhffhllkihghkmmjfdeiottqmjjmopojffgkqtuusqppomjfdfkpssojgghjljghijlomkhfegikkgddfjnpnjgfhkmmjgghmsvwvtrqponkgefimrrplhilpqpkhfgilkifedgjmljfdejpsrmighjlnjhhilqstsqnmllkiedeinsutpkihhjihhijlnmkfdbbdghfcbdhmqolgccfhigcbbejprrpnlkkkiebbdhmpokhfgjlkgfdehlmljgeegjkhcbchnsrnieegjlkgeegkprrpnlkjjhfcceinqqnifefhihfghkmnlifefgjmmjiikortsqonnoppnmlkkmmnnnnooqqqnmlmpstrnlmoruurpnlllkjihhjkmmjiiknsvvtrqpqsttrqonnoqsuvwwwvvvutsstttromlllljhgfgjnqtxyyyyyzz0124567888765433210zzyyyyyxwutsrqpqpqrrrrrrrrqqponmkigecaZXWVUTSRQPOOOONLJHFEDDDEEFFFEEEEEFGGHHHGGFEDDDDEEEEDDDDDDCCCCCCCCCCCBBBBCCCCCDDDEDDCCCCCCBBBBBBBBBBCBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBCBBCCCCCCBBBCCCDEEEDCBBBBBBCDDDDCBBBBAAAAAAAAAAAAAAAABBCCCCBBBBAAAAABBBCCCCDDDEEEEEFEDDCCBBCCCCDDEFFFEDCBBBBCDDEFGGGGGGGFFFGGGGGGFFFFFFFFGGGGGGFFFFFGGGHIIJKLMNOOPOPPRSUVVVUUVWXYacehjmqtx035789++///////////////////////////////////////////////////ymZ]], + note = [[BBBBBCIIGBBIIIIIIIHHBAFCCKKKCCCBBBIHHKKKKJJBBJJJIIIIIIIIJJJJJJJJIIJJKJJJJHJJJJJKKKKKKKKKKKKKKKKJCCCCCCCCCCKJKKKKKKKKJJJJJJKJJJJJJKCCCKKJJIILLLLCLLLCCLLLLLLLHHLLHGJIIHHCCCEEEELLEEEEEEEEEEEEEEEEEEEEEEEEEEJJCJJDEEEEEEEKKEEKKKCCEEEEEEEECCCCEELIIICCCCCCCCIICCIICLKCCCCJDDDJJJDDBDDKJKKKKKKKKKKKIIHJJKKKCCIIEECCCIIEEEEEEEEEEEEEIIEEEEEEEEJJJCCCCEEEEEEEKKKCCECDDDEEEEEELLLLLLLEELLLLLLLCCCILLLLLKKKKKKKDDDCCCHHHHHCCCCCCCCCHHHHHHHHJJHHDDDCCCCELGGGIICCBBEEEEEEILDEEEEEEEECCCCCCCDEEEEEKKKKEEECCCCCEEEEEEDCCBBBLCCCCCCCCLLLLILLLLCHHHCCCCCCCCCFFFCCCCCHHHHCCCCCCCCCCCCCCCCCEEEEEECCCEEELLLLEEEEEEELEEEEEEELLCCCCCCCELEDDKKKKKKKCEDDDCEEEEECCCIICCCCCCCCCCCCCCCIICIIICCAAAADJJJBCCCCCCCCCCCCCHHHHHHHHGGFEDDDCHEEEEEEEEECCJJJDDEEEEEEEEEEEEEELLCCCCCCDEEEELLLKKDEEEDCCDEEELLLLLIIIEECIIJJJJJJJJJILIIIIDDCIEDCCCJJJJBCCKKJJKKKKKIIGCBFKKKKKKKKKBIIIIIIJJCCCCCCCCEEEEEEEEEEEEEEEELJJJJJJEEECCLKKKCKKAACEDCCEEEELLLDDJIEDDCCCCCCCCCCCCCCCBBBCKKKCCCBAALLLLLLLLLLLLLLLLLLLLLLLGGFFEECCCLLLEEECCCCCCCEEEEEEEEEEEEEEEEECCCCCCEEECCKKKKKKKDDDDLLEEEEEEIIIIIJJJKKCCIIIIJJJJIIIIJJJJCIIICEEEEEEEJJJJJLLLLKKKJJJJJJJHHHHHHHEEEEEEEJJJJJJFLLLLLLLLLLKJJJJJJJJJKKLLLLLLLKKKKKKJAALJJLLLEEELLLJJJJJJJJLLJJJJJJCCCCCCHHIIIIILLLHHHHHHHLLLLLLCCCCCCLLLLLLHGGFEEECAAAALLAAAGGGCCGLAEEEEEJLEEEEEEEEDCCCCCEELLJELKKJJJLLLJJJJEEEEEEDDDJJJJJJJJJKKKKKKKJJJJJJJHHHHHHHHHHHHJJJJJJJJJJJJJJJJJJJJHHHHHHHHEEEEEEEEEEEEEEEEEFFFFFEEEEEEFFFFFEEEEEEEFFFEEEEEEEFFFFFEEEEEEFFFFFEEEEEEFFFFFEEEEEEEFFGFEEEEEEFFFFFEEEEEELLLLLLLLLLLLHHHHLHHHHHIIIIIIIIICCCCCCCCCCEEEEEELEEEEEEEEECCCCCDEEEEEKKKLABBHHCDDEEEELLCCCLLLLCLLCCCCCCCCCCCCCCCCIIHLLJJLLHHHHHJJKKKLLLLKKKKJJJJJJJHHHCCCCHJCCJJJJJJJJKKLLLLLEEEKKKJJJJJJJJKKKLLLLLEKKKKKKJJJKKKCCCEEEEEEELLLJJJCCCCCCCCCCCCCCCCCJJLLLCDHHHHHHHCCCLLLLCCCCCLCHHHHHGGFFEDDGGEEELLGGGGCCJJJCEEEEEEEEEEEEEEEEECCCCCDLLLEEKKKKBBEEECDCEEEEEEEEEEEEEFFFCCCCKKKKKKKJJJJJJJHHHHHHHHHHHHJJJJHJJJJJJJJJJJJJJJHHHHHHHEEEEEEEEEEEEEEEEEEFFFEEEEEEEFFFFEEEEEEEFFFEEEEEEEFFFFFEEEEEEFFFFEEEEEEFFFFEEEEEEEFFFFEEEEEEEEEEEEEEEEEEEEEHHHLLLEEEEEEEEFFFFEEEEEEFFFEEEEEEEFFFEEEEEEEEDCEHHLLLLECCCCDEELLCLEKKKKLLLLLEEDEEEEEELCGEILJCCCCCCCCCCCCCCCCCCJJJJEEDHHHHHHHHHHHCCCCCCCHHHHHHGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFFFEEEEEFFFFFEEEEEEFFFFEEEEEFFFFFEEEEEEFFFEEEEEEEEEEEEEEEEEECCCCCEEEEEEEEEFFFEEEEEEFFFFEEEEEEEEEEEEEEEDDCCEEEEEEEFCCCCCCCDCCCCCCKKKFFFCLEEEEEEEEELLLIIICEECCJJJJJJJJJJJJJJJJEEEJJJJJJJJJJJJJJJJJJJJJJJJEEEJHHHHHHHHEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEKKKKKEEEEJJJJJJJJJJJJKKKLLLLGGCCCCCCCJJCCCFFFFFFGGGGGFFGGGFFKKFFFKKFFFFKJJJJKKHHHHHHHIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEKKKLEEIIIICEEEEEEEEECCCECCEEJJJJJJJJJJJJJCEEEEEEEEEECCCCLLLLHCCCCCCLLLLLLLLHHCLEILLLLLHHHHHHHHCCCHHHHHHHCCCHHHHHHHHHHHHIIIIHHHEEEEEEEEEEIDEEEEEEEELIIIIIIIIICCCCCCCCCCCCCCEEEEEEEELLELEEEEEEHHHHCCCEEEEEEEEEEHHEEEHHIIHCHHHHCCCCCCCCHHHHHHHHCLLLEEEEECCCCCLEEEEIKKEEEEEIIKEEEEEEEEEEEIIIIIEECCCCCCCCICCCCCCEEEEEEEIIILLEEEEEIHHHHHHIIEEEEEEIIIIIIIIHHHLLCCCHCCCCCCHHHHHHHHHHHHHHHHHHHHHIIIIIHHHHEKCEEEEEHHCCEEEEEEEEEIIIHHIIICCCCCCCCCCCIIEEEEEEEEEEEKKKELLLHHHHHHHLLLLLLLLLEEEELIIIIHHHHHHICCCCCCHHHHHHHHHIEEEEEEEEEECCCDEEEEEEEKKKIIIILLLLLEEEEELLLIIIIICCCCCKKKKKKKKKJJJJJHHHHHHHCHHHHHFFFHLLLGCCCKKJJJJJCCCHHHHHCCHHHHHEEJJJJEEEFGGGGGGGGLLLLLGGLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLEEEEEEEEEELLLLLLLLLLLLLLLLLLLLEEEEELLLLLLLLLLLLLLLHHHHEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEECCCCCCCHHHHHHHHHHCCCCCCCCCEEEEEEEEEEEEEEEECCCCCCCCLLLCLLCCCCCCLLLLLLLLLLLLHHHHHLHHHHHLLLLLLLLLLLLLEEELLHHHLLHHHHHLLLLLCCCHHLLHLLLLEEEEEHLLLLLLHHHHHCCCCCCCHHHLHHHHHHHHHHHHHHHCCHHHCCCCCCLLLLLLLLLJJJICCLHHCCHHHLJJCCCCCCCEEEEEEELEEEEEEEECCCCCCCEEEELKKKLLLIIBBFEEEEEELLLJCCCCCCCCCCCCCCCJJCCCCCCCCCCCCCCHHCCHHHHHHHCHHCCJJEEEEEEDCCCCJJJEEEEEEEEEEECDDIIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEHHHHHEEEEEEEEEEEEEEEEEEJBEEJJJJEFFEJJJJJJJJKKJJJJJJJJJJJJJJEEEJJJJKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJEEEEEEEECCCCCCCCEEJJJJJJJEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEELEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEECCJJJJJCCEEEEEGGGGGGGGGGGGGGJJJJJJJJJJJCCCCCCCLLLLCCCJJJJJJJHHHHHHHECCJJJCCCCCCCCCKKKJJJJHHHHHHHHHHEEEEEEEDJJJJJJJKLLLLLLLGLLLCCCLLLLLLLLLLLLLLLLLLLLLLLLLLLLLGGGLGGGGGGGLLLLGGLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLCCCCCCCLEJJJJGGCCLLLLLLLLLEEELLLLCCLLLLLCLLLLLLLCLLLLLLELLLLJCCCCCCHHHHHJJJJJJJJJJJJJJJJJJJJJJJJJJJJJEEEJJJJJJJJJJJJJJJJJJJJLLEEEEIIIIIIIIEEEEEIIIIIIIIIEEEEEEEIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEELLLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEELLLLEEEEEEEEEEEEEECCCCCCCCCEEEEEEEEECCCEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEJJCCCCCEEEEEEEEEEEEEECCCLLLCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCEEEEJJJJCCCCCJJJCCEEEECCCCCCCCCCCLLLLLLLLEEEEEEEEEEEEEEEIIEIIIIIIIIIIIIIIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEECCCCCJEEEEEEEEEEEJJJJJEEEEEEEJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJEEEEEEEELLLGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGLLLGGGGGGGLGGGGGGLGGGGGGGGGGGGGGGGGGGGGGGGHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGCCCGGCGGGCCEEEEEECCBCCCCCCJJJJCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCJCCEEEEEEECIEEEEEEEGBBGGGGGGGGGGGGGGGGGGGGGGGBBBBBBBBBBBGHHHHHHHHHHHCCHHHHCCCHHHHCCCHHEEELJJJJJJJKKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLHLLEEJJKKKLLLLLLLLLLLLLLLLLLLLCKKJJJJJJCCCHHEEEJJJEEJJJJJJJJJJJJKFFKJJJJJJJJKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJCCCJJJCCCJJJJJJJCCCCCCCCGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGBBBGGGGBBBBBBBGGGGGGGGGGGGGBBBBHHHHHHLLLEEEEEEEEEEEEEEEEEEEEEEEFEEEEEEEEFFFFEEEEEEEEEEEEEEEEEEGGGGGGGGHHHHHHHHHHHHCHHHHHHHHHHHHHHHHHHHHHHHHHHHHJJJJJJJJJJJJJHHHHHHHCCCCHHHHHEEJJJJEELLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLHHLLLLLLLLLLLLLLLLLLLJJJJJJJJJJJJJJJJJJJGJJJJJJJJJJJJJJJJJJJJJJJBBJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGGGJJJJJJGJJGGGJJJJJGEEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHEEEEEHHHHHHHHHHHHHHHHEEEEHHHHHHHHHHHHHHHHHHEHHHHHHHHHHHHHHHHHHHHLHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGEGGGGGGGGGGGGGGGGGGGGGGECCHHHHHHHHHHHCCLHHECCLLLLLLLHHHHHHHHHHEEEEEEEEEEEELEEEEEEEELLEEEEEEEELEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEHEEEELLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEELLHHHHHEEEEEEEEEEJJJJJJJJJJJJJJJJJJKKEEJJJJJJKKKJJJJJJJJKJJJJJJJJJJKJJJJJJJJKKKJJJJJJJJJJJJJJJHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHCCCCCCHHHHHCCCCCCCCCCCCCCCCCCCCCCJJJLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLALLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLAALLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLCCCCKKKKKKJJJJJJJCHHHHHHHCCHHHCCCCJJKKKKKKLLLLLLFFKJJJJKKKKKKKLLLLLLLLLLLLLLLLLLLLLLLLLLLGLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKJJJJLLLLCLLLLLJCCCCLLLLLLKKKKKKJJJJECCCCHHCLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFEEEEEEFFFFEEEEEEFFFEEEEEEFFFFEEEEEEFFFEEEEEEEEEEEEEEEEEEEEEEEHCHHCCHHHHHHHHHHHHHCCHIIIIIIIIIIIICCCCCCEEEEEEEEEEEEEEEEJJCCCCIEEEEEECCEEEEECEEEEEEDDDDDDDLLJJJJCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCLLLLLLKKKJJJJJJHCCCCLLLLEHHHEJJLLLLLLLLEEEEEEEJJJJJJJJKKKKKKKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLAALLLLLLLLALLLLLLLLLLLLKLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKLEEEEEEEEEEEEEEEELLLLLLLCCCKJJJJJJCCCCCCJJCCCCCCJJJJJKKCCCCHHHHCLLHHHCCCLEEEEEEEEEEEEEEEEEEEFFEEEEEEEFFFFEEEEEFFFFFEEEEFFFFFFEEEEEFFFFEEEEEEFFFEEEEEEFFFFFEEEEEEEEEEEEECCCCCCCCCCCCCEEEEEEEEEEEEEEEEEEEEEEEEEEEFFEEEEEEEEEDDEEEEELLLLCCCECCCCJJJJJJJJJJCCCCCEEEEEDDCCCCCCCCCCCCCCCCCCCCJJJJCCJJCCCCCCCCCCCCCCCCCCCCEDDDDDEEDKKKKKKKEDDDDDLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFEEEEEEEEFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEECCCCEEEEEEEEEEEELLLLLLEEELLLLLLLEEEEEEEDDCCCIEEEEEEEEJJJJCCJCCCEEJEEEECCCCCEEEJJJJEEEJJJJJJJJJJJJBBJJCCCCLLBEEJJJJJJCCCCCCJJFGGKKKKKKKKJKKCCCCCCCCCEEEEEEEEEEEEEEEEEEEEFFFEEEEEEEEFFFEEEEEEEEEIIIIECCCCCCEEFFFIKFLLLLLLLLLLLLLLLGGGLLLLLKKKKKKKFFCCCCCCCFFLLLLLKKKFFFFEECCCCCCCCEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEELEEEEEEIIIIECCCCCIIIIIIIIICICCJJJCCCHHHHCCCCCCCCCIIEEIICCCCCCCCIILLLLCCCEEEIIIIIICCCCCCCCEEEIIICCCCCCCCIIIIEEEEEEEEIIIIEIIEEEIIIIIIEIIIICCCCCIIIIIIIIIIIIIIIIICCCCCCCCCCLLLCIIIIIIIICCCCCCCCILLLCCCCCIIEEIIIICCCCCCCIIIIIIIIIJJJJCIIEEEEEEEEEEEEEEEEJJCCCIIEEEEEIIEEEEEJJIIIIEEEIIIIIIEEIICCCLLCCCCCCCCCCCFEEEEEEJCCCCCJJIILLLLCCCIEEEEECCCCCCCCCCEEEEEEECCCCCCCEEEEEEEEEEEEEEIIIEEIIIIIIIIIIIIIEECCCCCEEEEEEEEECCEEEEEFLLCCCCCJFFHHHCEEEEEEECHCCCCCCEELHHHCCCCEEEEEEEJCCCCCCCEEEEEIIICCCCCCCCIIIEEEEEEEEEEECCCCCCEEEEEEEEEECCCCCCCEEEEEEEDCCJJJCJJLLLLLLLLLFFFJJJJLLLLLLLLLCCCCCCCLLLLLLLLCCCFJJECCCHHHHHEEEEEEJJELKKKKHHHHHHHHLLHHHHKKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLHLLLLLLLLLLLLLLLLLGGGLLLLLLLLLLLLLLLLLLLLLLCCHHHHHLLLLLHHHJJJJJJJJJJJJJJJJJJJJJJJJJJJJJEFKKKKFFFKKKKKKKKKJJJJEFFKKEJEEEEEEKKJEJJJJJJEEJJJJJJJJKKKJJJJJJJJJJJJJJJJJJJJJJJCCJJEEEEEIEECCIIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEELLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEJJJJEEEEECCCCJJJJJJJJCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCFLLLLLLKKKJJJJJCCHCCLLLLLHHHHCCLLLLCCCCCJJJJJJHHLHHHHHCCCCCCCCLFFIILLCCHHHHEEELLLLLFLLDDDDLGDGGLLLLLLLLLLDDLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLGGGGLLGGGLLGLLLLLLLLJJJJJJJJJJJJEEEEEEEJJJJJJJJBBBEEEEEEEJBEJJJJJJEEEEEJJEJJJJJJEEEJJJJJJJELLLLLGGGLLLLLLLLLGLLLLLLLLLLLLLGGLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEECCCCCCCCCEEEEECJJJJJJCCCHCCCCCCCJJJCJJJJJJJJJJACCCCCCCCCCCCCLCCCLLCCCCCCCCCCLLLLLLLCCFJEECCCCCCCCCLCCCCCCCCCCCFLLLLFFJJJJKKCHLLLLCCCCCCCCCCFKKKKLCCCCCCCCCCEEEFFFLLJJLLLLLLLJGGGLLGLLLLJDDLLLLLLLLLLLLLLLLLLLLLLLLLLLLGGGGGLLLLGLLLLLLLLLLLLLLLLLLLLLLLLCCCCLLLLLLLLLLJJGGJBBJJBBJJBBBBBJJJJJBBJJJJJJJJJJJJJJJJJJJJJJJJJEEJJJJJJJJJJJJBBEEEJJJJJJJJJJJJCCCCCCCCCCCJJCCCCCCCJLLLLLLJJJJJJJJJJJJJJJGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGEEEEGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHHHHGGGGHHHHHHHGGGGHHHHHHHHGGGGGGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJJGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGJJJGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJCCCCCCCCCCCCCCCEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEELEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEECCCEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEECCCCCCDDCDDDCDCCCCCCDCHCCGDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLEELLLLEEEEELLEEEEEELLLLLLLLLEEELELLLLLEELLLELLLLLEEEEEEEEEEEEEEEEEJJJJJEEEEEEEEEEEEEJEEEEEEEEJJJEEJJJEEJJEEEEEEEEEEEEEEEEEEEEEEEEEEEEJEEEJJJEJJJJJGCCCCCCCCCCCCCCCCCCCCCCCCJCCCCCCLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGCGGGGGJJJGGGCCFFFFFFFFFFFFFFFFCCCGGGFCCGGGCCHHHHHHHHHHHHHHHHHHHHHHEEEHHHHHHHHHHHHHHHEEEEHHHHHHHCHHHHHHHHHHHHLLCCHHHHHHHHHEEHHHHHLLLHHHHHHHEEEEEEEEEHHHHEEELLLLEEEEEHEEHLLLLLLLLLLEEEEEEHHHHHEEEEEEEELHEEEEEEEEEEEEEEELLLEEEEEEEEELLEEEEEHEEEEEEEEEEEEEEEEEEEEEEHEEELLLLLLLKKKKKJJJJHHHHHHHLLEEEEEEEEEEEELLLEELLLLLEEEEEEKKLLLLLLLLLLLLLLLLLLLLLLLLLLGGGGGGGLLLLLLGGGLLLLGLLLLLLLLLLLLLLLGLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLCLLLLLLLLLGGGGGLLLLLLGJCCCCCCCCCLLLGGGGJJJCCCCCCCCCCKKKKKKKKJJJJJJJJJHHHHCEEEEEEEEEEEEEEEEEEEEEEEEELLLLLEEEEEEEEELLLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFLEEHHHHHHHHHHHHHHHHEEEEEEEEEEEEEEEEEHEEEEELLLLEHHHHHEEEEEEELEEEEELHHEEEELLLEEEEEEEELLLLEELLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEELLKKKKKEJJJJJEHHHHHHEEEEEEEEJJJJKKKKKEEEECJJJJJJKKKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKCCLLGGGGLLGGLGGLLLLLLGJJJJBBGLLEEEEECCGJJJJJJKKKKKKKKFKKJJJJJHHHHHHHJJJEEGGJJJJJJJJJJJJJJEHHHHHHHHEEEEEEEEEEELLLLLEEEELLLFEEEEEEEEEEFEELLEEEEEFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEELEEEEEEEEELEEEEELLHHHHHLEEEEEEEFELLLLLLLFFEEEEEELEEEEEEEEEEEEEEEEEEEEEEEELEEEEELLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEHHAAAACCHHAEEEECCCCCCCCCLEEEEEEELCCCCCLLEEEELLLEELLLEEEEEELLEEEEELLLEEELLLEEEEEEFFEEEEEEEHFFEEEEEEEEHHHHHHHHEEEEEEEEEEEELLLLHHHHHHHHLLLLEEEEEEEELLLLLLLEEEEEEEEEEEEEEECCCJGGGJJGGGGGBGGGGGGGGGGGGGJJJJGGGGEEEGGGGGGGGGGCCCCJJGGGGGGGGGJJJEEEJJGGGGGGGGGKKKKGCCKKHJJJJJJHHHHHHHHHHHHHHLLEELLLLLLLLLLLCLLLLEEEEEEEEEEEEEELLEEEEEEEHHHELLLELLLLLELLLLLLLLLLLLEEEEEELLLEEIIIIILEEEEEELLLLLLLLLLLLLEEELLLLLLLLLCEELLEEHHEELHLLLELLLLLLEEELLLLLLLLEEEELLLLLLLEEEEEEEEELLLLLLLLHHLLLLLLLLLEELLHHEEHIIEEEEEEEEEEELEELLLLLLLLEEELLEEEEEEEEEEEHCEIIIELLLLLLHHLLLLIILLLIIIIIIIEEEEILLLEEEEIILLLLLLLLLLLLLLHHHLLLLLLLELLLEELLHHHLLLLLEEELIEEEEEELCCHLCCCCLLLLLLELLCCCCCHLJJJJJJJJJGGGGGGJGGGGEEEGKEEEEEIEIIJJJJJJEEEEEGGGJJJJJJJJJEEEGGGGJJJJJCEEEEEEEGGGGGGGGGGJJJJJJEEEJJJJJGCLLLCGGGEEEEECCCCCGGLLLCEELLEEEHEEHHEEEEEEEEEEEEELLLLEEEEEEEEEELLLEEEELLLLCCCCEEEELLLLLLEEECEEEEEELLLLEEEEEEEEEEEEEEEEEEJJJLLLLEEEEEEEEEEEECECCCCEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEHHEEEEEBBEFEEEEEEEEECCCLHHEEEHEELLEEJLLLLKFEEEJJEEHHHCCCHHJJJJCEELLIIIIEEEEELLLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEELLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFEEEEEEEEEEFEEEEEEEEEEEEEEEEEEEEEEEFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFFEEEEEEEEFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEELLDDDDDDADDCCCDDEEDDAADDBGDDDCDDKDDDDDDKDKDDDCCDDDJE]], + noteClear = [[AAACBAAAADECEHJMMOKHIEAAAEFAEIEDEDAAAACEEAAAAABAAABAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHMVVUUUTRRXZUUUZVIHAAACDACAABEAAABIXXTLIAAQYfgXCABKRhmbSGCAADPQGAHGFJKFACAAAAAAAAAFKKIFCAAABAAAAAAAACCAAAAAAAAABCAAAAAAAAAAAAAAAAAAAAACHNPOKJEDDAAAAAAAAAAAAAAAAAAAAAAAAAAAIQjnRCAACQZpolQEAEPSTLBBBEGHCACCAAAAAAAABRUULGEDBAAAAAAAAGIHECAAAADGHFCAAAAAAAAAAAAAAMPNLNRRPSWVUSPTUXXXSLEEAACGCAAAAAAAAAAAAAABAEMWRAAAAARbpmXPFGJUZZYFAACDCAEGGAAAAAAAAAKROIBAAAAABAAADCBAAAAAACBAAACCADEAAAAAAAAAAAAABCEDBCGLKELahtvvXJAAAABCAAAHNSQLAAABDBBABAAMUbYPAABIPdeWOAABIRdbDAAAAAADFFBAAAAAEGFCBMPNHCBACAAADGUXSHLXaYWTJEDABAAAAAAAAAAAAAAAABESXVTQNKJIKJPTXVPFCCAILKAAAAAAAABAAAAABAAANXnmfHAINWZRJCAADIUVSEDCAAAAACFBAAAAAAABGNMMKICAAAAAAAAACIJKHHKKCAAFGAAAAAAAAAAAAAAAAAAAAAAADDAAAAAAAAAFJLEAAAAAAEGDAAAAAAAACEDAAEKZZbWEGNdigcKBAJRYWMEHIGAAAAAAAAAAAAAABCMQTQPLGAAACAAAAAIOQOGDAAAAABAAAAAAAAAAAAAAAIRSQOXZXZaWVXacaacbURKLNGEMKACAAAAABDBFFBAFEGOfmmXNADRYbbaLHAALRXYKFEAAAAECAAAAAAAAAAADFIIBAGIIBAAACBEFMSQHFDFFABECAAAAAAAAAACDHHBALSVKCFMNKdopnv24zqePbopmfVIYomcTAAALTVPBIPRMBAAAAAAMUachkmleROXbdRJBAAADDDAAAAAAAAAAAAAABAAAABACEAABCNPQPMDFDAAAAAAAAAAAAADJQTRMFMOWWSPOPNOOKLOONNLFDFBCGCAAAAAAABAAAAAAAAAAARaTJAADKRccQJAACJNVUAAAAAAAFFAAAAAAAECAEIMLLGBBBAAEGGGJYTaabix47s1yutogOi672xoTPRQNQjhflntqlou5767//+0oKXjnssoNS3//////zw35+///4rzzvjyxz45us101q485//4qgruy+////vx689wnxwz0vm089wz/////qxswzq2////5620st7+//+x+4tmn7/qYGOWdgfeVTUVUPRTRLKKVXcgdoqbREKGAAAAGJMNQLAHPedKAADLcgaODCAJPaaHAABEDAACDAAAAAAAAAAHOMFFGCABDEAACGDEPSTTSMHJKEFFAAAAAAAABDCIPZPEAACFDDYfhinohnqt1yZKXaaYZTOAABDIOOQZmkbts78hUJPLADHEVcjqsyxjhmdjlWFGCCDIKLJBCBEDAAAAAGLQTOGAAAADCJPUVWadeilnkeSPHAAAAAAAAACFKNTTKJHLOTUSTROLJJIHJMNVXHGGGEBAAAAAAAAAAABBAAAAMTggYPEBGUYWRLBAFKQOEAABAAAAAAAAAAAAAAAAFXhpstmdJJGDCGEBJQNKSWekwvqx152fQclpvucTKMRQONSVTKPYegnrtvx2362gTXglrsodZr6////3umqu03/+wmfz1z9////8w8//0+///6tmjqx6////5v7//z5zz1xl0481x////1//240+////3///7////////////uokcRLNUUJMORUQRddegjjfjrsmu1653nezzs5/2xsmdigis32pebVUJDFIOUTBABEHDAAABAAABEHFBAAAAAAAAACHMNKAAAAAAAEIFEXdebZXWNIECDBAEFDAAAAGMRUXXUIAAEFIPZaZXPYdZWJAPXhw0890scVRQQGEJKIEHSanonnonnmmjigijmnnmkjjmmllklnsphrxqfpsw0rr331pp564zpy3xmy3zlfox54w7///zrw1vx7////81149//seebXRUPOMThz38/9shvzjt46873oyxll6/73uolnox43vbSLGAFLYaYRJAAIKVWTHAABAAAAAAAAAAAAAAAAKNPRPHFAAAAABAACFKTWSLLFDABDPRNLQYYXdnqicWKLTRQUaecYWTVYVUTVVRHIRYYbdWJVooklpqonmopstsqorwyxnlkikqu372vqps1230ueXKGCEFBAAACBFFCGMVYfjleVYUMOPMGFDKPaddTPNLKJHAEIPgjWiodSSSLQONOILWXVXXabZXLOUbXMKIQWdfgdILSUWZYXYWZekibXYfmpokieekmmjjmmbZamt52mheaUAAAAAAAAACAAAKbeWQIFAAAAAAAACMacVRONLLKEBAAJPVZZVSEDABDGEFHGEHNTacZTLQSTUURKCBAAAAKNOPNUYaYTFAAACAAEJMMKIHKLNNPRSRSVYVSQRUPHDCDFFCADEBABCAAAJRYVPMHAABBCGHAAAESVUQPPNJKLKHAALRWYYOEAAAAAABDCAFPOLLMFAUYXTUTQAAAAAAACAAEEFIXaRJPGDEDADGJKNQWVIGIPPMLIFACDDDAAAAAAAABAABBAAAAAGMRTRPNFAABDFDAAAABMNHGFCADEEEECBRYebQKDIHAAABDFGFIWYXXXMLSUWWOIFAAACBAAAAABDDIFEAAILJCGNPUWXYZYYabeeijkeaYYYcfYOHDBBAAAAAABAAAAAHOWVVWSJEFHGGHDECADEGGFCAAAAAAAFUXXVRCEEDAAABGGFHOPMPSQQVXURLJHCEEDAAABCCLNLMKDAACDBAAAEGIKJIJGCRYdedbZRLEMPKEKJICAAACDAAEEAAAAAAFHJKIGEBDMQROAAAAFFHLMSdgZTdbTPMHPZaaYULGKOSJIHEABKICDJOPKLNNNEOVTQRQQQQKACDBAAAIJIFFIGCGNPWXWJDABEFEFFIILNTUUNIJNTTSRTcfmnmnpnjYWUTRMLMMJLNQRQONNLGFJLLOUYbffaYVUVWWYYTPTUVVVUTXUQMMOPOMKNONRQJLPSaelomjktwwtbTPPRUWcgediuurmZYaijjifcVTUdeebROMKIHGHJJLNRTQGGMSUROONRVYYZZdcONYpoifaWTNSWYhigbaZabehcUPSPPPRRPQUTPOOKKKJLLNQSTUdfecaRORSVVWVUQMLLNSWYXUTOORSNEGKKIHJKGEEHJMMFJMMJGGHHHHMTSPLJCHRRQFGFHMPPPQTPKGSUUNKNOMMMOTSNNPQRTabUNQUWTQKHFEJMOOMIJMNNLLKIACBACBDCCAAAGGABAAEFEGHAAFTbfcHAEMTWVUPABGTacZECDFEAAAAAAAAAAAAAAKQMHEFAAAAAEFJIIQNNRUTPEFADCBAAAAAABGGFQRUWWYUOKFGFCABCABFJNNMAABEHIMNLDJTWUPFCBBAAAAACJMQOKHGGJRUVVWUUVUXbhknokaYZYVTSUVabbbeeYYchknsslgcbafkomeZWWVWbjmpqsqmbZaglqsz2rmfchy34216+/7z1zxxwy6+/7vwz48//yqjdcPGDDDDJRTGJYdgecYZbZYcfgdWVJKLMQVZZVORSQSahlieZXaYVXZZZdebXTNNXYghfbdbWbbjpttrrssqmcZiouvxtpmjgknleYcebVUXZYaeghZOQXXeilkfIKNQRRRQNBIIHGFFGGLQabaXYZaYXUTSPNOPTWZVPKSdegjkieWUSTYhhccgfeZVaceefffggaWZaafjkibZZfjnnosvsneejjhgddffaWdksuuvuqgYRQWljWTRRSVajhddgpxpeRPRXbjlgbbmsxwgTHKLDDDHIKMPQNLADEIHIIIPegfZWUTQMJJKMLLLKKKJJIHEAADCGJLIDKHCGHHGHGFPegfdWAAAAGICAAAAAEMPSOILMLIHTVehiiicPAEKLIEAAACGKJHCAMQTURPLHGIJNNKKQTRNOSTVVTLLOQQRSRPONPXaVSOQUVVTWYYWSONQQNIIIJPcfiidgnqoebbeinmjiVNLMNPSMJPTVVUSQKIIOQRSPMIKLPQLHECBCEDECDEKPUUPLJNRYXPHKMLHGMTVPGIMTUSJJJKKJGIMFACEGGDCCCDJJOPNJCLQXXVUUSSXYZXSQRYbffdZVSWcbWWaZWYchgffcXWZaZabYUPMHGDDEFFDEHIJGIOPKNPOLGGJKPTVUPQQSUXTMHJTWZacbYZcfhkkiZWTVXfhnmcabdfbXOPTVYhjiidWWYZYZZZZYXaenrvvusrqojjnljebSUUPKLNMJNQQOOSUOKFGIKIIGFFFHIKKMQNLKMNKGHKMRUcgkkmttofQOLLMTYhgedbioureaWTWXXdcPJNSVXRAAENPONLGCCDDCCABACORONHFGECBFMJAAACDKNJHLRTWWUQGGFFGHHDCHFDDDEDCFHKIKMJHDJMMMLLHABEILLJCEHJNOOMHIOQPNLLLKNRYYSONKMOVijmmhWUVWYaZSYffgjnkjfedcaXVUXXXYZbjnstsqoprtvzz07+4vmllotwoaTMRYllYYgjkfcWOABEDCDEOSbcXIHIGGGGPRSQPOUVURQWbijkfcdggdegheaTRSSTWZjoplijprnjeUTWYWadlptwwsqhdhz00zwtmkjeiqv10z48///+tompu12ofbddYYaaUSRLLKJGCAFHGJMNLFIJJNOQPMLMQQSUUSRQRQRUWUNMMNMIHIKSXcXRJHJKTXabYPPTPRVVPQYZXXcnonjeiy2ymigdWXVTZntvqngbVSdjtx34sYSMLMRMAAAAAADIDHHEGJOLCDEEEGIJOOLSUTSUQRXbdijgcWWXcecYXYZZbmoieZZadgcbbZWUSPRPNJPSROFBAAANVffOCGJNTYSPQPNLMQSWZbcaXWTSVUSXaaXKKOPOLGACGIMQRZbUPMHIIKIECFCEHLMNLJHEBEAAAHKMOLFJKNXYaaYXWOLJKNQVVUSSUTNLLPSYXWbgdXWbfghhffiprutrlhikw22pjopgfjrqooYNEDEEINPNVXqrkheZQNLFEFMhnnheTMFEEQXXSNJKNNOLJPSZfbXPRRQQUXVVTROKLNNHHSXZddVQOQPUYfehjnrvxukffjmprxvsuwus03449//992ynjkqrw02013440cVRMLMNSVPMLKMQRNLOMLWbknjbQKKILVZadgffecTRUbceaMLWYYYZbceeefgmrqkgbceeijhhimowzogcegijiiieaZZbehhigikjcccdfmliiaWVRQQWgjjggbbdbbaYYaccdcYTUTUTRMOSTTXacaZOMQQNKECEPTRNMGEGFRXeebWbggedcimttqpmgdWVdemsxxueVnoknlfbehidZWWXZcccRHKRZbcidKHcifegigffaXVTUUUVWXfjlhhmuuuwvrqssphdaaMNUVVWVTTRRRSRSWcefYPIJHDFJMLIAAFJLHHDNaaZWURRSTVRONONMLORZbbaURRPPSWefaXWZaTNSXbdfdbaYTRQRSWWPKJQTTTTSQQSXZaXTUWZYTNHKLOPPQRPMLKLLLLKIGECHIKPROMKJHJPSSQRUURMICLSTRQPOPPOOPPOMMNMGJRXXRJHHKLJLSQJHJJIJIEEHHIOONOPNQSUWYYWVUSGELORTVbgllaPHLSbcgljbQOSXXTOMPUbYQTZabaZTOEFDFFHINOMMNJJIJNOOHDDDJNQQPQRUVTQPQQPPOMJMTXVRQSRPQQRRQPQRQLIEGKHFLONOPONQSVVTVWTPVULEIJMRROOMKKKLMNTUTNMPUWUUUSMMPQSTVbbXVPGFMNOOOPPRTSSUTTTVbZUTICCFHLOPQQPPWYUTUUUSRIGRWVUWcdbXNJKNRUUaccVNEKSTSQPTVWURQQQQTURMAAGKJIJLLNTUTUUTSRRMJDACCDBADDDCBEFEDAABAABCCAAAAEECCCEIIHGFEBAACKNOPONMLKIJLMMLKJLKJLMMOQRRTUUQQTUPRWXWYYYZUQOUXZXaddaXadaZbeeYVSRRRQRQTRPQTWYbccaXYbbbWSTWYaZYXVVYYYdfghdbYQNDGMOONNJLRSRRTVVPRUVUTSSWfjlcYYYVRGDFHNTYkomZeeXWemoomjbXaipvx233xnto5/////4tzto5/////856+/+ykGRhkmopqpkjgYZgifddgjmnrqgXOdjjeSQMNQVYbZUTVdgYNELRVVTSSSZeffdZYWSOPRSTRSUUTPQSQJKNQSWUYaXOPTTMNRWafhijqppruwwkZNDEGEDOksutsy0tqoqqkjjjlongcefaUSbhnnuxxlgejvz0rmjhihz1y0286wkbejeciiWUUUalkijhbWRRaccefieOSUSQSRWZbcbPMSUYceheXXejqrqcWRUVRNMNPPPOMLJKJKOQTSGCMRVUXaYOJJLRQKABHGLMPWQAAIKQSMAAIMSTUXQGDFFEAABCFDGKMMMJMLIHGCAACELUVQWehgecTRUZcdehhbYVUVZdigbdgdemlcZWWZhjgcdgddglkimy1311upjnrsqnnoqoprusjetwwopz1unruxxtqqjgiu24zx386014yrptvrmmstojov0ukormhv42xv08//86///36///779////2ux00294149///zbbfeinnfVTURIMMKIPTTTSSVRDEKQRDEMRVWUOPRSSOMZaLCKPPPSPLILRXYZaifchhaZjszyz31ww693ytmkhekqx4353nbbekpr1viljdbvyuqkXeaYqvyuom17ygjnnkeiqlex6///1prx557/60tporqREGMQSQRUVSRSTYcWQLIIGHIJPYbdeWMAAAADLMMHAJQaaaXIFKaddZJBABDIJGBBBABDDCBBBLOQPIFFMRSPQOKAAAABCDDEKILLIHGIRfhgeJBAHNVZYSLGIKMRRJBBMQQRXTUYWNWiiaACIKQSKKHDEEFCAAAFRVagiTILNMMMFAFIQWiprdXegfgiWSXXVXbcbXURRWagfcYYcejlmmlklosunfUamnmrxvqnr350mlrrliirskfjmokddklhfilgaTbmmmqlXSVdssoqssofmvxrptpnouxogjrxvuwujfipurniirx3/9qlgfiihnmXQLTYeaLMgkmljaVKNUYcWOCHNOSbcRHPMILPUUPJVZbWQCABJVWVIBBDEGFGGDFECITTKEADIKLQRFGJKNRPNNTXbefigbabaVSVPTehicYUbbVagkhdQXfjigoleSXWYecYhkgYbkldcw12ulldVXdggjeeillijlXXjnnjjpmQHKNNIEFGLNPQQGGWbdfhigbdcabddgeaZZjowulfaXZbfkjgecddQILONJCKOIBABAADJIAABCBAAAAHQRXWFBCGLKGIEACDIKQQIJMMOSTGDIMOMLLDAABAABBCAACCCEAAAAACDJMICAAAEHCAAAEKJKKEAAEGHFAADGIKKOUZaccdfeQNPQPUZedXYbeejmjfbXadcWTUbdijgcTRXXcnrzxsdWjqmfhhionfeYWWhmtviccpstuyyokjlhVQLIGEHKKEOUZdknniOJKKOUXTNPKHRVXUNNNNNOTbXRXVWYIHFMKHIHFAAAEEBBAAAAAAAAACABJLONACFHJIGHFAFIFEDDFFDHHGGEDACGGDAAAADLOOLEAAHKLMFAAAAAABCEGIGECCDBDCCAACDDCFIJIKMLKGGFEGIKNNGBEGEEIRTWWQMJJIOPKHDEIGGJKJEAEHKMCAAEHIGEDCFHHHILIEACFLMNLHFDBGLJCAJUSRSOIDBGJIFDAAADGOQNILJFHHGEEJLJJLNNHGQSPOMIHJHGFKNPQPOMHECCGLNMLJIIJJKJIECCGMNNLECBBAEGGEAADIKJKMKEAAAAAAAAAAAEGFAAEHKIECBAACEAAAAAEHOPGAAAEHGCCAAEGHIIHEAADIJJECADKJBCAAAEEGHFAAIIHJIGFGHKMRTSLLLNOONHGEDDCHJNLFILNKECCGILLKFECDBBEFEAADGHFEEDAAAAAAAADHHFDCBENRSTQBAAIIFIIJBEFFFEGDBAAAAABAACHGHHFBAACCCBAAJPQPNLIIMQQPOLCAAACBACBGKOPMIGAAFGCCEAADFEEFFFBBABFDAAAAADCAEDBDNOIDAAADFHGDAAABJJGAAACGHEEECAABDEFCCHFDDHIHBABCDEEAABFHFECADKONPPOFDKNPNLNPLIJIKHFAEJKQRRKCAAJNRNHACHGFIMHBEBAAAAAAABBEHGAAAABCBAADHNMKCAAACDFMHAAAAFGJOLAEIJKIEAAADFHIAAACEEDBCAADEFGEBAFJHECAAEIKMOKEAABBBAAAAEEGIJGBAAABCDAAAEEBCEAAAAAAAAAAADGHHKMJMOJGJHCABEEEHIDAABEIGAAAAILNRNDIKEAEDAAAAAEHJDAAABCAAAAAACECGLRSTTTKFAABBAAECFHGIJKHJIIJIHKMOPRSVcdaWLMVXVRQQNNQWjmjcQSWbYMKSWcbaVTVacdeWQQQVULLVeebVPPPPPNOZeidYQLDCEEDBCECFJLJGDDAADKOWXVSONQRRXZddcVQJGEEGHJKHEDHJKJLOLNONJILLIEMQSNIHKIFDOTaZRLGHJGIOSVUUSMORbdcefgfhfVXbkkikiecddcbgilnkebLEDFGFGDGFDBCEDGDBEEGKNMJIJIHJLLLLLNOPPSTYaaaYRUXWYeecZXcgjibWPOQQRSUWXfijihaUHHJKLORSPJKPZeheacflornffmrw1whcgjkiijkklouwzwhbSRPJHFEEFFMOHEAAABACFHFFGGCDHIIGDDIUVNJDCCDEBBILLKJMNNNOMKORPMIJJKKMNRRQOPOLJFAABDDDCHGCBDHIBDEEECCGIIHFKKCAAAABBBEIHEGLOMGBACBDFIIGFGLNNIAAAAAAACCBBBKLAAAAABBAAABCDGIGDDABDIKKKOPPNMLLIHIHEDGJILMLGHLMFHMLLMOWaWQLQRTUNJIIHKPUUQORXXRKJLLQORTTROQRVVRLAAACDEGEAAIKGGGFBBHKIMMJIKJHHGFGHJKFBEDDFFGLZWGGDBCEFKJLJKNMKLGFJKJLKMOQQSVWVOAAAGKKIKLIKLKJFEFHGIIKJFGJNNPTOIEJIKMMONMNJJNMJJIEFNPPPPPRWZaSBAABBBEIJKMOPPNLIIJOONNIGFGGHJNNLNNORYXRPONQVXURPLJLNSVYbbZXUQGFGKMOOONMTYccfdYXXabefZXXbflohbYVUTSUYccchknobUQKFAAFIKMLHGKJEBAABDCFGFCCAAAACAAAAACEFFGFECBCDBAAAEGGHIJIGGHFBDGHEHIIOPMKLKFEBCGEACFGEGAADBADEEFHHFBACFIHFCABDECAAEBAEECFGCAAABCHIGBDIKKLCAAAACFDAAHLLNPOFBAABCBAAAAADCEGFAACDEGHBAAADFHEAAAFIKLIHJMMOPMJHFHKKKMPLKKLLJDBBDGLNONLIGLNNPPLLVaedaXWXYZYOGDCBDEEEGILLKMPNIFAAACACFGGFFFFHJLJFFFJLJJMIHMQQMKHJNPSSSTTSQOMLOOJIEEHIGKORRRRSQIEFGHFFGKLOPJHKOPJILPRNNNMOQNIJIJJKLKFDIPQROHNPTRIJOONPRQOIBAEPWVRUYZVXZaegeaTVYadefcWRQSRQQRdeZSPVbgeYTPSWZYYXYZcdgko020yscXaZillmpruvtoopmmuwvsrmjedfghdZlqnkklosstskeYFELOLHHJKMPSTWXUFAIMQRRONORTSWacdbTTaZTYabXflrniheYffbbmjgihdXMJTaiihidelmlorocZhjgecfhikonmnkfgmosuvtnfeedSQQPYigbehigjmpqspmhffgiigZWcbNPSEDMLNQQRTUWVUSRRVVTUZaZWahimkikmkhddegimnkfUOMZdlopokhgnqwy551iVdiopstrqonmnnmgcccZcksy44wtrturpv04573zmj05830wvvwxz1zxwx1yoGEHPRQRRQONMNOOOIGBBJMOVYeijifeeedbYVVVTQIMLOSVXVVTTSSSUWehdcejiZSdigdemqqlYTTXafknjZRVUSSTUWXXZcbYXYdcRSehjlmiigfhjmpmfgrwyfMKSWUNMMOPPNPPOLKKKKIISWWWWUVVUQPSUUUXZVPPOKJKNSSSQNNRYacdcaZXXQSXYehjjhhidbcnonlfghdWcjsuzyyxvrruxz210zmdhkmnnpqsrqpmlnoomXOKFMPSUURRRPMMNMJOPJHHBBEHRUWXXOIDHLLMRUXXTOMQVUROPSTWUQTWaaZWQCAEIMOQXWTVZacbWJFHKKIOaaZbilohZRPYbdgiYWVSONKACKMSVYeZOOYbcWKAHTVYYZaZZaefffdVUaceggbZZdhhidVajmlnmhfjnlecdeeikjlpqmmmmjfqsmjnomlmnkmnlkllkouury00ut11wstvpdbprsuxyshhvy0y02zmlt40orxxxy1rquwwxxwvry66674xv7998//+zy////4ty40u2+968/////+/+9///65+//////7ru17//8345////118+7//9y7/////4kekljjkfZTd+//3qhhmrtnurnmsvuqYdffnqqqkin+///5mbXds3//2WOlx+4snkjlmwz0xvz3yujgkrspv+5qr3/////1miZdm0ztu04//7mmw0/////1z/////vhJGGMRZYUUOMLONKNWXZhkbWPSflkecKJTXdmfagrtw0pVQMMPSZUPIHFIHNQPMKMPQPOOSZlomIEGJMNPTQKKTbysVDBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDFKPcgWSQPWZdXVSRTRUiiVPRWcdXFBCCMPSUTSUVVWWTSTUUffdUTRRUWWURIJUYaXWdeWXcbXUXbchigadhhebafhaYYbaUQWYTTXYYVSPTaaWXaWVXaVRRURKJKPUSSUSRRQUWQMJJGHHHIONMMPQRQPKKQUWYYWSQNPPOLKJIPOKIIMPRVZXRJEMOQQRQNPRONNMMKMPQRRPONPQZdeXQUUKJNOONMNRTQOQUKGILJFMNNQSTICCBLQTUUQPYdmpmTSddbcefYQNQSYVQJEIMQPPTTTXgingWTWUSONPYcjqrsqhcUTTVZXVUTUWVTRQUdchmnedikqy7wjXaggWWZXVSTXYOIJQSTUWVVTSWVTSSRLHHIMTTRXZYacbZTPIKRZfaTSVWWYWSMOUacbWSUXabbSMLSTJGKMRcdhmldTUZikkkeYTONPRUWWXblqmjgXURSUXUPLGFJLRWZUQSUYZXWTUZjibZVQRXWggWEKPPVZXTSQNORXZXTURORUVUNHKTVMGCEGKMPQRPSWTMLSZebWZbhgfiimruojhcQUdfoqnaekmggmoopnllligijswngXYUTXbYUYdbcecgiiZURTWTPHIQRSUVQKGMahgcZWVWYTPNRTXWWTIHHPSUQGGKSUSRNJLWWTUPJGKQNJOSWWTOMTYaZXROMOSWdZVNPUZbZZbXQOTZZXXfipjUPNNONMIHJQXeeZVVUPQQeePIGKKJKIHHADADJJLMPPLJJFDCEHHFHGCCEHJJEABEJMQSQNLHFGHHFIKJGFGHEHIIMMLMOOICEHOPJGDMMIIKKKJJGJJJOPNKKLMLIHJIGGKLLNKNOHEHIGMRRKOPOJNWSGEBFILMGEIIGLLGDDDDFFJJGHQROLLFDGILPQQOLJIFEFGIHEGHGGHKHHJKIIGBHIHJNOHFJKKGEGGGIIFIHJMMJIGJFCDEEDGIJHJLJKKIFDEFEGMOHDBCCBBEDCDEGINLAAHIJPRGAILMNMKHFGNQTURLKLLKJKORRPQRRNLEDGDDECADHLPehcbedghkmgJFMPRadZWSPNLOTUWTLKPRQQOOPNRUWTSSUbgnlnqnlhccTQPPQWXVUXZVRRRQORYbdaUSVYUPWcgeZYhmpbVbZSQTYUOQXceaWTRKLSUVOLNQQPRPHEGNORSQHDDCDDFEDBAKONLKJJJKKNNGCAADEGIJHGFFGFDABDCCCBADHINOOGBACJLOPSVTVbffdZWMEEFFEAMUaZYcbSRPNQRSUVUVWVWUQMMOQSRRMLPQTXaUQORPLRTUYYXXZYUMNVYccbWWWUbgpokZYaaYaebZhmpmYSSZgqsqnhSLNKIHKINLJGGKMNQSRRROKCDEGFGJJFDEEDDBAAAAACCBBAAAACDCCBEIKJIFAABDCBBAAAAAAAABGHRSNKHCBAAAAAAAAAIKJGHKHGIJKLGEEHLKGGIIIILOMKEBHKHAACCDEGJLKHILVTJEAHJMMNMHOUWVWVLLQNKMSPIBFFDBAACCDHHJPLRbihikgXPTUQQUXcZVRQPQRUXdgjihjonltzzrURWcbUUcgjpmddUUZYWadeccdYQPMNRYcRLWcjgWWZbYWXTOKPVZYachigfnqhSPOJGJQURPVYZTLHABBFGFFGHIMMKHDFDHJKKCACEFFGFDADHOOGABADBFJGBABEGGINMJJJOOWXOKKOQTRICDDBGHCBDGMNOQSRRRQRVSHFNQRNKIGEKLKKTXUQJFFLPOMPQQRRMIIHORRQUXYVRNMNNKSUQOKPNMNTUWehaYfgfbcbYXWYdikgUMONLMMFIMMLLLGGOUXZaWTRONRTTSLFGEJJKJJLNOPQNIEHKQTVWSOKPNRTTSNLHGGLPRRUUVVTJGDDIKLNNGAAACJIDBABCDDFFGKPQQLJDCEFGJJDCEHIHFDEGGHIIKIFECCEHIFEEGMPPFBBBDDDAAAABCAAACBAAFEAAADGMNMJDAAEILHCAAAAEGEACHJIHGFEEGGILMRQOKHKKLMNOMNPQPMDCIIJKMSSKJIHKMNSUMKKJKLLGGKJFEIKJILNHDLPTUUUUPOPOLPRJFKJKMPMHRWYVPPORWaXNSYTPOPQQROOWUKFDEEEGGDDCAAAIHCEEEECDCELKGBAACJMOJDCGJIBEHDBCDEIGDGOOMLAABDDAABDFCAEHEAGKLIKHGDEEAACDFEBAABAAAAAACEJLIFBFGFGMNONKFEEBAAAAADGKKKHKOOLIBBEKJGJLKJMOVXLHGJFDDEGIGGGGGGAAAAAEEFGHGHGJKDEHHDDAAAAAEFFEEDACDCEJKFEEGHJIADEDGLMIFFIJIHEFEBCCDFHHFAAACGEDBAAACCFGHHFHKKECBCFECJLHGGFFEDCADCDKMHDDEHKJEAAAAEFHJGEDGHFFAFRRQNLHIFEBCCCCAABCDEFGFDFGCCBAAAAAADEAADBBBCDBAAABDDBAAAAADAADBCDCCBADDCAAAADBBBCEFHGHIHAAAAAABCDIGADFFFIKGEDDFDCBEEGLLIEDAAAAAFGDADFGDEAAAADCDDEHHIHEAAAAACEDDABIKKIIDBABAAAAAACIHBAAAABDHKLCAAABAAAAAAAABBAAAAAABCBBAADECAADDEEFGGFCAABBAACGHKMNJFACCBDFEABKLHHIGEAAACFEBADEACEDAAAABDCABCDCDGGDAAAAAAAAAAAAAAAAGFDCAAABCDFKJCCEJKEBILLEEDDHGEAADCBDFEEECBDEAAFHHKQOJBABCDAACEFCEGHFDACEDCDCDEEEFFECDFEEFAAAAAACBAACDBBBBHHGDCAAAEHFFFCAABEEAABDCBACGNNFAAAECBDCCEEGHGGCBBCDGHCBBDFGHLKIIJLHEDAAAAACDAABCBCAABDFFJJJLJEAAAAAAAAAAAAAAAAAAACBAABGGFDAAAAAABBBAACCCAAAAAABBBAABBBDEDCEEFFEHJKIFFGGINONNONMJJJKKIILMLKKLMRTTRPONOSUSRVZZbddjkkmquttwxywusljknwy15630sojcbglrqomllnrrruwwwwvnknqrooqqoopomorsqr00yzzzxwvqmhimlklmmnoruxyxxyxtrqsutrqpprsvwz01zxzytsttvzzvtstuttuu03ywvnjikkmlcacdimonpz4+/98764yw123543320uuwy045323zvqqvyz2342yxux032zxxyxsrw079///30yy0357854zwursz03652ysruw466zvuujdagjot121vofissstsvxyxnkrux0246320xvlgdgklmvzytmkooosuwsohfekhcZbjuxzyssx1z022ulgnz5//////9x43ty566652wtxpsz3422440yposy05459/////zw6+/+++/851sohedfhhigghfdedbbYVSRQONEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]], +} diff --git a/demos/mirrorball/video/plasma.mp4 b/demos/mirrorball/video/plasma.mp4 new file mode 100644 index 000000000..caf534ece --- /dev/null +++ b/demos/mirrorball/video/plasma.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d2f1d7fafcf0a56cc0972c36e6bb9e9fb87b456ac669420b3f2297a5a32269a +size 1114979 diff --git a/demos/mirrorball/video/tunnel.mp4 b/demos/mirrorball/video/tunnel.mp4 new file mode 100644 index 000000000..7a12e8e2b --- /dev/null +++ b/demos/mirrorball/video/tunnel.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c17abfd9bf4ff3401b9a7089a2dd742075adc709847bd4cdfcee6b663f9c7d0 +size 3964419 diff --git a/demos/neonCoast/art/bob.png b/demos/neonCoast/art/bob.png new file mode 100644 index 000000000..76b5f0234 --- /dev/null +++ b/demos/neonCoast/art/bob.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ace021ff6910172a706b7dc675d34841f7fb9f6356eba68d1c3fbd36da345ca0 +size 2708 diff --git a/demos/neonCoast/art/car.png b/demos/neonCoast/art/car.png new file mode 100644 index 000000000..3b1e96f5e --- /dev/null +++ b/demos/neonCoast/art/car.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1bec822e316a1a4f7a35e7ab0600df76134c0dc68b0c72e3a673ff7201764efc +size 5489 diff --git a/demos/neonCoast/art/flag.png b/demos/neonCoast/art/flag.png new file mode 100644 index 000000000..fb7d034dd --- /dev/null +++ b/demos/neonCoast/art/flag.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9e77fbbc2209668cebbbd225f022d9fe1a647ee1168c340496688e4567edb44b +size 70389 diff --git a/demos/neonCoast/art/glow.png b/demos/neonCoast/art/glow.png new file mode 100644 index 000000000..88dadee9d --- /dev/null +++ b/demos/neonCoast/art/glow.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8589f0a42d8d118a65bf39dcc1e42139e3659dba62ad36bcfc95d498ff79736e +size 4093 diff --git a/demos/neonCoast/art/grid.png b/demos/neonCoast/art/grid.png new file mode 100644 index 000000000..f3982c5a2 --- /dev/null +++ b/demos/neonCoast/art/grid.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff6f06ac89c01ea109215476a89512b4b2473bd3718450c4dd1a055c5f13fd60 +size 1699 diff --git a/demos/neonCoast/art/gridCyan.png b/demos/neonCoast/art/gridCyan.png new file mode 100644 index 000000000..a2dc28837 --- /dev/null +++ b/demos/neonCoast/art/gridCyan.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:54aa633aa544791acc20c5b33b92294049ce8874df9902a38675c43b5c94c59f +size 1491 diff --git a/demos/neonCoast/art/lamp.png b/demos/neonCoast/art/lamp.png new file mode 100644 index 000000000..abdeed631 --- /dev/null +++ b/demos/neonCoast/art/lamp.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0e05567e543918df4b173502cc55399050b25a88062d30a67c583cc0f6bd945 +size 1586 diff --git a/demos/neonCoast/art/logo.png b/demos/neonCoast/art/logo.png new file mode 100644 index 000000000..f245c240d --- /dev/null +++ b/demos/neonCoast/art/logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b0e78bff3ca3caa2fd1f9c2c728665c3847b0426a9abe026e0c2f46d2aab3692 +size 104947 diff --git a/demos/neonCoast/art/mountains.png b/demos/neonCoast/art/mountains.png new file mode 100644 index 000000000..3c9054d74 --- /dev/null +++ b/demos/neonCoast/art/mountains.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4331b137b9cdb61cfe93e8bb4ee9b6dfc56bc48afea4e0c22218be4b88ac7ba +size 8956 diff --git a/demos/neonCoast/art/palm.png b/demos/neonCoast/art/palm.png new file mode 100644 index 000000000..11c7ce41b --- /dev/null +++ b/demos/neonCoast/art/palm.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d591d292dc5a70b993c975f7165542be897aa01a834bca7a6bfbd140bf9b0f3b +size 20910 diff --git a/demos/neonCoast/art/road.png b/demos/neonCoast/art/road.png new file mode 100644 index 000000000..655ee9852 --- /dev/null +++ b/demos/neonCoast/art/road.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09c1471130ec36be6aff24b672846efd05a7f6ffa0d9ef62d872dcc93ca57b37 +size 440 diff --git a/demos/neonCoast/art/singe.png b/demos/neonCoast/art/singe.png new file mode 100644 index 000000000..b4a2be2ee --- /dev/null +++ b/demos/neonCoast/art/singe.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e978b3715a1c462ce33d43e8f67470311fb8a7500582f7c7b7427a60e8deeabe +size 68433 diff --git a/demos/neonCoast/art/sky.png b/demos/neonCoast/art/sky.png new file mode 100644 index 000000000..83b72aadd --- /dev/null +++ b/demos/neonCoast/art/sky.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e8d27904a897f73d03cf92d5a86d17894c6c68375c5e5099646d2b57e0ae86c +size 182819 diff --git a/demos/neonCoast/art/skyline.png b/demos/neonCoast/art/skyline.png new file mode 100644 index 000000000..3d19e37da --- /dev/null +++ b/demos/neonCoast/art/skyline.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:82c434df40325a9df8795d67c0f2d0258ef1e824d0c8bedc9a4ba5245f164d6f +size 7495 diff --git a/demos/neonCoast/games.dat b/demos/neonCoast/games.dat new file mode 100644 index 000000000..09b256392 --- /dev/null +++ b/demos/neonCoast/games.dat @@ -0,0 +1,12 @@ +-- Neon Coast: a demo for Singe, to "Neons in Napoli" by eliza_music. +GAMES = { + { + TITLE = "Neon Coast", + SCRIPT = "neonCoast/neonCoast.singe", + CANVAS_X = 640, + CANVAS_Y = 480, + RESOLUTION_X = 1024, + RESOLUTION_Y = 768, + REQUIRES = { "SCENE", "POST" } + } +} diff --git a/demos/neonCoast/music.mp3 b/demos/neonCoast/music.mp3 new file mode 100644 index 000000000..550661787 --- /dev/null +++ b/demos/neonCoast/music.mp3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9e30b234828f03931d13ec58de4afd64537d79e5952d35924b9b2dfcf7417af5 +size 6026496 diff --git a/demos/neonCoast/neonCoast.singe b/demos/neonCoast/neonCoast.singe new file mode 100644 index 000000000..5ba9d4299 --- /dev/null +++ b/demos/neonCoast/neonCoast.singe @@ -0,0 +1,1030 @@ +-- Neon Coast: a demo for Singe, to "Neons in Napoli" by eliza_music. +-- +-- An eighties night drive in fourteen scenes, each on the bars of the track it belongs to: where the +-- bass drops out, where it slams back, the breakdown, and the dead stop before the last chorus. The +-- song's structure is in demos/README.md, and sync.lua holds what util/demoSync.py heard in it. Every +-- motion runs on the music's clock, never the frame count, so it stays with the song on any machine. +-- +-- What it shows off: the 3D scene (a chrome logotype and a chrome knot under a sky they reflect, +-- glass, bloom, fog, a cloth flag blown by the kicks), video three ways (scrubbed by the music on a +-- surface in 3D, playing on billboards in 3D, and flat on the overlay), and sprites rotated, scaled, +-- tinted, and added together: a road drawn a screen row at a time, vector bobs, a sine scroller, +-- a rotozoomed logo, and fireworks. +dofile("Singe/Framework.singe") +local K = dofile(DIR .. "../kit.lua") + +local W = 640 +local H = 480 +local FOV = 62 -- The 3D camera's vertical field of view, in degrees +local GRID_CELL = 4 -- The floor grid's cell in world units: the tiling the floor uses +local FLOOR_SIZE = 600 +local CRUISE = 14 -- World units a second the floor runs under the camera + +-- The road, drawn a row at a time as the arcade racers drew theirs. +local HORIZON_Y = H / 2 +local FOCAL = 320 -- Screen offset = world offset * FOCAL / distance ahead +local CAM_HEIGHT = 60 +local SEG = 20 -- World units of road in a segment +local DRAW_SEGS = 120 +local ROAD_HALF = 110 +local STRIP_W = 256 +local HAZE = 8 +local LAMP_EVERY = 6 -- Segments between streetlights: one passes the car each beat +local SEGS_PER_BAR = LAMP_EVERY * 4 +local PLAYER_AHEAD = 92 -- The car's distance ahead of the camera +local CAR_SCALE = 1.3 + +local sync = K.load(DIR, W, H) +local beat = sync.beats[3] - sync.beats[2] +local speed = LAMP_EVERY * SEG / beat -- So the streetlights pass on the beat + +-- Pictures, videos, and the 3D world, made once. +local art = {} +local video = {} +local world = {} + +-- The road's state while a road scene is on. +local road = { track = {}, start = 0 } + +local SCROLL_TEXT = " NEON COAST ... A SINGE DEMO ... EVERYTHING HERE RUNS ON THE MUSIC'S CLOCK: THE BEATS, THE BARS, THE KICKS AND THE SNARES ARE ALL READ OUT OF THE TRACK ... THE TUNNEL IS A VIDEO SCRUBBED BY THE KICK DRUM, THE ROAD IS A STRIP OF PIXELS STRETCHED ROW BY ROW, AND THE CHROME REFLECTS A SKY THAT WAS PAINTED BY ARITHMETIC ... GREETINGS TO EVERY CODER, PIXEL PUSHER, AND MUSICIAN WHO EVER STAYED UP TOO LATE MAKING SOMETHING SHINE ... " +local GREETINGS = { "ARE", "YOU", "READY", "?" } + + +-- Loading -------------------------------------------------------------------------------------------- + +local function loadArt() + for _, name in ipairs({ "car", "palm", "lamp", "skyline", "road", "bob", "glow", "logo", "singe" }) do + art[name] = spriteLoad(DIR .. "art/" .. name .. ".png") + end + spriteQuality(art.car, RENDER_SMOOTH) + spriteQuality(art.singe, RENDER_SMOOTH) + spriteQuality(art.logo, RENDER_SMOOTH) + spriteQuality(art.palm, RENDER_SMOOTH) + video.noise = videoLoad(DIR .. "video/noise.mp4") + video.plasma = videoLoad(DIR .. "video/plasma.mp4") + video.tunnel = videoLoad(DIR .. "video/tunnel.mp4") + video.tunnelFrames = videoGetFrameCount(video.tunnel) + videoSetVolume(video.noise, 0, 0) + videoSetVolume(video.plasma, 0, 0) + videoSetVolume(video.tunnel, 0, 0) +end + + +local function buildWorld() + sceneEnable(true) + sceneSetSky(DIR .. "art/sky.png") + sceneSetSkyIntensity(1.0) + sceneSetBloom(0.75, 0.6) + sceneSetFog(110, 28, 100, 60, 260) + + world.camera = nodeNew() + cameraSet(world.camera) + cameraSetPerspective(FOV, 0.1, 600) + + -- A dark glossy floor that reflects the sun, with the grid in it as light alone: a black base + -- colour would tint the reflection black too. + world.floorMaterial = materialNew() + materialSetColor(world.floorMaterial, 70, 30, 90) + materialSetEmissiveMap(world.floorMaterial, spriteLoad(DIR .. "art/grid.png")) + materialSetEmissive(world.floorMaterial, 255, 255, 255) + materialSetTiling(world.floorMaterial, FLOOR_SIZE / GRID_CELL, FLOOR_SIZE / GRID_CELL) + materialSetMetallic(world.floorMaterial, 0.85) + materialSetRoughness(world.floorMaterial, 0.3) + world.floor = nodeNew() + nodeSetMesh(world.floor, meshPlane(FLOOR_SIZE, FLOOR_SIZE), world.floorMaterial) + + local hills = materialNew() + + materialSetColor(hills, 50, 14, 70) + materialSetEmissiveMap(hills, spriteLoad(DIR .. "art/gridCyan.png")) + materialSetEmissive(hills, 255, 255, 255) + materialSetTiling(hills, 48, 8) + world.mountains = nodeNew() + nodeSetMesh(world.mountains, meshHeightmap(DIR .. "art/mountains.png", 520, 34, 70), hills) + nodeSetPosition(world.mountains, 0, 0, -230) + + world.logo = modelInstance(modelLoad("Singe/SingeText.glb")) + K.paint(world.logo, K.chrome(255, 225, 240, 0.06)) + + -- The knot, and glass spheres to circle it. + world.knotMaterial = K.chrome(245, 245, 255, 0.05) + world.knot = nodeNew() + nodeSetMesh(world.knot, K.torusKnot(1.6, 0.42, 220, 18), world.knotMaterial) + world.spheres = {} + for i = 1, 6 do + local r, g, b = K.hue(i / 6) + local s = nodeNew() + + local m = K.glass(r, g, b) + + materialSetColor(m, r, g, b, 150) + materialSetEmissive(m, r // 3, g // 3, b // 3) + nodeSetMesh(s, meshSphere(0.55, 32), m) + world.spheres[i] = s + end + world.sparks = emitterNew(world.knot) + emitterSetBlend(world.sparks, PARTICLE_ADD) + emitterSetRate(world.sparks, 0) + emitterSetLife(world.sparks, 0.5, 1.2) + emitterSetSpeed(world.sparks, 3, 7) + emitterSetSpread(world.sparks, 180) + emitterSetGravity(world.sparks, 0, -4, 0) + emitterSetSize(world.sparks, 0.12, 0.02) + emitterSetColor(world.sparks, 255, 200, 255, 255, 255, 40, 200, 0) + emitterSetRadius(world.sparks, 1.5) + emitterSetTrail(world.sparks, 6, 0.04) + emitterStart(world.sparks) + + -- Two coloured lights that circle the knot, so its chrome has something bright to catch. + world.lights = {} + for i, c in ipairs({ { 255, 60, 200 }, { 60, 220, 255 } }) do + local l = lightNew(LIGHT_POINT) + + lightSetColor(l, c[1], c[2], c[3]) + lightSetIntensity(l, 0) + lightSetRange(l, 30) + world.lights[i] = l + end + + -- Billboards round the knot, each showing the plasma. + local screen = materialNew() + + materialSetVideo(screen, video.plasma) + materialSetUnlit(screen, true) + materialSetDoubleSided(screen, true) + world.billboards = {} + for i = 1, 4 do + local a = (i - 0.5) / 4 * 2 * math.pi + local b = nodeNew() + + nodeSetMesh(b, meshPlane(6.4, 4.8), screen) + nodeSetPosition(b, math.sin(a) * 15, 3.2, math.cos(a) * 15) + nodeSetRotation(b, 90, math.deg(a) + 180, 0) + world.billboards[i] = b + end + + -- The tunnel and the tape's snow, as quads that fill the camera's view. + local tunnel = materialNew() + + materialSetVideo(tunnel, video.tunnel) + materialSetUnlit(tunnel, true) + materialSetDoubleSided(tunnel, true) + world.tunnel = K.screenQuad(world.camera, FOV, tunnel, 2, 1.7) + local snow = materialNew() + + materialSetVideo(snow, video.noise) + materialSetUnlit(snow, true) + materialSetDoubleSided(snow, true) + materialSetColor(snow, 255, 255, 255, 110) + materialSetBlend(snow, true) + world.snow = K.screenQuad(world.camera, FOV, snow, 0.5, 1.02) + + -- The flag on its pole, cloth that the kicks blow about. + local pole = materialNew() + + materialSetColor(pole, 40, 30, 50) + materialSetMetallic(pole, 1) + materialSetRoughness(pole, 0.3) + world.pole = nodeNew() + nodeSetMesh(world.pole, meshCylinder(0.06, 7, 10), pole) + nodeSetPosition(world.pole, -2.2, 3.5, -6) + local cloth = materialNew() + + materialSetTexture(cloth, spriteLoad(DIR .. "art/flag.png")) + materialSetDoubleSided(cloth, true) + materialSetRoughness(cloth, 0.7) + materialSetEmissiveMap(cloth, spriteLoad(DIR .. "art/flag.png")) + materialSetEmissive(cloth, 170, 170, 170) + world.flag = nodeNew() + nodeSetMesh(world.flag, meshPlane(5.2, 3.25, 30, 18), cloth) + nodeSetPosition(world.flag, 0.4, 5.2, -6) + nodeSetRotation(world.flag, 90, 0, 0) + softNew(world.flag, SOFT_CLOTH) + softSetStiffness(world.flag, 0.95, 0.1) + softSetMass(world.flag, 0.6) + for i = 0, 5 do + softPin(world.flag, -2.2, 3.575 + i * 0.65, -6) + end + + -- Light beams that shoot along the floor at the camera, one on each kick. + local beam = materialNew() + + materialSetColor(beam, 0, 0, 0) + materialSetEmissive(beam, 120, 240, 255) + world.beams = {} + for i = 1, 16 do + local b = nodeNew() + + nodeSetMesh(b, meshBox(0.12, 0.06, 9), beam) + nodeSetVisible(b, false) + world.beams[i] = { node = b, z = -1000, x = 0 } + end + world.nextBeam = 1 + + -- Stars streaming at the camera for the run into hyperspace. + world.warpAnchor = nodeNew(world.camera) + nodeSetPosition(world.warpAnchor, 0, 0, -60) + world.warp = emitterNew(world.warpAnchor) + emitterSetBlend(world.warp, PARTICLE_ADD) + emitterSetRate(world.warp, 0) + emitterSetLife(world.warp, 0.6, 1.0) + emitterSetSpeed(world.warp, 40, 80) + emitterSetDirection(world.warp, 0, 0, 1) + emitterSetSpread(world.warp, 25) + emitterSetRadius(world.warp, 18) + emitterSetSize(world.warp, 0.25, 0.1) + emitterSetColor(world.warp, 200, 240, 255, 255, 255, 80, 220, 0) + emitterSetTrail(world.warp, 10, 0.08) + emitterStart(world.warp) +end + + +-- A beam leaves the horizon on each kick and runs past the camera. +local BEAM_SPEED = 160 + +local function beams(t, lastT, on) + if on and K.hitCount("kicks", lastT, t) > 0 then + local b = world.beams[world.nextBeam] + + b.z = -160 + b.x = (math.random() - 0.5) * 30 + world.nextBeam = world.nextBeam % #world.beams + 1 + end + for _, b in ipairs(world.beams) do + b.z = b.z + BEAM_SPEED * (t - lastT) + nodeSetVisible(b.node, on and b.z < 20) + nodeSetPosition(b.node, b.x, 0.05, b.z) + end +end + + +-- The knot's lights circle it, brightening with the kicks; off when the knot is. +local function knotLights(t, on) + for i, l in ipairs(world.lights) do + local a = t * 1.3 + i * math.pi + + nodeSetPosition(l, math.cos(a) * 4, 4.5 + math.sin(t * 0.9 + i), math.sin(a) * 4) + lightSetIntensity(l, on and (25 + 40 * K.decay("kicks", t, 7)) or 0) + end +end + + +-- Everything in the world is hidden, and a scene shows what it uses. +local function hideAll() + for _, node in ipairs({ world.floor, world.mountains, world.logo, world.knot, world.tunnel, world.snow, world.pole, world.flag }) do + nodeSetVisible(node, false) + end + for _, s in ipairs(world.spheres) do + nodeSetVisible(s, false) + end + for _, b in ipairs(world.billboards) do + nodeSetVisible(b, false) + end + emitterSetRate(world.sparks, 0) + emitterSetRate(world.warp, 0) + knotLights(0, false) + sceneSetSkyIntensity(1.0) + for _, b in ipairs(world.beams) do + nodeSetVisible(b.node, false) + end +end + + +local function show(...) + for _, node in ipairs({ ... }) do + nodeSetVisible(node, true) + end +end + + +-- The grid -------------------------------------------------------------------------------------------- + +local function gridCamera(t, height, lookUp) + local sway = math.sin(t * 0.7) * 0.6 + + nodeSetPosition(world.camera, sway, height, 6) + nodeLookAt(world.camera, sway * 0.3, height + (lookUp or 0.6), -20) + nodeSetPosition(world.floor, 0, 0, (t * CRUISE) % GRID_CELL) +end + + +-- The grid flares on every kick. +local function gridPulse(t, base) + local k = base + 0.9 * K.decay("kicks", t, 7) + local v = math.floor(K.clamp(k, 0, 1) * 255) + + materialSetEmissive(world.floorMaterial, v, v, v) +end + + +-- The road --------------------------------------------------------------------------------------------- + +-- A road built a bar at a time: each piece is { bars, curve, rise }, easing in and out of its bend +-- and its climb, so every bend begins on a downbeat. +local function buildRoad(pieces) + local track = {} + local y = 0 + + for _, p in ipairs(pieces) do + local n = p[1] * SEGS_PER_BAR + local y0 = y + local y1 = y + (p[3] or 0) + + for i = 0, n - 1 do + local k = i / n + local c = p[2] * math.sin(k * math.pi) + local y2 = K.easeInOut(y0, y1, (i + 1) / n) + + track[#track + 1] = { curve = c, y1 = y, y2 = y2, things = {} } + y = y2 + end + end + -- Streetlights on both sides on every LAMP_EVERY'th segment, palms between. + for i, segment in ipairs(track) do + if (i - 1) % LAMP_EVERY == 0 then + segment.things[#segment.things + 1] = { sprite = art.lamp, x = -ROAD_HALF - 18, width = 30, lamp = true } + segment.things[#segment.things + 1] = { sprite = art.lamp, x = ROAD_HALF + 18, width = -30, lamp = true } + elseif (i - 1) % LAMP_EVERY == 3 then + segment.things[#segment.things + 1] = { sprite = art.palm, x = -ROAD_HALF - 90 - (i * 37 % 60), width = 110 } + segment.things[#segment.things + 1] = { sprite = art.palm, x = ROAD_HALF + 90 + (i * 53 % 60), width = 110 } + end + end + return track +end + + +local function roadSegment(index) + local n = #road.track + + return road.track[((index % n) + n) % n + 1] +end + + +-- The road from where the camera is: sky and city first, then the road nearest first, each segment +-- filling the screen rows between its near edge and its far edge with one row of the strip art +-- stretched to the road's width at that row, then streetlights and palms farthest first. +local function drawRoad(t, position, bright) + local base = math.floor(position / SEG) + local within = position - base * SEG + local car = roadSegment(math.floor((position + PLAYER_AHEAD) / SEG)) + local carK = ((position + PLAYER_AHEAD) % SEG) / SEG + local camY = car.y1 + (car.y2 - car.y1) * carK + CAM_HEIGHT + local x = 0 + local dx = -roadSegment(base).curve * within / SEG + local clip = H + local drawn = {} + local tint = math.floor(170 + 85 * bright) + + -- The city slides the other way as the road bends. + road.cityX = (road.cityX or 0) + car.curve * 2.2 + local cityW = spriteGetWidth(art.skyline) + local from = math.floor(road.cityX % cityW) + + spriteDrawGrid(art.skyline, 0, HORIZON_Y - 149, from, 0, math.min(W, cityW - from), 150) + if cityW - from < W then + spriteDrawGrid(art.skyline, cityW - from, HORIZON_Y - 149, 0, 0, W - (cityW - from), 150) + end + + spriteSetTint(art.road, tint, tint, tint) + for n = 0, DRAW_SEGS - 1 do + local index = base + n + local segment = roadSegment(index) + local z1 = math.max(1, n * SEG - within) + local z2 = n * SEG - within + SEG + local s1 = FOCAL / z1 + local s2 = FOCAL / z2 + + segment.sx1 = W / 2 + x * s1 + segment.sy1 = HORIZON_Y - (segment.y1 - camY) * s1 + segment.s1 = s1 + segment.sx2 = W / 2 + (x + dx) * s2 + segment.sy2 = HORIZON_Y - (segment.y2 - camY) * s2 + segment.s2 = s2 + segment.clip = clip + segment.index = index + x = x + dx + dx = dx + segment.curve + drawn[#drawn + 1] = segment + if segment.sy2 < clip and segment.sy1 > segment.sy2 then + local top = math.max(0, math.ceil(segment.sy2)) + local bottom = math.min(clip - 1, math.floor(segment.sy1)) + local light = (index // 3) % 2 + local haze = math.min(HAZE - 1, math.floor(z1 / (DRAW_SEGS * SEG) * HAZE * 1.4)) + local height = segment.sy1 - segment.sy2 + + if top <= bottom then + spriteDrawGrid(art.road, 0, top, 0, (2 + light) * HAZE + haze, STRIP_W, 1, W - 1, bottom) + for row = bottom, top, -1 do + local k = (segment.sy1 - row) / height + local cx = segment.sx1 + (segment.sx2 - segment.sx1) * k + local half = ROAD_HALF * (s1 + (s2 - s1) * k) + + spriteDrawGrid(art.road, math.floor(cx - half), row, 0, light * HAZE + haze, STRIP_W, 1, math.floor(cx + half), row) + end + clip = top + end + end + end + + -- Things by the road, farthest first, each cut off by any nearer crest. + local lampGlow = 0.55 + 0.45 * K.decay("snares", t, 5) + + for i = #drawn, 2, -1 do + local segment = drawn[i] + + for _, thing in ipairs(segment.things) do + local s = segment.s1 + local w = math.abs(thing.width) * s + local sw = spriteGetWidth(thing.sprite) + local sh = spriteGetHeight(thing.sprite) + local h = w * sh / sw + local cx = segment.sx1 + thing.x * s + local foot = segment.sy1 + local top = foot - h + + if w >= 1 and cx + w > 0 and cx - w < W and top < segment.clip then + local left = math.floor(cx - w / 2) + local right = math.floor(cx + w / 2) + + if thing.width < 0 then + left, right = right, left + end + if foot <= segment.clip then + spriteDraw(thing.sprite, math.min(left, right), math.floor(top), math.max(left, right), math.floor(foot) - 1) + else + local shown = math.min(sh, math.max(1, math.floor(sh * (segment.clip - top) / h))) + + spriteDrawGrid(thing.sprite, math.min(left, right), math.floor(top), 0, 0, sw, shown, math.max(left, right), segment.clip - 1) + end + if thing.lamp and foot <= segment.clip + h * 0.9 then + -- The lamp's light: a glow added over its head, the head being at the arm's end. + local headX = cx + ((thing.width > 0) and -0.39 or 0.39) * w + local g = w * 3.2 * lampGlow + + spriteSetBlend(art.glow, SPRITE_ADD) + spriteSetTint(art.glow, 255, 220, 170) + spriteSetAlpha(art.glow, 255) + spriteDraw(art.glow, math.floor(headX - g / 2), math.floor(top + h * 0.07 - g / 2), math.floor(headX + g / 2), math.floor(top + h * 0.07 + g / 2)) + end + end + end + end + spriteSetBlend(art.glow, SPRITE_ALPHA) + return car +end + + +-- The car: one picture, leaned into the bend by turning it, bounced by the kick, with its taillights +-- and its underglow added over the road. +local function drawCar(t, car, lift, spin) + local lean = -car.curve * 9 + (spin or 0) + local bounce = 3 * K.decay("kicks", t, 10) + local cx = W / 2 + math.sin(t * 0.9) * 18 + local cy = H - 52 - bounce - (lift or 0) + + spriteRotateAndScale(art.car, lean, CAR_SCALE) + spriteDraw(art.car, math.floor(cx), math.floor(cy), true) + local glowW = 260 + 80 * K.decay("kicks", t, 6) + + spriteSetBlend(art.glow, SPRITE_ADD) + spriteSetTint(art.glow, 255, 30, 60) + spriteSetAlpha(art.glow, 200) + spriteDraw(art.glow, math.floor(cx - glowW / 2), math.floor(cy - 40), math.floor(cx + glowW / 2), math.floor(cy + 20)) + spriteSetTint(art.glow, 255, 40, 200) + spriteDraw(art.glow, math.floor(cx - 150), math.floor(cy + 20 + (lift or 0)), math.floor(cx + 150), math.floor(cy + 60 + (lift or 0))) + spriteSetBlend(art.glow, SPRITE_ALPHA) + spriteSetTint(art.glow, 255, 255, 255) + spriteSetAlpha(art.glow, 255) +end + + +-- The 3D camera for a road scene: level, at the height that puts the sky's horizon on the road's. +local function roadSky() + nodeSetPosition(world.camera, 0, 1, 0) + nodeLookAt(world.camera, 0, 1, -100) +end + + +local function roadPosition(t) + return speed * (t - road.start) - PLAYER_AHEAD +end + + +-- Fireworks ---------------------------------------------------------------------------------------- + +-- Fireworks: a burst on every snare, in a random neon colour, falling and fading. +local function fireworks(t, lastT) + if K.hitCount("snares", lastT, t) > 0 then + local r, g, b = K.hue(math.random()) + + emitterSetPosition(art.fireworks, math.random(80, W - 80), math.random(60, H / 2 - 40)) + emitterSetColor(art.fireworks, 255, 255, 255, 255, r, g, b, 0) + emitterBurst(art.fireworks, 120) + end + emitterDraw(art.fireworks) +end + + +-- The scenes ------------------------------------------------------------------------------------------- + +local lastT = 0 + +local SCENES = { + -- Bars 1 to 3: pads only. The tape starts: snow, the deck's own lettering, and the title typed + -- out a letter a beat. + { + from = 1, to = 4, + enter = function(t) + hideAll() + videoPlay(video.noise) + end, + draw = function(t, bar, k) + videoDraw(video.noise, 0, 0, W - 1, H - 1) + local dark = 1 - 0.75 * K.smooth(1.0, 2.0, bar) + 0.75 * K.smooth(3.5, 3.95, bar) + + K.flash(0, 0, 0, math.floor(255 * K.clamp(dark, 0, 1))) + local blink = (math.floor(t * 2) % 2 == 0) + + K.text(40, 34, "PLAY", 30, 255, 255, 255) + if blink then + K.text(126, 34, ">", 30, 255, 255, 255) + end + K.text(W - 40, H - 70, string.format("0:%02d:%02d", math.floor(t / 60), math.floor(t % 60)), 26, 255, 255, 255, "right") + local title = "A SINGE PRODUCTION" + local shown = math.floor(K.clamp((K.beat(t) - 1) * 3, 0, #title)) + + if shown > 0 then + local jitter = (bar > 3.5) and math.random(-4, 4) or 0 + + K.text(W / 2 + jitter, H / 2 - 18, title:sub(1, shown), 32, 255, 120, 230, "center") + end + end, + leave = function(t) + videoPause(video.noise) + end, + }, + -- Bars 4 to 16: the bass comes in, and the sunset grid with it. The logotype rises from the + -- horizon at bar 9, and the title arrives at bar 13. + { + from = 4, to = 17, + enter = function(t) + hideAll() + show(world.floor, world.mountains) + sceneSetBloom(0.75, 0.6) + end, + draw = function(t, bar, k) + local crane = K.easeOut((bar - 4) / 5) + + gridCamera(t, K.lerp(0.35, 1.4, crane), K.lerp(1.6, 0.6, crane)) + nodeSetPosition(world.floor, 0, 0, (t * CRUISE * 2.2) % GRID_CELL) + gridPulse(t, 0.35) + beams(t, lastT, true) + sceneSetBloom(0.75, 0.55 + 0.6 * K.decay("kicks", t, 8)) + if bar >= 9 then + local rise = K.easeOut((bar - 9) / 2) + + show(world.logo) + nodeSetPosition(world.logo, 0, K.lerp(-3, 2.6, rise), -16) + nodeSetRotation(world.logo, 0, math.sin(t * 0.6) * 12, 0) + end + if bar >= 13 then + -- The title slams in on the downbeat and settles; a shine runs across it each bar. + local p = (bar - 13) + local scale = 1 + 2.5 * math.exp(-p * 9) + local lw = spriteGetWidth(art.logo) * 0.8 * scale + local lh = spriteGetHeight(art.logo) * 0.8 * scale + local y = 395 + + spriteSetAlpha(art.logo, math.floor(255 * K.clamp(p * 6, 0, 1))) + spriteDraw(art.logo, math.floor(W / 2 - lw / 2), math.floor(y - lh / 2), math.floor(W / 2 + lw / 2), math.floor(y + lh / 2)) + spriteSetAlpha(art.logo, 255) + end + local fade = 1 - K.smooth(4, 4.5, bar) + + if fade > 0 then + K.flash(0, 0, 0, math.floor(255 * fade)) + end + K.strobe(t, "kicks", 14, 255, 120, 220, (bar >= 13) and 40 or 0) + end, + }, + -- Bars 17 and 18: the bass drops out under a snare build. The logotype turns once, the fog + -- closes in, and the screen strobes with the snare roll, faster and faster. + { + from = 17, to = 19, + enter = function(t) + hideAll() + show(world.floor, world.mountains, world.logo) + end, + draw = function(t, bar, k) + gridCamera(t, 1.4 + k * 3, 0.6 - k * 1.2) + gridPulse(t, 0.15) + nodeSetPosition(world.logo, 0, 2.6, -16 + k * 6) + nodeSetRotation(world.logo, 0, K.easeIn(k) * 360, 0) + sceneSetFog(110, 28, 100, 60 - k * 50, 260 - k * 200) + K.strobe(t, "snares", 22, 255, 255, 255, 90 + 120 * k) + end, + leave = function(t) + sceneSetFog(110, 28, 100, 60, 260) + end, + }, + -- Bars 19 to 28: the night drive. A streetlight passes on every beat, the bends begin on + -- downbeats, and the city slides by under the sun. + { + from = 19, to = 29, + enter = function(t) + hideAll() + road.track = buildRoad({ { 2, 0 }, { 2, 0.55 }, { 2, -0.6, 140 }, { 2, 0.3, -140 }, { 2, 0, 260 } }) + road.start = K.barTime(19) + road.cityX = 0 + end, + draw = function(t, bar, k) + roadSky() + local car = drawRoad(t, roadPosition(t), K.decay("kicks", t, 6)) + + drawCar(t, car) + K.strobe(t, "kicks", 30, 255, 255, 255, (bar < 19.02) and 255 or 0) + local intro = 1 - K.smooth(19, 19.25, bar) + + if intro > 0 then + K.flash(255, 255, 255, math.floor(255 * intro)) + end + end, + }, + -- Bars 29 and 30: the bass drops out again, and the car takes the crest and flies, the road + -- falling away beneath it in slow motion. + { + from = 29, to = 31, + enter = function(t) + road.flyStart = t + end, + draw = function(t, bar, k) + roadSky() + local slow = road.flyStart + (t - road.flyStart) * K.lerp(1, 0.25, K.ease(k * 3)) + local car = drawRoad(t, roadPosition(slow) + k * k * 400, 0) + + drawCar(t, car, 60 * math.sin(math.min(1, k * 1.2) * math.pi) + k * 40, k * 25) + K.strobe(t, "snares", 18, 255, 255, 255, 120 * k) + end, + }, + -- Bars 31 to 46: chrome. A knot, glass round it, and the grid; the camera cuts on every + -- second downbeat, the knot pumps on the kicks, and sparks fly off it on the snares. From bar 39 + -- the plasma plays on billboards round the scene. + { + from = 31, to = 47, + enter = function(t) + hideAll() + show(world.floor, world.mountains, world.knot) + for _, s in ipairs(world.spheres) do + show(s) + end + videoPlay(video.plasma) + end, + draw = function(t, bar, k) + if bar >= 39 then + for _, b in ipairs(world.billboards) do + show(b) + end + end + local shot = math.floor((bar - 31) / 2) + local inner = ((bar - 31) / 2) % 1 + local shots = { + { 0, 3.0, 9, 0, 3, 0 }, { 6, 1.2, 4, 0, 3.2, 0 }, { -5, 6, 6, 0, 2.6, 0 }, { 0, 1.0, 5.5, 0, 3.8, 0 }, + { 8, 4, -2, 0, 3, 0 }, { -7, 2, 3, 0, 3, -1 }, { 0, 9, 2, 0, 3, 0 }, { 3, 2.4, 7, 0, 3, 0 }, + } + local s = shots[shot % #shots + 1] + local drift = inner * 1.4 + + nodeSetPosition(world.camera, s[1] + drift, s[2] + drift * 0.3, s[3] - drift) + nodeLookAt(world.camera, s[4], s[5], s[6]) + local pump = 1 + 0.18 * K.decay("kicks", t, 9) + + nodeSetPosition(world.knot, 0, 3, 0) + nodeSetScale(world.knot, pump) + nodeSetRotation(world.knot, t * 23, t * 41, t * 11) + for i, sphere in ipairs(world.spheres) do + local a = t * 0.8 + i / #world.spheres * 2 * math.pi + + nodeSetPosition(sphere, math.cos(a) * 3.6, 3 + math.sin(a * 2 + t) * 1.1, math.sin(a) * 3.6) + end + nodeSetPosition(world.floor, 0, 0, (t * 4) % GRID_CELL) + gridPulse(t, 0.3) + knotLights(t, true) + sceneSetSkyIntensity(1.5) + if K.hitCount("snares", lastT, t) > 0 then + emitterBurst(world.sparks, 60) + end + -- Each cut opens on a white frame. + K.flash(255, 255, 255, math.floor(200 * math.exp(-inner * 2 * 1.967 * 14))) + end, + }, + -- Bars 47 and 48: the tape is rewound. The last shots run backwards at speed under snow, with + -- the deck's lettering, and stop dead. + { + from = 47, to = 49, + enter = function(t) + show(world.snow) + videoPlay(video.noise) + road.rewindFrom = t + end, + draw = function(t, bar, k) + local back = road.rewindFrom - (t - road.rewindFrom) * 4 + local b = K.bar(back) + local shot = math.floor((b - 31) / 2) % 8 + + nodeSetPosition(world.camera, math.sin(back) * 6, 2 + shot * 0.4, math.cos(back) * 6) + nodeLookAt(world.camera, 0, 3, 0) + nodeSetRotation(world.knot, back * 23, back * 41, back * 11) + nodeSetScale(world.knot, 1) + K.text(40, 34, "<< REW", 30, 255, 255, 255) + -- The picture rolls as the tape slows. + if bar > 48.5 then + K.flash(0, 0, 0, math.floor(255 * K.smooth(48.5, 48.95, bar))) + end + end, + leave = function(t) + nodeSetVisible(world.snow, false) + videoPause(video.noise) + hideAll() + end, + }, + -- Bars 49 to 58: the tunnel. A video scrubbed by the music on a quad that turns with the bass, + -- vector bobs morphing every two bars, and the scroller. + { + from = 49, to = 59, + enter = function(t) + hideAll() + show(world.tunnel) + road.tunnelPhase = 0 + road.tunnelLast = t + sceneSetBloom(0.6, 0.5) + end, + draw = function(t, bar, k) + nodeSetPosition(world.camera, 0, 0, 0) + nodeLookAt(world.camera, 0, 0, -1) + -- Through the tunnel at a speed the kick pushes: one texture period is one pass of the video. + local dt = t - road.tunnelLast + local push = 0.55 + 1.6 * K.decay("kicks", t, 5) + + road.tunnelLast = t + road.tunnelPhase = (road.tunnelPhase + dt * push) % 1 + videoSeek(video.tunnel, math.floor(road.tunnelPhase * video.tunnelFrames)) + nodeSetRotation(world.tunnel, 0, 0, t * 25 + math.sin(t * 0.5) * 40 * K.env("bass", t)) + K.bobs(t, bar, art.bob, 48, 1.3, 20, W / 2, H / 2 - 20) + K.scroller(t, art.scrollFont, SCROLL_TEXT, H - 70, 18, 170, K.barTime(49)) + local intro = 1 - K.smooth(49, 49.2, bar) + + if intro > 0 then + K.flash(255, 255, 255, math.floor(255 * intro)) + end + end, + }, + -- Bars 59 and 60: the bass drops out. The tunnel slows to a stop, the bobs fall in to a point, + -- and the question is asked a word a beat. + { + from = 59, to = 61, + draw = function(t, bar, k) + local dt = t - road.tunnelLast + + road.tunnelLast = t + road.tunnelPhase = (road.tunnelPhase + dt * 0.55 * (1 - k)) % 1 + videoSeek(video.tunnel, math.floor(road.tunnelPhase * video.tunnelFrames)) + nodeSetRotation(world.tunnel, 0, 0, t * 25 * (1 - k)) + K.bobs(t, bar, art.bob, 48, 1.3 * (1 - K.easeIn(k)), 20, W / 2, H / 2 - 20) + local words = math.floor((bar - 59) * 4) + 1 + + for i = 1, math.min(words, #GREETINGS) do + K.text(W / 2 + (i - 2.5) * 130, H / 2 + 120, GREETINGS[i], 40, 255, 255, 255, "center") + end + K.flash(0, 0, 0, math.floor(140 * k)) + end, + leave = function(t) + hideAll() + end, + }, + -- Bars 61 to 68: plasma under a rotozoomed logo and a ring of turning palms, punched in on the + -- kicks. + { + from = 61, to = 69, + enter = function(t) + hideAll() + videoPlay(video.plasma) + end, + draw = function(t, bar, k) + videoDraw(video.plasma, 0, 0, W - 1, H - 1) + local punch = 1 + 0.25 * K.decay("kicks", t, 8) + + for i = 1, 8 do + local a = i / 8 * 360 + t * 30 + local r = 170 * punch + local px = W / 2 + math.cos(math.rad(a)) * r + local py = H / 2 + math.sin(math.rad(a)) * r + + spriteRotateAndScale(art.palm, a + 90, 0.55 * punch) + spriteDraw(art.palm, math.floor(px), math.floor(py), true) + end + local scale = (0.9 + 0.35 * math.sin(t * 1.3)) * punch + local angle = math.sin(t * 0.7) * 25 + + spriteRotateAndScale(art.singe, angle, scale) + spriteDraw(art.singe, W // 2, H // 2, true) + K.strobe(t, "kicks", 12, 255, 255, 255, 70) + local intro = 1 - K.smooth(61, 61.15, bar) + + if intro > 0 then + K.flash(255, 255, 255, math.floor(255 * intro)) + end + end, + leave = function(t) + spriteRotateAndScale(art.palm, 0, 1) + spriteRotateAndScale(art.singe, 0, 1) + end, + }, + -- Bars 69 to 76: the breakdown, then the kick's return. A flag on the night grid, blown by a + -- wind that gusts on every kick once the drums are back. + { + from = 69, to = 77, + enter = function(t) + hideAll() + show(world.floor, world.mountains, world.pole, world.flag) + sceneSetSkyIntensity(0.55) + sceneSetBloom(0.7, 0.5) + end, + draw = function(t, bar, k) + local a = math.sin(t * 0.3) * 0.8 + + nodeSetPosition(world.camera, 0.2 + math.sin(a) * 6.5, 3.6 + math.sin(t * 0.3) * 0.6, -6 + math.cos(a) * 6.5) + nodeLookAt(world.camera, 0.4, 5.0, -6) + nodeSetPosition(world.floor, 0, 0, (t * 2) % GRID_CELL) + local gust = (bar >= 73) and K.decay("kicks", t, 4) or 0 + + physicsSetGravity(4 + 30 * gust + 3 * math.sin(t * 1.7), -9.81, 1.5 * math.sin(t)) + gridPulse(t, 0.12 + ((bar >= 73) and 0.2 or 0)) + local fadeIn = 1 - K.smooth(69, 69.5, bar) + + if fadeIn > 0 then + K.flash(0, 0, 0, math.floor(255 * fadeIn)) + end + end, + leave = function(t) + physicsSetGravity(0, -9.81, 0) + sceneSetSkyIntensity(1.0) + end, + }, + -- Bars 77 and 78: the riser. Into hyperspace toward the sun, faster and whiter, to the dead + -- stop just before bar 79. + { + from = 77, to = 79, + enter = function(t) + hideAll() + show(world.floor, world.mountains) + end, + draw = function(t, bar, k) + local z = 6 - K.easeIn(k) * 120 + + nodeSetPosition(world.camera, 0, 1.6, z) + nodeLookAt(world.camera, 0, 1.9, z - 20) + nodeSetPosition(world.floor, 0, 0, z - z % GRID_CELL) + emitterSetRate(world.warp, math.floor(200 + 1600 * k)) + gridPulse(t, 0.3 + 0.7 * k) + sceneSetExposure(k * 2.5) + local white = K.smooth(78.3, 78.85, bar) + + if bar >= 78.92 then + K.flash(0, 0, 0, 255) + elseif white > 0 then + K.flash(255, 255, 255, math.floor(255 * white)) + end + end, + leave = function(t) + sceneSetExposure(0) + emitterSetRate(world.warp, 0) + emitterClear(world.warp) + end, + }, + -- Bars 79 to 94: everything, every two bars cutting between the road under a chrome sky and the + -- chrome knot among its billboards, with fireworks on the snares; the last eight bars put the + -- knot and the logotype in the sky over the road. + { + from = 79, to = 95, + enter = function(t) + hideAll() + road.track = buildRoad({ { 2, 0.5 }, { 2, -0.5 }, { 2, 0.4, 200 }, { 2, -0.4, -200 }, { 2, 0.6 }, { 2, -0.6 }, { 2, 0.3, 150 }, { 2, 0, -150 }, { 2, 0 } }) + road.start = K.barTime(79) + road.cityX = 0 + videoPlay(video.plasma) + end, + draw = function(t, bar, k) + local phrase = math.floor((bar - 79) / 2) + local final = bar >= 87 + + if final or phrase % 2 == 0 then + hideAll() + roadSky() + show(world.logo, world.knot) + nodeSetPosition(world.logo, -3.4, 7.6, -20) + nodeSetRotation(world.logo, 0, math.sin(t * 0.8) * 20, math.sin(t * 0.5) * 6) + nodeSetPosition(world.knot, 6.0, 7.4, -22) + nodeSetScale(world.knot, 0.8 + 0.2 * K.decay("kicks", t, 9)) + nodeSetRotation(world.knot, t * 23, t * 41, t * 11) + local car = drawRoad(t, roadPosition(t), K.decay("kicks", t, 6)) + + drawCar(t, car) + else + hideAll() + show(world.floor, world.mountains, world.knot) + for _, s in ipairs(world.spheres) do + show(s) + end + for _, b in ipairs(world.billboards) do + show(b) + end + local a = t * 0.4 + phrase + + nodeSetPosition(world.camera, math.sin(a) * 9, 2.5 + math.sin(t * 0.7), math.cos(a) * 9) + nodeLookAt(world.camera, 0, 3, 0) + nodeSetPosition(world.knot, 0, 3, 0) + nodeSetScale(world.knot, 1 + 0.2 * K.decay("kicks", t, 9)) + nodeSetRotation(world.knot, t * 23, t * 41, t * 11) + for i, sphere in ipairs(world.spheres) do + local b = t * 0.8 + i / #world.spheres * 2 * math.pi + + nodeSetPosition(sphere, math.cos(b) * 3.6, 3 + math.sin(b * 2 + t) * 1.1, math.sin(b) * 3.6) + end + gridPulse(t, 0.35) + knotLights(t, true) + beams(t, lastT, true) + sceneSetSkyIntensity(1.5) + nodeSetPosition(world.floor, 0, 0, (t * 4) % GRID_CELL) + end + fireworks(t, lastT) + local cut = ((bar - 79) / 2) % 1 + + K.flash(255, 255, 255, math.floor(220 * math.exp(-cut * 2 * 1.967 * 12))) + end, + }, + -- Bar 95 on: the last hit, a burn to white, the set switched off the old way, and the credits. + { + from = 95, to = 200, + enter = function(t) + hideAll() + videoPause(video.plasma) + end, + draw = function(t, bar, k) + local p = t - K.barTime(95) + + K.flash(0, 0, 0, 255) + if p < 0.6 then + -- The picture collapses to a line, then to a point, then is gone. + local hgt = (p < 0.25) and K.lerp(H, 3, K.easeIn(p / 0.25)) or 3 + local wid = (p < 0.25) and W or K.lerp(W, 2, K.easeIn((p - 0.25) / 0.3)) + + K.box(W / 2 - wid / 2, H / 2 - hgt / 2, W / 2 + wid / 2, H / 2 + hgt / 2, 255, 240, 255, 255) + end + local lines = { + { "NEON COAST", 56, 255, 120, 230 }, + { "", 16 }, + { "music \"Neons in Napoli\" by eliza_music", 28, 255, 255, 255 }, + { "code and art Claude", 28, 255, 255, 255 }, + { "engine Singe", 28, 255, 255, 255 }, + { "", 16 }, + { "everything you saw ran live, on the music's clock", 22, 160, 220, 255 }, + } + local y = 100 + + for i, line in ipairs(lines) do + local a = K.smooth(1.0 + i * 0.35, 1.6 + i * 0.35, p) * (1 - K.smooth(K.duration - K.barTime(95) + 0.5, K.duration - K.barTime(95) + 1.8, p)) + + if line[3] and a > 0 then + K.text(W / 2, y, line[1], line[2], math.floor(line[3] * a), math.floor(line[4] * a), math.floor(line[5] * a), "center") + end + y = y + line[2] + 18 + end + end, + }, +} + +loadArt() +art.scrollFont = fontLoad("Singe/FreeSansBold.ttf", 44) +art.fireworks = emitterNew() +emitterSetBlend(art.fireworks, PARTICLE_ADD) +emitterSetRate(art.fireworks, 0) +emitterSetLife(art.fireworks, 0.8, 1.6) +emitterSetSpeed(art.fireworks, 80, 260) +emitterSetSpread(art.fireworks, 180) +emitterSetGravity(art.fireworks, 0, 160) +emitterSetDrag(art.fireworks, 1.2) +emitterSetSize(art.fireworks, 7, 2) +emitterSetTrail(art.fireworks, 6, 3) +emitterSetMax(art.fireworks, 3000) +emitterStart(art.fireworks) +buildWorld() +hideAll() + +-- The last scene of each frame remembers the time, for "what happened since last frame". +SCENES[#SCENES + 1] = { + from = 0, to = 1000, + draw = function(t, bar, k) + lastT = t + end, +} +K.run(SCENES) diff --git a/demos/neonCoast/sync.lua b/demos/neonCoast/sync.lua new file mode 100644 index 000000000..544b31c3e --- /dev/null +++ b/demos/neonCoast/sync.lua @@ -0,0 +1,273 @@ +-- Written by util/demoSync.py from music.mp3: what the demo synchronises to. Times are seconds of +-- music; envelopes are 60 samples a second, one character each, 0 to 63 in the base64 alphabet. +return { + duration = 188.328, + rate = 60, + barStart = 1, -- The beat (counting from 1) that begins the first whole bar + beats = { + 0.1008, 0.5926, 1.0845, 1.5763, 2.0681, 2.5599, 3.0517, 3.5436, 4.0354, 4.5272, 5.0190, 5.5108, + 6.0027, 6.4945, 6.9863, 7.4781, 7.9700, 8.4618, 8.9536, 9.4454, 9.9372, 10.4291, 10.9209, 11.4127, + 11.9045, 12.3963, 12.8882, 13.3800, 13.8718, 14.3636, 14.8554, 15.3473, 15.8391, 16.3309, 16.8227, 17.3145, + 17.8064, 18.2982, 18.7900, 19.2818, 19.7736, 20.2655, 20.7573, 21.2491, 21.7409, 22.2327, 22.7246, 23.2164, + 23.7082, 24.2000, 24.6918, 25.1837, 25.6755, 26.1673, 26.6591, 27.1509, 27.6428, 28.1346, 28.6264, 29.1182, + 29.6101, 30.1019, 30.5937, 31.0855, 31.5773, 32.0692, 32.5610, 33.0528, 33.5446, 34.0364, 34.5283, 35.0201, + 35.5119, 36.0037, 36.4955, 36.9874, 37.4792, 37.9710, 38.4628, 38.9546, 39.4465, 39.9383, 40.4301, 40.9219, + 41.4137, 41.9056, 42.3974, 42.8892, 43.3810, 43.8728, 44.3647, 44.8565, 45.3483, 45.8401, 46.3319, 46.8238, + 47.3156, 47.8074, 48.2992, 48.7911, 49.2829, 49.7747, 50.2665, 50.7583, 51.2502, 51.7420, 52.2338, 52.7256, + 53.2174, 53.7093, 54.2011, 54.6929, 55.1847, 55.6765, 56.1684, 56.6602, 57.1520, 57.6438, 58.1356, 58.6275, + 59.1193, 59.6111, 60.1029, 60.5947, 61.0866, 61.5784, 62.0702, 62.5620, 63.0538, 63.5457, 64.0375, 64.5293, + 65.0211, 65.5129, 66.0048, 66.4966, 66.9884, 67.4802, 67.9720, 68.4639, 68.9557, 69.4475, 69.9393, 70.4312, + 70.9230, 71.4148, 71.9066, 72.3984, 72.8903, 73.3821, 73.8739, 74.3657, 74.8575, 75.3494, 75.8412, 76.3330, + 76.8248, 77.3166, 77.8085, 78.3003, 78.7921, 79.2839, 79.7757, 80.2676, 80.7594, 81.2512, 81.7430, 82.2348, + 82.7267, 83.2185, 83.7103, 84.2021, 84.6939, 85.1858, 85.6776, 86.1694, 86.6612, 87.1530, 87.6449, 88.1367, + 88.6285, 89.1203, 89.6121, 90.1040, 90.5958, 91.0876, 91.5794, 92.0713, 92.5631, 93.0549, 93.5467, 94.0385, + 94.5304, 95.0222, 95.5140, 96.0058, 96.4976, 96.9895, 97.4813, 97.9731, 98.4649, 98.9567, 99.4486, 99.9404, + 100.4322, 100.9240, 101.4158, 101.9077, 102.3995, 102.8913, 103.3831, 103.8749, 104.3668, 104.8586, 105.3504, 105.8422, + 106.3340, 106.8259, 107.3177, 107.8095, 108.3013, 108.7931, 109.2850, 109.7768, 110.2686, 110.7604, 111.2523, 111.7441, + 112.2359, 112.7277, 113.2195, 113.7114, 114.2032, 114.6950, 115.1868, 115.6786, 116.1705, 116.6623, 117.1541, 117.6459, + 118.1377, 118.6296, 119.1214, 119.6132, 120.1050, 120.5968, 121.0887, 121.5805, 122.0723, 122.5641, 123.0559, 123.5478, + 124.0396, 124.5314, 125.0232, 125.5150, 126.0069, 126.4987, 126.9905, 127.4823, 127.9741, 128.4660, 128.9578, 129.4496, + 129.9414, 130.4332, 130.9251, 131.4169, 131.9087, 132.4005, 132.8924, 133.3842, 133.8760, 134.3678, 134.8596, 135.3515, + 135.8433, 136.3351, 136.8269, 137.3187, 137.8106, 138.3024, 138.7942, 139.2860, 139.7778, 140.2697, 140.7615, 141.2533, + 141.7451, 142.2369, 142.7288, 143.2206, 143.7124, 144.2042, 144.6960, 145.1879, 145.6797, 146.1715, 146.6633, 147.1551, + 147.6470, 148.1388, 148.6306, 149.1224, 149.6142, 150.1061, 150.5979, 151.0897, 151.5815, 152.0734, 152.5652, 153.0570, + 153.5488, 154.0406, 154.5325, 155.0243, 155.5161, 156.0079, 156.4997, 156.9916, 157.4834, 157.9752, 158.4670, 158.9588, + 159.4507, 159.9425, 160.4343, 160.9261, 161.4179, 161.9098, 162.4016, 162.8934, 163.3852, 163.8770, 164.3689, 164.8607, + 165.3525, 165.8443, 166.3361, 166.8280, 167.3198, 167.8116, 168.3034, 168.7952, 169.2871, 169.7789, 170.2707, 170.7625, + 171.2543, 171.7462, 172.2380, 172.7298, 173.2216, 173.7135, 174.2053, 174.6971, 175.1889, 175.6807, 176.1726, 176.6644, + 177.1562, 177.6480, 178.1398, 178.6317, 179.1235, 179.6153, 180.1071, 180.5989, 181.0908, 181.5826, 182.0744, 182.5662, + 183.0580, 183.5499, 184.0417, 184.5335, 185.0253, 185.5171, 186.0090, 186.5008, 186.9926, 187.4844, 187.9762, + }, + kicks = { + 0.046, 0.313, 0.662, 0.789, 0.940, 1.184, 1.405, 1.649, 1.892, 2.148, 2.380, 2.624, + 2.763, 3.135, 3.367, 3.611, 3.738, 3.866, 4.122, 4.249, 4.470, 4.598, 5.085, 5.213, + 5.445, 5.584, 5.724, 6.060, 6.304, 6.432, 6.722, 6.943, 7.070, 7.198, 7.419, 7.674, + 7.941, 8.173, 8.417, 8.649, 8.789, 8.928, 9.265, 9.427, 9.764, 9.903, 10.286, 10.414, + 10.728, 10.879, 11.238, 11.378, 11.610, 11.738, 11.877, 12.109, 12.330, 12.597, 12.841, 13.084, + 13.340, 13.688, 13.839, 14.176, 14.315, 14.698, 15.163, 15.290, 15.546, 15.790, 16.033, 16.277, + 16.521, 16.765, 17.020, 17.252, 17.508, 17.670, 17.995, 18.135, 18.274, 18.657, 19.098, 19.226, + 19.458, 19.632, 20.085, 20.236, 20.457, 20.584, 20.712, 20.944, 21.072, 21.223, 21.699, 21.931, + 22.071, 22.419, 22.547, 22.674, 23.046, 23.197, 23.406, 23.533, 23.661, 23.905, 24.126, 24.393, + 24.520, 24.671, 24.880, 25.124, 25.530, 26.122, 26.355, 26.482, 26.633, 26.854, 27.086, 27.341, + 27.585, 27.736, 27.945, 28.108, 28.549, 28.944, 29.071, 29.431, 29.942, 30.174, 30.407, 31.045, + 31.347, 31.498, 31.916, 32.148, 32.496, 32.624, 32.763, 32.891, 33.019, 33.251, 33.506, 33.739, + 33.982, 34.122, 34.366, 34.737, 34.865, 35.480, 35.828, 35.968, 36.200, 36.328, 36.455, 36.699, + 36.931, 37.291, 37.419, 37.790, 37.918, 38.290, 38.650, 38.801, 39.277, 39.416, 39.753, 39.880, + 40.147, 40.380, 40.739, 40.867, 41.123, 41.262, 41.715, 41.866, 42.098, 42.249, 42.376, 42.597, + 42.829, 43.096, 43.247, 43.572, 43.723, 44.188, 44.687, 44.826, 45.174, 45.302, 45.534, 45.790, + 46.057, 46.277, 46.533, 46.765, 47.020, 47.264, 47.624, 47.752, 47.996, 48.123, 48.251, 48.495, + 48.739, 48.913, 49.145, 49.459, 49.586, 49.737, 50.085, 50.469, 50.608, 50.968, 51.107, 51.572, + 51.699, 51.955, 52.210, 52.535, 52.663, 53.162, 53.406, 53.534, 53.685, 53.905, 54.149, 54.393, + 54.520, 54.996, 55.124, 55.391, 55.635, 55.867, 55.995, 56.250, 56.494, 56.854, 56.993, 57.365, + 57.597, 57.725, 57.853, 57.980, 58.340, 58.468, 58.596, 59.083, 59.431, 59.919, 60.047, 60.418, + 60.546, 60.790, 60.918, 61.057, 61.405, 61.544, 61.777, 62.009, 62.264, 62.531, 62.764, 63.007, + 63.240, 63.367, 63.495, 63.866, 64.006, 64.342, 64.470, 64.842, 64.981, 65.213, 65.457, 65.712, + 65.945, 66.316, 66.444, 66.688, 66.827, 66.955, 67.315, 67.442, 67.791, 67.930, 68.278, 68.441, + 68.650, 68.778, 68.917, 69.149, 69.381, 69.753, 69.880, 70.136, 70.380, 70.740, 71.227, 71.355, + 71.529, 71.750, 72.214, 72.377, 72.516, 72.725, 72.853, 72.992, 73.201, 73.352, 73.839, 74.083, + 74.315, 74.803, 75.163, 75.326, 75.546, 75.790, 76.022, 76.150, 76.289, 76.765, 77.021, 77.253, + 77.508, 77.752, 77.996, 78.124, 78.251, 78.611, 78.739, 78.983, 79.145, 79.586, 79.726, 80.086, + 80.213, 80.469, 80.701, 80.956, 81.189, 81.444, 81.688, 81.932, 82.059, 82.187, 82.442, 82.570, + 83.035, 83.185, 83.522, 83.661, 84.021, 84.149, 84.509, 84.637, 84.881, 85.008, 85.159, 85.496, + 85.624, 85.867, 86.100, 86.494, 86.982, 87.458, 87.597, 87.829, 88.085, 88.329, 88.816, 89.060, + 89.223, 89.432, 89.699, 90.523, 90.778, 90.906, 91.045, 91.266, 91.394, 91.521, 91.765, 91.893, + 92.032, 92.253, 92.508, 92.752, 92.903, 93.240, 93.367, 93.727, 93.867, 94.006, 94.494, 94.737, + 94.958, 95.213, 95.469, 95.701, 95.945, 96.316, 96.444, 96.676, 96.816, 96.955, 97.176, 97.431, + 97.791, 97.919, 98.278, 98.406, 98.662, 98.801, 99.149, 99.289, 99.753, 100.124, 100.252, 100.403, + 100.624, 100.751, 100.902, 101.123, 101.274, 101.727, 102.214, 102.342, 102.586, 102.713, 102.864, 103.073, + 103.201, 103.573, 103.805, 104.072, 104.304, 104.676, 104.826, 105.163, 105.291, 105.535, 105.662, 106.150, + 106.289, 106.638, 106.777, 107.137, 107.265, 107.624, 107.764, 107.892, 108.112, 108.240, 108.751, 108.890, + 109.122, 109.261, 109.529, 109.726, 110.237, 110.399, 110.573, 111.073, 111.212, 111.351, 111.572, 111.723, + 111.955, 112.419, 112.663, 113.035, 113.174, 113.406, 113.534, 113.662, 114.033, 114.161, 114.532, 114.672, + 114.892, 115.032, 115.159, 115.403, 115.635, 115.775, 116.007, 116.378, 116.622, 116.750, 117.110, 117.365, + 118.073, 118.445, 118.573, 118.944, 119.316, 119.455, 119.803, 120.047, 120.291, 120.419, 120.779, 120.906, + 121.034, 121.278, 121.510, 121.777, 121.928, 122.392, 122.520, 122.764, 122.996, 123.252, 123.484, 123.751, + 123.983, 124.227, 124.471, 124.842, 124.970, 125.214, 125.457, 125.829, 125.968, 126.200, 126.351, 126.804, + 126.955, 127.303, 127.687, 127.919, 128.174, 128.406, 128.650, 128.778, 129.149, 129.382, 129.649, 129.776, + 130.252, 130.740, 130.879, 131.239, 131.379, 131.738, 131.866, 132.098, 132.261, 132.586, 132.725, 133.201, + 133.341, 133.584, 133.712, 133.956, 134.188, 134.327, 134.560, 134.931, 135.187, 135.419, 135.674, 136.162, + 136.417, 136.649, 136.905, 137.160, 137.404, 137.660, 137.892, 138.136, 138.507, 138.751, 139.111, 139.366, + 139.598, 139.738, 139.993, 140.214, 140.341, 140.469, 140.608, 140.957, 141.084, 141.317, 141.700, 141.944, + 142.292, 142.547, 142.675, 142.814, 143.035, 143.163, 143.406, 143.534, 143.662, 143.790, 144.045, 144.254, + 144.509, 144.997, 145.125, 145.252, 145.519, 145.868, 145.995, 146.367, 146.599, 146.843, 146.971, 147.098, + 147.226, 147.470, 147.725, 147.969, 148.201, 148.445, 148.817, 148.944, 149.827, 149.954, 150.233, 150.361, + 150.512, 150.941, 151.301, 151.533, 151.777, 152.009, 152.172, 152.404, 152.892, 153.031, 153.507, 153.739, + 154.355, 154.482, 154.842, 154.970, 155.214, 155.341, 155.492, 155.829, 155.957, 156.201, 156.328, 156.479, + 156.688, 156.932, 157.187, 157.315, 157.443, 157.675, 157.942, 158.163, 158.290, 158.430, 158.662, 158.906, + 159.266, 159.405, 159.649, 159.904, 160.148, 160.369, 160.752, 160.891, 161.251, 161.379, 161.634, 162.226, + 162.354, 162.609, 162.760, 163.097, 163.225, 163.573, 163.701, 163.840, 164.072, 164.328, 164.688, 164.815, + 165.059, 165.210, 165.674, 165.825, 166.150, 166.301, 166.650, 166.812, 167.149, 167.288, 167.544, 167.671, + 168.124, 168.252, 168.635, 168.983, 169.111, 169.378, 169.599, 169.726, 170.098, 170.585, 170.736, 171.073, + 171.212, 171.445, 171.572, 171.700, 171.932, 172.071, 172.431, 172.559, 172.698, 173.058, 173.407, 173.534, + 174.034, 174.173, 174.405, 174.649, 174.881, 175.009, 175.137, 175.380, 175.508, 175.880, 176.007, 176.367, + 176.611, 176.855, 176.982, 177.122, 177.482, 177.865, 178.085, 178.329, 178.457, 178.956, 179.316, 179.444, + 179.827, 179.966, 180.419, 180.570, 180.918, 181.069, 181.394, 181.557, 182.044, 182.288, 182.544, 182.764, + 182.904, 183.147, 183.391, 183.635, 183.867, 184.146, 184.692, 184.831, 185.005, 185.202, 185.481, 185.841, + 185.980, 186.479, 186.735, 187.164, 188.082, 188.291, + }, + snares = { + 0.046, 0.174, 0.302, 0.430, 0.662, 0.789, 0.917, 1.045, 1.289, 1.533, 1.660, 1.904, + 2.148, 2.276, 2.519, 2.763, 3.007, 3.135, 3.379, 3.622, 3.866, 3.994, 4.238, 4.481, + 4.609, 4.853, 4.981, 5.224, 5.468, 5.712, 6.072, 6.316, 6.444, 6.687, 6.815, 7.059, + 7.303, 7.430, 7.930, 8.417, 8.661, 8.789, 9.033, 9.160, 9.392, 9.648, 9.880, 10.019, + 10.379, 10.623, 10.751, 10.879, 11.122, 11.366, 11.610, 11.738, 11.865, 12.109, 12.341, 12.597, + 12.841, 12.968, 13.328, 13.584, 13.816, 13.955, 14.315, 14.803, 14.930, 15.058, 15.302, 15.546, + 15.673, 15.801, 16.289, 16.660, 17.020, 17.148, 17.519, 17.763, 18.251, 18.495, 18.739, 18.994, + 19.238, 19.482, 19.725, 19.853, 19.981, 20.213, 20.584, 20.712, 20.956, 21.084, 21.455, 21.699, + 21.827, 22.187, 22.442, 22.674, 23.046, 23.174, 23.545, 23.789, 23.917, 24.149, 24.404, 24.648, + 24.892, 25.020, 25.391, 25.635, 25.879, 26.122, 26.366, 26.494, 26.622, 26.982, 27.353, 27.585, + 27.725, 28.085, 28.456, 28.584, 28.711, 29.071, 29.327, 29.698, 30.058, 30.186, 30.430, 31.533, + 31.660, 31.893, 32.020, 32.264, 32.392, 32.520, 32.752, 32.879, 33.007, 33.251, 33.495, 33.622, + 33.994, 34.122, 34.354, 34.482, 34.725, 34.853, 35.457, 35.840, 36.212, 36.444, 36.571, 36.931, + 37.187, 37.314, 37.674, 37.802, 38.174, 38.406, 38.534, 38.661, 38.789, 39.160, 39.393, 39.648, + 39.776, 40.380, 40.507, 40.867, 41.355, 41.610, 41.738, 42.109, 42.342, 42.469, 42.713, 42.841, + 43.085, 43.212, 43.340, 43.584, 43.712, 44.071, 44.315, 44.443, 44.803, 45.302, 45.546, 45.674, + 46.045, 46.277, 46.405, 46.533, 46.777, 47.032, 47.264, 47.520, 47.752, 48.007, 48.251, 48.379, + 48.739, 48.994, 49.238, 49.482, 49.609, 50.213, 50.341, 50.596, 50.956, 51.084, 51.212, 51.699, + 52.187, 52.431, 52.674, 52.930, 53.058, 53.429, 53.661, 53.917, 54.149, 54.648, 54.892, 55.136, + 55.391, 55.635, 55.879, 56.239, 56.483, 56.738, 56.982, 57.109, 57.342, 57.597, 57.725, 57.969, + 58.096, 58.329, 58.456, 59.072, 59.571, 59.931, 60.058, 60.314, 60.546, 60.918, 61.045, 61.289, + 61.533, 61.777, 62.020, 62.264, 62.508, 62.764, 63.007, 63.507, 63.750, 63.994, 64.482, 64.726, + 65.213, 65.457, 65.712, 65.956, 66.200, 66.444, 66.699, 66.943, 67.187, 67.431, 67.802, 67.930, + 68.174, 68.418, 68.789, 69.161, 69.393, 69.648, 69.892, 70.136, 70.380, 70.635, 70.879, 71.367, + 71.866, 72.353, 72.597, 72.841, 73.085, 73.329, 73.700, 73.828, 74.072, 74.315, 74.571, 74.803, + 75.302, 75.790, 76.045, 76.289, 76.533, 76.777, 76.904, 77.032, 77.264, 77.520, 77.752, 78.007, + 78.135, 78.495, 78.739, 78.867, 78.994, 79.226, 79.482, 79.610, 79.970, 80.097, 80.469, 80.596, + 80.840, 81.200, 81.456, 81.688, 81.816, 81.943, 82.071, 82.559, 82.802, 82.930, 83.174, 83.418, + 83.661, 83.917, 84.149, 84.405, 84.648, 84.776, 85.136, 85.391, 85.624, 85.879, 86.007, 86.367, + 86.610, 86.738, 87.098, 87.353, 87.597, 87.725, 88.085, 88.340, 88.828, 89.072, 89.443, 90.059, + 90.430, 91.034, 91.162, 91.289, 91.521, 91.649, 91.777, 92.021, 92.148, 92.392, 92.764, 93.008, + 93.251, 93.379, 93.623, 93.867, 94.238, 94.482, 94.970, 95.225, 95.469, 95.597, 95.956, 96.328, + 96.700, 96.932, 97.187, 97.315, 97.559, 97.802, 98.174, 98.302, 98.662, 98.789, 99.161, 99.393, + 99.521, 99.648, 99.892, 100.264, 100.635, 100.867, 101.123, 101.251, 101.483, 101.738, 101.866, 102.098, + 102.237, 102.725, 103.097, 103.329, 103.457, 103.584, 103.816, 104.200, 104.559, 104.687, 105.059, 105.186, + 105.430, 105.674, 106.046, 106.278, 106.661, 107.032, 107.265, 107.520, 107.752, 108.135, 108.495, 108.751, + 108.878, 109.111, 109.238, 109.366, 109.610, 109.738, 110.214, 110.713, 110.968, 111.212, 111.340, 111.700, + 111.943, 112.187, 112.443, 112.686, 113.058, 113.662, 113.905, 114.033, 114.405, 114.649, 114.892, 115.020, + 115.264, 115.508, 115.635, 115.763, 116.007, 116.251, 116.622, 116.982, 117.110, 117.238, 117.481, 117.969, + 118.584, 118.956, 119.327, 119.560, 119.943, 120.314, 120.546, 120.802, 121.034, 121.289, 121.533, 121.777, + 122.021, 122.520, 122.892, 123.495, 123.751, 124.238, 124.482, 124.738, 124.970, 125.225, 125.469, 125.713, + 125.957, 126.444, 126.827, 127.431, 127.814, 128.174, 128.418, 128.662, 128.906, 129.161, 129.405, 129.776, + 130.380, 130.879, 131.123, 131.367, 131.738, 131.866, 132.110, 132.354, 132.853, 133.341, 133.956, 134.200, + 134.444, 134.571, 134.815, 135.059, 135.303, 135.546, 135.674, 135.918, 136.046, 136.290, 136.533, 136.777, + 136.905, 137.149, 137.276, 137.520, 137.764, 137.892, 138.136, 138.379, 138.623, 138.751, 138.995, 139.122, + 139.366, 139.494, 139.738, 139.981, 140.225, 140.353, 140.597, 140.725, 140.968, 141.212, 141.456, 141.584, + 141.827, 141.955, 142.199, 142.443, 142.687, 142.814, 143.058, 143.186, 143.430, 143.673, 143.801, 144.045, + 144.289, 144.417, 144.660, 144.904, 145.032, 145.276, 145.519, 145.763, 145.891, 146.135, 146.262, 146.506, + 146.750, 146.878, 147.110, 147.238, 147.365, 147.493, 147.853, 147.981, 148.213, 148.468, 148.596, 148.840, + 149.084, 149.328, 149.455, 149.699, 149.943, 150.187, 150.430, 150.674, 150.802, 151.046, 151.290, 151.417, + 151.661, 152.021, 152.149, 152.393, 152.520, 152.764, 152.892, 153.496, 153.995, 154.366, 154.738, 154.970, + 155.353, 155.713, 155.957, 156.212, 156.456, 156.700, 156.944, 157.187, 157.443, 157.931, 158.314, 158.674, + 158.917, 159.161, 159.289, 159.660, 159.904, 160.148, 160.392, 160.636, 160.879, 161.135, 161.379, 161.866, + 162.238, 162.366, 162.609, 162.842, 163.225, 163.596, 163.828, 164.084, 164.328, 164.571, 164.815, 165.059, + 165.198, 165.802, 166.058, 166.290, 166.545, 166.777, 167.033, 167.277, 167.520, 167.764, 167.903, 168.147, + 168.751, 169.006, 169.239, 169.738, 169.982, 170.109, 170.597, 170.969, 171.212, 171.456, 171.700, 171.955, + 172.083, 172.443, 172.571, 172.931, 173.174, 173.430, 173.674, 173.917, 174.161, 174.417, 174.649, 174.904, + 175.148, 175.392, 175.636, 175.880, 176.123, 176.379, 176.623, 176.866, 177.006, 177.366, 177.598, 177.853, + 178.097, 178.352, 178.585, 179.084, 179.328, 179.572, 179.827, 180.059, 180.315, 180.558, 180.802, 180.930, + 181.174, 181.301, 181.534, 181.789, 182.033, 182.288, 182.520, 182.892, 183.507, 183.867, 184.099, 184.494, + 184.622, 184.866, 185.237, 185.365, 185.597, 185.841, + }, + hats = { + 0.046, 0.186, 0.302, 0.430, 0.557, 0.673, 0.789, 0.917, 1.045, 1.173, 1.289, 1.416, + 1.544, 1.660, 1.776, 1.904, 2.032, 2.148, 2.276, 2.392, 2.519, 2.635, 2.763, 2.891, + 3.007, 3.135, 3.251, 3.379, 3.506, 3.622, 3.750, 3.866, 3.994, 4.110, 4.238, 4.365, + 4.481, 4.609, 4.725, 4.853, 4.981, 5.097, 5.224, 5.341, 5.468, 5.596, 5.712, 5.840, + 6.072, 6.316, 6.444, 6.687, 6.815, 7.059, 7.303, 7.430, 7.930, 8.173, 8.301, 8.417, + 8.661, 8.789, 8.905, 9.021, 9.149, 9.276, 9.392, 9.648, 9.776, 9.892, 10.019, 10.136, + 10.263, 10.379, 10.623, 10.751, 11.122, 11.250, 11.366, 11.610, 11.749, 12.109, 12.237, 12.341, + 12.597, 12.725, 12.841, 12.968, 13.084, 13.224, 13.328, 13.572, 13.711, 13.827, 13.955, 14.199, + 14.315, 14.571, 14.698, 14.930, 15.058, 15.174, 15.302, 15.546, 15.685, 16.045, 16.289, 16.533, + 16.660, 16.788, 17.020, 17.148, 17.276, 17.519, 17.763, 17.891, 18.007, 18.251, 18.506, 18.994, + 19.122, 19.238, 19.482, 19.609, 19.725, 19.853, 19.981, 20.097, 20.213, 20.468, 20.596, 20.712, + 20.956, 21.084, 21.200, 21.455, 21.583, 21.827, 21.943, 22.187, 22.430, 22.570, 22.930, 23.057, + 23.174, 23.417, 23.545, 23.917, 24.149, 24.404, 24.532, 24.648, 24.776, 24.892, 25.020, 25.136, + 25.379, 25.519, 25.763, 25.879, 26.122, 26.366, 26.494, 26.865, 26.982, 27.109, 27.353, 27.597, + 27.725, 27.852, 28.085, 28.340, 28.456, 28.584, 28.700, 28.828, 28.955, 29.071, 29.327, 29.443, + 29.698, 29.814, 30.058, 30.314, 30.430, 30.685, 31.533, 31.660, 31.904, 32.020, 32.148, 32.264, + 32.392, 32.508, 32.636, 32.752, 32.879, 33.007, 33.123, 33.251, 33.367, 33.495, 33.622, 33.739, + 33.982, 34.122, 34.354, 34.482, 34.725, 34.853, 34.969, 35.468, 35.724, 35.956, 36.200, 36.328, + 36.444, 36.571, 36.688, 36.827, 36.931, 37.187, 37.314, 37.431, 37.558, 37.674, 37.802, 37.918, + 38.162, 38.290, 38.417, 38.534, 38.661, 38.789, 38.905, 39.149, 39.393, 39.520, 39.648, 39.776, + 39.892, 40.136, 40.263, 40.380, 40.507, 40.623, 40.751, 40.867, 41.123, 41.250, 41.366, 41.494, + 41.610, 41.738, 41.854, 42.098, 42.353, 42.469, 42.597, 42.713, 42.841, 43.085, 43.212, 43.340, + 43.456, 43.584, 43.712, 43.828, 44.071, 44.199, 44.315, 44.443, 44.559, 44.687, 44.803, 45.047, + 45.186, 45.302, 45.418, 45.546, 45.674, 45.790, 46.034, 46.173, 46.277, 46.405, 46.533, 46.660, + 46.777, 47.020, 47.148, 47.264, 47.520, 47.636, 47.763, 48.007, 48.135, 48.251, 48.379, 48.495, + 48.623, 48.739, 48.982, 49.122, 49.238, 49.366, 49.482, 49.609, 49.726, 49.969, 50.225, 50.341, + 50.469, 50.585, 50.712, 50.956, 51.084, 51.212, 51.699, 51.943, 52.071, 52.198, 52.315, 52.431, + 52.558, 52.686, 52.930, 53.058, 53.174, 53.418, 53.661, 53.905, 54.033, 54.161, 54.277, 54.404, + 54.648, 54.892, 55.020, 55.136, 55.391, 55.635, 55.879, 56.250, 56.494, 56.738, 56.854, 56.982, + 57.098, 57.226, 57.353, 57.597, 57.725, 57.853, 57.969, 58.096, 58.340, 58.456, 58.572, 59.327, + 59.571, 59.815, 59.942, 60.186, 60.302, 60.546, 60.801, 60.918, 61.289, 61.533, 61.777, 61.904, + 62.020, 62.148, 62.264, 62.508, 62.764, 63.007, 63.263, 63.507, 63.750, 63.878, 64.238, 64.482, + 64.726, 64.853, 65.225, 65.353, 65.469, 65.712, 65.840, 65.956, 66.084, 66.200, 66.444, 66.688, + 66.827, 66.943, 67.199, 67.431, 67.686, 67.802, 67.930, 68.174, 68.418, 68.661, 68.789, 69.161, + 69.404, 69.648, 69.892, 70.136, 70.380, 70.635, 71.134, 71.262, 71.367, 71.622, 71.866, 72.110, + 72.353, 72.597, 72.725, 72.853, 72.980, 73.085, 73.224, 73.340, 73.584, 73.712, 73.828, 73.956, + 74.083, 74.327, 74.571, 74.815, 74.908, 75.059, 75.314, 75.546, 75.790, 76.045, 76.173, 76.289, + 76.533, 76.777, 76.904, 77.032, 77.276, 77.520, 77.764, 78.007, 78.135, 78.251, 78.495, 78.750, + 78.867, 78.994, 79.238, 79.482, 79.610, 79.970, 80.109, 80.225, 80.469, 80.596, 80.840, 80.968, + 81.200, 81.456, 81.583, 81.943, 82.187, 82.442, 82.559, 82.802, 82.930, 83.174, 83.418, 83.545, + 83.789, 83.905, 84.045, 84.161, 84.405, 84.648, 84.776, 84.892, 85.148, 85.391, 85.635, 85.867, + 86.007, 86.123, 86.367, 86.622, 86.738, 86.866, 86.982, 87.110, 87.353, 87.481, 87.609, 87.725, + 87.841, 87.969, 88.097, 88.340, 88.712, 88.828, 88.956, 89.072, 89.327, 89.443, 90.059, 90.186, + 90.430, 90.546, 91.045, 91.289, 91.417, 91.533, 91.661, 91.777, 92.021, 92.148, 92.392, 92.508, + 92.880, 93.008, 93.135, 93.251, 93.379, 93.495, 93.623, 93.739, 93.867, 93.983, 94.366, 94.482, + 94.737, 94.981, 95.225, 95.353, 95.469, 95.597, 95.713, 95.840, 95.956, 96.200, 96.328, 96.444, + 96.572, 96.688, 96.827, 96.932, 97.187, 97.315, 97.431, 97.559, 97.675, 97.802, 97.919, 98.162, + 98.302, 98.418, 98.545, 98.662, 98.789, 98.905, 99.149, 99.277, 99.393, 99.521, 99.648, 99.776, + 99.892, 100.136, 100.264, 100.380, 100.508, 100.624, 100.751, 100.879, 101.123, 101.251, 101.367, 101.494, + 101.622, 101.738, 101.866, 102.110, 102.237, 102.365, 102.481, 102.597, 102.725, 102.841, 103.085, 103.213, + 103.329, 103.457, 103.573, 103.712, 103.816, 104.072, 104.200, 104.316, 104.443, 104.559, 104.687, 104.803, + 105.047, 105.186, 105.302, 105.430, 105.546, 105.674, 105.790, 106.034, 106.173, 106.289, 106.417, 106.533, + 106.661, 106.777, 107.021, 107.148, 107.265, 107.392, 107.508, 107.636, 107.752, 108.008, 108.135, 108.251, + 108.495, 108.623, 108.751, 108.867, 108.994, 109.111, 109.238, 109.366, 109.482, 109.610, 109.726, 110.097, + 110.214, 110.481, 110.713, 110.968, 111.212, 111.340, 111.456, 111.583, 111.700, 111.943, 112.071, 112.199, + 112.443, 112.686, 112.930, 113.058, 113.174, 113.302, 113.418, 113.546, 113.662, 113.905, 114.045, 114.149, + 114.416, 114.660, 114.904, 115.264, 115.519, 115.635, 115.763, 116.367, 116.611, 116.994, 117.110, 117.354, + 117.470, 117.597, 118.097, 118.584, 118.828, 118.956, 119.316, 119.455, 119.560, 119.815, 119.931, 120.303, + 120.546, 120.790, 121.046, 121.289, 121.417, 121.533, 121.777, 121.905, 122.032, 122.160, 122.276, 122.520, + 122.764, 122.892, 123.008, 123.252, 123.391, 123.507, 123.751, 123.878, 124.238, 124.482, 124.738, 125.109, + 125.225, 125.469, 125.713, 125.968, 126.084, 126.200, 126.340, 126.456, 126.700, 126.827, 127.187, 127.315, + 127.431, 127.687, 127.803, 128.174, 128.418, 128.662, 128.789, 128.906, 129.149, 129.289, 129.405, 129.649, + 129.776, 129.904, 130.148, 130.276, 130.392, 130.635, 130.763, 130.879, 131.007, 131.123, 131.251, 131.379, + 131.622, 131.750, 131.994, 132.110, 132.238, 132.354, 132.609, 132.725, 132.853, 132.969, 133.097, 133.224, + 133.341, 133.596, 133.712, 133.956, 134.084, 134.200, 134.327, 134.444, 134.571, 134.699, 134.815, 134.943, + 135.059, 135.175, 135.303, 135.430, 135.558, 135.674, 135.802, 135.918, 136.046, 136.173, 136.290, 136.417, + 136.533, 136.661, 136.789, 136.905, 137.033, 137.149, 137.276, 137.404, 137.520, 137.648, 137.764, 137.892, + 138.008, 138.136, 138.263, 138.379, 138.507, 138.635, 138.751, 138.879, 138.995, 139.122, 139.250, 139.366, + 139.494, 139.610, 139.738, 139.865, 139.981, 140.109, 140.225, 140.353, 140.481, 140.597, 140.725, 140.841, + 140.968, 141.096, 141.212, 141.340, 141.468, 141.584, 141.711, 141.839, 141.955, 142.083, 142.199, 142.327, + 142.454, 142.571, 142.698, 142.814, 142.942, 143.070, 143.186, 143.314, 143.430, 143.557, 143.685, 143.801, + 143.929, 144.045, 144.173, 144.289, 144.417, 144.533, 144.660, 144.788, 144.916, 145.032, 145.160, 145.276, + 145.403, 145.531, 145.647, 145.775, 145.891, 146.019, 146.135, 146.262, 146.390, 146.506, 146.634, 146.762, + 146.878, 147.006, 147.133, 147.249, 147.377, 147.493, 147.621, 147.737, 147.853, 147.981, 148.097, 148.213, + 148.352, 148.468, 148.584, 148.840, 148.956, 149.072, 150.187, 150.314, 150.547, 150.674, 150.802, 150.918, + 151.046, 151.174, 151.290, 151.417, 151.533, 151.661, 151.777, 152.021, 152.149, 152.393, 152.520, 152.764, + 153.008, 153.496, 153.995, 154.239, 154.366, 154.738, 154.982, 155.225, 155.353, 155.597, 155.713, 155.957, + 156.201, 156.456, 156.584, 156.700, 156.944, 157.187, 157.327, 157.443, 157.687, 157.814, 157.931, 158.174, + 158.302, 158.557, 158.662, 158.917, 159.161, 159.289, 159.649, 159.904, 160.148, 160.520, 160.636, 160.879, + 161.123, 161.251, 161.379, 161.622, 161.750, 161.866, 162.110, 162.238, 162.598, 162.853, 163.097, 163.225, + 163.585, 163.828, 164.072, 164.328, 164.455, 164.571, 164.815, 165.059, 165.187, 165.314, 165.442, 165.558, + 165.802, 166.058, 166.174, 166.301, 166.429, 166.545, 166.673, 166.789, 167.033, 167.160, 167.532, 167.660, + 167.764, 168.020, 168.147, 168.263, 168.507, 168.635, 168.763, 169.006, 169.123, 169.250, 169.343, 169.494, + 169.738, 169.982, 170.109, 170.225, 170.353, 170.469, 170.597, 170.713, 170.969, 171.096, 171.212, 171.340, + 171.456, 171.584, 171.700, 171.944, 172.071, 172.199, 172.327, 172.443, 172.571, 172.687, 172.931, 173.058, + 173.174, 173.314, 173.430, 173.674, 173.917, 174.045, 174.161, 174.405, 174.533, 174.649, 174.904, 175.032, + 175.148, 175.276, 175.392, 175.520, 175.636, 175.880, 176.007, 176.135, 176.251, 176.379, 176.506, 176.623, + 176.866, 176.994, 177.110, 177.366, 177.493, 177.598, 177.853, 177.981, 178.097, 178.225, 178.341, 178.469, + 178.585, 178.828, 178.968, 179.084, 179.212, 179.328, 179.572, 179.815, 179.943, 180.071, 180.187, 180.303, + 180.442, 180.558, 180.802, 180.930, 181.046, 181.174, 181.290, 181.418, 181.534, 181.777, 181.917, 182.033, + 182.149, 182.277, 182.404, 182.520, 182.764, 182.892, 183.008, 183.136, 183.263, 183.391, 183.507, 183.751, + 183.879, 184.494, 184.622, 184.726, 184.866, 184.970, 185.272, 185.435, 185.853, 187.281, + }, + kick = [[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]], + snare = [[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]], + hat = [[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]], + bass = [[AABCEGHIIIIJJKLMLLLLMMNNMMNNOOONLKJIIIHHGGFFGGFFFFGGGFFFFGGHHGGFFFGGHHIKLNNNNMMNNOONOPQSTTSQOMLLLLLMNOQRRQQRRSTSRQOMLLLLKJIHHHHHIJKMNNNNNNNOOONNNNOOONMKIHGGGHHIJKLLLKKLLLLKJJJJJIIHFFEEEEEEFFGGHHIJKKLLLLMNOPPPONLJIHGHIJMOQQQQPQQRRRQPOOOOONMKJHGFEEEEEEFFEEEFFGHHHGHHIIIIHGGGGGGGGHIJJIIIIJJKKJHHGGGHGGFFEEEEEFGIJLMMMMMMNNNMNOQRTTSQOMKJJJJKLNOPPONNNOOOONMLLLLKKJIHHGGHHIKNQTUUSRQRSSSQOOOPRRQPPPRTVWWVTRQOOOQSVZbbaZYaejkkgcZYYXXXXXZdghhgdaZaaZYZabegggfffgeZVSQPQQQPPPPPQQQQPPPQQQQUZejopnjeYSPNMMNPRUWXXVSQPOOOQRUYdhkljdXROMLNPRUYZaaaaabcdfkqv033xrlfZWVTSSTUVWWWXXYabbZZZaceffdcbaZZYWVTTSSTTSSSRRRRTWbgmrrojdXTRRRRRRRRTUVWWXXXXWWYbfjmmjeaWUUVUTQOLJJJKLNOPQQQUZdhkiebYXWWWVVWYadghgfdbZXWVVXaceecZYYYYZZaZYWVUVVUUTTTUVWZdhnrtrnhcZYZYYWVTTSRRRSVYbddeffgknppojdYVTTVYbdghgfecbZZYYYacgkmlgbWTSTUUUTTTTTTSSSTUVWWXYaehihfbYWWXXXVTSSRQQQQSTVUUXbflrqnjfZXWWVUSRQQQQQQTVYbdbcfjnstqlfZWUUUTSRQRRTVVWWXYZabgmrwyvqkfcYXVTSSSTVWXXYZbceedcefhijgcZXWVXYYXVUSSSSRQQQQRRSVZchkmlkhebaaZZYYXVUSQPQRTUUUTTUXchkkkhecbaYXVTRQOOOPPQSTSTVXbhmonidXUTUUUVUUUSRQRSVYbccbaabdgiiheaXUTTTUVWXYZYYXXXYZYYbfimpokifcaZYXXYZbccbaZYYXXVVYdiorpkgcYWWVVVVVWYZaaZZYYZZachlorqlfaVSRRSSSTUVWWVUVVWXYYZbdeffdaZYXXYZYXVTRQRSUWXXXXXVVYchossplhecbaYXWWWXXXXWVUUTSSUWadghfbXTQPQRRSTUVXXWVVWWXYXYZcipwzytnfaXWUUTRQQQQQQQRSTTUWZdgjjhfeccccbaZYYYZZZZaceghgimsx0ztngcZXWWWWXYZbbbabbdeeecbabeijheaWUUUTSQPPPRSTSRRQQRSUXbgnrsqnhdZXWUTSRRRQQPOOPQSSUWaehkkifcZWVUUTUUVXZaaYXVUVVWYbeinqqokeYUSSSTUWYbcbaZYYZbbcdfgilmnmjeZVTRRTWaehihfcaYXWVXZbfjkjifdZYXXWVUUVWXXVUSRRSRSUWZfkmmlhdZXWWWYZabbaYXXXYZaZaejptvsmfZUQQQPONNNOPQRQQPPOPQTWZbcaYWUTTUUUUVWXYZZYWUTSSTVXbgjlkiebZXWUTRRRSTVXXWUSQONOQUXbegfecaXWVVVUUTSSRRQQRTVXYYadipvywrkeZYXXVUVWXYaZYXWUTTTTWZekpqnhbWTTTSSRSTVYZZZYXWWVUVYciosqleXRQQPONOPRTUUUUTSRRSUWadikkifbZXXYYXWVWXacfhjlnomjdYTPMLKKMOQSUUTRQPOPQQQQRSTUUUTTUUVVUWchlnlfZVTUVXXXYYZabaYWUTSSTUUVVVVUUTRQONLLLLLLLKKJJJKLNPRTVXXXXXWWWXZbcdefggeaVRQRTUTQLIGFFGGGFFFGGGHHHHIIIIHGGFFEEEEFFFGFEEDDDEEEEFFFFGGGGFFFFFFFFFFFGGGGGGGGFFFEEEFFFFFFFGGGGGGGHHIIIHIIJKKKJJIIJJJIHHGFFFEEEEEEFFFFGJPVbefcYVUTSRQQTWbefedddfgffedddcaZYZbegiheccceghhfdddcaadhnuz0xuttux0ztmfaagmomfYQLIHGGHHGFFEEDDDCCDFJMQTWYYXVTSTUVUTTTUVXXYZabbbbbdfilmkigfeffecaZXXXWWWXZbefeedfipv0zwqkfefedbaZZZZXXXZbefeedehnsutrmiffedbZYXXXWWXZbegffgimsxxunfXTSSTSRPPOOPPSWaehhhhhilquvtohaYXYYXWVVWXXXYZceggfghkorrojebZcdedaYWVUTTTVYbdeeefimrutqlfbaabbaaZaaaZYZbeikmptw032ztoifdeffecbbcdedbZYYYYYafjnpolgdZXVVVVWXYacdedZWTSRSWaflruspjdXTSSSTXaeikkjhfdbbbadhmpsrmhfddeghhfdccegiihgggghinsy484xpicbcddcZXVUTTTTVWYabbdiotxytmfaWWXYYXWWXYZZZacfilnqv03663ytokhhhhgffffgfebaYYZaacgkortrokhecdeecZXVUUUUVXadghkptw2542ysnkjkkihggghiiiijlmliiijmrtsqnkiijkjhfcbbcddddegijihghkptvtojgefgeaWTSTVWYZbdfgghiijmnnmjgddeggfdcbaaZZZabdfgilnqw131xqjdbbaZYZZacdccddeggfgjmruvsleZXWZbcaYXVUTSRRTVXZZZZdiqx21wpgZVTRQQQQSTTSUWZcggfddfjorqkeZWWYaaZYYYZaaaaabefghjmqw22zupifffedbaaacddddddddccdgkpsqmhcYXXWVVWXZbddbaaabdeegimrwwtoicZYZZZZbcefggfeeeffeehlquwsmgcZZbbbaZYYXXXWWWXYZachouz22yupkebaabcdfhijjihhgggghjlmonkgcZXWWXXYacfjllkjjjkmmoqtvxxwsnjgddefffedccdccbbbbbabdgkopmieaXWXYYXWVWXZabcccdeefkpuy21xrkdYVUVWYacfhihgecbaaYYaejoqokfbYXXXYZbehjlljfcZXWXXacfjnpomhdYWVUTTVXZabbaZYYXXWWaekqusnhbWTTTTUXadhjjhdaXVUUUXbhpwzxtmgcZZYXZcfjmnkgdbZZZadhmrusoidZYYYZZYXWXXYYYXYZacdekrx251vojfcbbbaYVRONNORUXZbcbdfilnmkhfdcccdffgijkkkihhijlmlmopruuqkeXPLHFEFHLPTVVTOKGDCDEGIMQTWXVSOLIHHJLOTXYZXUSRTVXXVRNJGFGILORUVWVTSQPOOOOPQSTUTSPNKIHHHHIIJJKJJJIHGFEFHIKKKKJJJIIHGFFFFFGGGHIKOSXbddbYYXYZYWWXadghgghijkjjlmoqomkhfhhiiihhjknnligeccbZacglswvrmjintz0vngfiosqkcTMJHGGGFFEDDDDDDDEFHLSZfhhcYWWWYZZZYZacfggecbaZZacglquurlfZWWWXXZacehjjihfddddceinty0xtojfdcbZXXWXZbbbbcdegghjmostrniebYWWYZcehjjjhebZXXXYchow22ztnigghhfcaYXXYYYYZacdccddfjnoolfZVUUVVVUUUUVWXadhjkjjmpuyzvqlifghhfcaYXXXXXYZbdeeefgilnmjgdaZabbZWUSRRRRQRRSTTUXdkt141vpkgfggecaZYZabbaZXWUUXdltzyvqkhggghhgdbaZabbaYXWVVVagnv230upjfdcbaabdfijjhecaZZYaehlopmjgdaZZZZZZZZZaaZYXXWXXXbhnv363ypgYUSTTUUVWXYYYYYYZaZYYZchlnlifbYXWVUVWXZaabcdefggeehkqx12wpicZbcdcbbbcdccbbbcddcbdglruurlfbaZZYZZbdffecaYYYYadjqy330unifeffffghjlnnnmkjhhggiloqqnjebZYYYYYZbdgijjihgggggjnqtvuromljjjjjigedbaZYYZabdcdfilnpnkhgffhjjigfggijhecbaabdglry350unhddeecccdfhiihfeddcbaaabdgigdbaacfffcZXWWXYZacdffeefiow241xsnkkjhgeeefgecaYXYZYZbdhmppnhdZYYZZXVTSSSTSTTUVWWWZeksz32vogZWWXYYZacefgfcZVSRQQUYekpplgbXVVWWWWXZbccbaXVTSRRSVaiputogYSQQRRRRRTUUUUTSRRQQQTXckqsqmhcYZZZYYXYZbbbZYWWVVXbipx23zsmgcbbbaZZZZbbaYXVUVXXXZaceggedcbbbcdcbZYXXXYXXYZabbehlopmidaZYZabbbaaacefgecaZYWVWYadfecbaZZZZZYXVUTTTTTSSRQONRXfnrrnidaYXYYZbdgjklljfcZWVXagnuz0wqjdaYYYYYYacfhihebYWVVXdlu2895xofZVVWWWVWXZbcaZYYYYYZcglrvvrleZVTVWYadfhjigdaZZabbfjou2551wqkfedbaabcdedbbbbcddcbbdgkmmjfcbbdecZVSPPPQSUVWYYYachmuz0xslebaaZZabdgijiihhghggggikmmlifddfghfbYVTTUUUVXYabdhov3771tmgddeffedddeffedcbbbaachmqtsmhbXUUVVVWXZcefedccdeegkqw253xpicZYZZZYYYZbdeedcbbbcejotxzxsnidaYXWWYadgjjhgfeeffdehms0674xpidbaaYXVVUVWVVWWXYXXYZchnrutqlgeccbabbdfgfdbZYYYXYbfkrvvrkdXVWYYYYZceghfcZXVUVWYaekpttrmhcaaZZYYZbdefdcaZYYaels0685yqicYXXXYZbdfggebZXXXWXaeiostqkfaWVVWWXWVUUTTUVXYabbfkqw22ytmgbZZaaaabbcddcaYXXXYYcglqusnhcYWWWXXXWWXYZZZZZZabbeimt0442wphdaaZYYZacdedccbcccbbbcfjllifdbbdeecbaZZZZYXXYYZZbdflsx0ztleZZabbbbbcccaZZZabcbbdfjnpplgcZYaaaYVTSRRRRRRSSSTVagpy1zskbWVWXXYadgijhebZXWXWVWYemvzyrjaURRRSUXaeijigdaXVTSVZgpy440riZUSTTTUVXZaaZYWUTTTTWbgmrspjdYUUUUUUUVWXXYbiouyzwpjdXUTSSTVWYaaaZZbehkmkhhghjlkihfdcbbfmv266zslhedeeglsy33zskeZWUUUVWWWVUTRPMJGECCBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAABBDHOVdkoolhdaZacdcaYXWXYZbdfikllosvx0zwsokgfefecccdfhhfefghkkjlmoqrpkfaWWXabbaaacefeedefhjjjkkmqsrqmjfeeedcaYYXYZbdfikkkklnqtwurnjgeffecZYYZbdcccdfhiijmnqtusplfaWVVVYbejmoolifcbbcdgkpuwvrmhecdefhnsx12ysrrsv0ytmheehjieYSOLJIIHHHHHGFEDDCBCEHPWcgheaXWVWYacdfjoswxuqlhdcbbehkmonkhfefhkmmkjihikllllkkjighjlotusqmieefgfdcaZabaZaabdefgjmopokfcaZZbdefhknruvtqnkiijkmpruwwuspmjhhgecaZabccbZXWWWXadhloomjgfghjlljiiikmmkhfefhikmoqtvvtrokhfedbZXXXZabcdefggfffhjmonljhffggfddcdegfdbZXXXXYdjpuxvpkgdbdefffghjlmlifdbaZZagmrttmfYVTTUVWYbglqsrnhcYVUWZfmsxyvoidaZZabaZZacfggecaZYYZbgmrutpicZXWXXXZbfimonkgdbaaabflqvxwrmhcYXYZZbdgjmnmjheccbachmquurmieaXWWXYZbcdedaZZZZaaZekpuywrmhdaZYYXWYaehkigeddfgfehjmqspmiebZYXWTQONNOQRTUUVWXZdjpvzzuojdaabcdccdeghhgggijkiiijloqpnmkihhihgdbZYYXXWXYabbdgkmqrqnkifeeghgggilpssqomkjhfeefimppomjgffggfecZXVSRSUXadddehknrsqnjebacdfghikmnlifcbbcceghjorrrokeaYXWVWWWWWWWYaehkkikmoqtsojdaYZbddcbbcefdddegikjjlnpsvuspmjhiiigdaXVVXYZbcdeffinsw00vpjfcbdeefgjlopokgcZXWWZflquuqjebZZbbbbdehlopnjfbZYYaekqwywqkeaYYZabbcegjlljigfffgkpuz20uohdbcdfgffedccbaaaabddfkpuxzwrnkhedcccaZYZabbaZXWUSQNMORVaccaXWVXYaaZYXWWVUUSRUWZabaZZabcdeghjjihgijkmooooonoqtuwxxwvurpmjihhigdcaYWURPNNMMLPWgpy21wogYTQRSSTVXadggfedccdbbdhmsxwrleYWWXXXYacfhiheaWTRRRVagntvuqkfaYWVUUWYbdeebXURPOOQWdlswsnfYROMMNPSVZceffedddccdgmsy22wogaWWXYYXYZceedaYXWXXXZgmrvwrmiecaaZYXWWYaddbZYYZabcgntz21wqkfdcdedccccefebZYXXYYbfloroicXVWXYZZYWVVVXYYWSNIFDEINRVZZXUQLHFDEFGHIJKKKJHGFEEEEFFGHIJJJIHGGGGHHJKMOQQOLJHGGGGGFEDDDEFGGHHHHGGEEDEEEFFGHIIIHGFEEEEEEEDDDCDDDEEFFGFFEDDDDDDDCCCCCCCDDDDDEGKQWacaXUROMLKKLNRTXZYXWXXZaZYWUUVUVWWWXYZacccbcccdefhjkmnoqtwwwtrrvz12yusvxzzxrlhebaabZXURPPPPONLKJJMWgr164xohcYZbcccfhkoqpnnnoqssrtvyz0wpiecbbbaceinrtsqmjhffggjpuz22wqkgdddddegilpqrqnkhecbbfjnrsqlhdbZZZZacegjkkjfbZXXYaejpuz0xsnheddffgghjmnnmllmnpqsuwwxwurpnmmoppmieaWWVVWYbfjllmpsuxxupmjhhjkkjjjkmnopooonmkiiijnrstsqnlkkkifcaYXYXXXYacdeflqvyztmgbXXXXZcfkpsuusqnlkkkjmprstpkgdbaaZZabdgknpqppoonnnpuz354ztokihhhghhjlopomkjijkklortvvtqmkhfdbaYZadhlmkhfdccdcfkoswvrnkigghhgedcbccddfgjlnmlkkklmljgdaZYZZZZabceebZYXYbdegilpturnidaabcbZZYaceecccdfhhghhikmnnmlkjkmnonmkihhhfecbaabemty0yqjeddfhiihhhjlmljgeeefghlpsusoiebaaabbbaaaceffeddddddglsx22ztokjjlnnnligffeefghkllmoruvuspljhfdccbcdfghhhijkmoonoprtvwuromjjjjigfdddddcdfhjllklmmoqqnjfcZacddcccegiiijlnprrrstwz21zvqkhfeddefhijjjjlosuvsqpoopoligffhjjjihhhhhgfdcbccdgkrx230uoigfghgeddegjkjigeddcceinsxwsmgbYXYYXXXXXZaZZZZabdcdhmt042xqjedccdddeffggfcaXUSRRTYemuvsmfYVUVWXYabcdeefghiijiinsx24zsmhddeeedcccdfffecbaZYZcjqvwunhcbceghiiijkmmljgecbbbemt0561tldYWWXYZadfiklkjhfddccfilnnkhecbbbcdcbaaabcbZVRMIEDCCCDDDDDDDDDDDDDEEEFFFFFFFFGGGFFEEEEEEEEEFFFFFFEEEEEEEEEFEEDDDCDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDEEFFFFFFGGFFFFEFFFFFFFEEEDDDDEEFFFFGGGGGGGHIJJJIIIIIJJIHGGGGGGGGGGGGGGGGGGGGGGGGGFFFEDDDDDEEEFFFFFEDDDDEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCDDDDDDEEDDEEEFFFFFFFFGGGGFEDDDDDDDDDDEEEEEFFGGFEEDDEEEEEEEEFFFFFFFFGGFFFFFFFFEEEEEEEEEEEEEDDDEEEFFFFFFFFFEEEEEEEEDDDDEEEEEEEFFFFFFFFFFFEEEEFFFFFFFFFFFFFFGGGGGGGGHHHGFFEEEEEEEEEEEEEEFFFFFFEEEEEEFFFFFGGGFFFFFFEEEDDDEEEEEFFGGGGGGGFGGHKNQSUUUVWXYZYYWWWYbegfdbYWWWVTQNMMOSXchloqsttssrqpnkigffggdZUQMMNQTWZbcdddddeeeecbccdffeaVQMJKMOSVYacdefhjlnomkgebbbbZVRNLKMNPRTVWWWXadhlopomifcbaZXTPMKIJKMOQSTUVWYadfggfdaYXXWVTPNLMOTXbehijjhfeefhjiihgfghfdYTPOPTXbegiiihhijkmmmlkiiijjhdYSONOSWZdfhihfdbaZZZYYXXXXYYWTQOMMNOQSTVWWXYadfjlmlkjiijjhdYTQOQUYbehiigedefhkkifcaZabbYVRNMNRVZcfhiihfgghkmlifdbbccaWRNKJLPTWaceeecdegknonliebZXWTSSSUWXWWWXZaccceffggdaYWWXabaZYZadecZWVUWYZZbcehiihdZVSQQQPONMLKIGFEDDDEEDDCCCBBBBCCDDDDDDCCCCCCCBBBBBBBBBBBBBBCCCDDDCCCCCCCCCCCCDDEEEEEDDDDDDDDDDDDDDDCCDCCCCCBCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDCCCCBBBBCCCCCCCCCCCCDDDDCCCCCDEILPRSRPOOQSUUSQPQSUTSRSVafhigecbZXVSRSVacdaWVWZdhhgecaYXURNLIHGHHIIHGGFFGHIIIIHGGGGFFFFEEEEEDDDCCBBBDKUht362voieddeeefhjmopomjiggffgkoswvrmifddddddefffebZXWWYZaciqx261wqmjjklmnmljhfdaYXXYaccfjmqttrplifbYXXZcgknopnligeddekry585yrkgeghhgedcdefeddegikkklnpsutromlmopoljijknonmlklmnoprtxz0xsnifefecbZZZaaZYXZbehhhiikortrokgddedbZWUTUWYabccbacfmsz43ztnigfffdcaZZabaaZYYYYYaekpuurleYTQPOPSVaeiklkjihggghmswz0xrmifdccccdfhjkkjhgfffgghknrtvsnhdaYZabbaaabcdcaaacegffjou2762wpjgffghijklllifeefhiijkmprsplgcZabbbbcdgjjhfeefhiihikotxywrkeYXWVUSRQPPQSUYcfhhgfefinsuspjebabcdfhknoonlkjkllmpsw11ytnhdbaZZZbdgjkjhfdccdefjotwwrmgdbaZYYXYacfhigecaZYYYbhpx350tlfaYXYYZbdgijigeeefhhilnqstsokgcZXXXacgkoqqpmkihijjlorvzzwrmiggijhebZXXYXXYcgloqpoooruvvtqomlmmjhffgiklkjjijjijlnrvyywslgcaaaZYXWWWWWXYbeghhijkosuusnidbbbbbcdegihgffeedbcglsz2zskcWUVVVWYadgijihfdaZYXaekqvwtngaVTSTVZeinppoliebYWVXcjqwzwrkfbaabaacehmopokfcZXXaelry0yrjbVSRSTTVXadgiigdbaZZcgnu2650skcYWVVUUWYadggfcZXWVWZchmqqnjebaabdedddccdcaZYZadeehmqtwwtplifcaaaabcegggedcccdefjnqssqmjhfedcccccegijigedbbbachmrwxupkgcaZYYYZabdeedcbbccehlquyxunhdaZZZZZbehkmmkgdbaZZadhnuz10vpkgeefffffffgecZXXXZacfiknpnkgdaYYacccaZZZZZabcdffeint07960rjcZYabdgjmprqmkiijllkkkknrtutpkgeeefghjlnpnkihgikkkmpsx10wrmhfeeddefhikkifeeeghgikmrwzzyupmllllkjiiijjjjjjjjikpv1785zsmhfffeeeeeghhgghhjklnqvz10vpiecbbbbaabegjkjiggghhhlrx264yrkeccdgikmnprtsqomlkkihjnrvzxtokgeccbbacegjkifdcbdeeint0682ukbVTTVXYadgjmnlkjjjkkjjklpuxwtpmiiijiiijklmljiijlopprty3663xsnkkkjhgghkmonkiihijkmorvy00wqkfccccccdehijigfddcdglsz696zskeZXWVXbflpssqmieaYWXbipwzwqidZZZabaabdgjmmljhgghhmsy4882wqlhhhihgghjlnonmlkjihfhlortspmkjihgfdbbcdfggffgijlklptz4873zvronmlkihhhhhgeffhjllmmnpstsqmidcbaZZabehjllmnoppnljknrvxupjfdcddefhjmoponmmmnljjjknruusqmkiihfdbaabdfimpsvvvvx03783wpieeeedbbbdfijifdbZYXYbelsyyvohbaacdeegilnonmmmnnnljkntz41uldXWWWXXYadfhhfcaZYYYZbglrwwrlfaWWXWXZcfikkjkntz54zqgXROPRUYbefgggfghjlopqqpnmlkkloppokiinszzwqjfegkmlijmruwsldWQNKIIJLORTVVWXXYZaaaaaZZYXXWUSPMJHGFEDDCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]], + level = [[EIMQVVUSQONNNOOOPQRSTTSRRRRSTTSRQOONMMMMNNNNNNNOPQQQPPPPPPPONMMMLLLMMNOPQQQQQQQRRRRRRSTTTTTSRQQPOOPPRSSTTTUVVWVVUTSSRRRRQPOONNNNOOPQQQQQQQRRRRQQQQQQQQPOONNNNNOOPPPOOOPQQRRQQPPOONNNOOONMMMMMNNNNNNNOPPPPPQRSSSRQONMLKKKMNPRRRRRRSSTSSSRRRRRQPONMMLKKKKKKLLLLMMNOONNNNNOOONNMMNNNMMMMNNNNNNOOPPPOOOOOPPOONNMMMLLLMNOPPPPPPQQQQQRRSTUVUTSQPONNNOOPQRRRRRRRRRRRQQQQQPOONNNNNOQTWYabbaZYXWVWXYZbcbaZYXXXXXXXWWVUTTUVWYabcdeffhijjihecaYYZbcegghggfedcbbccdegghijkmoqqpnkhfddccccbbbbbccdefffghkotx00yupjeaYYYZabccdcccbbabeiov1343zunhbXUUVXZbcccccdddegkntz2441wqlfcZYXXYYYZZZabccdehlqw0332xsmieccddfgfecbaacddefilptwxwtojebYXXXYZabbcdefggghiknsvxyxuplhdbabcdeeddcbcdeffgiknrtvvtqmifdccefhjkkjihggfegikotwxxwtpmjgeddefggggggghijjkmnquvvurojgdcccdeeedcbaacdfgilnrvz122zvplgdbbcehijjjihhgfefhkoruvurmidbYYYZbcdddccbbcccdfimruxxwupmjgddccdeeeeeeeeeedegilqsuutrnljhgghgggfdcccceghjlorvy00yvrnkjiiiiiiihggghijklnpruxyyyxurpmjgfeeghiiiiijkllllmoruwxxvussrqrqqqqpoonmllllllmnpsuuvutsrrqqqqppponmljiiiijkmptwyz0yvtqomlkkjjjiijjjjjiiijmptvwvtplhebbbcdeffefghjmoooopqsvwxxwsokgdbbdfhjlmmmllkkkkkmoqtuvutqomljkkklnoopoonmlkjkmptxz00xuqnjhhhjkmnnnnmmlllllnoqtwwwurmiebabcefgggffghijjkmnpsvwwvsokheddegikllmmmmmlkihhhkosuwwuromkjiiiijjjjihgffefhlpuxz0yvsoljhghhiklllkkjjkkllmnpswy00zvrmhdcbccddcccdegijkmorvyzzywspnljjjihgfeddefhjlnpqrtwyyywuqomlkkkllmnoooonmmmmnpsvy0zyvrnkhfefgiklmmlkjihgghikosvxyywtrolkjjjjkkkkkklmnopqrtvxzzywspmkiiiijjiiiijkmnoppppqrstttsqomkjjkklmmlllkklllmnpruxyzzyvsolhffgilopqqpoonnnooqsuwxxvtpligeddeeffffffghhiikmorvxyywuplhdccdfhijjiihiiijjlnqtwxwvtqomllkkjiiiijjjjjjijkmpsvxyywtqnljjjkmopqqqpnlkjijkmpsvwxxwtromjhgffgggggfgghhhiknrvyzywsnifcbcdfghhhgfedeeegjmqvxyywtqnlkjjjjkklmnnnmlkkjkmosvxyywurpomlkjihhhhhhgggfffhjnruwwvspnlkjjjjjjkllmllkjjijlorvwwvtqnmkkkllmoppqrsvy0231zupkgcZYYZbdeghijklmmllkjjiihhiijjjihiloswz0zxvsqonnnoqtvxyywusqponmmllllkjiihhhhhhgggfffffffghhiijjjjjjjkklmmmmlkjiffffgikkkjjhggecZXVUSRQPPPQQQQPOONNNMMMMMNOONNNMNNONNNNNOOOONMLLLKKKKKLMMMMLMMMNNNNMMNNNNMMLLLLLLLMMNOPOOONOOPPOPPPPQPPPONNNNMMMMMNNNNPSVaehijihfecbbbcegijkjjjjjkkjhgedcbabbceghiiihhhiiihgfedcbcfjouz11210z01000001220yvpkgcZXVTRPPONNMMLKKMSZhpwz10yvroljhhhggfeeddeefffhkpu03330vqnkhhggghhggfedeeffghjmquxy0xuqmjgfgghhihgfeccccehmqw14542xsokhgfffeeddcddefghikmptwxywtnhcXVVXYbcddccccefghjmpu03453ysmheccddefffffggiijjkmosvwvuqmigeeeffffedccbcdefhjlotx011yuplhfddeefggfeedefhiknpsvy00zwsnkhfffghihhggfeeedefimrw011zvqlhecbcdfghiihgedaZZbeiotwxxvqlgcYYZbdgijjjhgfedcfimrx021zvqmkigggggfffghhiiiikmosw0220wrmhedbcdeeedccccdefgjmpty121xtmiecabcdefghhiijklmmpsvz35552yurolkkjkklllkkjjjiiiloty2431xsnjgeefhiihgfffghjklmnptwz00zwspmkjkllllllllmmnnooqsvy1321ytpmkjjjjiiiiiijjiijklnpsvxyywtpligggggffeeeeeeeffimqvz232zwrmkigghiiiihhgghhiijlnquy021zuojfbaacdfghiihiiijjkmoswzzyvqkgeccdeefffedcbbcccdegkotxz0yupkfbZZabcddeddefghilorvz11zwqlgeccdefghhhggffghhjkmoquwxyyurnkhggggggfgghijjkkmpsw0232zvplifeeefghiiiihhhiiiklnruwxywtpmigffghijjjiihhgghiknsx122zupligfffffffeeeeefgghjmpuy121zvqmifeeghijkkkklllmmnpsw02320vqligeefghjlmnnnnnoopqsux03342zvspnmlmmnnmmllklllklnpty1220wrnkhghijkmnnnnnopqqrstwy1220zwtrqpooopqrtuvuutrpoopruxz00ywtqonnopqrsssssrqpoonoprtwxyyxvtrqpoooooonnnnmmllllorvz3430wsnjgfefgiklmmmmlkjjijlnqtwxyxvspnkjjjkmnopponmlllmosv03432ytpljiijklmnnmmmmmmmnprvy23320wspnllkjjihhhhijkllmoquy24542yuqnlkkmmnoppppppppppqrsuxz00yungaVSSUWZbdeedcZXVTTUWZcefgfecZWSQQRUXbegiiiihggfecaXTPNMORVZcddcbZWUSSSUWZbcccaZWURPNNNOPQQQQQQQQQPPOOPQQPPOOOOONNNNNOOPPQTWaehijihfeddcddfgijjkjjiiihhhijklmmlkihhggghhjkmmmljhfdbaacglrx1121zy022332123220xsolhfffghijiihgfedddfimqvy00ywspmkjijkllmmmllkkjjjmquz35541xtqmkjjiijjjklmnpqqqrrsvy13430vroljjjjjkllllllllmnoruy13431yurpnnnnnooooonnnmmmnpsw13542ytqnlkkkkklllllkjihgikosx0221yupkfdcegjlnnnnmlkkkkmoruz1220wrnkihhiijklllkjjhhghknrw0210wrmifeefgikmnopponmlkkmosw02330xusqqqqqqqqponmmmnoqtwz245531yvusqponmkjiiiijllmmnprvz24430wsomjkkklmnnnnmlkjijloswz111yvroliiijklmnnnnnmmmmnprvz2342ztojfefgilmoooomljhggjmrw13430vrnjgfffgijklmmmmnnnoqsvz2442zuqnlklmnopppponljhgfhkouz3440wqlgeddfikmopponmlkjknquz24540wspmllllmmnnooonmlkkmpsw02320vrnkiiiiiijjklmnoppprsux034430wurpooonmlkjihhhhhijmorvyz00yvtsrrqqponmlllmnnoppqrtx03442yuqnkjjklmnopoomljihhjnrw0221xtplihhhijjjjjiihhggghjmqv03552zurnlllmnpqrqpoligdegkpvy010yvsqonnmmmmmmnnooopoopqtvz24441xuronnopqqrrrrrrqpppqsuy0121zwtsrrrsrrqponnopqqpppqruy1232zwtqoonoopoonnmmmllmmorux1221zwsqpoopqqrsttsrqomkiikoty35652ytqonoopqqqqqqponnmmmoquxz000ywusrqqrrrrrrrsssssstuwy12310xurqonnnnnopppppoonmnpruxz011zxvtsrrrrrrqqppoopppopqrux13320wtqonnnnnoooooonmmmmpsw046652xspmlkllmmnnnnnmlkjijmpu04553ysnjfdddefhhiiijjjjklmptx1332ysmieccegjmopqponlkjijloty36773zwtrqppnmljjiihhhhhiknrwz110ytqmkjjjjiihfffghijjjkmosx13431wrnjggfghiijkkklmmnoprux011zwspmkjjkkkkjjihgfeeefgkpv16774zupljiijklmnnnmlkkjjkmpsw02320wsqonmmmllmmnnonnnmmnpsvz3554ztojgfefghiiiiiijjjjknquz36641wsomkkkjjjjjkklllmmlmoruz35764zvrnkjjjklmmmlkjhgffhkotz2331yuqnkjjklnnnnmljihgfgilqvz120xsokihijklmmmmmlkjihhjmqv03553zuqnlkllmmmlkjjjkkkklnpuz25540vrolkjkklnopqpnljhgfhkpu03552ysnkgeeeffghijlmmnnmnoruy24430vqmjgggghhiiiijjkkklmorvz221yuokgedefgijjjjihhgggikoty13431xtpmkjjiijjjkkkklmnprtwz2342zvqmjhghhiijkkllllllllmosw13430vqlhfeeghiiiiiijkllmnpswz210xsnjgedefghhhhgfeeddegjmrx1332xsnkgffhiknppqpomlkjklosw03553ytplihhhijlmmmmlkihggimrw14541wqmjhhhijlmmmllllkkjlnrw14541wsomkkllmllkjkmpty1221xrmgcZYZabcdfgikmoqrrrqponnnopqqrqooprv035640xtqnmmpsw156641wtpnlkjjiihhgffecbaYXWVUUSSSSTVWXXXXWVVVWWXYYYXXWWWWXYabeiot046630uqmkjiihgfedccdfgiijloquy00zxtokifedddeeffefeeffgiloruwwurmhdbaZabcddeeeeeddeffhknquwwwurnkhfeddccbaZabcefhiiknqtwxwtqlhfdddddddeffgghhhhhikmptwxwuqlgdZXXYadgikkkkjhgffgjmruvvtqmigfeehknruutsrqrtuuvvwxz00xtohcYURPPOPPPPOOOPPPPSXdkty231xtoljiiklnprtttsqnkhfgkouz220wrmkiijklllkkkkkkkkjjijkmpsuvuspljhgfggggffeedddddfimrw131yuojgeddefgiklnooonlkjijlnquwwvtqmkhgfffffeeeedddccceinty00yuplihhijjjjjjjjjjiihhikmpsvxxwuqnkhfedddddddeefghhhjmqv0220wsoljhhhhhhhhiihhgfedcegjnrttsplifddcefghijjjjihgffgjmqvzzyvrmhebbbdfilnppomkhfdcfimquwwurokhfeeeefgghhggfdcbbdhlqvz0zxsnifdccdfhjkllkjihgfefilptvwvsojfcabcdfhjkllkkjigfhjnsx120yuojfdbbceghijjiiiiihghjlptvwwuspnljhggghjjkkkllmmmnpsvz232zvpkgdbabceffffeefhiiikmorvxxwtojfdccdfgghiijjkkllmnqtx14430vrmkhhghhhhgfedcccccdehkosvutqnjhggghiklnopponmkjijmpty121yvqnkigggfffecbbbcdefghjmqtwwusniecabdfhjklmllkjihgilosx010yuplhecccdeeeeeeefgijjlmortvusolgdcccdefghhhhhhiijkmpswz221zvroljjihhgfddccefghiijkmptvvusokhgefgijlmnnmmkjhgghjnrvyzywtoljggghijlnpppomkigefhknruvutpligfefghijklllkjihhjmptx010yuqmjihhhhhhiiiiiijkklmpsvz110xtpliffghjkllkjihggfeccbcefghiiijjjjjihgfdccbcdeffghgggggffghijkkjjkklmnnnnnnoopruwz110xvromkjihgfedbaZYXXWXWXZejqw1220wsomlllmmnnoopppppppqsuwz1220xtqnmllmmmmmnnnnnmlkjkmpswyyxvspmkjihhhiijkkkkjiiikmquz121zvqlheddehjlmooopoooonopruxzzzwtpnlkkklmmnnooonmmllmpswz2320xtqnmllllmmmnnnnnnnnnnpqtwz00yvspnmmmnoopppponmlllmosvz120xtpmlkllmllkkjjiihgecbceimruvusoicXTQQRSUWWXXWWVUSRRRRSSTTTTTSSRRQQRSTVWWXXXXXXWWVUTRQPNNOPRTUVUUTSSRRRRSTUVVVVUTTSRQPPOOPPPOOPPQRRRRRQQRRQQPOONNNNNNNOOPOQSVZehijjihgedcbbbcdefghghhiiijjihgfdddefghhiijjkkkkkjjjjjjknquz355543223566789++973zvronnnmmljhgedcccdehkpuz2330xtpnlllmnpqstttssrsstuwy03331zwtrpoooopqrsssrqqqppqrsuxz00yvspmllmmnppqrrqqonlkknquy2432zvsqoonnnnooooopppqqqqrsuwz0zyvrnljjkmnprstuutsrqpqsvy24552zvsqoooppponnmmmlllllmorvz2320xsolkjklmoqrsssrqpnmnpsvz24431xuqomllmnoopooonnnnopqsuxz01zxusqpooopprstuvvuutsstuwz13320xuspnmlkkklmnprstuuuuvwy03321yuqonmnnopqqqqqqpooooqsvz24430xtpmjiijlnpqrsssssrrrsuvxz0zxvromlkllmmmmmmlllmmnortw024420wtqpoopoooonnnmmlkkklnpsvxxxvtqnmllmmnnopppponlkkkmquy35430wspnmmnopqqpppooonnmmoqtx1221yusponoonnnmmmmlkkkklnquy24442zvtqomlkjiiijklmnopppqruxz110xurpooooooonnmllllmmoqtw0345420xvussrqpnmllmnoqstuvwxy01210yuronlmmnnoooonnmllllnqux1220xsnjgffhjmoqrrssrqqqpprtwz24420wsoljijloqstuuttssstuwy135430xurppppppponnnnnnoopprtwz24430xusqqqqqqqqrrrrrqqppqtvz24430xurpoooooonnnmmmmlmmmoqtx0220xtqnmmnooppppoonmlkiiknrw1342zvrolkklmnopqqqqqqqqrrtuwy0221zwtrqppooooppppppppooqsvy24542yurpoooqqrrssssssssrrsuxz2431yupnkjklmnopqrrrqqpoooqswz122zwtqonnoopppppponljhfdbZYWVVVVWWVVVVVWXYYYYXXXXYYYYXWVUTSRQQQRSTTTUUVVWVVWXYZaZYXWVUUUTTTTUWXXXXXXYZabbbbbbccbaYXVUTTTUWXabbbaZYYYYYYXYYZZZYWVUUUTTTUVXYXXWVVWXYYXXWVWVVVVUUUUTTTTUVXYYYXXXXXWWVVWXXXWVTSSSTUVWWWWWWWWWWWXWVVUUUVWWXXXWWWWWVWWXYYYYYYYYZZZZacdfffebZWVTTTTUUWXYYZabceeedcbbbbaZXWVVVVVVVVWXYYZabcddcaZZZabbaZYWWWVVVVVWXYYYXXXXYZaabbbcbaZYXXXXXWXXYZabbbaaaaaaaZZZZaZZYYXWWWVVVVVVWWVVVWWYYYYYXXYYYYYXXWVVTSSSTVWXYYYYYZZZZZZYYXWVUUUUUTTUUVWXYXYYYYYXWVVWYZbaZYXXYZaaaaaabbaYXVVVWXXXYYZabaZYYYZbcefghijkkkkkjjjjjjiiihgfedcbaZYZadhlnqrssssrrqponmmllkkihecaZYZbdfgiijjkkkkkjjiiiijiihfdbaabdfhjklmnoprrqpomllkkjihfdbZXXYZbdefgijmoqqrqpnlkihfedcbZYXXYacefghijklmmmmlkkjihgggggfeeefhjlmnnoonnnnnnmmmmmlkigecbcdfikmmmmmmmmmmmmmmnnnnmljgecbabdegijkllllllkjihhgghhgfecaZYZacfhhiijklnooonnmmmmllkjhfedddfhjklmmmmmmmnmmmlkjihgfdcbbbdfhikllmlmmmnnoonnmmllkigebZXYZbehijkklnpqsssrqoljhfffggggggghiiiijjkkllllkkkklkkjjjjjjjihfeeddeghiklllkjihfedddefgggffeddddefghhiiihgffgggggedcbaZZYYXWUUUUVWYZZZZZZZYYXWVVVVWWWWWWVVUUTUUVWWXXXXXXXXWWVVUUUUUTTUUVVVWWWWXXXXXYYYXXWVVUUUVVVUUUUUUUUVVWWWWWWWWWWVVUUUUTTTUUUVUVWXYbdefggfffffeeeeeeedddddefghhhgfedcccdeffgggfffffggfedcbaZYYXWWVVUUUUUUWZfmv279850vpkgdbaYVSPMJHGFFFEIPYiu279862yvsqpppqqrrrrsssssstvy15788740xusponmmmmllllmnpqsuwz257764zvsqooppqqqqppoonmmloqv0589863zwusqpooopqrssssttsstvy157640wqnkkklmoprstttssqqqrtx1689851wtqnnnnpqrstuutsrppoqsw047652xrmjgghjlnopqppnmkjjlnrw157751vqmjiijlmnonnnnnooopqsvy245530xusqqppoonnnnopppppqsvz367752yuplihghjlmnopqqsttuvwy034320wspljhhikmopqrrqppoopruy36763ysnkgghikmnooooooppqrsuwz356640wrnlkklnqstuutrqnmlmpsw168862ytrpoppqqqqqqqqqqqqqrtvz257752yuqnljjjjkkkkkjjjjjlnrw1588740uokgfgjmprstuuuuuuvvwyz134320wtpnkklmnpqqpponnnnpsvz467751xtqnljiiijklmnopqrssuvx034540wqlhedegjmoqqqqqppppqtw04899851wtqnlkklmnoppqqqrstuwz146530vqnkjjkklmnnooooooooqtw0579874zvromllmnpqrssrrponmmosw157640upjfccdfiklmmmmllkkmosw1467641xtrpooooooppqqqqqqpqsuy14542zvromllmmnoopppponnnnqtx157762yuqnkjjkmpsuvwvutrqoopsvz2332zwtqonmnopqstuuutrpooqsw036540wrokjijkmoprsssssrrqrtvy256652zxusqppprstttssrqppqsvz4688640wtrqqrrsrrrrqqrrsstuwxz245542zwtrppppqqpppppqqqqqrtx0456530wtrqpqqrsstttttssssstuvxzzzxwtrqoonooooooonnopqstwy14788740wspnmmnprtuutsrqqqqqsux035530wspnmmnnoooooooonnnpsvz367751vpkhffhjlmnoonnnmmnnprvy256530wtqonnnoprtuuusrqppqsuy1467530wsqonnnopqssssrqpppqtvz367751wrnkiijlmopqqqqqqqqpruy279+962xsolllnoqstttsrrqqrrux04899851xtrpnnnnopqqrrrssstvy1589873zurpnnnnnopqrrqqqqpqrtwz256530vqnkijklnprssssssssuvy04688751xurpooooppqqqqrsstuwxz146641xspnnmnnnopqrssrqponoqtx1689740uqmkkkmoqsuvvutrqpppsvz478863zvsqpoooppqrrssrqqqqrvz3799851wtqoonnmmllmmnnopppqsuy268872ytplkklmptvxyxwusqppruy2699740vsqopqrstvwxxxxxxxxxy13699852xtpnmmmnoqrtuuuutsrrsvy2678740wtpnmmnqsvwxwvutsrqqsv048++8631zxvutsssssssttuvvvxz14899851wspnmmnpstuvuutuuuuuwx0479972xsnkiikmoqstuvvvwwvvwy0479+962xrolkklmnopqrrstuvvwx0369+973zwtrqppppqrstsrqppopruz379+852yvusssstuvwwwvvvvwwxz14689851xvtsrrqqqrrrrrrrrrrrtvy267752ytrpoopqsuvvwwz158+/950tmfbZZbegijklmoqtuwwwwvusqpopqsttssuw0589863zwtrrsuy268863ytolihhhijklmmnoooonnnmmlllkkkkllllkjihhgggghhijkkkjhgfedcccccccbaZYXVVVUVVWYZZZZYWVUTSSSRQPOONNMMMMMMMMMMMLLLKKJJJIIHHHGFFEEEDDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]], + bright = [[lw641zwtqonnmljfeegiljgfghijhdbbehlljfdeimppmjijloolihiknpnljjknpomigggihfdcdgjkjfeegikjgdbbcfhgfeefhihdcccfihebbbehjhdbcdgjjgedefhgebbcfikiebbcfihebacfiljfdefilkhfffhkjhedehlnmigffhiifddfillieddfiljfdccehgdbadinqqmjiijkiebbcfijfddegjkiecbcfjkigghjnnkggghknlihhikmlhffgilljhgghjkjgefgilkiffgjlmkgffhjmmjihghihebbcfiigbZadgihdYXZdgjgcaabdgeaZbcgjiebbdhkljfccdgjjhkosxyvpkghijjhhjnswwtomoswzxupljjjjigjmquxtommprtqmhedeeedbeinrurlgdcdeecYcgmqtpjikoty00122zwtpnnnoopppppoooppqrrrqpoopsvxz0001110yvtrrtuuuuttuuuuvwyzzxvrpprtvwtpmllmmljgghiigcXYafknlhghlpstpljjkmomihjlpsuvwz00wrkfcehknnmlkkjigcZYabddaXVXbehihegkpsurmihgghgdeilqvwvvwwvsokgfilpttrnkjjlnopqrqokfbZZbehihffgilmmigfghijghjmotuuuvwvsqnkjloruusoljjkmnoppomjfcabdgiihfgilprroljijjifehkotwvvvvuspmjjloqsrnjhhiiigeccdedaWTVZehjhddgjnqoligghhhggimosuuuvwvuqnjhjmqturnkihihgeefghgcXVWZdimooqrsssrpnmmmmljjloqtutsttttsrqprsuvutqonmlllmmmmkhfcbdhlqtusrrqqqomkmoqtvtqppqswxyyywutrqpqrtvwxwvvvvvvvutrqrsvy000zzyyyyxyyyyyxwvutsstuuvvwwxwvusqpppqrsuuuutsqponnnmlllmnprrqponopqrrqomllmnopqstuuvvvwwvusqonnpqsssrpoomlkjiiihgecbcfhknqqqrssrqolklllllkmoqrttssttssrqppqrrrrponmlllllmmmmkjjjlmnonmmnopqpnlklmoqrrsttuuttuuutqmjggjloppnmkjihfddfhihdYUVYchkllnoqstusrqppppnnnpqstttuvvvtsqooopqqpommllkkjjklllkjiijklmmlmnprsspnllmoqrstuutttttutsrqonnopqqoljijlmmlllkkhebZZbehjllnoprrqonlkkjjiilnprssrrsrqponnopqqqpnmmlkklllllkjiggghijkkklnpqrqomlkjjihghjlnqrrrssrqponnopppnjhggijkllllkifcaZacfiklmnoqsssrqpomkjjloqsuuuuvutsrqpqrrrqomllmmmlkjjjjjjjjlmmljihiknppolihiknqrrttttuuuvvurolihjlorssrqpomllkkkkjgdbZZcgilmmnoqsttsqonnmmmmnoprsssssrponllmopqqpommmmmmmmmmlkihggghhiijkmopqpnlkklnoprtvvwwvuvwvurnkhikmprqonmljhebabcddcbbdgjmmnmlnoqqqomkkkkkkkmoqrssrrsrqqpoopqrrqnjgghjlmlkjjifbYVVYbfhiiikmopnligfhjlnoqrsstttvvvusrqpppqqpomlkkjjiiijkkkkkkmnprsttuvwwvusqpponljiimqv146652zvsqppqrrrqpooopppppqsuvwwwvvvvutsrrrsrqqpppponmmllkjigfdcaXWUSRQPONMMLLKKJIIIMSahqvy14555443320xtpljjjkljfccdgjjgcdehkkgbacglolfaZadhhdXTVYdecVRTYehhbTUYejmfXWYcimhYSRUZfeZSRUagkgYTUZejjaRRTYejdWVYcimhZVVZfmlgbcgnvzwsomllkhecejpuwvspoooonkihhhgfbYbejpsqmlloqsspljjjigcYYaceeZTPRUYZZWTWcjouwx03689++++/////////////951xttuwz246888877654332210ywvvvvvwxxz00xuqmkloqssqnlkmmmieaZbeheYSQSWbdZUWagotrmhfgijhcZadhosuvxyxvsnjfhkorurnkjihfbVUVZdhdXQOTZgigZYagnrpkecdfgfaTVZgnwxyzzzxupkhilptspkgfghfcVQRVZcaTMMQXcgbWVZfosrnifeffdYTWahpxxxyyxvspkijmquurmihgggcWSUXbgdWPOQWdgcVVYfmsqlhffghfZWXciqwyz000xtokgimqstpjfefhheZXYaeieXPMPVbedXVYfmrrlfceghgaTVagoxxyxyxvrniffjostrmhffhfcWUUXbebVPNQWdgdYWZfntrmiggjkhbTWaiqzzz011yvqlhilpstpkfddeebWRTWacbVOOTajrsqonooqokggjntvvrqppqtvwxyyxurmiilptyxutttuvurmkigfeaWTVYbddZXZdimnjfccddcZWXbhnsuvvwvtqnjfhlptuqkfddedbXVVYcfdXRNPUZcbVTWcjrsnifegfdYRUahowxxxyxuqmhefimrsqlhgggeaVQRVaddXPNQWbfcWWZekqnidaabdbXSTXemuyz0220wrlggkosuqlhghjjfaWWZeigZRNNTadeYZcipusniefghgbXXafmsvwyzzyvqlhhjnrsqligggfcXTUXaffcZXYadffedhlprqnifgggebYZdhmstuvxxvrmieegknnlhdcdedbWSSVZcbWPMOSWZXUUXdkpokfbbdecZUTYfmuwwxxwvrnieehmqsqniggijigdcdffeaWVWbeggeegknqplheddddaXXbfkqstuwwurniffjnpqnidccccbXUUXZcaXSQUahnqokkkkkkhdehlptrnlmmortttutsqnkhgjmqssollmnprokihgilnprtuvvvuuuuutsqonnnooonnoqqssssssqoljhgiklmligffgggfeeffecZWVWadfffefhkmmljiijkllklmnoqrssttsqomjiknoomjgffikmoonmljhfddeghjkkkmoppomjiijkkjiikmoqsssttsqomkjkmonmjgfgijjihhhhgecaZbefhijjlnqrrqponnnmkjjloprsttuusplifegilmljgffhhiigffebXSOLLNQTVXYZbceghijifdaYYZacdeghijjieZURRUYcghhhiihhijlmmkgbXTUWadhjklnnlhcXVUXaeiknqrrpjcWSUYdgfZUUWaefaVTUXbecWVWYcfeXTUYdjlgZYchpwwtpnmlifcXYciouuspooooonlkmoppoljkmpqrpmlnoppnkhhihfbWUWYbcXQKJMQUUPKJPXgqvxy0123579+987789+////////83zvstvxz012332210zyyxxxwwwvuutttuvwwwwvtsrqqrsttrpoonnnmmmmmmkigfgikkkjijmprttrqppomljjkmosuvvvutrqponopqqpmjijlorrsrrpnkhffhjklkihiknprrqommmlkihiknrtvwwwvtqokijlnqqomkjjheaVVWadgebabdeebWUXciprqomkkkjgbZadipuvwwwvsqmihiknponljjjkkkjjjjihfedegijkkklnoqqqpooooonmlllnqtvwwwvusqomnoqrrpnllmnoooonnlkigffghijjijloqrqommmnnnnnoprtvvvuusqnkhgilostrpoopqrrqqppnligfhjmoonmmmnoppnmlllkjhfgjmrvwxxvurolihjloqrqomlllkjhghhhgebZbeilnmkklnopnljihhheaacgmswxxxxvtqnjjkmpsrpmkjjklllkkkjgecbdgijkkjkmoprqpnmmmmljhikmqtuvwxxwvtrppqqqpmihhjkmmlkkkihgfeeggggffgjmprsrqqqqpnljkmoruutttsrqomkkmoqqoljjlnppoonnmkigfgijkkjiijlnooonmllljihikmpstuvvtsplihhknrrrpomljfaWUWZdgfcaabdcaVQSXdlqqpnlkjheaacglsuvvvusqnkhghknqrqomkkjjjiiijhgebabegijkjjklnnnljjjkjjiijloqstuuusqoljhiknpppmlkjjiighhiihfcbbdghiihhikmoonmllllkjijkmprtuvvuspnkiiklnnljijklmmmlmmljgdcdfijkjijmprtrpmmnnonmllnpsuvvvvuttsqooopqqponoppqpnmmnmljhffhjkllklnpqrqomllmmmllmoprtvwxwuspoooopqssssqppppqrrrqomkknqvxzzyyyz0112210zywwwwwvvvwxyzzzyxwwvvwxyxxwuttsrrrrrqnkihilpssroljloqsrpmlmoqtvwxxwwwwxz010wtpnnpruuutsrrqpnkjiihgcXTVYdhllkklortuvuuuttssrrsstvwyyywvtrqpqruwzzzxvtrponmmlkigfgiloomjfegkorrokiikmprsuvvvxxxyzyvsnjghkotwyxwwwvtqlhgggebXVWbhmpqppqstuvuttttsrqppppsuwxzyxvtrqqrtuvvvutttsrqpoonmjgfgjnqqolggimpsqnkijlnqstuvuvvwxzzywutsstvvutqmjijknpqqqpnkgdbcfkorssssuvwwutrrqpolijlnrwxyyyyxwvtqoprtvwvtsrrrrrqpomhdaZZdimpqqpqrtuutrqppqrsstttuwxyzyxvusrqqrssrpmjjklmnnmmlkgcYVWafkopoopqrtsrqqqssssrsttvwxyzzyxwvutuvxyzzxwutsrpoooonkhffgkopnkgdfjnrtqnmmnoqqqrsstuvwyzzyvrnkkmpswwwwwwwusoliihgdZXXaejmnmlnpsuvutsrrponmmnoqtvxyyxwusrqqsuwwwvutsrqonnnnmkhffgkopokgfgjnrqomklnpsuvwxwxxxxzzzywtpnnpswxwvuuuutromllkhdZVWaflpqrrstuutrqpqrtuvvvvvwwwxxxwwvvvuwyzyzxusssssssrrqolifdehlprsrqrstuutsrssssssttttuvvwwwwvvuuuvwxyxwusqnkigghlnppnjiiklmliikmpqolhfghhfcZYbhovz01yvqligfhknpqomlkjihfdddegilmnoonnnnnmmlkkkklkkhfcZYbhnv146777666544334556765566642xtqppqrstttuutsqomllkjigdbYWXaccaVPLMPSUTRONOQSSQNLMQTUTOOQVZZTNIIPXcdYRLKMRVVSMIFEDDCCIPWbaTMIINRUSOIEDDDEEDFLQVYVPNPSWWSLFAAAAAAAABDEEEDEIPVZYTOORXaYTLFHNTVWQKKNSWYTNKLPUXVQPQUYbWPIGLSYZXQMNSWYVOJLQWZZRPQVckpsuwxxwurpnnpqrpmhgimqtqmllmorqrstwxxxxwwwxwvtrpooqqpomlmnortvxzzxtoieeinstsnjhijigcYYcggfYSQUafieYWZfnusnhefikjeXVWbiptvxxxwrmgaaekquqjedehieXSSVaecVNIKPVXVOQUdnvunheegjidYXZdjqtwyzyvrmgbcgnuyvoieeeecXUVZcfcVNLPVchfYWZfouvpheehhidWWZdjtvwxyxvrlgbbfmsvtoighihgaUUXcedWNJLRWZWSSXfovtneaadgfcVTVaiquvwwvurniffjostohaYaehgcXXZdhfXPORZhlhZYahpxwphddfijfZXYciqtuvwvuqnideinrurkeddegeZVVYbfcVNJLSYbZSOSakrsldabdfhbTSUZgqtvwxvtqlhddhnsvtmgdeffeYRSWbefXRQUcmtvvsssuvvsnmmorvvsqpnoqstuuuurokggkpvz0xusssuvurpnmjgbWVWbehgedgkpttqkgfghgdYWXciosuvvutqmiddhnrurlhghklicYXYcfcWPLOUbeeXSTZgmpjcZacfgcYXZekrtuuutspmiedglrutnighjjgZWVYdgeXPLNSYcaURVbjrrlebadhieXXYciruwxxwtqmhdeintxvpjhghhfaUUYdffYPOSZflhaYZeltsngbacffcWTVZgotvwwvuqlgabfkrwvrmjjjifZTSUZdebWTVZdffddfkprrmheehjjgcabejqtvvvsqnjfabejorohcabdfeaXXadgfZSPQVaeeYVYckpqlebbdefcWUXbhptvwwvtrmhcbekprpjcabeefcYYbddcYVSTVXZaaadgjlljgffhiihfehlopojfehjlmidZZadffdcehloolgfgijjgcbbehigdaadfihebZbcddbYXYbflprssrqolifdceeedaZaehjjgddfhlnoqsuwxxxwvvwwvvusqqqppponnnnprtuvusqonllmoqrrpmkkkkkkkkkkigdcbehjjjjjknprqpnkklnnnmmmmnqsttuttsrrqqqrstrpnmmmmllkklmljhgffikmnppqstuusqonnnooonnnnprtvvvtrqpoopqsssqnmlkkjjiijjigeccdhklnmkkmopqpnmmnnnmlklmnqsuvvvtrpmjhjmpsusrppooonnnnmibUPMNQTVXYZbdfhklllligdZXWXaeikllkigdaXVUWYbdfggggggghiijifcYUUWaeikmnnnkgbXUTWZdhjkkkkifbXUTVWXXUSRSUVVUSRRSUVUSQPQSTTSPNOQSTTQPUagloljhhhfdbYYbfjmmkiiijjheaXWWXacdfhjlmmkighhiihgeefffebZZbddcXSRTYabYTSVagmpqqpqqqrsrrrsux012111244530xvttuwy0010000zzyxvussssqpnlklmpsuvwwwwutrpprrrqmhffhjmnmllllkjhggikkjhffhknomjgghjkkihhiknrtvwwvutssrsssrplhfgjmprrqqpnmkjiijjihfdehlorqomkkjigedegjoruvwwuspmighkorsqomllkifbabeghfdbceghfcZZdjpstqmkkjigdccfjpsuwwvuspmiggjmqrqnmlmnnljjijjjhgghjlmnnnnprstsqpoooponmmmnpsuvwvvuutsqqrrrqnjhhilnoonnmlkigefgiiigeehloqolihhijigeefimpsuvvutqnkiiloqroliijmoppooonlkjiijkkjhfgjnrttrqooomkgeehjosuvvvvusrpnnprtuusrqqqppooopomkjjlptvvvtrsuwxwvtsrqolhdefinsuwyyxurnjghknrtutrrrrrrqponlhebZZbeffdbbehlonliijklkhedehmruvxxwvuusqrtvwuqmihiknoonnmkjhgefhijjhefhlpsqnkiijkjhedfhkoqsssssrrrrstutsokiijlopppoonljigghiiihfgjnrtusqonnljgddgjotuvwxxwtplhhjnrsrolkkkheaWXaehigeefghfcZadhnqqoljjjifcYZbflruvwwvurqnmlmorrqnljjkkjihhhihfdcceghhgfgjmopoljiijkkkjjklortuwvusqonmnprsrpnlmnoonljjkjigdbcfilmmlkmorssqnnopppomlmmnpqstuutsqonmnoqqomkklmnnlkkkkihfedgikllllnoqrqnkkkmnoonnooqstuvusrqpoooppqqomkjjjjjiiijihfdcdgkmonmmnprrrpmlllllkjjkmprtuvwwwwvutrqrrrrrqqrtwy00zyvsqnlkjihgedcbbbaZYXXXWWVTTTUVWVUTTUVVUSPNOPRSRPMLLMNOMKLNPRTRNLMOQRQNKKMORSPLIKMQRQMIJNRTUQLJKMOQNJHHKNQQOKJJLNOMJHILPRRNJJLOQSOKJKNRTQMJKMPTSOKJLOSTRMJJMPRRMIILORTQNMNPSTRNLLOSVURNMNRUWSNMMPSVUQOPRUXWSNLMORTRNLMORUTPLLMPSURNLMOQSQNLLORUVRNMNPTTRNLMOSUTPMLNQSTQMLMPRUROMMNQTTQNMMORSRNLLNPRROLLNQTVSONOQTVTQPPQTWVSONNPSTSOMMORTURPPQTVURONOQTVURQQSUXWTPPQSVXVSSSVXbaXVUUWYZYVUUVYbaXVUVXabZWWWYacbXWWWXaZXUUVWZbaXVWXacdbYXYYabaXXXYZbaYXWWYaaZXXXZabaXWVWZbcaZZabddbXWWWXZXVUUVXXWTQOOQSSRONNPSUVTRQRSUVTSRSUXYYVTSRSTTRPOOQSTTRQPQRSSQPPRUYZYWUUTUVTQOPQTVVTQQQSTUTQPQTWaaXUSSSTTSQOOPRSSRRRSUWVTRRSVYaZWVUUUWVTRQQRSSRQQQSTUTSRSUXaaYWVVWXXVTSSSUUTRQRSVXXVTRSTWYYWVUVWWVSQPQRUTSQPQRUVVTSTVYbcZVTRRTUTSRRSTVVUTTTUVUSRRTWZaZXVVWXYYVTSTUWXXWWWXYaYWVVWZbbZXVVWXYXWVUUWXYXWWWWXYVTSTVYbaYWWWXYXVTSTVYZZXVUWXYZXWWYbdecZYXXYZYWVVWYaaZXWWXXWVTUWaeggdbZYYZZYYZaabaYWXYZbbabcfhjhdaZadffcYTSSTVWWWYadeebXWZbefdZVTTUVWVUTUWXYYWVVXYabZZbfkqwxyxusrpoomlkkjjjjjjjiiihhgfedcbaZaaZaaaaaZYXWWWWVUUTTTUVVUTQPQSUVUROOPRSTRONOPQRQOOQTVXVSNMORTTQMJKNQRSPLLNQRSPMLOSVWTOLLORUTQMLMPSUSOMMPSTSOLLOSUVSONORVXURQSWchhdWSPPPPNJMRYgljdaYadggbWRQQRSROPTYfjidXXYcgjgbWSQOONMLNQTVVTQPQSTTRQTYemtwxzzyyyy0123430xusrstuvvxyywwuttwy01111112100zzyxxvtrpoppqrsttuuuutsqppqrrqnjiiklnnmmmligedcegijjihjmpstsqonnnlkiijkmpqrstttsrrrrsuutqmhffhknppppomkhffhkllljhilorsrpnlkigecbehkoqqqrqomjfcceilonljihihfcZYZbccaYXaeijidcdimrrpmjjjjjhedehkqstuvvutplgefjnqqomjjjjihgghiiigeegjlmmlklmpqqpnkkkjjiiijlmprstvwwwwvusttusqlhfgikmnmmmmkjhfegijlljijlprsrpnmnnmkighjlptuvwwvtqnkijlorsqmjijkmooooonljhghjlnnlklmpqrpmjiiiihfegikorrstttsqoljjlnqrqonmllkkklmlkheddgjmprrrstuvvutsqpnkgdcehkpstuvvvtqnjhilorspmkjjjjihgghgfedcdgjlmmlkmoppnkihijjigfgikoqrtuuutsronnoqrqmhfefiklmmmlkigeefjmoonllmoqsrpnnmmljgeghknrssttsrrsstvwwwsojggiknoonnljhgedfiklmkiiknprqnlkkkjifegjlpstttsrpmjfdehlopmigfgfecZZbdfebXVWafjjhefinruroljiihfccdhlqstsssqpnljijloqqnljijkkkkjjjigecbdfijkkjjmoqrqomllmlljhijkmpqrssrponmlnoppnlhgghijjihhihfdbacehijjiikmnomjgfghiiiiiklorsstsrqonljjlmnnmkijkmopponljhecbdfiklkklmoqqoljhiiiiihjlmoqqqqqqpnliggilllifdfgikkiiijihfdbceghijjjkmooonlkklkkjhhjlnqsstssrrrqqpppponlkklmmmljjjkmoruxz00zzyzz000zzyyxwuromlmmoqrrsrqpomkjknoqpnjhhijjjhggggfeddfhklmkiikmnonjgfghjkjijlloqrrttttrpmjjlnpqnkiijkkjhffgfecZYZcfhiihgilnonjgdeeffddegjorssrqpmkhecdgknnlhedeffebaaceebYVVZehjhedfjnpojfddfijifhilptuvvvurokfcdgkoomigfggfdZXYadedbZadhjkkjjloprqnljjjjhfeefilprssssrpnkhiknpqokhgghhgeddeffecbcfilmmlkmprsqmiffghiiijlnpsssssrqomljklnpolhfdeghhgffggfdaYaehklkjiknppolhffggfecdgjmrssssrpnkhffilnnlhddeffebYYacbaWTTXcfhhfegjmomidaabdeeccehlqtuvutrolhffimqrojfedfgfdbcdeffedehklmmmnoqrrplihhijjiijlmprsstutrpnkiikmnomjgffffeddeffecaZaegiihffimprqlhefgijighiknrstuutqnkhffiloomifeeffecbcdedaXTTVZbddcdfjnppnkhggfecacehlqstuutromjhikmoomigffggfdccccbZWTUXcfgeaadimpnjecbbdedcdgimrtuvvusojebcglprplihhhhfdcdghgdYTTVadffedgknpplheeghjihikmosstttsqnkighjkllieccefggeefhigbWTSWbefdbbfjnqpmigffggfegilorrstttsqolkkmopolhfedbZXVVZflpqokiijjjhedehjlkgcabdeecZZchqy36860tmfaYaglpqnifeefhijmortvxyyxvtrqomljhfedccbbaZZYYYZcgjmoqrsuvwwwwwvvuuuvvwwwxxyzyvsnkihiiiijjjihhggggggghhiiiihgedcccccddcbbaaabcccccdddeeeedbaZYYXXXWWWVVVUUUUUUUUUUTTTSSRQPOOOONNMMMMMMMLLKKJJJJJJJKKKKJJJIIIIIIIIJJJKKKLLMMNNOOOOPQRTVWZbdeggiknqsvxyz1358+//////////////////////////ym]], + note = [[IIIIIIIIIIIIILLLLLDDDDDDDDDDIIIIIIIIIIIIIIDDDDILLKKKKKKKKIIGGGGGGGIIIIILLLLLLLDDDDDDDDDGGGGGGGGGGGIIDDDDLDDKKKKKKKKKGGGGGGGGGIIIIILLLLLLLDDDDDDDIIIIIIIIIIIIIIIIILLLDDDKKKKKKKKKGGGGGGGGGGGGKKLLLLLLLIBBBBBBBGGGGGGGGGGGGGKKKKKKKKKKKKKKKKDDDDDDDDDIIIIDDDKILLLDDDDDDDDIIIIIIIIIIIIIIILLLLLLIIIIIKKKKKKGGGGGIIIIIIGIILLLIIDDDDDDDDDGGGGGGGIIIIIIIGGLLLLKKKKKKKKGGGGGGGGIIIIIKKKLLLLLLIDDDDDDIIIIIIIIIDIIIIIDDIIIIIIKKKKKKKGGGGGGGGGGGGGGGGGGGGGGBBBBBBBBGGGGGGGKKKKKKKKKGGGGGGKKKKKKKKIIIIIIIIGGGGGGKGGGIIIIIIIDIIIIIIIIIIIIIIIIIIILLLIIIIKKKKKKKIIIIIIIIIIIIDDIIILLLLDDDDDDDDGGGGGGIIIIIGGDDLLLLLLKKKKKKKKGGGGGGGGLIIIIIILLLLLLLDDDDDDDDIIIIIIIIIIIDDDLLLLLLLKKKKKKKKKGGGGBBBBBBBBBBGBBBGGKBBBBBBBBGGGGGGGGGGGBBBKKKKKKKKLLLLLLLLLDDDDDILLLLLLLLLLLLLLDDDDDDDDDDIIIIIIIDIIIDDLLLLLLLKKKKKKKKLGGGGGGGGDDIIIDLLLLLLLDDDDDDDGGGGGGGLLIIIIDLLLLLLLLIIKKKKKKGGKKGGIIIIIIIDLLLLIIILDIIIIIIIIIIIIIIIIIIIILLLLLLLLLKKKKLKKKKKKKKKKKGGGGGGGGKKKKKKBBBBBGKKKGGGGKKKKKKKKGGGGGGGGKKKKKKKKDDDDDDDDDIIIDDDDDDDDDDIIIIIIIIDDDDDDDKKKKKKKDDDDDDDDKKKKKDDDDKKKDDDLLLLLLLLLDDDDDDDDDDLLLLLLLLLLLLLLLLLLLLLLLGGGGGGGGGGGGGLLLLLLLLLLLLLLLLLLEEEEEEELLLLLLLGGGGGGGGLLLLLLGGGGGGGGGGGKKKGGGGGGGGGGGGGGGGGGGBBBBBBBBBBBBBBBBBBBBBBBBBBBBDDDDDDDDDDDDDDDDDIDDDDDDDDDDDIIIIIIDDDDDDDDDKKKKKKDDDDDDDDDKKKKKKKDDDDDDDDLLLLLLLLLLLLDDDDDDLLLLLLLLLLLLLLLLLGGGGGGGGLLLLLLLLGGGGGGGGGGGGGLLLLLLLLLEEEEEEEEEEEIIIGGGGGGGLLLLGLLDDDDDDDDDDDDKKBBBBBBBBBKKDDDDDBBBBBBBBLLLLLLLLBBBBBKKKKKKKKKKKKKKKDDDDDIIIIDDDDDDDDDDDDDDDIIDIIIIDDDDDDDKKKKDKDDDDDDDKKKKKKKKKKKDDDDDDDLLLLLLKKDLKKDDDDDDDDLLLLLLLLLLLLLLKLLLLLLLGGGGGGGKLLLLLLLLLLLLLLLLLLLLLLLEEEEEELLLLLLLLLLGGGGGGLLLLLLLGGGGGGGLLLLLLKKGGGGGGGGGGGLLKBBBGGGGBBBBBBBBBBBBBBBBBBBBBBKKKKDDDKBBDDDDBBBBBBBBDDDDDDDDDEEEEEEELLLLLLLLLIILLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLFFFFFFGGGGGGGGBBBBBBBBBBBBBBBBBBBBBGGGGGGGGGIIIIIIIIIIGGGGDDDDDDDIIIIGGGLLLLLLLLLLLLLLLLLLLLLLLLLLLLIIKKKKKKKKKKKKKKKKKKGGKKKKKKKKKKKKKKKKFEKKBBBGKKIIGGFKKKKGGGGDDDDDDIIIIIIIIIIIIIIIIIDDDDIIIDDIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIDDDDDDDDDIIIIIIIIIIIIIIIIIDDDDIKKKGGGDIIIIIIIIAAAAAIDDDDDDDDIIIIDDDDDDDDDDDDGEEDDCCFFFDIFFFFFFFFKGGGGGGBBGGBBBGGBBBBBGGGGKBBBBGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGBBBGGGIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIDDDDDDIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIILIIIIIDIIIIIIIIIIGGGGGGGGGIIIIIIIIIIIIIIIDIIIDIDDDDIIIIIDDDDDDDIIIIIIIDDDIIIDDDDDDDDDDDGGGGDIIIIIIIIDDIIDGLLLLLLLLIIIIBBDLLLLLLLLLKKKKKKIIIIIIIIGGGGGGIIIIIIIIIIIIIIIDDDDDGIIILLLLLLIIIIIIIIDDGGGIDDDDDDDDDGGGGGGGIIIIIIIIIIIIIIIIIIIIIILLLLLLLLLLLLLLIIIIIIIIGGGGGGGGIIIIIIIIIIIIIIIGGGIGGDDKKKIIIGKKKBBGIIIIIIIIIKGBBBDDDDDDDDGGGGGGGDDDDDDDDDDDDDDDDDDDDDDDBBBBBBBBKKKKKKKKKLLLLLLDDLLLKKKKKKKKKKKIGGKKIIIIIIIIIDDIIIIIDDDDLDDIIIIIIIDDDDDDDDDDDDDDDDDDDDDDIIIIIIIIDDLLDDIIIIIIIIILLLLLLDDDDDDDDIIIIIIIGGGGGGGIIIIIIIIIIIIIIIIDDDDDDDDDDDDDDDDDDIIIIIIIIIIIIDDDDDDDDDDDDDDIIIIIIIIIIIIIIIIBBBBLLLLLLLLLLIIBBBBLLLLLLLLLKKKKKIIIIIIIIIIIGGGGGIIIIIIIIIILLLIILLLLLLLIEEELLLLIIIIIILLLLEEEEDDDDDLLEEEEEEEEIIIIIIIIIIEEEEEIIIIIIILLLLLLLLLLLLLIIIILLLLLLGGGGGGGEEEEEELIIIIGGGGGKGGGKKBBBKKGGGGGBBKKGIIIKKKKKKKBBBKGKKKKKKKKKGGGKKKDDDDDKKKKKKKKKDDDDDDDBBBBBBKKKKGGGGGKKKGGKKKKKKKKKKKKKKKKKBEEKBBBEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEGGGGGGGGGGGGGGGEEEEEGGGGGGGGGGGGGGGGDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDGGGGBBGGGGGGGGGGGGGGGKKGGGGGGGGGGGGGGGGGGGGBBBBBBBBKKKKKKKKIIIIIIIGKKKKKKIIIIIIIIIIIDDDDIIIIIIIIIIIIIIIIIIIIIIGGGGGGGGDDDDDDDDDDDGIIDDIIIIIIIIIIIIIIIIIIIIIIIIIIDDDDDDDDDDGGGGGGDDDDDDIIDDDDDDDDDDDDDDDDDDDDDDDDDDDDDEDHCEEDDBBDDBBDBBBAAABGBBGGGBBBJBBBBBBIIIIGGKKKKBBBBBKBBBKKKKKKKKKKGGGGGGGKKKKKKKKIIIIIIIIDDDDDDDIIDDDIDDDDDLDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDBBBBBBBBBBBBBBBBBBBBBBBBBBBKDKKKKKGGGGGGKKKKKKDDDDDDDIDDDDDDIIDDDDDDIIIIIIIIIDDDLLDDDLLLLLLLLLDDDDDBBBBBBBBBDDDDDDDDDDDDDDBBBBBBBBBBBBBBBDDDDDBBBBBLLLLBBDDDDDKKKKKKKIIIIIIIIIDDDDIIIIIIIIIIIIIIIIIIIIIIIIIIDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDGGKGGGGBBKKKBBBBBBBBBBBKDDDDDDDDDGKBBBGDDDKKKDDDDDDDDDDDIIDDDDDDDDDDDDDDDDDDDDDDDDDGGGGGGGGDDDDDDDDKKKKKLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKLLLLLLKIIIIIIIIIKKKLLGGGGGGGIIIIIIIIIIDDDDDGGDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDBBBBBBBBDGBBBBBBBBBBBBBKKKKKBGGGGGGGKKBBBBKDDDDDDDDIDDDDDDDDDDDLLDDIIIDDDDDDDDDDLLLLLLLLLDDDDDDDIIIBBBBBDDDDDLBDDDDDDDDDBBBBBBBBBBBBBBBBDDDDLLLLLLLLKKKKKKKBBBBBBBEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEGGGGGGGGGGGGGBBBBBBIIIIIIIIIDDDDDDDDDDDDDDDDDDDDIIIIIIIDDDDIIDDIIIDIIIIIIIIIDDDDDIIIIIIIIIIIIIIIGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGKKKKKKKKGGGGGGGKKKKKKKIIIIIIIIIIIIIKKKDDDDDDIIIIIIDDDDDDDDDDKKKKKKDDDDDDDDKKKKKKDDDDDDDDDDKKLLLLLLKKKKKKKBBBBBLLLLLLLLLLLLLLLLKKDDBBGGGGGGGGGGDDDLLDDDDDDLLLLLLLLLLLLLLLLLLLLGLLLLGGGGGGGDDDDGGGGGGGGGGLLLLLLLLLLLLLLLLLLLLLGGDDDLLLLBBBBBBBBBBBBBBBBBDBBBDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDIIIIIIIDDDDDDDDDDKKKKKDDDDDDDKKKKKKKKKDDDDDDDKKLLLLLLKKDDDDDDDKKKLLLLLLLLLLDDDDDDGGGGGGGGGGGGGGGGGGGGGGGGDDGGGIIIIIIDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDBBBBBBDDDDLLLLDDDDDDDKKKKKKKKIIIIDDDDIIIIIIIDDDDDDDDDDDDDDIIIIIIIIDDDDDDDDKKKKKKDDDDDDDDKKKKKKKKDDDDDDKKLLLLLLLBBBKDDDDDBDKKLLLLLLLLLLLLLKDDDDDLLBBBBBBBGGGGBGGGGLLDDGGGLLLLLLLLLDDDLLLLLLLLLLLLLGGGGGGDLLLLLLGGGGGGGGLLLLLLLLLLLLLLLLLLLLLLLLLLLLBBBBBBBBBBBBBGBBDDDDBBDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDEEEEEEELLLLLLLLLLEEEELLLLLLLLLEEELLEEIIIEEEEEBGGGGGGGFFFFFFBGGGGGBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBIIIIIIILLLLLGLIIIIIIIILLIIIIIIIIELLLLLLIIIIELLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKGGGKKKKBBBGKKKKGKKKKKKKKKKGKKGGGGKKKKKKKKIIIIIIIIIIIIIIIIIIIIIIIIIDDIIIIIIIIIDDIIIIIDDDDDDDGGGGGGIIIIIIIIIIIIIIIIDDIIIIIDDDLLLLLDDIIDIIIDDDDGDDGGGGGGGDDDDDDDDIIIIDDDDDDDDDIIIIIIIIIIIIIIIIIIIIIIIIIIIDDDDDDDDDDDDGGGGGGIIIIIIIIIDLLLLLLLLLLLLLLBBBBBBLLLLLLLLLLLLLLLIIIIIIIGGGGGGGGIIIIIIIDDDDDIIIIIIIIIIIDDIIIIIIIIIIDDDDDDDDDDDDDDDDDDDDDDDDDIIIIIDDIIDDDDDIIIIIIILLLLDDDIIDDDDDDDDDIIIIGGGGGGGGDDDDDDDDDDDDDDDDIIIIIIDDDDDDDDDDDDDDDDDIIIIIIIIIDDDDDDDDDDDGGGGIIDIIIIIIIDDLLLDDLLLLLLLLIIIIIDDLLLLLLLLLDIIIIIIIIIIIIIGGGGGDDDIIIIIIIIDDEGGGGGIIIIIIIIEEEEIIIIIIIDDLLIIIIDDDDDDDGGGGGGGIIIIIIIDDDDDLLLDIIIIIIILLLLLLLLDDDIIILLLLLLLLGGGGGGGGLEEEEEEIIIIIIIIGGGGGGGIGGIIIIIBBBBBBBIIIIIIIIGGBBBBDDDDDDDBBBBBGGDDDDDDDDDDDDDDDDDDDDDDDBBBBBBBBBDDDDDKDDDDDDDDDBDDDKKKKKKKKKDDIIDIIIDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDIIIIDDDDDDIIIDIIIIIIIDDDDDDDDDDDDDDDDDDDDIIIGGGGGGGDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDIIIIIDDDDDDIIIDDDDDDDDDGGGIIIIDDDDDDDDDLDDDDLLLLLLLDDDDDIILLLLLLLLLDDDDDIIIIIIIIIGGGGGIIIIIIIIIIIIILLLLLLLLIIDDLLLLLLDDIIIIILLLDILLLLDDDDDDDGLLLLLLIIIIIIILLLLLLEDDIIDDDLLLLLLLLLDDDLLIIIILLLLLGGGGGGGLDDDEEEEIIIIBBBBBBBBBBBBBBBBBBBBBDDBBBBIIIBBBBBBBBBBBDDDDDBBBBBBBBBDDDDDDDDDDDBBBBDDDDDDDBBBBBBBBBBBBBBBBDDBLLKKKKKKKKKDDDDDDDIIIIIIIIIEEEIIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEELLEIEEEEEEEEEEEEEEEEEEEEEEEEEBBBBBBGGBGGGGBBBBIIIIIIIIIIIIDDDDDDDDDDDIIIIIIIDDIIIIIIIIIDDDDIDDIIDDDDDDDDIIIIDDDDDDDDDIIIIIIIIGGGGGGGGGGGGGGBBGGGGBBBBGGGGGGBBBGGGGBBBBBBBBGGGGGGBBKKKKKKIIIIIIIIIIIIIBBBKKKKKIIIIIIIIIIIIIIIIIIIIIIIDIIIIIIIGGGGGGGDDDDDDDDDDDDIIIIIIIIIDDDIIDDIIIIIIIDDIIIIIIAAAAAAAAIIIIGGGDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDIIIDDDDIIIDDDDGGGGDDDDDDDDDDDDGGGGBBBKKKKDDDDDDDDBBBBKKKKKKKKKKGGGGGGGGKKKKKKKKIIIIIIIIIDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDILLLLIIIBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBKKGGGGKKGGKKKKGGDDDDDIIIIIDDDDDDIIIIIIIIIIIIIIDDDDDDDDDLLLDDDDDDDDDDDDDDBBBBBDLLLDDDDDDDDDDDDDDDDBBBBBBBBBDDDDDDDLLLLLLLLLDDDDDDKKKKKKKIIIIIIIDDDDDDDDIIIDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDIIIDDIIIDDIIBBBBBBBBBBBBBBIIIIBBBBBBBBBBBBBBBBBBBBBBBBGGGGBBBBBGGGGGGGIIDDDDDDDDDDDDDDDDDIIDDDDDDDDDDDDDIIDDDDDDDDDDDDDDDDKKKKKKKLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKLLLDDIIIIIIIIKKKKKKGGGGGGGIIIIIIIIIDDDDDDDDDDDDDDDDDDDIIIDDLLDDIIDDIIDDDDDIIIIIDDDDDDIIIBBBBBBBBBBBBBBBBBBBBGBBBBBBBBBBBBBBBBBBBBGGGGGGGGGGKKKKKKDDDDDDDIIDDDDDDDDDDDKIIIIIIIDDDDDDDDDDLLLLLLLLDDDDDDDBBBBBBBDLDLLDDDDDDDDDDDDDDDBBBBBBBBBBDDDDDDLLLLLLLKKKKKKKBGGGGGGBEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEGGGGGGGGGBBBBBBIIIIIIIIIIIIIDDDDDDDDDDIIIIIIDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDIGGGGGGGGGGGGGGGGGGGGGBBBBBBBBGGGGBBGGGKKKKKKKGGGGGGGKKKKKKKKKIIIIIKKKKKKKKKKKKKKKKKKKKKKKIIIIIIKKKKKIIKKKKKKKKKKKKKKKKGGGGGGGDDDDDIIIIILLKKDDDDDDDDDGGGGGGGIIIIDDDLLLLLLLLKKKKKKGGGGGGGDIIIDIIILLLLLLKDDDDDDDDIIIIIIIIIIDIIIIILLLLLLKKKKKKKKGGGGGGGGGGGGGGGLLLLLLLBBBBBKGGGGGGGGGGGGGGGGGKKKKKKKLLLLLLLDDDDDDDDDDDDDDDLLLLLLDDDDDDDDDIIIDDIIIIDDDIIDDDDLLLLKKKKKKKGGGGGGDDIIIIIIILLLLLLLDDDDDDDDDGGGGIIIDDDDIIDLLLLDDKKKKKKKKGGGGGGLLLIIIIIILLLLLLKDDDDDDDDDIIIIIIIIIIIIIILLLLLLLKKKKKKKGGGGGGGGGGGGGGGGLLLLLLLBBBBBBBGGGGGGGGGGGGGGKKKKKGGGGGLLLLLLDDDDDDDDDIIIIDDLLLLLDDDDDDDDIIIIIIIIIDDDDDDLLLLLDDKKKKKIIIDDGGGGGIDDDDDDDLLLLLDDDDDDDDDDGGGGGGDDDDIDDDDLLLLLDDDKKKKKKGGGGGGDIIIIIILDLLLLLLLDDDDDDDDIIIIIIIIIIIIIILLLLLLLLIKKKKKLGGGGGGGGGGGGGGGLLLLLLLBBBBBBGGGGGGGGGGGGGGGGKKKKKKKKLLLLGGBBKDDDDDDDIIIDIIDDDDLLLDDDDDDDDDIIIIIIDDDDDDDDDDDDDDDKKKDDDDGGGGGGGIIIIIIIIDDDLLIDDDDDDDDDIGDDIDDDIIIDDIIILLDDIIIIIIKKKDGGIIIIIIIDDIIILLLLLLDDDDDDDDDDDDDIIILLLIIIIIIILLLIIKKKKKKLLGGGGGGGGGGGGGGGGLLBBBBBBBBBBGGGGGGGGGKKKKKKKGGGGGGGKKKKKKKKKIIIIIIKKKKKKKKGGKKKIGGGGGGGKKKIIIIIIKKKKKKKLLLLGGIKKKKKKKIIIIIIIIIDLKKKKGGGGGGGGKKKKKDDDGGGGGGGGKKKKKKKKKKKDKKKKKKKDDDDIIIIICCKKKKKDDLLKILLLLLGGGGGDIIIIIILLKKKIILLIIGGGKKKKIIIIKKKIIIIKLLLLKKKKKKKKDKKKKKKKKKKKKKKKKKKKKKGGGGGGGGGGGGGGGGGGGGGGGGGDDDDDDDDDDDDDDIDDDLLIDDDDDDDDDDDDDDDDDDDDIIIIIDDIIGGGGGBBBBBGGBBGGGGGGGGKKKBBGGGGGGBBBBBBBBBBBGGGGGKKKKKKKKKKKDDDDDDDDDDDDDDDDDDDDDDIIIIIIIIIDDDDDLLLLLLLLLLDDDDDDDDDDBBBLDLKKLDDDDDDDDDDBBBBBBBBBBBBBBBBIDDBBLLLLLLLLLLLBLLKKKKKKKIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIDDIIIIDDDDDDDDDDIIIIIDDBBBBBBBGGBBBBBGBBBBBBBBBBGGGGGBBBBBBBBBKKKKKKGBBBGGGGGGGGGIIDDDDDIDDDIIIIDIGIIIDDDDDDDDDDIDDDDDDGGGGGGGDDDDDDDDKKKKKKLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKLLLLIIIIIIIIIIKKKKKGGGGGGGGIIIIIIIIIDDDDIIIIIIIDIIIIIIIIIIIDDDDDDDDDDDDDDDDIIDIIIIIIDDGGGGGBBBBBBBBBBBBBBBBBGGGBGGGBBBBBBBBBKBBBBKKKGGKKKKKKKKBBDDDDDDIIDDDDDDKKKKKDDIIIIIIIIIIIDDDDKLLLLLLLLLDDDDDDDIIIIBBBIDLLLLDDDDDDDDDDDBBBBBBBIBBBBBDDDDDDDLLLLLLLKKKKKKKKBBGGGGGLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEBBGGGGGGGGGGGGGGIIIIIIIIIIIIDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDIIIIIIIIIGGGGGGGGGGGGGGGGGGGGGGGGBBBBGGGGGGGBBKKKKKKKGGGGGGGKKKKKKKKKKIIIIIIKKKKKKKDDDDDDDIIIIIIIDDDDDDDDDDLLLLLDDDDDDDKKKKKKKKKDDDDDDDLLLLLLKKKKBBBBKKBBBBBLLLLLLLLLLLBBBBBBBBLLLBBGGGGGGLLLLLLLDDIIILLLLLLLLLLLDDDDDDDDDLLLLLLLLLLLLLLLLLLLLLGGGGGGGLLLLLLLIIIIIIIILGGGGDIIDDDDDBBBBBBBBBBBDDDDDDDLLLDDDDDDDDDDDDLLLLLDDDDDDDDDDDDDDIIIIIIIIDDDDDDDDLLLLLLDDDDDDDDKKKKKKKKDDDDDDDDLLLLLLLKKKKBBBBBKGGGKLLLLLLLLLLKKKGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGIIIIIIIIDDDDDDDGGGGGGGGLIIIIIIIIIGGGGDDDDDDDDDDDDDDLDBBBBBBBDDDDDDDDBBBBBBLLLLLLLLLDDDDDDKKKKKKKKDDDDDDDDDIIIIIIIIIDDDDDDDDDDDIIIIIIIDDDDDDDDDDDDDDDDDDDDDDDKKKKKKDDDDDDDDDLLLLLLLLLLLLKKBBGGGGGLLLLLLLLLLLDDLLLLLLLLLGGGGGGGGGGGDDLLLLGLLLLLLLLLLLLLLDDDDDLLLLLLLDDLLLLLLLLLLLLLGGGGGGGLLLLLLLDIIIIIIIIIIIIIIIIIIIIIIIBBBBBBBBBBBBBBIIIDDDIDDDDDDDDDDLLBBBDDBBIIIDDDDDDDDDEEEEEELLLLLLLLLLDDDDLLLLLLLLLEEEEEEELEEEEEEEELLLLLFFFFFFFFFGGGGGBBBBBBBBBBBBBBBBBBBBBBBBBGGGGGGIIIIIIIIIBGGBBBBLLLLLGGGGGGGGGGLDDDIIGIIIIIGGGGGGGGGGIIIIIIKKKKKKKKKKKKKKKKIGGGKKKKKBKKKKKKKKKKKKKKKKKKKKGGKGKKKKKKKKKIIIIIIIKKKKKKKKKGKKIIKKKKKKKKKIIIIIIIKKKKKKKKGGGGGGKKKKKKKKKIIIIIIIKKKKKKKGGGGGGGGGKKIKKKKIIIIKKKKKKKKKKKKKKKKKKKKKGGGGGGGKKKKKKGKKKGGGGGKKKKKKKKKKKKKKKKKKKGGGKKKKKGGGGKKKKKKKKKKKKJJIHAADDDJJCCADDDCJBDDCCCAA]], + noteClear = [[OTboy0yvppzkVPTZceh1//9567tbbw043whdabqz2bUbYSPQMWfgqx5raTPSWVRMLLKLMMKVbdZUUHQcqsniZOEHMSUbaSRQLIONPPQOQQQZgijp14lTajqvsleTNHLLKGNPQPPOMNTbeggcQagip492unjYXbhaPOOLJNLNWry31tUMOYqvxnjkibXTORVVZbbUMFKTUYYVRZrvrmfQOOONOJQYiidejhfikfbWVRYckjhiVRNPPRRHHHGFMSNbmnmrsjUhklmiTVfjljjmlPJOMKNMQSVXXaffaSLQfkkYVYYZYRMLMNQRPNSVdkuvvgVVbeehhXQWdfgeULKQTOMOjokbRZcYfdWTWcQPUSNJLLGKRWRDBBBFNSaZNUacXONGAAGIHFBAADDDGMLFLPNQYVGMSVUVUKJKNNKLIFEEFIGCIQTXileNRXcaWNINYuxy2yibUdjvzgWjltx1iRglrqlXTJJXWUNIEFKKOPNMNNLHEDJPXZYXVQPYXOLJJIDDGHIKJFJRVVPDCCCCDGKJIJJFDHEIKKLOPNEJLJJRRDDEIJLFGHNNIBDBBLMKNPKKWbgZWTLSWaZZcdKJKOQPPDJTSLNQOIQQRVbgaflieeeZRRNJIMOINVWQMISdqssqpofOUXUVXYSOMKIHIKKKKNNMJOVWWWRKOTUaaVPJKNJKJGCIOUTTTHMRZbZXQNLTVSRNOKKKMPRPONNQQUUXcdXPLNTWYaiojPHIHFIJGEMRadeZQTVOMQcbJFRVWceRKFEIIMGBNSWTPLDKNNNNMHYcWPPUUFGHJHDCHPYYZYPGEILblvmWLKCFNPDHLMMKFCGJMLGJIIHNNQTPPaffYcmokiePPTSQXbaZbZNGRRRLHIMMMLORSRKHOPNIIFEHILLMKIHJKLMFEIJQUTKMYeilomeYgijlpkLQeiprseTHMSTTNJBBBDHHVlkhgebaSZjidaXPNWZfikZNbcgklfVPORWZWSPPXdnlWceVRVSOKIUZbdbVUSOKINPQQPONIPpwzurhbSQKKKEDJNRTUVTHGSbnongaQQQNJEGLMRQQUXRQbhonlXPRUXZcZQOQSUVQLNSVUbfeQSOIMRSTafbTVYXTLHJMPLUigcZYZWMIHIIJNPRPRQNRZiqogeljefhaUPQQONRSXUKMOadffnqnjgaWSTQRRKLRTYXXWYZVSUdghhcRWcfgrzocSUUbeRVhkhggZSUUaZYcYMOXXaefYSRWcfijjdXSSSOVbaPKJWfmovy42taVPNIFGMRTUXZSJMNLMKEGFTZcbSMGKLGFIGQVZaZWVLHHORYccYMJHJMNJGKLNPQMJKIFEFIJQVWYaZRMFBACEEGILRVXQIHHOQRNHTZghinmSSdbWVVOLFHFFFDFHIORbgfTOPQOKISTQPXbbOKHGGDFOWdfkonfXTXXWbfeXbcccbSOVSPMLKNSbbVQSXZZYZchhZYejkopeWUZahkVOPONUXPVZWTSTNVipuvv1zfWRSSMLUYVSQNJHIGIOPNIJJHIKMSUXWQNKRZhjhebZVMHPQQSTLSYZjokZRFELLKKJTXaaZWPZfjhedRKMMMMLMKMQQRUdedVQKJHGILNQTTNQYfmmeaOKMQSSQOLHHJOSROOMKKJKIHGILMJGEIMLJIGEKSTSLKHDLPXZZRKILRSTSOHFKIFFMhnonjhfTPSTSVYZYUSSSPONMLJKKLNMPZddaTDGRXefVMWoohhieWJGFDFLZcffedaUelmlhaNMNSRSQOLKMMRSPIGLQMKHGGIIFFKLKNNJHKOJIKJKPQNNTTcikfYMNKIFFEFKWachjkmsshgieVJJTRPQPQSQOOPUWUQQMGEEGEJHBFFCAAGHCAFCAAAAAAAAABEFXvyqq+/5yumkz4mUMSRLQXTQSRWYaVNMNQVhdRPNNRccPPQTVWYVUUTSQSPLRUXbdeVQRTUWXPLQWWVVUKHRUYYWJGGHRYdMCFGGIMLDBBHIKJBADNSZaVGCCEHIHAAILNOIAABEDBBCAAAABCBAAAAAAAAAAAAAAAAAAAAAAAAAABABAAAAAAAAAAAAAAAAABBACCEECGLNOONRg03552yz42xlhaUPRTVYaWPPLVdOTousvz77zuqqsphXabZNJKQXfgdYUKHGHKIKKIRUYaXQNSRLJJKLXfnppqdQIPUXXQUZhkquxjUTSNLJJGFFJJMMFEFJJIHEKTUUWYVMMRTQONNZflsv2uLEIHGGGCDEEGMOQQSSPMLNLXdlprnWGFBAAAFZfgeddcPOMLQOJKReimppeMDDDCCBIWdosvscJMOMMNGIRdhmonWHNQTTPIRfhijlgGMPOQUSNUZfilojZSSSWWIACBAAAEGGHJJKPOTaknqwtKAAAAAAGPYZZYWOEPUWWWRIYgnoprnLCDDDIOUZlpqqrUIXbbZXSMCCDEGHEMRRMJKHOWfghhfNKPOHEGMVimrtuoYACCCCDBABIHJKEBFKLJKEHQcfnrnWBAAAAACQTWUSQPDHMUWYWMYqvz89kVEAAHKMPXYcdfdRCHSVXaYFADCCCCAAAACDDCAAAAAAAAIMTWYXRAAAAAAACFLPPRUROLLOSVRKSWSNQRTQYhjjgYRONPSTTXbbYXaeXPMOTURQRYcfgedMHFFFHJPUZefdcOMQQQUTMHNNMORZUNRTLLNMGKPRTUQHNQPOMMRVdfggigVIIJLNNMJJJKMNNOOONJJINVgjnruZJHHCAAJSceccdbTJNOMJJLTZiloqfRFDFEFAMTdjuwqbIKMOOPLPYelnsqQDADFJKMVcgfccaRHGFLOOIainrtuoSQPOSQRROagiaTOMMMMNPTRTWaaYTRMKJKORMHOSSNLOJJPUWUSFJYdkkjbTMPQPONJRWccZXRbfifVTUSOOSVTWSNIJKKJIGIJLMNMCELUUROFFJLIGKPOLKNPKLLOPNQRVZTOKNMLNHGKKJRUSQNGJMLHIRSRPRSNPSRQPORRVZYWPPKJUYXPLHIMMQUWIFNPRRQNPPMMNONJIKEAABEPVaabddMIKLLLIEADEAAAAAJQURTUUTUXYbcZVSWXabcbYYZZXUUSQPPTYaZVPRTXcgffcYVZcYWWYaZUTSSWaaWUYaelnnjPHTVWVUSRNNQTWXSHJKLKIMLJHJMQNCBCFKUUJTbbYWWTNOSPNNSUcdbdeZTRTTWbcbggaXUWZRNROIKTXZWTXgqldSWceeZSINOKFGEEGGHHKTSRSSZXLGGOUaYabbeifbSPIIKPRRPPSXXWTSNQZXQTYSKQYdecVNJKZehibJPOPRYbWSPKNPQPRoutstulUXXWVURIGILNPMDGLMMMLACOQSTSMIBBCCFCAADNOQRRKIKLKLGGHFGKKIEDKMLKLOQUXcegVAEIPRNCOTXYWONDCDGJOPHGIJKOPICCDDADMLGILKJICAAAAACCAAAAAAAAAAACAAAAABDDBAAAAAAAAAAAAAAAAAAEHJJLEBCDHHFEJbfcglkeQZghgeYPdsqkkWJOdgidSRODDFGJKKLIFECCFJLLHDHRSQOLJIKKNRRVcihkhedeXSJIJOQOORUUPQVVTWTNJLMLNQQPNNLJTYYXVRPMLPSTVRDBCEHKLGDQTWWWRLKLKHGFFILWXSTSSVVQPPQOOUTMIGKQbdeggaRONLMNNHJLMNSSLIIMQXaPQYjklkeYPQSSSRNLPUghliSOTWXaVOSXbdhhXOHHFGIHIKJGGJMLDCEGHHEPTWZciePZfcZYXQKHLPMMYaXWXdgcWagifZWUNOVYcdbQLOUdhllmpojhdWPKOVTPNQZaSQSWZWPNLNMCDEFGGFMLJLJJJKKKLMSYbVEEFKLNONIEDEFGAAGJJINQMSUbihkiVTRLPQTSPOPQTWbhnnnnqofQPRSSLCIOVagomXQehiliUQdjmmkVfqs1470qglssy130vov980YYdglnnaRXXcaLEDKIMPPLIBCEFGEAOVdffcISYZXdjeVLIKKLJJHJLRTXXRRTRPOPOOOKKMPQSbdgongikifaZUROQRUUSSXaSQRVVSRUUXbVHMTVWUVPJEFKORSSPPUZcaVHILMKGFMTZXVSNIFEFGIEEHXgieVPOLRQQVZaQNLLOJTTYbWceYVVVVWWQINOOVafeRKPTUZYKHMPQWXRLKQSPLCESgowy0tXNLMPTVjorsrnhSRVRQVTFHYgkoogXRXbceUGHLMMMMJOWdcZYWSRPNGJOWWTVabaUSVXYVPRTWXYXWTPJJMNSTTUWVTYcXRLJIGKUYaZXRVgcPOSXXUUWXXWXcdWNHPPMMNOSUUWWQJCCFHIKKJJKNRWUVgrsuxxmdVSPMPPORSTTUbZRVYYXdaPQQPQWaWUSVTTRNMNLMQSSQPTXWUVVZckosqhMSadfebPMNOPPWZbdaWWTSVWXcZPRUSRZcYUMOZcYfmjaZqw00nbimjfhfWVdimnkfRPQLIDHQQXbhkiUQdebXVSXilkgktnRFLOUXURUhosvrWZdbZZYUbgebgkbSLMMNUcbRMFHXdaJFDHKJILSZZbgmkdJKQQHGHFFGHEGESbkjiiYRLIKGFFHOTODFHRYfhjkldMGHMOMKNRRIIRVQJLPTbfaQHMOONSakgadebWSYcccedYXels0ygYXZZXWKJIKGHLMIVdkkjtqZPJNRQORSLKNQPUdpqmgbPPbeWRLMLNONMJNUiokgjkedmvwvtcZimjklspiOOSXhcYkuyyytXdgkmsugUUfebdYRKHLeovpQNJKLPOLJFJLLKVYVPPflcTCFIOQKEZgotvumRKFHKMNVXSSUdeXRCDQWXOYcbXTVXertvvtokcaXWVWVQNQTbikbVTXdfnrw8983kgffbZerroz126/9unnmt7+qZUZaaXNPSRPUadWINOMLKGUYaZaffQLRQMILSPTZdedVNSVTJHTcnojjmphXhpqqvuYOcfdXSQPUchijbTefVRQQNRUZftyxaVhiaVQNKKRZddTLIKJIJOPLIBBFHHckhaTYTMKRREDBDGKJHJLOQSSQRTXRKGKLHHEDEGJTSLWekjfdTOIIIILLMXejrvumTLFJPbbMGHHILOKIXdecacYXbilmcWZktqnjfYVVTTVVMHGHJLLNVkonmjUNUXRJEBFJLNMGIMbdYVWYZPNJGNQONPSPSWVagombdcVTXbdfjgQWYnsspZPEDGHKKVfiibZTKSROLNSPJKIQVZVFCNRRUWNFMOUfgNLRTVWVWgvxyxtnfSONNLGKchkl058viYWOPUTOeheeeZSFJNMLJGMMNONMMINLJPOLLLLKJKTRNLKEHIECGNRbsviaXbfcVIHLRTgnpoopmgfYUNMOPVUMXccQYVMOOOPQURpz56+//vmabfgnoesx///+4Wk133yyphZYYbgknnhabdfebXPNOOQXWTTXYULLQOOOKOUefbWPEJLMNMJNQWWTVbcXUXWVURPUVZZZaSNLRWbaQKIJLOPRQRROHHLHVabccbXWhmiebYQTaaZcdbXUTQLHEFJOPNMMLKMPQSbebYXXXXWSTaXWSMJOVXXXZXKNRPOQPNQUXWYbbNGOMLLLPXknoomZLSaggdUOfowy1zkYaUTXYJLSXXVULFNYaddUHOSXcfhZSckkhhonnpqsecbVURRXYUQSXbXUUSKJHFHHKWZZZYYXNJJLMPQRQYaZYVQLHGJNSWURWcdeleLRPOOPNIJUWXadaVNHHHHFGRVabVQKRXcdcbZUWbdebMFDGFGKOKFMRbfhZTTTSVbaWTSYZbcOJJIEHKTYcfeaZTJFGHFEHJQVZZYVRFCKLIJJOWgihhgNOWXVNNHOeikmpoaCCFJLIGIMSVXYWGINNLKINNUWaeggYECCAEGGDBCFJMLGIFEFHIFPYYVSLDBBBCCEEGSVRPLIEIKLLHGFKPWYXTJGECBGIDFNQSWXYTKQVbcecKEFFGKJIILMLJIDFRUVYaWMABFGHJENTZYVTSCHMMNLJECDEDHLKEKMPQTSHSVXXYWPAAABFECHMTUVXXJPWVPQOGTegiheYRORYXPQUaeebWUIFGOPPOOJCEGFDCAAJMQRNKECEFDABFLPSSTTJFIJIKMOIEGHEFHEHLQVXVSFENSVWYUQTUWcdUQNMIGEIOUUQPQPNLLMOQUUOSZaWWYXSNLLLKOPWYXWXUPTTSTRQPRTWVQMKILQMKLNHIPQNLLEISWYXSRUXYWWVUMKLLIIMLMQTUSYXUWcdZUTScggbZWVOMKDCEDRVUTUYYOJFHHJKNOWYYYXSOHGLJPUNUaiihcTEHMMMQSGQceffeSJAEFCACJVXXWWVNEGIJIINTXdfedbMEDCBGKIGKLEDFDDEGKMONGJMQQNMIJJCDGKLFHNNKJFCCCFLNQKMQTSPNKKNOKIGEGIKLLLMKJNQSSRRRHMKEGMPNMRPMFFDKQOMIEADFEHKNHIQQJJKOPNQSQQONONIGGJLPPFDCFJKFKKIGGECHLQOLMKIPRNFFKRTVVXXLLUZYVWRMKLLFHLJPdfdbVPOTWTROLFHLNMJGEDDAAAACISVYYVPKMRUVTQMKQVVVWXJEHJJIIOSVUUWYaWQOOQPPSVWVWWaZNHHIQSRONPQQRSVQIHHHHOSWWPNSSQIHKLHFIQQSVYZULJOOQRORRSVYWTROGBGKQSSTTTSXaSSZgghjkhedaVVXXUTQMOWdkmoqqhcYcbZadcdaabbelupVMOTUSWejieciebbdhhaYLHPRRSUOIHKOQSRSUTPPQSQRRVVSRTRUVUQUVLMNNNNQPUYcffbUQNSZdfcWMSWXbefUMGHJIGDAEGEDFFKQSSTTRKJKOPPOPPOIHJKGEELMNPMJGHGJKJCJNPPPPOGDEGGGIJOSSRPOHFGIKLNJHHJMNMKHAABDEEBAABBEIIGIIGFFEFGFGHHIGCEINOQMICBAAGJNYbWSOPOJHIHHHJNPNKJNPMIDCACDBBAAAABACHLKLQRGCDDBDEBAAAAACDADHKKLNIAAAAAAAABAABNRQUnstuxqfcgilnoeLNZeikcIFFEEHISWRMKMPNJJMPOMECHJKJJPQQRWZeikihigffbNHIIHEGKJMQTVVQLMQSSPNJHIGIPPLNRURMNPOMKOUVUSRQOIIEJUXXVUUTRRRQNLIGMU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]], +} diff --git a/demos/neonCoast/video/noise.mp4 b/demos/neonCoast/video/noise.mp4 new file mode 100644 index 000000000..cff37a6dc --- /dev/null +++ b/demos/neonCoast/video/noise.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:10dc85fe97cf2c216d2eb987aa939475f98a0394cfc1e9d9891302c8031b52d1 +size 2366662 diff --git a/demos/neonCoast/video/plasma.mp4 b/demos/neonCoast/video/plasma.mp4 new file mode 100644 index 000000000..5b8e83f1f --- /dev/null +++ b/demos/neonCoast/video/plasma.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:acd24ced50bb95f48e8afdfd09a2e61bb61062daef81860c99d89bc70363dca2 +size 1415258 diff --git a/demos/neonCoast/video/tunnel.mp4 b/demos/neonCoast/video/tunnel.mp4 new file mode 100644 index 000000000..52ec901d0 --- /dev/null +++ b/demos/neonCoast/video/tunnel.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64752ad4f592a1b55cf6c9b1a83245070b547c49522c8c3e5b3b2eb79d07cb09 +size 5156234 diff --git a/docs/Learn.adoc b/docs/Learn.adoc index 825e5aaf9..038874ad3 100644 --- a/docs/Learn.adoc +++ b/docs/Learn.adoc @@ -116,7 +116,7 @@ in the same download as this one. == The Series -Thirty lessons in four parts. Each one needs the one before it and nothing +Thirty-one lessons in four parts. Each one needs the one before it and nothing else. *Part One: The Ideas.* No artwork, no video, nothing to install. You draw with @@ -166,6 +166,7 @@ order. . *Characters That Move Themselves* -- navigation and pathfinding. . *Music and MIDI* -- tracks, soundfonts, and instruments. . *Online* -- accounts, high score tables, and the catalogue. +. *Keeping Data* -- databases, tables, and the questions you ask of them. . *Shipping It* -- packing, patching, licences, and the release. . *In a Cabinet* -- controls, service menus, bezels, and the things that only matter on real hardware. @@ -226,6 +227,8 @@ include::lessons/27-midi.adoc[] include::lessons/28-online.adoc[] -include::lessons/29-shipping.adoc[] +include::lessons/29-databases.adoc[] -include::lessons/30-cabinet.adoc[] +include::lessons/30-shipping.adoc[] + +include::lessons/31-cabinet.adoc[] diff --git a/docs/Reference.adoc b/docs/Reference.adoc index 0c35b8b3b..99cfeaa18 100644 --- a/docs/Reference.adoc +++ b/docs/Reference.adoc @@ -21,7 +21,7 @@ Singe uses the Lua programming language (http://www.lua.org) for scripting game logic. Lua is fast, lightweight, object-oriented, easy to use, and actually used in the games industry. This book does not teach it; _Learn to Program with Singe_, in the same download as this one, does, from nothing to a -finished game in thirty lessons. Video tutorials for Lua are on the Kangaroo +finished game in thirty-one lessons. Video tutorials for Lua are on the Kangaroo Punch YouTube channel, and the language's own reference is at http://www.lua.org. @@ -307,7 +307,7 @@ When Singe runs a game from a database the menu passes `CONTAINER` in the For your own data, `require("sqlite3")` gives scripts the https://lua.sqlite.org[lsqlite3] binding to the same SQLite the engine -uses. Keep such databases in `singeGetDataPath()`: +uses. Keep databases the game writes in `singeGetDataPath()`: [source,lua] ---- @@ -320,6 +320,23 @@ end db:close() ---- +`sqlite3.open` finds a name the way `io.open` does, so a database can ship +inside the game -- level tables, dialogue, item lists -- and still open when +the game is packed. Opened read only, a packed database is read where it lies, +with nothing copied: + +[source,lua] +---- +local levels = sqlite3.open(DIR .. "levels.db", sqlite3.OPEN_READONLY) +---- + +Opened for writing, which is `sqlite3.open`'s default, a packed database is +copied once to the game's data directory, under `files/` like everything else +a packed game writes, and the copy is opened. From then on the name means the +copy, read only or not, and the packed original is never changed. A loose +game's database opens in place exactly as before. `testScripts/packedSql` is +the test; its header says how to run it. + The file format, for anyone writing tools: three tables. `meta(key, value)` holds `version` (1), `gamedir` (the packed directory's name), `chunk` (chunk size in bytes, 4194304), and `packer`. @@ -2460,6 +2477,7 @@ available to `controls.cfg` and to `Framework.singe` alike: | `MOUSE_SINGLE`, `MOUSE_MANY` (also `SINGLE_MOUSE`, `MANY_MOUSE`) | Arguments for `mouseSetMode`. | `OVERLAY_NOT_UPDATED`, `OVERLAY_UPDATED` | Return values for `onOverlayUpdate`. | `RENDER_PIXELATED`, `RENDER_SMOOTH` | Arguments for `spriteQuality` / `videoQuality`. +| `SPRITE_ALPHA`, `SPRITE_ADD`, `SPRITE_MULTIPLY` | Blending for `spriteSetBlend`. | `DISC_STOPPED`, `DISC_PLAYING`, `DISC_PAUSED`, `DISC_EJECTED` | Return values of `discGetState`. | `LIGHT_DIRECTIONAL`, `LIGHT_POINT`, `LIGHT_SPOT` | Arguments for `lightNew`. | `BODY_STATIC`, `BODY_DYNAMIC`, `BODY_KINEMATIC` | Body types for `bodyNew`. @@ -8370,6 +8388,295 @@ nodeSetRotation(ring, 90, 0, 0) [#model] [#midi] +=== Microphone + +A microphone, for a singing game or anything that listens. One recording +device is open at a time, heard as one channel at 48000 samples a second +whatever the hardware gives; SDL converts. Singe keeps the newest eight seconds +of what it hears, and every call below answers from that, so asking costs +nothing the game did not already pay for. + +What a game usually wants is <> -- the note being sung -- +and <>. A game that analyses the sound itself, or sends it +somewhere, reads the samples with <>; the +<> calls encode them for a network. + +The microphone closes when the game ends. Nothing is opened until a script asks. + +[NOTE] +==== +A sung note reaches the game a little after it was sung: the sound card, the +driver, and the buffers each hold it for a moment. A singing game that judges +timing subtracts that. <> measures it by playing +clicks through the speakers and timing them coming back, and the answer is kept +for the machine, like the <>. +Monitoring and calibration have only been tested without real hardware so far; +the pitch, level, reading, and recording have been tested with a known signal. +==== + +[#miccalibrate] +==== micCalibrate + +[source,text] +---- +started = micCalibrate() +---- + +Measures the microphone's latency: plays five clicks through the speakers, a +fraction of a second apart, and times each one coming back through the +microphone. It takes a few seconds; <> says +when it is done. The answer is the middle of the clicks heard, and is kept for +this machine. Do it in a quiet room, with the speakers loud enough for the +microphone to hear them. + +*Returns:* `true` when it started; `false` with no microphone open or no +speaker to play the clicks. + +*Since:* 3.00. +*See also:* <>, <> + +[#miccalibration] +==== micCalibration + +[source,text] +---- +state, latency = micCalibration() +---- + +How a calibration is going. + +*Returns:* `state`, one of `"idle"`, `"running"`, `"done"`, or `"failed"` +(fewer than three of the clicks were heard back), and the latency in +milliseconds once one is known, otherwise `nil`. + +*Since:* 3.00. +*See also:* <> + +.Example +[source,lua] +---- +local state, latency = micCalibration() +if state == "done" then + message = "Your microphone runs " .. latency .. " ms behind." +elseif state == "failed" then + message = "I could not hear the clicks. Turn the speakers up and try again." +end +---- + +[#micclose] +==== micClose + +[source,text] +---- +micClose() +---- + +Stops listening, and stops any recording and monitoring with it. The microphone +also closes when the game ends. + +*Since:* 3.00. + +[#micisopen] +==== micIsOpen + +[source,text] +---- +open = micIsOpen() +---- + +*Returns:* `true` while a microphone is open. + +*Since:* 3.00. + +[#miclatency] +==== micLatency + +[source,text] +---- +milliseconds = micLatency() +---- + +*Returns:* the time between a sound being made and the game hearing it, as +measured on this machine by <> (at any time, in any +game), or set by <>; `nil` until then. + +*Since:* 3.00. + +[#miclevel] +==== micLevel + +[source,text] +---- +rms, peak = micLevel() +---- + +How loud the last moment heard was. + +*Returns:* the RMS and the peak of the last block of samples, each `0` to `1`. +A steady tone at full scale reads about `0.71` RMS. Both are `0` with no +microphone open. + +*Since:* 3.00. + +[#miclist] +==== micList + +[source,text] +---- +names = micList() +---- + +*Returns:* a list of the names of the microphones this machine has, for +<>. It is taken afresh each time, so a microphone plugged in +since the last call appears. + +*Since:* 3.00. + +[#micmonitor] +==== micMonitor + +[source,text] +---- +ok = micMonitor(on [, volume]) +---- + +Plays what the microphone hears back through the speakers, so a singer hears +themselves over the music. Off until asked for: on most hardware the voice comes +back late enough to be off-putting, and on a laptop the speakers feed the +microphone. Anything waiting to be played longer than a tenth of a second is +dropped rather than heard late. + +*Parameters:* + +* `on` -- boolean. +* `volume` -- number, `0` to `1`; `1` unless given. + +*Returns:* `true`, or `false` with no microphone open or no speaker to play to. + +*Since:* 3.00. + +[#micopen] +==== micOpen + +[source,text] +---- +opened = micOpen([name]) +---- + +Starts listening, to the microphone named (from <>) or the +machine's default. A microphone already open is closed first. + +*Returns:* `true` when it opened. + +*Since:* 3.00. + +.Example +[source,lua] +---- +if not micOpen() then + message = "No microphone. This game needs one." +end +---- + +[#micpitch] +==== micPitch + +[source,text] +---- +hz, clarity = micPitch() +---- + +The note being sung, found in the newest 43 milliseconds heard. It finds a +fundamental between 50 and 2000 Hz, which covers every singing voice, and it +answers within a hertz or two on a clean tone. + +*Returns:* the fundamental in Hz, and how clearly the sound is one note, `0` to +`1`. With nothing voiced -- silence, a breath, a cough, a crowd -- `hz` is `0`. +Turn Hz into a note number with `69 + 12 * math.log(hz / 440, 2)`: 69 is the A +above middle C, and every 1 is a semitone. + +*Since:* 3.00. + +.Example +[source,lua] +---- +local hz, clarity = micPitch() +if hz > 0 and clarity > 0.8 then + local note = 69 + 12 * math.log(hz / 440, 2) + local off = note - targetNote -- semitones sharp (positive) or flat + if math.abs(off) < 0.5 then + score = score + 1 + end +end +---- + +[#micread] +==== micRead + +[source,text] +---- +samples = micRead([max]) +---- + +What was heard since the last call, oldest first. + +*Parameters:* + +* `max` -- number, the most samples to return; everything waiting unless given. + +*Returns:* a string of 16-bit samples, two bytes each, little endian, one +channel at 48000 a second: `#samples / 2` of them. Read one with +`string.unpack(">. The name is any file the game +may write, and goes where the game's other written files go. + +*Returns:* `true` when the file was opened. + +*Since:* 3.00. + +[#micrecordstop] +==== micRecordStop + +[source,text] +---- +micRecordStop() +---- + +Finishes the recording. + +*Since:* 3.00. + +[#micsetlatency] +==== micSetLatency + +[source,text] +---- +micSetLatency(milliseconds | nil) +---- + +Sets this machine's microphone latency, as a service menu does from a +measurement made some other way; `nil` forgets it. It is kept with the machine's +other settings. + +*Parameters:* + +* `milliseconds` -- number, `0` to `1000`, or `nil`. + +*Since:* 3.00. + === MIDI Two unrelated things share this name, and it is worth keeping them apart. @@ -9166,6 +9473,40 @@ Every format the sound family reads is read here: WAV, Ogg Vorbis, Opus, FLAC, M Pausing the engine (the pause key, or `singeSetPauseFlag`) pauses the music with it, and resuming brings it back; a reload stops and frees every track. +[#musicgetposition] +==== musicGetPosition + +[source,text] +---- +seconds = musicGetPosition(id) +---- + +Where the listener is in a playing track, in seconds: the mixer's own position, less what is still on its way to the speakers -- the device queue, the machine's audio calibration, and the game's audio delay -- so a picture timed to it lands with the sound. It is the clock to animate to when the music leads, as in a demo or a rhythm game, and it stays with the song however long it plays, where counting frames or ticks drifts. The mixer moves its position a buffer at a time, so between moves the answer runs on with the clock, never more than 50 ms, and it moves smoothly every frame. A paused track holds still. A track that is not playing answers `-1`. + +*Parameters:* + +* `id` -- number; a music handle. + +*Returns:* number; seconds into the track, or `-1`. + +*Since:* 3.00 +*See also:* <>, <>, <> + +.Example +[source,lua] +---- +-- Flash on every beat of a 120 beat a minute song, on the beat as it is heard. +function onOverlayUpdate() + overlayClear() + local t = musicGetPosition(song) + if t >= 0 and (t * 2) % 1 < 0.1 then + colorBackground(255, 255, 255, 120) + overlayClear() + end + return OVERLAY_UPDATED +end +---- + [#musicisplaying] ==== musicIsPlaying @@ -15102,7 +15443,7 @@ Hypseus extension, accepted and ignored. It decides whether Hypseus sets colour spriteBlend(boolean, sprite) ---- -Hypseus extension, accepted and ignored. It is a workaround for that engine: Hypseus loads sprites with SDL's blend mode off, and this turns it back on for one sprite. Singe draws every sprite with its alpha channel already, so blending is never off to begin with. The sprite handle is still checked, so a bad one is still an error. +Hypseus extension, accepted and ignored. It is a workaround for that engine: Hypseus loads sprites with SDL's blend mode off, and this turns it back on for one sprite. Singe draws every sprite with its alpha channel already, so blending is never off to begin with. The sprite handle is still checked, so a bad one is still an error. To add a sprite's light or multiply by it instead, see <>. *Returns:* nothing. @@ -15191,13 +15532,16 @@ end [source,text] ---- spriteDrawGrid(id, x, y, sourceX, sourceY, width, height) +spriteDrawGrid(id, x, y, sourceX, sourceY, width, height, x2, y2) ---- -Hypseus extension. Draws one rectangle out of a sprite, at its own size, with its top left corner at `x`, `y`. It is the only call that takes a source rectangle: <> stretches the whole sprite into a destination and <> takes a whole frame of a sheet, while this takes any rectangle at all -- which is how a game cuts a tile, a digit or a letter out of one image without loading it many times over. +Hypseus extension. Draws one rectangle out of a sprite with its top left corner at `x`, `y`: at its own size, or, given `x2` and `y2`, stretched to fill the box out to that corner, the way <> stretches a whole sprite. It is the only call that takes a source rectangle: `spriteDraw` takes the whole sprite and <> takes a whole frame of a sheet, while this takes any rectangle at all. That is how a game cuts a tile, a digit, or a letter out of one image without loading it many times over. -The rectangle is in the sprite's own pixels and must lie inside it; a rectangle that does not, or one with no width or height, terminates the script naming the sprite's size. The sprite drawn from is the sprite as it is currently drawn, so a <> or a <> changes what the coordinates mean. +The stretched form is Singe's own, and it is what a road-racing game is built on. Each row of the screen below the horizon is a slice of road at some distance, so the game cuts one row out of a picture of the road's cross-section and stretches it to the road's width at that distance, centred where the bends have carried it. A hundred-odd calls a frame draw the whole road, curves and hills included, and nothing is rebuilt. The same form draws a sprite partly hidden behind the crest of a hill: cut its top part out and stretch it to what is left showing. <> can do neither, since it rebuilds the whole picture each time the size changes. -Under `LEGACY_SPRITE_ARGS` the handle is third, `spriteDrawGrid(x, y, spr, sourceX, sourceY, width, height)`, which is where Hypseus puts it. +The rectangle is in the sprite's own pixels and must lie inside it; a rectangle that does not, or one with no width or height, terminates the script naming the sprite's size, and so does an `x2` with no `y2`. A stretch whose box has no width or height, because `x2` is left of `x` or `y2` above `y`, draws nothing. The stretch picks the nearest pixel rather than blending, which keeps a one-pixel row's colours exactly as drawn. The sprite drawn from is the sprite as it is currently drawn, so a <> or a `spriteScale` changes what the coordinates mean. + +Under `LEGACY_SPRITE_ARGS` the handle is third, `spriteDrawGrid(x, y, spr, sourceX, sourceY, width, height)`, which is where Hypseus puts it, and `x2`, `y2` follow on the end as they do here. *Parameters:* @@ -15205,10 +15549,11 @@ Under `LEGACY_SPRITE_ARGS` the handle is third, `spriteDrawGrid(x, y, spr, sourc * `x`, `y` -- numbers; where the rectangle's top left corner lands, in overlay coordinates. * `sourceX`, `sourceY` -- numbers; the rectangle's top left corner in the sprite. * `width`, `height` -- numbers; its size, at least 1. +* `x2`, `y2` -- numbers, optional together; the bottom right corner of the box to stretch it into, inclusive. *Returns:* nothing. -*Since:* 3.00, as a Hypseus Singe extension. +*Since:* 3.00, as a Hypseus Singe extension; the stretched form is new in 3.00 and Singe's own. *See also:* <>, <> .Example @@ -15223,6 +15568,27 @@ local function drawNumber(sheet, x, y, value) end ---- +.Example +[source,lua] +---- +-- A straight road to the horizon, one screen row at a time. road.png is 256 pixels across and two +-- rows deep: a light cross-section of road and a dark one, which alternate down the road to show +-- it moving. Row y of the screen is the ground EYE * FOCAL / (y - HORIZON) away. +local EYE = 60 +local FOCAL = 160 +local HORIZON = 110 +local HALF = 100 + +local function drawRoad(road, travelled) + for y = HORIZON + 1, 239 do + local z = EYE * FOCAL / (y - HORIZON) + local half = HALF * FOCAL / z + local light = math.floor((z + travelled) / 60) % 2 + spriteDrawGrid(road, 160 - half, y, 0, light, 256, 1, 160 + half, y) + end +end +---- + [#spritedrawrotatedframe] ==== spriteDrawRotatedFrame @@ -15873,6 +16239,68 @@ function onOverlayUpdate() end ---- +[#spritesetalpha] +==== spriteSetAlpha + +[source,text] +---- +spriteSetAlpha(id, alpha) +---- + +Multiplies every pixel's alpha by `alpha / 255` on every draw of the sprite, in every form: `spriteDraw`, `spriteDrawFrame`, `spriteDrawGrid`, and `spriteDrawRotatedFrame`, turned or not. `255`, the default, draws it as it is and `0` not at all, so a logo fades in and out with no second image. Out-of-range values are clamped. + +*Parameters:* + +* `id` -- number; a sprite handle. +* `alpha` -- number; `0` to `255`. + +*Returns:* nothing. + +*Since:* 3.00 +*See also:* <>, <> + +.Example +[source,lua] +---- +-- The title fades in over two seconds. +spriteSetAlpha(title, math.floor(255 * math.min(1, elapsed / 2))) +spriteDraw(title, 120, 80) +---- + +[#spritesetblend] +==== spriteSetBlend + +[source,text] +---- +spriteSetBlend(id, SPRITE_ALPHA | SPRITE_ADD | SPRITE_MULTIPLY) +---- + +How every draw of the sprite lays it over what is already on the overlay. `SPRITE_ALPHA`, the default, draws it over by its alpha. `SPRITE_ADD` adds its colour, scaled by its alpha, to what is there, so it can only brighten: glows, light, sparks, and the shadebobs of the old demos, where a ball drawn over itself again and again burns to white. `SPRITE_MULTIPLY` darkens what is there by its colour, for shadows and tinted glass. + +Added and multiplied pixels keep the overlay's own alpha, so they show only where something is already drawn on the overlay: over a transparent overlay, above a video or the 3D scene, they change nothing. Draw something opaque first, or use `emitterSetBlend` with `PARTICLE_ADD`, which adds over everything. Anything other than the three constants raises an error. + +*Parameters:* + +* `id` -- number; a sprite handle. +* `blend` -- `SPRITE_ALPHA`, `SPRITE_ADD`, or `SPRITE_MULTIPLY`. + +*Returns:* nothing. + +*Since:* 3.00 +*See also:* <>, <>, <> + +.Example +[source,lua] +---- +-- Shadebobs: a soft white ball added along a path, never cleared, so the trail builds to white. +spriteSetBlend(ball, SPRITE_ADD) +spriteSetAlpha(ball, 40) +for i = 0, 15 do + local a = t * 2 + i * 0.4 + spriteDraw(ball, 320 + math.cos(a) * 200, 240 + math.sin(a * 1.3) * 150, true) +end +---- + [#spritesetframe] ==== spriteSetFrame @@ -15903,6 +16331,38 @@ function onOverlayUpdate() end ---- +[#spritesettint] +==== spriteSetTint + +[source,text] +---- +spriteSetTint(id, r, g, b) +---- + +Multiplies every pixel's colour by `r`, `g`, `b` / 255 on every draw of the sprite, in every form. A white sprite draws in any colour, and any sprite can be darkened or shifted toward a colour, with no second image: one white ball becomes a rainbow of them, and a one-pixel white sprite stretched with `spriteDraw` becomes a filled rectangle of any colour. `255, 255, 255`, the default, draws it as it is. Out-of-range values are clamped. + +*Parameters:* + +* `id` -- number; a sprite handle. +* `r`, `g`, `b` -- numbers; `0` to `255`. + +*Returns:* nothing. + +*Since:* 3.00 +*See also:* <>, <> + +.Example +[source,lua] +---- +-- A ring of balls, each its own colour, from one white picture. +for i = 1, 12 do + local hue = i / 12 + spriteSetTint(ball, 128 + 127 * math.sin(hue * 6.28), 128 + 127 * math.sin(hue * 6.28 + 2.1), 128 + 127 * math.sin(hue * 6.28 + 4.2)) + spriteDraw(ball, 320 + math.cos(hue * 6.28) * 150, 240 + math.sin(hue * 6.28) * 150, true) +end +spriteSetTint(ball, 255, 255, 255) +---- + [#spriteunload] ==== spriteUnload @@ -18379,6 +18839,240 @@ discSearch(TITLE_FRAME) ---- [#enginecallbacks] +[#voice] +=== Voice + +The pieces a voice chat is built from, without the network: Opus to make a +voice small enough to send and back again, a processor that cleans a microphone +up before it is sent, and a jitter buffer to play what arrives late and out of +order in the right order. Sending the packets and finding the other players are +a game's own business, or a later version of Singe's. + +Samples are strings of 16-bit values, two bytes each, little endian, as +<> gives them; with two channels they alternate left and +right. A *frame* is a fixed slice of time: 20 milliseconds, 960 samples at +48000, is the usual one for a voice. + +Every object here is a handle. <> releases one; all of +them are released when the game ends. + +.A microphone, cleaned, encoded, and decoded again +[source,lua] +---- +micOpen() +local processor = voiceProcessorNew() +local encoder = opusEncoderNew() +local decoder = opusDecoderNew() +local pending = "" + +function onOverlayUpdate() + pending = pending .. micRead() + while #pending >= 960 * 2 do + local frame = pending:sub(1, 960 * 2) + pending = pending:sub(960 * 2 + 1) + local cleaned, voiced = voiceProcess(processor, frame) + if voiced then + local packet = opusEncode(encoder, cleaned) -- this is what you send + local heard = opusDecode(decoder, packet) -- and this is what the other end plays + end + end + return OVERLAY_UPDATED +end +---- + +[#jitterget] +==== jitterGet + +[source,text] +---- +packet, status = jitterGet(jitter [, span]) +---- + +The packet due to be played now, and the buffer moved on by one step. Call it +once a frame's worth of time, whatever arrived. + +*Returns:* the packet, or `nil`, and a status: `"ok"`, `"missing"` (nothing is +due: hand `nil` to <> to cover the gap), or +`"insertion"` (the buffer is growing to absorb late packets: play a little +silence). + +*Since:* 3.00. + +[#jitternew] +==== jitterNew + +[source,text] +---- +jitter = jitterNew([step]) +---- + +A jitter buffer: packets go in by their timestamp as they arrive, and come out +in order, one step at a time, a little behind so a late one still makes it. + +*Parameters:* + +* `step` -- number, the samples each <> moves on; `960` + unless given. + +*Returns:* the jitter buffer's handle. + +*Since:* 3.00. + +[#jitterput] +==== jitterPut + +[source,text] +---- +jitterPut(jitter, packet, timestamp [, span]) +---- + +A packet that arrived. The buffer keeps its own copy. + +*Parameters:* + +* `packet` -- string, 1 to 4000 bytes. +* `timestamp` -- number, where the packet starts, in samples: the sender counts + them, `0`, `960`, `1920`, and so on. +* `span` -- number, the samples the packet covers; the step unless given. + +*Since:* 3.00. + +[#opusdecode] +==== opusDecode + +[source,text] +---- +samples = opusDecode(decoder, packet | nil) +---- + +A packet back to samples. `nil` for a packet that never arrived asks Opus to +cover the gap with something plausible, as long as the last packet. + +*Returns:* the samples. + +*Since:* 3.00. + +[#opusdecodernew] +==== opusDecoderNew + +[source,text] +---- +decoder = opusDecoderNew([rate [, channels]]) +---- + +*Parameters:* + +* `rate` -- number: 8000, 12000, 16000, 24000, or 48000; `48000` unless given. +* `channels` -- number, `1` or `2`; `1` unless given. + +*Returns:* the decoder's handle. + +*Since:* 3.00. + +[#opusencode] +==== opusEncode + +[source,text] +---- +packet = opusEncode(encoder, samples) +---- + +One frame of samples as one packet. A frame is 2.5, 5, 10, 20, 40, or 60 +milliseconds of samples; anything else is refused. + +*Returns:* the packet, a string. + +*Since:* 3.00. + +[#opusencodernew] +==== opusEncoderNew + +[source,text] +---- +encoder = opusEncoderNew([rate [, channels [, application]]]) +---- + +*Parameters:* + +* `rate` -- number: 8000, 12000, 16000, 24000, or 48000; `48000` unless given. +* `channels` -- number, `1` or `2`; `1` unless given. +* `application` -- string: `"voip"` for speech, tuned for being understood; + `"audio"` for music; `"lowdelay"` for the least delay at some cost in quality. + `"voip"` unless given. + +*Returns:* the encoder's handle. + +*Since:* 3.00. + +[#opusencoderset] +==== opusEncoderSet + +[source,text] +---- +opusEncoderSet(encoder, bitrate [, complexity]) +---- + +*Parameters:* + +* `bitrate` -- number, bits a second; `0` leaves it as it is. A voice is clear + at 16000 to 24000. +* `complexity` -- number, `0` to `10`: how much work to spend for quality. + +*Since:* 3.00. + +[#voicefree] +==== voiceFree + +[source,text] +---- +voiceFree(handle) +---- + +Releases an Opus encoder or decoder, a voice processor, or a jitter buffer. + +*Since:* 3.00. + +[#voiceprocess] +==== voiceProcess + +[source,text] +---- +cleaned, voiced = voiceProcess(processor, mic [, speaker]) +---- + +One frame of the microphone, cleaned: the echo of what the speakers were playing +taken out, background noise suppressed, and the level evened out. + +*Parameters:* + +* `mic` -- string, one frame of samples from the microphone. +* `speaker` -- string, the same frame of what the speakers played, if anything: + the voices of the other players, say. The echo of it is what is taken out. + +*Returns:* the cleaned frame, and `true` when it sounds like a voice -- the way +to send nothing while nobody is talking. + +*Since:* 3.00. + +[#voiceprocessornew] +==== voiceProcessorNew + +[source,text] +---- +processor = voiceProcessorNew([frame [, rate [, tailMs]]]) +---- + +*Parameters:* + +* `frame` -- number, samples a call; `960` unless given. +* `rate` -- number; `48000` unless given. +* `tailMs` -- number, the longest echo to cancel, in milliseconds: how long a + sound rings around the room. `200` unless given. + +*Returns:* the processor's handle. + +*Since:* 3.00. + === Engine Callbacks These are functions the script defines and Singe calls when the matching event happens; all are optional, and an undefined one is skipped. Input callbacks fire as events are read, `onOverlayUpdate` runs at most once every 15 milliseconds, and none of them runs while the pause key holds the game frozen (see <>). An error inside a callback ends the game with a traceback. In the threaded model `singeMain` takes the place of most per-frame logic (see <>): the other callbacks still fire, but `Framework.singe` installs its own `onOverlayUpdate` to drive the `singeMain` coroutine, so a threaded game defines `singeMain`, `onShutdown` and whichever input callbacks it wants. @@ -18695,7 +19389,7 @@ function onOverlayUpdate() end ---- -The one callback where drawing is allowed. Singe calls it at most once every 15 milliseconds while the game is not frozen; any `overlay*`, `spriteDraw`, `videoDraw`, `fontPrint` or similar call made elsewhere will not appear on screen and may corrupt the overlay. Return `OVERLAY_UPDATED` (`1`) when the overlay changed so that Singe composites it over the video again, or `OVERLAY_NOT_UPDATED` (`0`) when nothing changed so the previous composite is reused; returning nothing counts as `OVERLAY_NOT_UPDATED`. The display is redrawn regardless whenever a new video frame arrives or a 3D scene is enabled, so the return value is an optimization for static screens. After it returns the engine clears the values behind `keyboardGetLastDown` and `keyboardGetLastUp`. In the threaded model `Framework.singe` defines this function itself to resume `singeMain` and always returns `OVERLAY_UPDATED`; do not define it as well. +The one callback where drawing is allowed. Singe calls it at most once every 15 milliseconds while the game is not frozen, counted from when the previous call began, so the time the script itself takes falls inside those 15 milliseconds rather than being added to them; any `overlay*`, `spriteDraw`, `videoDraw`, `fontPrint` or similar call made elsewhere will not appear on screen and may corrupt the overlay. Return `OVERLAY_UPDATED` (`1`) when the overlay changed so that Singe composites it over the video again, or `OVERLAY_NOT_UPDATED` (`0`) when nothing changed so the previous composite is reused; returning nothing counts as `OVERLAY_NOT_UPDATED`. The display is redrawn regardless whenever a new video frame arrives or a 3D scene is enabled, so the return value is an optimization for static screens. After it returns the engine clears the values behind `keyboardGetLastDown` and `keyboardGetLastUp`. In the threaded model `Framework.singe` defines this function itself to resume `singeMain` and always returns `OVERLAY_UPDATED`; do not define it as well. *Returns:* `OVERLAY_UPDATED` or `OVERLAY_NOT_UPDATED`. diff --git a/docs/images/learn/29-databases.png b/docs/images/learn/29-databases.png new file mode 100644 index 000000000..d9e212fc4 --- /dev/null +++ b/docs/images/learn/29-databases.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:552f33bea9818e8e299885686ab52ad58b42da8f9663cbdf18a54776f451ec06 +size 25654 diff --git a/docs/images/learn/29-shipping.png b/docs/images/learn/30-shipping.png similarity index 100% rename from docs/images/learn/29-shipping.png rename to docs/images/learn/30-shipping.png diff --git a/docs/images/learn/30-cabinet.png b/docs/images/learn/31-cabinet.png similarity index 100% rename from docs/images/learn/30-cabinet.png rename to docs/images/learn/31-cabinet.png diff --git a/docs/learn/29-databases.singe b/docs/learn/29-databases.singe new file mode 100644 index 000000000..e2ac67e0b --- /dev/null +++ b/docs/learn/29-databases.singe @@ -0,0 +1,133 @@ +-- Lesson 29: Keeping Data. The finished script, exactly as the lesson ends. + +dofile("Singe/Framework.singe") + +local sqlite3 = require("sqlite3") + +local PERFECT = 1000 + +-- What ships with the game: the stages, read once and closed. +local stages = {} +local shipped = sqlite3.open(DIR .. "art/stages.db", sqlite3.OPEN_READONLY) + +for row in shipped:nrows("SELECT name, waitMin, waitMax FROM stages ORDER BY id") do + stages[#stages + 1] = row +end +shipped:close() + +-- What the game writes: every run anybody plays, kept in the data directory. +local runs = sqlite3.open(singeGetDataPath() .. "runs.db") + +runs:exec([[ + CREATE TABLE IF NOT EXISTS runs ( + id INTEGER PRIMARY KEY, + stage TEXT NOT NULL, + score INTEGER NOT NULL, + at INTEGER NOT NULL + ) +]]) + +local addRun = runs:prepare("INSERT INTO runs (stage, score, at) VALUES (?, ?, ?)") +local stageAt = 1 +local state = "attract" +local goAt = 0 +local score = 0 +local best = {} +local perStage = {} +local played = 0 + + +-- The questions, asked when a run is added rather than every frame. +local function refresh() + best = {} + for row in runs:nrows("SELECT stage, score FROM runs ORDER BY score DESC, id LIMIT 5") do + best[#best + 1] = row + end + perStage = {} + for row in runs:nrows("SELECT stage, MAX(score) AS top, COUNT(*) AS tries FROM runs GROUP BY stage ORDER BY stage") do + perStage[#perStage + 1] = row + end + for count in runs:urows("SELECT COUNT(*) FROM runs") do + played = count + end +end + + +local function record(stage, points) + addRun:bind_values(stage, points, os.time()) + addRun:step() + addRun:reset() + refresh() +end + + +local function play() + local stage = stages[stageAt] + + state = "waiting" + goAt = singeGetTicks() + math.random(stage.waitMin, stage.waitMax) + score = 0 +end + + +function onInputPressed(what) + if what == SWITCH_BUTTON2 and state ~= "waiting" and state ~= "go" then + stageAt = stageAt % #stages + 1 + return + end + if what ~= SWITCH_BUTTON1 then + return + end + if state == "waiting" then + state = "result" + score = 0 + record(stages[stageAt].name, score) + elseif state == "go" then + score = math.max(0, PERFECT - (singeGetTicks() - goAt)) + state = "result" + record(stages[stageAt].name, score) + else + play() + end +end + + +function onOverlayUpdate() + if state == "waiting" and singeGetTicks() >= goAt then + state = "go" + end + + overlayClear() + overlayPrint(2, 0, "REACTION TEST: " .. stages[stageAt].name) + + if state == "attract" then + overlayPrint(2, 2, "Button 1 to play, button 2 for another stage.") + elseif state == "waiting" then + overlayPrint(2, 2, "Wait for it...") + elseif state == "go" then + overlayPrint(2, 2, "NOW!") + else + overlayPrint(2, 2, "You scored " .. score .. ". Button 1 plays again.") + end + + overlayPrint(2, 4, "Runs kept: " .. played) + overlayPrint(2, 6, "BEST RUNS") + for place, row in ipairs(best) do + overlayPrint(2, 6 + place, string.format("%d. %-8s %4d", place, row.stage, row.score)) + end + overlayPrint(24, 6, "BY STAGE") + for line, row in ipairs(perStage) do + overlayPrint(24, 6 + line, string.format("%-8s best %4d of %d", row.stage, row.top, row.tries)) + end + + return OVERLAY_UPDATED +end + + +function onShutdown() + addRun:finalize() + runs:close() +end + + +refresh() diff --git a/docs/learn/29-shipping.singe b/docs/learn/30-shipping.singe similarity index 96% rename from docs/learn/29-shipping.singe rename to docs/learn/30-shipping.singe index bda04159d..54b1b30e4 100644 --- a/docs/learn/29-shipping.singe +++ b/docs/learn/30-shipping.singe @@ -1,4 +1,4 @@ --- Lesson 29: Shipping It. The finished script, exactly as the lesson ends. +-- Lesson 30: Shipping It. The finished script, exactly as the lesson ends. dofile("Singe/Framework.singe") diff --git a/docs/learn/30-cabinet.singe b/docs/learn/31-cabinet.singe similarity index 98% rename from docs/learn/30-cabinet.singe rename to docs/learn/31-cabinet.singe index 58919ba9a..d6a1c0dc2 100644 --- a/docs/learn/30-cabinet.singe +++ b/docs/learn/31-cabinet.singe @@ -1,4 +1,4 @@ --- Lesson 30: In A Cabinet. The finished script, exactly as the lesson ends. +-- Lesson 31: In A Cabinet. The finished script, exactly as the lesson ends. dofile("Singe/Framework.singe") diff --git a/docs/learn/art/README.txt b/docs/learn/art/README.txt index 5d44e72f5..7e512217a 100644 --- a/docs/learn/art/README.txt +++ b/docs/learn/art/README.txt @@ -11,8 +11,10 @@ will find these files where they say they are. walk.png 96 x 32 Four frames of a walk cycle, each 24 x 32, side by side. shoot.wav A shot. boom.wav An explosion. + stages.db The stages of lesson twenty-nine's reaction test, a SQLite + database: stages(id, name, waitMin, waitMax). -All of it is drawn and synthesised by util/learnKit.py rather than painted, so +All of it is drawn, synthesised, or written by util/learnKit.py rather than painted, so it is part of Singe and carries Singe's licence. Use it in your own games, change it, or replace it with something better as soon as you can. diff --git a/docs/learn/art/stages.db b/docs/learn/art/stages.db new file mode 100644 index 0000000000000000000000000000000000000000..859224903523999c7493e48ab94ec617a724b21b GIT binary patch literal 8192 zcmeI#u};G<5C-70lZc@z$%3Mafg3@JSa^Yk%0d-sDIrL7G!P(C8>+^o?bwmGVeG=r z!ZWb4@&=?-MF_->#DDVH=d-OM^m#8WjJ{5b zesnt8WNB_HbAM134sA%ObTPGFEAw~CuSQ(} literal 0 HcmV?d00001 diff --git a/docs/lessons/12-score.adoc b/docs/lessons/12-score.adoc index 2f490696d..e9d175c6f 100644 --- a/docs/lessons/12-score.adoc +++ b/docs/lessons/12-score.adoc @@ -297,7 +297,7 @@ when you want to print the whole save while you are hunting something. It does not go beside your script, and this is not an accident. A finished game may live on a disc, on a network share, or inside a single -packed file (lesson twenty-nine), and none of those can be written to. A game +packed file (lesson thirty), and none of those can be written to. A game that saves next to its own script works perfectly on the machine you wrote it on and fails on half the machines it is installed on. Singe 2 did it that way and it was wrong. diff --git a/docs/lessons/13-game-folder.adoc b/docs/lessons/13-game-folder.adoc index 7886e317c..f3b1ba7bf 100644 --- a/docs/lessons/13-game-folder.adoc +++ b/docs/lessons/13-game-folder.adoc @@ -212,7 +212,7 @@ finished Singe game can be packed into a single `.game` file that the engine runs directly, artwork and sounds and all, which a player copies next to Singe and is done. -Nothing in your game has to change for that. It is lesson twenty-nine, and it +Nothing in your game has to change for that. It is lesson thirty, and it is worth waiting for: pack a game that is not finished and you will pack it again tomorrow. @@ -305,7 +305,7 @@ folder. Put the `DIR ..` back and start it from both places. folder beside it, sorted by title. * A game launched by name gets its `games.dat` entry too, so it behaves the same either way. -* A finished game can be packed into one file later, in lesson twenty-nine. +* A finished game can be packed into one file later, in lesson thirty. === Next Time diff --git a/docs/lessons/17-light-guns.adoc b/docs/lessons/17-light-guns.adoc index 326df87c1..7eb7b93fe 100644 --- a/docs/lessons/17-light-guns.adoc +++ b/docs/lessons/17-light-guns.adoc @@ -472,7 +472,7 @@ appearing to have died. *No mouse at all.* A cabinet with a joystick and no pointing device can drive the cursor from the stick, which `joyMouseEnable` turns on. -None of that changes the game you wrote. All of it is lesson thirty. +None of that changes the game you wrote. All of it is lesson thirty-one. === Try It diff --git a/docs/lessons/28-online.adoc b/docs/lessons/28-online.adoc index ddbff8256..1ee9098a0 100644 --- a/docs/lessons/28-online.adoc +++ b/docs/lessons/28-online.adoc @@ -216,7 +216,7 @@ has a game has it. Your game does not call any of this, and should not. The catalogue matters to you as the author of a game rather than as the writer of a script: it is where -your `.game` file goes when you publish it, which is lesson twenty-nine, and it +your `.game` file goes when you publish it, which is lesson thirty, and it is another reason your `games.dat` needs a `GAME_ID` that never changes. If you ever do want the list from inside a script, `Singe/Master.singe` is the module underneath all of this and is worth reading once. @@ -527,6 +527,7 @@ in `Singe/Framework.singe`. === Next Time -Your game runs on your machine, out of a folder you have been editing for -twenty-eight lessons. Lesson twenty-nine turns that folder into one file a -stranger can copy onto their own machine and play. +A high score is one number, and lesson twelve's save is the right place for it. +Lesson twenty-nine is for everything else a game wants to keep: every round +anybody plays, the stages you ship, and the questions you want to ask of both. +It takes this reaction test and gives it a database. diff --git a/docs/lessons/29-databases.adoc b/docs/lessons/29-databases.adoc new file mode 100644 index 000000000..36d8d8617 --- /dev/null +++ b/docs/lessons/29-databases.adoc @@ -0,0 +1,488 @@ +== Lesson 29: Keeping Data + +image::learn/29-databases.png[The finished lesson, 480] + +Lesson twelve saved a high score: one number, under one name, there the next +morning. That is exactly right for a high score, and wrong for almost +everything else a game wants to keep. A list of every round anybody has played. +The best time on each of twenty tracks. Forty levels somebody designed in a +spreadsheet. The question "what is my best on the hard stage?", which a pile of +saved numbers cannot answer without you writing the answer by hand. + +That is what a database is for, and Singe has one built in. This lesson takes +the reaction test from lesson twenty-eight, gives it stages that ship with the +game, and has it keep every run anybody plays and answer questions about them. + +=== What a Database Is + +A database is a file of *tables*. A table is rows and columns, like a +spreadsheet with the column names decided in advance: a table of runs might +have a stage, a score, and a time for every row. You put rows in and you ask +questions to get rows out, and the questions are written in *SQL*, a small +language that has been doing this job since before most programming languages +you have heard of. + +The database Singe carries is *SQLite*. It is not a server you install or a +service you sign up for. It is a library, the database is one ordinary file, +and the same SQLite is in your phone, your browser, and probably your car. You +do not have to know SQL to follow this lesson; every statement in it is +explained as it goes past, and the three you will use most -- `CREATE TABLE`, +`INSERT`, and `SELECT` -- are all here. + +=== Opening One + +[source,lua] +---- +local sqlite3 = require("sqlite3") + +local runs = sqlite3.open(singeGetDataPath() .. "runs.db") +---- + +`require("sqlite3")` loads a library that comes with Singe and hands it back as +a table, so everything SQLite can do is `sqlite3.` something. `sqlite3.open` +opens a database file and +creates it if it is not there yet, so the first run of your game makes an +empty one and every run after that finds it again. + +The file goes in `singeGetDataPath()`, and for the same reason lesson twelve's +save does: a game's own folder may be on a disc, on a share, or packed into one +file, and none of those can be written to. Everything a game writes goes in its +data directory. + +=== Making a Table + +An empty database has no tables. You make one by describing it: + +[source,lua] +---- +runs:exec([[ + CREATE TABLE IF NOT EXISTS runs ( + id INTEGER PRIMARY KEY, + stage TEXT NOT NULL, + score INTEGER NOT NULL, + at INTEGER NOT NULL + ) +]]) +---- + +`exec` runs SQL that does not hand anything back. The double square brackets +are Lua's long string: everything between them, newlines included, is one +string, which is how you keep SQL readable. + +`CREATE TABLE` names the table and its columns, each with a type: `TEXT` for +words and `INTEGER` for whole numbers. `NOT NULL` means every row must have a +value there. `INTEGER PRIMARY KEY` is special: SQLite fills it in by itself, +counting up, so every row gets its own number without you thinking about it. + +`IF NOT EXISTS` is what makes this safe to run every time the game starts. The +first time, it makes the table. Every time after that, the table is already +there and the line does nothing. Without those three words the second run of +your game would stop with an error saying the table already exists. + +=== Putting a Row In + +You could build the SQL for a new row by gluing strings together: + +[source,lua] +---- +runs:exec("INSERT INTO runs (stage, score, at) VALUES ('" .. stage .. "', " .. score .. ", " .. os.time() .. ")") +---- + +Do not. It works until a name has an apostrophe in it, at which point the quote +ends the string early and the statement is nonsense. In a game that lets +players type, it gets worse: whatever they type becomes part of your SQL. + +The right way is to write the statement once, with question marks where the +values go, and hand the values over separately: + +[source,lua] +---- +local addRun = runs:prepare("INSERT INTO runs (stage, score, at) VALUES (?, ?, ?)") + +local function record(stage, points) + addRun:bind_values(stage, points, os.time()) + addRun:step() + addRun:reset() +end +---- + +`prepare` turns the SQL into a *statement* that can be used again and again. +`bind_values` puts a value in each question mark, in order. Whatever a value +contains, apostrophes included, it is a value and never part of the SQL. `step` +runs the statement, and `reset` makes it ready to run again. `os.time()` is +plain Lua: the current time as a number of seconds, which is the easiest way to +store "when". + +Preparing once and reusing the statement is also faster, because SQLite works +out how to run it only once. For a game that writes one row a minute that does +not matter. For a level editor that writes a thousand, it does. + +=== Asking Questions + +Rows come back out with `nrows`, which runs a `SELECT` and hands you each row as +a table with the column names as keys: + +[source,lua] +---- +for row in runs:nrows("SELECT stage, score FROM runs ORDER BY score DESC LIMIT 5") do + debugPrint(row.stage .. " " .. row.score) +end +---- + +Read the SQL left to right. `SELECT stage, score` says which columns you want. +`FROM runs` says which table. `ORDER BY score DESC` sorts the rows by score, +highest first, and `LIMIT 5` stops after five. That is a high score table, and +it never needed sorting code of yours. + +The questions can be cleverer than the ones you would want to write by hand: + +[source,lua] +---- +for row in runs:nrows("SELECT stage, MAX(score) AS top, COUNT(*) AS tries FROM runs GROUP BY stage ORDER BY stage") do + debugPrint(row.stage .. ": best " .. row.top .. " of " .. row.tries) +end +---- + +`GROUP BY stage` gathers the rows into one group per stage, and `MAX(score)` and +`COUNT(*)` are worked out for each group: the best score on that stage and how +many times it has been played. `AS top` names the answer, which is the key you +read it back with. + +When a question has one answer, `urows` hands back the columns themselves +rather than a table, which is tidier for a count: + +[source,lua] +---- +for count in runs:urows("SELECT COUNT(*) FROM runs") do + played = count +end +---- + +=== Ask When It Changes + +None of those questions belong in `onOverlayUpdate`. A query is fast, but sixty +of them a second, to get answers that change once a minute, is the game asking +the same question and getting the same answer fifty-nine times out of sixty. + +So the game asks when the answer can have changed -- once at the start, and +again each time a run is recorded -- and keeps what came back in ordinary +tables: + +[source,lua] +---- +local function refresh() + best = {} + for row in runs:nrows("SELECT stage, score FROM runs ORDER BY score DESC, id LIMIT 5") do + best[#best + 1] = row + end + -- and the same for the other two questions +end +---- + +`onOverlayUpdate` draws from `best`, which costs nothing. `record` calls +`refresh` after every new row, so the table on screen is never out of date. + +=== Data That Ships With the Game + +The other half of a game's data is the part you write before anybody plays: +the stages, the levels, the items, the lines of dialogue. That can be a +database too, made with any SQLite tool -- the `sqlite3` program on the +command line, or a program with windows such as DB Browser for SQLite -- and put +in your game's folder beside its art. The art kit has one, `stages.db`, with a +name and the shortest and longest wait for each stage. + +A game opens that one differently: + +[source,lua] +---- +local stages = {} +local shipped = sqlite3.open(DIR .. "art/stages.db", sqlite3.OPEN_READONLY) + +for row in shipped:nrows("SELECT name, waitMin, waitMax FROM stages ORDER BY id") do + stages[#stages + 1] = row +end +shipped:close() +---- + +`DIR` is your game's folder, where the art is. `sqlite3.OPEN_READONLY` says you +only mean to read it, and that matters for the day you ship. When you pack your +game into one file in the next lesson, a database opened read only is read +straight out of that file, with nothing unpacked. One opened for writing is +copied, once, to the game's data directory, and the copy is what you change from +then on; the file you shipped is never written. + +So keep the two kinds apart. What you made goes in your folder and is opened +read only. What the game makes goes in the data directory. The stages here are +read once at the start into an ordinary table and the database is closed, +because a list of four stages is not worth keeping a file open for. + +=== Closing Up + +Statements and databases hold memory and a file open until you say you are +finished, and the tidy place to say it is `onShutdown`: + +[source,lua] +---- +function onShutdown() + addRun:finalize() + runs:close() +end +---- + +`finalize` is `close` for a statement. A database will not close while a +statement made from it is still around, so the statements go first. + +=== The Whole Script + +[source,lua] +---- +dofile("Singe/Framework.singe") + +local sqlite3 = require("sqlite3") + +local PERFECT = 1000 + +-- What ships with the game: the stages, read once and closed. +local stages = {} +local shipped = sqlite3.open(DIR .. "art/stages.db", sqlite3.OPEN_READONLY) + +for row in shipped:nrows("SELECT name, waitMin, waitMax FROM stages ORDER BY id") do + stages[#stages + 1] = row +end +shipped:close() + +-- What the game writes: every run anybody plays, kept in the data directory. +local runs = sqlite3.open(singeGetDataPath() .. "runs.db") + +runs:exec([[ + CREATE TABLE IF NOT EXISTS runs ( + id INTEGER PRIMARY KEY, + stage TEXT NOT NULL, + score INTEGER NOT NULL, + at INTEGER NOT NULL + ) +]]) + +local addRun = runs:prepare("INSERT INTO runs (stage, score, at) VALUES (?, ?, ?)") +local stageAt = 1 +local state = "attract" +local goAt = 0 +local score = 0 +local best = {} +local perStage = {} +local played = 0 + + +-- The questions, asked when a run is added rather than every frame. +local function refresh() + best = {} + for row in runs:nrows("SELECT stage, score FROM runs ORDER BY score DESC, id LIMIT 5") do + best[#best + 1] = row + end + perStage = {} + for row in runs:nrows("SELECT stage, MAX(score) AS top, COUNT(*) AS tries FROM runs GROUP BY stage ORDER BY stage") do + perStage[#perStage + 1] = row + end + for count in runs:urows("SELECT COUNT(*) FROM runs") do + played = count + end +end + + +local function record(stage, points) + addRun:bind_values(stage, points, os.time()) + addRun:step() + addRun:reset() + refresh() +end + + +local function play() + local stage = stages[stageAt] + + state = "waiting" + goAt = singeGetTicks() + math.random(stage.waitMin, stage.waitMax) + score = 0 +end + + +function onInputPressed(what) + if what == SWITCH_BUTTON2 and state ~= "waiting" and state ~= "go" then + stageAt = stageAt % #stages + 1 + return + end + if what ~= SWITCH_BUTTON1 then + return + end + if state == "waiting" then + state = "result" + score = 0 + record(stages[stageAt].name, score) + elseif state == "go" then + score = math.max(0, PERFECT - (singeGetTicks() - goAt)) + state = "result" + record(stages[stageAt].name, score) + else + play() + end +end + + +function onOverlayUpdate() + if state == "waiting" and singeGetTicks() >= goAt then + state = "go" + end + + overlayClear() + overlayPrint(2, 0, "REACTION TEST: " .. stages[stageAt].name) + + if state == "attract" then + overlayPrint(2, 2, "Button 1 to play, button 2 for another stage.") + elseif state == "waiting" then + overlayPrint(2, 2, "Wait for it...") + elseif state == "go" then + overlayPrint(2, 2, "NOW!") + else + overlayPrint(2, 2, "You scored " .. score .. ". Button 1 plays again.") + end + + overlayPrint(2, 4, "Runs kept: " .. played) + overlayPrint(2, 6, "BEST RUNS") + for place, row in ipairs(best) do + overlayPrint(2, 6 + place, string.format("%d. %-8s %4d", place, row.stage, row.score)) + end + overlayPrint(24, 6, "BY STAGE") + for line, row in ipairs(perStage) do + overlayPrint(24, 6 + line, string.format("%-8s best %4d of %d", row.stage, row.top, row.tries)) + end + + return OVERLAY_UPDATED +end + + +function onShutdown() + addRun:finalize() + runs:close() +end + + +refresh() +---- + +Run it. Button 1 starts a round and stops it, as in lesson twenty-eight, and +button 2 between rounds moves to the next stage. Play a few on each. Then quit +and run it again: every run is still there, the best five at the left and each +stage's best at the right. + +=== What Just Happened + +[source,lua] +---- +local runs = sqlite3.open(singeGetDataPath() .. "runs.db") +---- + +Two files are in play, and they are not alike. `art/stages.db` is yours: you +wrote it, it ships with the game, and the game only reads it. `runs.db` is the +game's: it did not exist until the first run made it, it lives in the data +directory, and nobody ships it. + +[source,lua] +---- + if state == "waiting" then + state = "result" + score = 0 + record(stages[stageAt].name, score) +---- + +A button pressed too soon still records a run, with a score of nothing. The +database is a record of what happened, and a jumped start happened. Whether to +show those rows is a question for the `SELECT`, not something to hide by never +writing them. + +[source,lua] +---- + for row in runs:nrows("SELECT stage, score FROM runs ORDER BY score DESC, id LIMIT 5") do +---- + +`ORDER BY score DESC, id` sorts by score, and where two scores are equal, by +`id` -- the order they were played. Without the second key, two equal scores +come back in whatever order SQLite finds convenient, which can change between +runs. A table that reshuffles itself for no visible reason looks broken even +when it is not. + +=== Try It + +. *Show the date.* `os.date("%Y-%m-%d", row.at)` turns a stored time back into + something a person can read. Add the date to each of the best runs. +. *Ignore the jumped starts.* Add `WHERE score > 0` to the best-runs question, + between `FROM runs` and `ORDER BY`. Then count the jumped starts on each stage + with a question of your own. +. *Add a stage.* Open `stages.db` in a SQLite tool, add a row, and run the game. + Nothing in the script changes. That is the point of keeping data out of the + script. +. *Reset the history.* `runs:exec("DELETE FROM runs")` empties the table. Put it + on a button, call `refresh` after it, and watch everything go to nothing. + This is the "clear high scores" in a service menu. +. *Write a thousand rows.* Loop `record` a thousand times and time it with + `singeGetTicks`. Then put `runs:exec("BEGIN")` before the loop and + `runs:exec("COMMIT")` after it, and time it again. A *transaction* makes many + writes one, and the difference is large enough to be worth remembering. + +=== Break It on Purpose + +Take `addRun:reset()` out of `record` and play three rounds on three different +stages. + +No error. The game plays perfectly. But the table at the right says you played +the first stage three times, and the best runs are three copies of your first +score. `bind_values` could not put new values into a statement that had already +run and not been reset, so it gave up -- quietly, returning a number you were +not checking -- and `step` ran the statement again with the values it already +had. + +This is the bug that matters in this lesson, because it does not look like one. +A query that fails is loud. A write that writes the wrong thing is silent, and +you find it a week later in the data. When the rows in a database are not what +you expect, look at the code that put them there before the code that reads +them. + +Put `reset` back, and break it the loud way: change `score` to `scroe` in the +first `SELECT` in `refresh`. + +---- +Error running script: no such column: scroe +stack traceback: + [C]: in method 'nrows' + 29-databases.singe:43: in local 'refresh' + 29-databases.singe:133: in main chunk +---- + +SQLite reads the column names when it prepares the question, so a misspelled +one stops the game at once, and the message names it exactly. The traceback +reads from the inside out: `nrows` complained, `refresh` called it at line 43, +and the script itself called `refresh` at line 133, the last line, as the game +started. That is why it says *running script* rather than naming a function +the engine called: it never got as far as the first frame. + +=== What You Learned + +* A database is a file of tables; a table is rows with named columns. +* `require("sqlite3")` gives you SQLite. `sqlite3.open` opens a file and creates + it if it is missing. +* What the game writes goes in `singeGetDataPath()`. What you ship goes in your + folder, opened with `sqlite3.OPEN_READONLY`. +* `CREATE TABLE IF NOT EXISTS` is safe to run every time the game starts. +* Values go in through `prepare`, `bind_values`, `step`, and `reset`, never by + gluing strings into SQL. +* `nrows` hands back rows as tables; `urows` hands back the columns themselves. +* `ORDER BY`, `LIMIT`, `GROUP BY`, `MAX`, and `COUNT` answer the questions you + would otherwise write loops for. +* Ask when the answer can change, not every frame. +* Statements are finalized, then the database is closed, in `onShutdown`. + +=== Next Time + +Your game now has a folder full of things: a script, art, sounds, and a +database or two. Lesson thirty turns that folder into one file a stranger can +copy onto their own machine and play -- and your read-only database goes with +it, still opening exactly as it does now. diff --git a/docs/lessons/29-shipping.adoc b/docs/lessons/30-shipping.adoc similarity index 99% rename from docs/lessons/29-shipping.adoc rename to docs/lessons/30-shipping.adoc index 4883123c0..1c2e67eb6 100644 --- a/docs/lessons/29-shipping.adoc +++ b/docs/lessons/30-shipping.adoc @@ -1,6 +1,6 @@ -== Lesson 29: Shipping It +== Lesson 30: Shipping It -image::learn/29-shipping.png[The finished lesson, 480] +image::learn/30-shipping.png[The finished lesson, 480] You have a folder. It has a script in it, some pictures, a few sounds, and the `games.dat` you wrote in lesson thirteen. It runs, because everything it needs diff --git a/docs/lessons/30-cabinet.adoc b/docs/lessons/31-cabinet.adoc similarity index 99% rename from docs/lessons/30-cabinet.adoc rename to docs/lessons/31-cabinet.adoc index 3b5b4071c..70c17c844 100644 --- a/docs/lessons/30-cabinet.adoc +++ b/docs/lessons/31-cabinet.adoc @@ -1,6 +1,6 @@ -== Lesson 30: In a Cabinet +== Lesson 31: In a Cabinet -image::learn/30-cabinet.png[The finished lesson, 480] +image::learn/31-cabinet.png[The finished lesson, 480] There is a difference between a game and an arcade machine, and it is not the wood. A machine switches itself on in the morning, plays to an empty room, takes @@ -683,7 +683,7 @@ turn the quit key off, never later. === The End -That is thirty lessons, and you can write a game. +That is thirty-one lessons, and you can write a game. Not a perfect one, and not a large one yet, but the gap between here and either of those is time and practice rather than another book. You started diff --git a/src/main.c b/src/main.c index 163d4472f..0a7562f62 100644 --- a/src/main.c +++ b/src/main.c @@ -59,6 +59,7 @@ #include "main.h" #include "midi.h" +#include "mic.h" #include "midiIo.h" #include "stddclmr.h" #include "util.h" @@ -2653,6 +2654,7 @@ int main(int argc, char *argv[]) { _stopSDL(); midiIoQuit(); + micQuit(); midiQuit(); vfsQuit(); free(_commandLine); diff --git a/src/mic.c b/src/mic.c new file mode 100644 index 000000000..3f7c2cbc1 --- /dev/null +++ b/src/mic.c @@ -0,0 +1,671 @@ +/* + * + * Singe 3 + * Copyright (C) 2006-2026 Scott Duensing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + + +// Singe: the microphone. SDL hands captured audio to _micCaptured on its own thread; that keeps +// the newest MIC_RING_SECONDS in a ring, the level of each block, and -- while calibrating -- the +// moment a click came back. Everything else runs on the engine's thread from the ring: reading, +// pitch, recording, and stepping the calibration. The speaker stream (monitoring and the clicks) is +// a second SDL playback stream beside the mixer, which SDL mixes onto the same output. + + +#include +#include +#include +#include + +#include + +#include "mic.h" +#include "util.h" + + +#define MIC_RING_SAMPLES (MIC_RATE * MIC_RING_SECONDS) +#define MIC_BLOCK_SAMPLES 1024 // Read from SDL this many at a time +#define MIC_RECORD_SAMPLES 4096 // Written to a recording this many at a time +#define MIC_MONITOR_QUEUE_MS 100 // More than this waiting to be heard is dropped: the singer would hear the lag +#define MIC_PITCH_WINDOW 2048 // Newest samples the pitch is found in (43 ms) +#define MIC_PITCH_DECIMATE 2 // ...halved to 24 kHz first, a quarter of the work +#define MIC_PITCH_MIN_HZ 50.0f // Below any singer +#define MIC_PITCH_MAX_HZ 2000.0f // Above any singer's fundamental +#define MIC_PITCH_THRESHOLD 0.15f // YIN's dip that counts as periodic +#define MIC_PITCH_SILENCE 0.01f // RMS under which nothing is voiced +#define MIC_CLICKS 5 // Clicks a calibration plays; the median is the answer +#define MIC_CLICKS_NEEDED 3 // Heard back at least this many times, or it failed +#define MIC_CLICK_SAMPLES 96 // 2 ms +#define MIC_CLICK_LEVEL 0.9f +#define MIC_CLICK_GAP_NS (400 * 1000000LL) +#define MIC_CLICK_TIMEOUT_NS (1000 * 1000000LL) +#define MIC_FLOOR_NS (300 * 1000000LL) // Quiet listened to before the first click +#define MIC_FLOOR_FACTOR 6.0f // A click is this much louder than the quiet +#define MIC_THRESHOLD_MIN 0.05f +#define NS_PER_MS 1000000LL +#define NS_PER_SECOND 1000000000LL +#define WAV_HEADER_BYTES 44 + + +typedef struct MicS { + SDL_AudioStream *capture; + SDL_AudioStream *speaker; + SDL_Mutex *lock; // The ring, the level, and what the callback reports + SDL_AudioDeviceID *devices; + int32_t deviceCount; + float *ring; + int64_t written; // Samples ever heard; the ring holds the newest of them + int64_t readAt; // micRead's place + int64_t recordAt; // The recording's place + FILE *record; + int64_t recordBytes; + float rms; + float peak; + bool monitoring; + float monitorVolume; + MicCalibrationE calibration; + int32_t clicksPlayed; + int32_t results[MIC_CLICKS]; + int32_t resultCount; + int64_t clickAtNs; // When the click will leave the speaker + int64_t heardAtNs; // When the callback heard it, 0 until then + int64_t nextClickNs; + int64_t timeoutNs; + int64_t floorUntilNs; + float floorPeak; + float threshold; + bool listening; // A click is out and has not been heard + bool measuringFloor; + int32_t latency; +} MicT; + + +static void SDLCALL _micCaptured(void *userData, SDL_AudioStream *stream, int32_t additional, int32_t total); +static int32_t _micCompareInt(const void *a, const void *b); +static void _micRecordWrite(void); +static bool _micSpeakerOpen(void); +static int16_t _micToInt16(float sample); +static void _micWavHeader(FILE *file, int64_t dataBytes); +static void _micWrite16(FILE *file, uint16_t value); +static void _micWrite32(FILE *file, uint32_t value); + + +static MicT _mic = { .monitorVolume = 1.0f, .latency = MIC_LATENCY_UNKNOWN }; + + +// SDL's thread: everything newly heard, into the ring, with its level, the monitor fed, and a click +// noticed if one is being listened for. +static void SDLCALL _micCaptured(void *userData, SDL_AudioStream *stream, int32_t additional, int32_t total) { + float block[MIC_BLOCK_SAMPLES]; + float scaled[MIC_BLOCK_SAMPLES]; + int32_t bytes = 0; + int32_t count = 0; + int32_t i = 0; + int64_t now = 0; + int64_t at = 0; + double squares = 0.0; + float peak = 0.0f; + float value = 0.0f; + + (void)userData; + (void)additional; + (void)total; + for (;;) { + bytes = SDL_GetAudioStreamData(stream, block, (int32_t)sizeof(block)); + if (bytes <= 0) { + break; + } + count = bytes / (int32_t)sizeof(float); + now = (int64_t)SDL_GetTicksNS(); + squares = 0.0; + peak = 0.0f; + for (i = 0; i < count; i++) { + value = fabsf(block[i]); + squares += (double)block[i] * (double)block[i]; + if (value > peak) { + peak = value; + } + } + SDL_LockMutex(_mic.lock); + for (i = 0; i < count; i++) { + _mic.ring[(_mic.written + i) % MIC_RING_SAMPLES] = block[i]; + } + _mic.written += count; + _mic.rms = (float)sqrt(squares / (double)count); + _mic.peak = peak; + if (_mic.measuringFloor && (peak > _mic.floorPeak)) { + _mic.floorPeak = peak; + } + if (_mic.listening && (_mic.heardAtNs == 0)) { + for (i = 0; i < count; i++) { + if (fabsf(block[i]) >= _mic.threshold) { + // The block ends now; sample i was heard that many samples earlier. + at = now - ((int64_t)(count - i) * NS_PER_SECOND) / MIC_RATE; + if (at > _mic.clickAtNs) { + _mic.heardAtNs = at; + break; + } + } + } + } + if (_mic.monitoring && (_mic.speaker != NULL)) { + // A queue longer than a singer can bear is dropped rather than heard late. + if (SDL_GetAudioStreamQueued(_mic.speaker) > (int32_t)((MIC_RATE * MIC_MONITOR_QUEUE_MS / 1000) * sizeof(float))) { + SDL_ClearAudioStream(_mic.speaker); + } + for (i = 0; i < count; i++) { + scaled[i] = block[i] * _mic.monitorVolume; + } + SDL_PutAudioStreamData(_mic.speaker, scaled, count * (int32_t)sizeof(float)); + } + SDL_UnlockMutex(_mic.lock); + } +} + + +bool micCalibrate(void) { + if ((_mic.capture == NULL) || !_micSpeakerOpen()) { + return false; + } + SDL_LockMutex(_mic.lock); + _mic.calibration = MIC_CALIBRATION_RUNNING; + _mic.clicksPlayed = 0; + _mic.resultCount = 0; + _mic.listening = false; + _mic.heardAtNs = 0; + _mic.floorPeak = 0.0f; + _mic.measuringFloor = true; + _mic.floorUntilNs = (int64_t)SDL_GetTicksNS() + MIC_FLOOR_NS; + SDL_UnlockMutex(_mic.lock); + + return true; +} + + +MicCalibrationE micCalibrationState(void) { + return _mic.calibration; +} + + +static int32_t _micCompareInt(const void *a, const void *b) { + return *(const int32_t *)a - *(const int32_t *)b; +} + + +void micClose(void) { + // The capture stream goes first, so the callback is finished with everything below. + if (_mic.capture != NULL) { + SDL_DestroyAudioStream(_mic.capture); + _mic.capture = NULL; + } + micRecordStop(); + if (_mic.speaker != NULL) { + SDL_DestroyAudioStream(_mic.speaker); + _mic.speaker = NULL; + } + free(_mic.ring); + _mic.ring = NULL; + _mic.written = 0; + _mic.readAt = 0; + _mic.rms = 0.0f; + _mic.peak = 0.0f; + _mic.monitoring = false; + _mic.listening = false; + if (_mic.calibration == MIC_CALIBRATION_RUNNING) { + _mic.calibration = MIC_CALIBRATION_FAILED; + } +} + + +int32_t micDeviceCount(void) { + int count = 0; + + SDL_free(_mic.devices); + _mic.devices = SDL_GetAudioRecordingDevices(&count); + _mic.deviceCount = (_mic.devices != NULL) ? count : 0; + + return _mic.deviceCount; +} + + +const char *micDeviceName(int32_t index) { + if ((index < 0) || (index >= _mic.deviceCount)) { + return NULL; + } + return SDL_GetAudioDeviceName(_mic.devices[index]); +} + + +bool micIsOpen(void) { + return (_mic.capture != NULL); +} + + +int32_t micLatency(void) { + return _mic.latency; +} + + +void micLevel(float *rms, float *peak) { + if (_mic.capture == NULL) { + *rms = 0.0f; + *peak = 0.0f; + return; + } + SDL_LockMutex(_mic.lock); + *rms = _mic.rms; + *peak = _mic.peak; + SDL_UnlockMutex(_mic.lock); +} + + +bool micMonitor(bool on, float volume) { + if (_mic.capture == NULL) { + return false; + } + if (on && !_micSpeakerOpen()) { + return false; + } + SDL_LockMutex(_mic.lock); + _mic.monitoring = on; + _mic.monitorVolume = (volume < 0.0f) ? 0.0f : ((volume > 1.0f) ? 1.0f : volume); + SDL_UnlockMutex(_mic.lock); + if (!on && (_mic.speaker != NULL)) { + SDL_ClearAudioStream(_mic.speaker); + } + + return true; +} + + +bool micOpen(const char *name) { + SDL_AudioSpec spec; + SDL_AudioDeviceID device = SDL_AUDIO_DEVICE_DEFAULT_RECORDING; + int32_t i = 0; + + micClose(); + if (_mic.lock == NULL) { + _mic.lock = SDL_CreateMutex(); + if (_mic.lock == NULL) { + return false; + } + } + if (name != NULL) { + device = 0; + for (i = 0; i < micDeviceCount(); i++) { + if ((micDeviceName(i) != NULL) && (strcmp(micDeviceName(i), name) == 0)) { + device = _mic.devices[i]; + } + } + if (device == 0) { + return false; + } + } + _mic.ring = (float *)calloc(MIC_RING_SAMPLES, sizeof(float)); + if (_mic.ring == NULL) { + utilDie("Out of memory opening the microphone."); + } + spec.format = SDL_AUDIO_F32; + spec.channels = 1; + spec.freq = MIC_RATE; + _mic.capture = SDL_OpenAudioDeviceStream(device, &spec, _micCaptured, NULL); + if (_mic.capture == NULL) { + free(_mic.ring); + _mic.ring = NULL; + return false; + } + SDL_ResumeAudioStreamDevice(_mic.capture); + + return true; +} + + +// YIN (de Cheveigne and Kawahara, 2002) over the newest MIC_PITCH_WINDOW samples, averaged in pairs +// to 24 kHz first: half the window is compared with itself shifted by every period from the highest +// pitch to the lowest, and the first shift that matches well enough, refined by a parabola through +// its neighbours, is the period. +void micPitch(float *hz, float *clarity) { + float window[MIC_PITCH_WINDOW]; + float halved[MIC_PITCH_WINDOW / MIC_PITCH_DECIMATE]; + float difference[MIC_PITCH_WINDOW / MIC_PITCH_DECIMATE / 2]; + int32_t count = MIC_PITCH_WINDOW / MIC_PITCH_DECIMATE; + int32_t half = count / 2; + float rate = (float)MIC_RATE / (float)MIC_PITCH_DECIMATE; + int32_t minTau = (int32_t)(rate / MIC_PITCH_MAX_HZ); + int32_t maxTau = (int32_t)(rate / MIC_PITCH_MIN_HZ); + int32_t tau = 0; + int32_t j = 0; + int32_t found = 0; + int64_t start = 0; + double running = 0.0; + double squares = 0.0; + float delta = 0.0f; + float shift = 0.0f; + float a = 0.0f; + float b = 0.0f; + float c = 0.0f; + + *hz = 0.0f; + *clarity = 0.0f; + if (maxTau >= half) { + maxTau = half - 1; + } + if (_mic.capture == NULL) { + return; + } + SDL_LockMutex(_mic.lock); + if (_mic.written < MIC_PITCH_WINDOW) { + SDL_UnlockMutex(_mic.lock); + return; + } + start = _mic.written - MIC_PITCH_WINDOW; + for (j = 0; j < MIC_PITCH_WINDOW; j++) { + window[j] = _mic.ring[(start + j) % MIC_RING_SAMPLES]; + } + SDL_UnlockMutex(_mic.lock); + + for (j = 0; j < count; j++) { + halved[j] = (window[j * 2] + window[j * 2 + 1]) * 0.5f; + squares += (double)halved[j] * (double)halved[j]; + } + if (sqrt(squares / (double)count) < MIC_PITCH_SILENCE) { + return; + } + // The cumulative mean normalised difference, d'(tau). + difference[0] = 1.0f; + running = 0.0; + for (tau = 1; tau <= maxTau; tau++) { + double sum = 0.0; + + for (j = 0; j < half; j++) { + delta = halved[j] - halved[j + tau]; + sum += (double)delta * (double)delta; + } + running += sum; + difference[tau] = (running > 0.0) ? (float)(sum * (double)tau / running) : 1.0f; + } + for (tau = (minTau > 2) ? minTau : 2; tau < maxTau; tau++) { + if (difference[tau] < MIC_PITCH_THRESHOLD) { + while ((tau + 1 < maxTau) && (difference[tau + 1] < difference[tau])) { + tau++; + } + found = tau; + break; + } + } + if (found == 0) { + return; + } + a = difference[found - 1]; + b = difference[found]; + c = difference[found + 1]; + shift = ((a - 2.0f * b + c) != 0.0f) ? 0.5f * (a - c) / (a - 2.0f * b + c) : 0.0f; + *hz = rate / ((float)found + shift); + *clarity = 1.0f - b; +} + + +void micQuit(void) { + micClose(); + SDL_free(_mic.devices); + _mic.devices = NULL; + _mic.deviceCount = 0; + if (_mic.lock != NULL) { + SDL_DestroyMutex(_mic.lock); + _mic.lock = NULL; + } +} + + +int32_t micRead(int16_t *out, int32_t max) { + int32_t count = 0; + int32_t i = 0; + + if (_mic.capture == NULL) { + return 0; + } + SDL_LockMutex(_mic.lock); + if (_mic.written - _mic.readAt > MIC_RING_SAMPLES) { + _mic.readAt = _mic.written - MIC_RING_SAMPLES; + } + count = (int32_t)(_mic.written - _mic.readAt); + if (count > max) { + count = max; + } + for (i = 0; i < count; i++) { + out[i] = _micToInt16(_mic.ring[(_mic.readAt + i) % MIC_RING_SAMPLES]); + } + _mic.readAt += count; + SDL_UnlockMutex(_mic.lock); + + return count; +} + + +bool micRecordStart(const char *path) { + if (_mic.capture == NULL) { + return false; + } + micRecordStop(); + _mic.record = fopen(path, "wb"); + if (_mic.record == NULL) { + return false; + } + _micWavHeader(_mic.record, 0); + _mic.recordBytes = 0; + SDL_LockMutex(_mic.lock); + _mic.recordAt = _mic.written; + SDL_UnlockMutex(_mic.lock); + + return true; +} + + +void micRecordStop(void) { + if (_mic.record == NULL) { + return; + } + // The ring outlives the capture stream in micClose, so the last of it is written either way. + if (_mic.ring != NULL) { + _micRecordWrite(); + } + fseek(_mic.record, 0, SEEK_SET); + _micWavHeader(_mic.record, _mic.recordBytes); + fclose(_mic.record); + _mic.record = NULL; +} + + +// What has been heard since the recording last caught up, onto the end of the file. +static void _micRecordWrite(void) { + int16_t samples[MIC_RECORD_SAMPLES]; + int32_t count = 0; + int32_t i = 0; + + for (;;) { + SDL_LockMutex(_mic.lock); + if (_mic.written - _mic.recordAt > MIC_RING_SAMPLES) { + _mic.recordAt = _mic.written - MIC_RING_SAMPLES; + } + count = (int32_t)(_mic.written - _mic.recordAt); + if (count > MIC_RECORD_SAMPLES) { + count = MIC_RECORD_SAMPLES; + } + for (i = 0; i < count; i++) { + samples[i] = _micToInt16(_mic.ring[(_mic.recordAt + i) % MIC_RING_SAMPLES]); + } + _mic.recordAt += count; + SDL_UnlockMutex(_mic.lock); + if (count == 0) { + break; + } + // WAV is little endian; so is every machine Singe runs on, which SDL would refuse to hide. + fwrite(samples, sizeof(int16_t), (size_t)count, _mic.record); + _mic.recordBytes += (int64_t)count * (int64_t)sizeof(int16_t); + } +} + + +void micSetLatency(int32_t milliseconds) { + _mic.latency = milliseconds; +} + + +// The second playback stream: the monitor and the calibration clicks. Opened when first needed. +static bool _micSpeakerOpen(void) { + SDL_AudioSpec spec; + SDL_AudioStream *speaker = NULL; + + if (_mic.speaker != NULL) { + return true; + } + spec.format = SDL_AUDIO_F32; + spec.channels = 1; + spec.freq = MIC_RATE; + speaker = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, NULL, NULL); + if (speaker == NULL) { + return false; + } + SDL_ResumeAudioStreamDevice(speaker); + // Published under the lock: the capture callback reads it there. + SDL_LockMutex(_mic.lock); + _mic.speaker = speaker; + SDL_UnlockMutex(_mic.lock); + + return true; +} + + +static int16_t _micToInt16(float sample) { + if (sample >= 1.0f) { + return INT16_MAX; + } + if (sample <= -1.0f) { + return -INT16_MAX; + } + return (int16_t)lrintf(sample * (float)INT16_MAX); +} + + +// The engine's thread, once a frame: the recording caught up, and the calibration stepped -- the +// quiet measured, a click played when it is time, its return or its timeout taken, the answer made. +bool micUpdate(void) { + float click[MIC_CLICK_SAMPLES]; + int64_t now = 0; + int64_t queued = 0; + int64_t heard = 0; + int32_t i = 0; + bool finished = false; + + if (_mic.capture == NULL) { + return false; + } + if (_mic.record != NULL) { + _micRecordWrite(); + } + if (_mic.calibration != MIC_CALIBRATION_RUNNING) { + return false; + } + now = (int64_t)SDL_GetTicksNS(); + SDL_LockMutex(_mic.lock); + if (_mic.measuringFloor) { + if (now >= _mic.floorUntilNs) { + _mic.measuringFloor = false; + _mic.threshold = _mic.floorPeak * MIC_FLOOR_FACTOR; + if (_mic.threshold < MIC_THRESHOLD_MIN) { + _mic.threshold = MIC_THRESHOLD_MIN; + } + _mic.nextClickNs = now; + } + SDL_UnlockMutex(_mic.lock); + return false; + } + if (_mic.listening) { + heard = _mic.heardAtNs; + if ((heard != 0) || (now >= _mic.timeoutNs)) { + if ((heard != 0) && ((heard - _mic.clickAtNs) / NS_PER_MS <= MIC_LATENCY_MAX)) { + _mic.results[_mic.resultCount++] = (int32_t)((heard - _mic.clickAtNs) / NS_PER_MS); + } + _mic.listening = false; + _mic.nextClickNs = now + MIC_CLICK_GAP_NS; + } + } else if (_mic.clicksPlayed < MIC_CLICKS) { + if (now >= _mic.nextClickNs) { + // The click leaves the speaker after whatever is already queued in front of it. + for (i = 0; i < MIC_CLICK_SAMPLES; i++) { + click[i] = ((i / 12) % 2 == 0) ? MIC_CLICK_LEVEL : -MIC_CLICK_LEVEL; + } + queued = (int64_t)SDL_GetAudioStreamQueued(_mic.speaker) / (int64_t)sizeof(float); + _mic.clickAtNs = now + (queued * NS_PER_SECOND) / MIC_RATE; + _mic.heardAtNs = 0; + _mic.timeoutNs = _mic.clickAtNs + MIC_CLICK_TIMEOUT_NS; + _mic.listening = true; + _mic.clicksPlayed++; + SDL_PutAudioStreamData(_mic.speaker, click, (int32_t)sizeof(click)); + } + } else { + if (_mic.resultCount >= MIC_CLICKS_NEEDED) { + qsort(_mic.results, (size_t)_mic.resultCount, sizeof(int32_t), _micCompareInt); + _mic.latency = _mic.results[_mic.resultCount / 2]; + _mic.calibration = MIC_CALIBRATION_DONE; + finished = true; + } else { + _mic.calibration = MIC_CALIBRATION_FAILED; + } + } + SDL_UnlockMutex(_mic.lock); + + return finished; +} + + +static void _micWavHeader(FILE *file, int64_t dataBytes) { + fwrite("RIFF", 1, 4, file); + _micWrite32(file, (uint32_t)(WAV_HEADER_BYTES - 8 + dataBytes)); + fwrite("WAVEfmt ", 1, 8, file); + _micWrite32(file, 16); // The format chunk's size + _micWrite16(file, 1); // PCM + _micWrite16(file, 1); // Mono + _micWrite32(file, MIC_RATE); + _micWrite32(file, MIC_RATE * (uint32_t)sizeof(int16_t)); // Bytes a second + _micWrite16(file, (uint16_t)sizeof(int16_t)); // Bytes a frame + _micWrite16(file, 16); // Bits a sample + fwrite("data", 1, 4, file); + _micWrite32(file, (uint32_t)dataBytes); +} + + +static void _micWrite16(FILE *file, uint16_t value) { + uint8_t bytes[2]; + + bytes[0] = (uint8_t)(value & 0xff); + bytes[1] = (uint8_t)(value >> 8); + fwrite(bytes, 1, 2, file); +} + + +static void _micWrite32(FILE *file, uint32_t value) { + uint8_t bytes[4]; + + bytes[0] = (uint8_t)(value & 0xff); + bytes[1] = (uint8_t)((value >> 8) & 0xff); + bytes[2] = (uint8_t)((value >> 16) & 0xff); + bytes[3] = (uint8_t)(value >> 24); + fwrite(bytes, 1, 4, file); +} diff --git a/src/mic.h b/src/mic.h new file mode 100644 index 000000000..d194a5bf3 --- /dev/null +++ b/src/mic.h @@ -0,0 +1,98 @@ +/* + * + * Singe 3 + * Copyright (C) 2006-2026 Scott Duensing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + + +#ifndef MIC_H +#define MIC_H + + +#include +#include + + +// The microphone: one recording device at a time, heard as mono float samples at MIC_RATE. SDL's +// stream callback keeps the newest of them in a ring, with the level of each block; everything a +// game asks is answered from that ring on the engine's thread (PLAN.md section 62). + +#define MIC_RATE 48000 // Opus's native rate, so a voice frame needs no resampling +#define MIC_LATENCY_UNKNOWN -1 // micLatency before any calibration has finished +#define MIC_LATENCY_MAX 1000 // A measured latency longer than this is not believed +#define MIC_RING_SECONDS 8 // The newest this much is kept; a slower reader loses the rest + +typedef enum MicCalibrationE { + MIC_CALIBRATION_IDLE = 0, // Nothing asked, or the last one finished + MIC_CALIBRATION_RUNNING = 1, + MIC_CALIBRATION_DONE = 2, // micLatency holds the answer + MIC_CALIBRATION_FAILED = 3 // The clicks were never heard back +} MicCalibrationE; + + +// Starts a latency measurement: clicks played through the speakers and timed coming back through +// the microphone. False when no microphone is open or the speakers cannot be opened. +bool micCalibrate(void); + +MicCalibrationE micCalibrationState(void); + +void micClose(void); + +// The recording devices SDL can see, and each one's name (NULL when the index names none). The +// list is taken afresh by micDeviceCount. +int32_t micDeviceCount(void); +const char *micDeviceName(int32_t index); + +bool micIsOpen(void); + +// The milliseconds between a sound being made and the game hearing it, or MIC_LATENCY_UNKNOWN. +int32_t micLatency(void); + +// RMS and peak of the last block heard, 0 to 1. +void micLevel(float *rms, float *peak); + +// Plays what the microphone hears through the speakers, at volume 0 to 1. Off by default. +bool micMonitor(bool on, float volume); + +// Opens a recording device by name, or the default for NULL. Closes one already open. +bool micOpen(const char *name); + +// The fundamental of what was heard most recently, in Hz, and how clearly periodic it is, 0 to 1; +// 0 Hz when nothing voiced is there. +void micPitch(float *hz, float *clarity); + +void micQuit(void); + +// Up to max samples heard since the last read, as 16-bit, oldest first. Returns how many. A reader +// that falls a whole ring behind skips to the oldest still kept. +int32_t micRead(int16_t *out, int32_t max); + +// Writes everything heard from now on to a 16-bit mono WAV file at path, until micRecordStop. +bool micRecordStart(const char *path); +void micRecordStop(void); + +// Sets the latency a game already knows (from the machine settings), MIC_LATENCY_UNKNOWN to forget. +void micSetLatency(int32_t milliseconds); + +// Once a frame on the engine's thread: the recording written, the calibration stepped. True on the +// frame a calibration finishes with an answer, so the caller can keep it. +bool micUpdate(void); + + +#endif // MIC_H diff --git a/src/singe.c b/src/singe.c index bddbc65d5..9b619f3b8 100644 --- a/src/singe.c +++ b/src/singe.c @@ -72,12 +72,15 @@ SSL_CTX *lsec_checkcontext(lua_State *L, int idx); #include "decode.h" #include "main.h" #include "midi.h" +#include "mic.h" #include "midiIo.h" #include "netTrust.h" #include "pack.h" #include "util.h" #include "frameFile.h" #include "vfs.h" +#include "voice.h" +#include "sqlite3.h" #include "persist.h" #include "scene.h" #include "render.h" @@ -257,6 +260,7 @@ SDL_COMPILE_TIME_ASSERT(codeGamepadBase, CODE_GAMEPAD_BASE >= SDL_SCANCODE_RESER #define EFFECT_TAG "effects" #define MUSIC_TAG "music" // Music carries its own gain, so musicSetVolume never moves a sound effect #define MUSIC_LOOP_MAX 64 // Hypseus clamps musicPlay's loop count to this +#define MUSIC_GLIDE_MAX_MS 50 // musicGetPosition runs on with the clock between mixer updates, no further than this #define HELD_KEYS_MAX 64 // Keys physically down at once #define CHORD_CODES_MAX 4 // Buttons held together in one chord #define INPUT_DEVICE_DIR "/dev/input" @@ -335,6 +339,13 @@ typedef enum RenderQualityE { RENDER_SMOOTH = 1 } RenderQualityE; +// How spriteSetBlend lays a sprite over the overlay. +typedef enum SpriteBlendE { + SPRITE_ALPHA = 0, // Over what is there, by the sprite's alpha + SPRITE_ADD = 1, // Added to what is there, so it can only brighten + SPRITE_MULTIPLY = 2 // What is there, darkened by the sprite's colour +} SpriteBlendE; + // How an io function hooked through the vfs uses its file name. typedef enum IoHookModeE { IO_HOOK_INPUT = 0, // io.input: reads, and becomes the default input @@ -453,6 +464,11 @@ typedef struct SpriteS { SDL_Surface *flippedFrame; // spriteFlip's mirrored copy of the sheet frame spriteDrawFrame last drew int32_t flippedIndex; // Which frame that is SDL_FlipMode flip; // How spriteFlip mirrors every draw + SpriteBlendE blend; // spriteSetBlend + uint8_t alpha; // spriteSetAlpha: every pixel's alpha is multiplied by this + uint8_t tintR; // spriteSetTint: every pixel's colour is multiplied by this + uint8_t tintG; + uint8_t tintB; bool surfaceOwned; // True when surface is a transformed copy to free int32_t frameWidth; // Unscaled size of one frame (the image, for a still) int32_t frameHeight; @@ -487,6 +503,8 @@ typedef struct MusicS { int32_t id; MIX_Audio *audio; MIX_Track *track; + Sint64 heardFrames; // musicGetPosition: the mixer's position when it last moved + uint64_t heardTicks; // and when that was UT_hash_handle hh; } MusicT; @@ -1032,8 +1050,10 @@ static int32_t _luaIoType(lua_State *L); static int32_t _luaLoadfile(lua_State *L); static int32_t _luaLoadFile(lua_State *L, const char *name, const char *mode, bool watch); static int32_t _luaopenLfs(lua_State *L); +static int32_t _luaopenSqlite3(lua_State *L); static int32_t _luaPanic(lua_State *L); static int32_t _luaSearcher(lua_State *L); +static int32_t _luaSqliteOpen(lua_State *L); static void _luaTrace(lua_State *L, const char *method, const char *fmt, ...) __attribute__((format(printf, 3, 4))); static int32_t _luaTraceback(lua_State *L); static char *_machineFilePath(void); @@ -1130,6 +1150,7 @@ static void _soundDestroy(SoundT *sound); static SoundT *_soundLoadFromIO(lua_State *L, const char *method, SDL_IOStream *io); static int32_t _soundQueueDrain(int32_t *finished); static void _spriteAdoptAnimation(SpriteT *sprite); +static void _spriteBlit(SpriteT *sprite, SDL_Surface *surface, const SDL_Rect *source, SDL_Rect *dest, bool stretched); static void _spriteDestroy(SpriteT *sprite); static SDL_Surface *_spriteFlippedFrame(SpriteT *sprite, SDL_Surface *source, int32_t frame); static void _spriteFreeSurface(SpriteT *sprite); @@ -1168,6 +1189,11 @@ static void _unrotatePoint(float px, float py, float *vx, float *vy); static void _updatePauseState(void); static void _updateSounds(void); static void _videoDestroy(VideoT *video); +static bool _voiceIsAny(int32_t handle); +static bool _voiceIsDecoder(int32_t handle); +static bool _voiceIsEncoder(int32_t handle); +static bool _voiceIsJitter(int32_t handle); +static bool _voiceIsProcessor(int32_t handle); static bool _watchedChanged(void); static void _watchFile(const char *name); @@ -1303,6 +1329,9 @@ static int32_t apiGuiSetHandler(lua_State *L); static int32_t apiGuiSetInput(lua_State *L); static int32_t apiGuiSetValue(lua_State *L); static int32_t apiGuiShow(lua_State *L); +static int32_t apiJitterGet(lua_State *L); +static int32_t apiJitterNew(lua_State *L); +static int32_t apiJitterPut(lua_State *L); static int32_t apiJointBall(lua_State *L); static int32_t apiJointDelete(lua_State *L); static int32_t apiJointHinge(lua_State *L); @@ -1355,6 +1384,20 @@ static int32_t apiMeshNew(lua_State *L); static int32_t apiMeshPlane(lua_State *L); static int32_t apiMeshSphere(lua_State *L); static int32_t apiMeshTorus(lua_State *L); +static int32_t apiMicCalibrate(lua_State *L); +static int32_t apiMicCalibration(lua_State *L); +static int32_t apiMicClose(lua_State *L); +static int32_t apiMicIsOpen(lua_State *L); +static int32_t apiMicLatency(lua_State *L); +static int32_t apiMicLevel(lua_State *L); +static int32_t apiMicList(lua_State *L); +static int32_t apiMicMonitor(lua_State *L); +static int32_t apiMicOpen(lua_State *L); +static int32_t apiMicPitch(lua_State *L); +static int32_t apiMicRead(lua_State *L); +static int32_t apiMicRecordStart(lua_State *L); +static int32_t apiMicRecordStop(lua_State *L); +static int32_t apiMicSetLatency(lua_State *L); static int32_t apiMidiCloseInput(lua_State *L); static int32_t apiMidiCloseOutput(lua_State *L); static int32_t apiMidiControlChange(lua_State *L); @@ -1377,6 +1420,7 @@ static int32_t apiModelGetAnimations(lua_State *L); static int32_t apiModelInstance(lua_State *L); static int32_t apiModelLoad(lua_State *L); static int32_t apiMouseGetPadding(lua_State *L); +static int32_t apiMusicGetPosition(lua_State *L); static int32_t apiMusicIsPlaying(lua_State *L); static int32_t apiMusicLoad(lua_State *L); static int32_t apiMusicPause(lua_State *L); @@ -1441,6 +1485,11 @@ static int32_t apiNodeSetSprite(lua_State *L); static int32_t apiNodeSetSpriteFrame(lua_State *L); static int32_t apiNodeSetText(lua_State *L); static int32_t apiNodeSetVisible(lua_State *L); +static int32_t apiOpusDecode(lua_State *L); +static int32_t apiOpusDecoderNew(lua_State *L); +static int32_t apiOpusEncode(lua_State *L); +static int32_t apiOpusEncoderNew(lua_State *L); +static int32_t apiOpusEncoderSet(lua_State *L); static int32_t apiOsClock(lua_State *L); static int32_t apiOsTime(lua_State *L); static int32_t apiOverlayBanner(lua_State *L); @@ -1610,7 +1659,10 @@ static int32_t apiSpriteRotate(lua_State *L); static int32_t apiSpriteRotateAndScale(lua_State *L); static int32_t apiSpriteRotateFrame(lua_State *L); static int32_t apiSpriteScale(lua_State *L); +static int32_t apiSpriteSetAlpha(lua_State *L); +static int32_t apiSpriteSetBlend(lua_State *L); static int32_t apiSpriteSetFrame(lua_State *L); +static int32_t apiSpriteSetTint(lua_State *L); static int32_t apiSpriteUnload(lua_State *L); static int32_t apiSrtClear(lua_State *L); static int32_t apiSrtEnable(lua_State *L); @@ -1685,6 +1737,9 @@ static int32_t apiVldpGetShift(lua_State *L); static int32_t apiVldpSetScale(lua_State *L); static int32_t apiVldpSetShift(lua_State *L); static int32_t apiVldpSetVerbose(lua_State *L); +static int32_t apiVoiceFree(lua_State *L); +static int32_t apiVoiceProcess(lua_State *L); +static int32_t apiVoiceProcessorNew(lua_State *L); #define MODL(name, array) { name, { (const char *)array }, sizeof(array) } @@ -1703,7 +1758,7 @@ static const LuaModuleT _luaModules[] = { MODC("cjson", luaopen_cjson), MODC("lpeg", luaopen_lpeg), // SQLite for script data - MODC("sqlite3", luaopen_lsqlite3), + MODC("sqlite3", _luaopenSqlite3), // LuaSocket MODC("mime.core", luaopen_mime_core), MODC("socket.core", luaopen_socket_core), @@ -4663,6 +4718,10 @@ static void _loadMachineSettings(void) { if ((at != NULL) && (sscanf(at, "tier = %d", &value) == 1) && (value >= 0) && (value <= TIER_MAX)) { _global.machineTier = value; } + at = strstr(data, "mic = "); + if ((at != NULL) && (sscanf(at, "mic = %d", &value) == 1) && (value >= 0) && (value <= MIC_LATENCY_MAX)) { + micSetLatency(value); + } at = strstr(data, "delay = "); if ((at != NULL) && (sscanf(at, "delay = %d", &value) == 1) && (value >= -VIDEO_AUDIO_DELAY_MAX) && (value <= VIDEO_AUDIO_DELAY_MAX)) { delay = value; @@ -5436,6 +5495,18 @@ static int32_t _luaopenLfs(lua_State *L) { } +// require("sqlite3") with open resolving names the way io.open does, so a database packed in the game +// opens (see _luaSqliteOpen). +static int32_t _luaopenSqlite3(lua_State *L) { + luaopen_lsqlite3(L); + lua_getfield(L, -1, "open"); + lua_pushcclosure(L, _luaSqliteOpen, 1); + lua_setfield(L, -2, "open"); + + return 1; +} + + // Lua panic handler: something went wrong outside a protected call. static int32_t _luaPanic(lua_State *L) { lua_Debug ar; @@ -5483,6 +5554,51 @@ static int32_t _luaSearcher(lua_State *L) { } +// sqlite3.open with the name resolved through the vfs. A database packed inside the game is opened +// where it lies, read only, when that is what the script asked for; asked to write, it is copied +// once to the game's data directory -- where io.open sends a write to a packed name -- and the copy +// is opened, then and from then on. Any other name resolves as io.open's would. SQLite's own +// special names (":memory:", "", a "file:" URI) pass through untouched. Upvalue: the original. +static int32_t _luaSqliteOpen(lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_Integer flags = luaL_optinteger(L, 2, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); + bool writing = ((flags & (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)) != 0); + char *path = NULL; + int32_t base = 0; + + if ((name[0] != 0) && (strcmp(name, ":memory:") != 0) && (strncmp(name, "file:", 5) != 0)) { + if (vfsIsPacked(name) && !writing) { + path = vfsSqliteUri(name); + flags = SQLITE_OPEN_READONLY | SQLITE_OPEN_URI; + } else { + path = vfsFilePath(name, writing); + if (path == NULL) { + lua_pushnil(L); + lua_pushinteger(L, SQLITE_CANTOPEN); + lua_pushfstring(L, "%s reaches outside the game", name); + return 3; + } + if (writing && vfsIsPacked(name) && !vfsExtract(name, path)) { + lua_pushnil(L); + lua_pushinteger(L, SQLITE_CANTOPEN); + lua_pushfstring(L, "%s could not be copied out of the game to %s", name, path); + free(path); + return 3; + } + } + } + // The arguments stay on the stack below the call, so name stays alive until it is done with. + base = lua_gettop(L); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_pushstring(L, (path != NULL) ? path : name); + lua_pushinteger(L, flags); + free(path); + lua_call(L, 2, LUA_MULTRET); + + return lua_gettop(L) - base; +} + + static void _luaTrace(lua_State *L, const char *method, const char *fmt, ...) { va_list args; char *message = NULL; @@ -6349,6 +6465,13 @@ static void _pushConstants(lua_State *L) { lua_pushinteger(L, RENDER_SMOOTH); lua_setglobal(L, "RENDER_SMOOTH"); + lua_pushinteger(L, SPRITE_ALPHA); + lua_setglobal(L, "SPRITE_ALPHA"); + lua_pushinteger(L, SPRITE_ADD); + lua_setglobal(L, "SPRITE_ADD"); + lua_pushinteger(L, SPRITE_MULTIPLY); + lua_setglobal(L, "SPRITE_MULTIPLY"); + lua_pushinteger(L, DISC_STOPPED); lua_setglobal(L, "DISC_STOPPED"); lua_pushinteger(L, DISC_PLAYING); @@ -6835,6 +6958,9 @@ static void _registerApi(lua_State *L) { lua_register(L, "guiSetValue", apiGuiSetValue); // 3.00 lua_register(L, "guiShow", apiGuiShow); // 3.00 + lua_register(L, "jitterGet", apiJitterGet); // 3.00 + lua_register(L, "jitterNew", apiJitterNew); // 3.00 + lua_register(L, "jitterPut", apiJitterPut); // 3.00 lua_register(L, "jointBall", apiJointBall); // 3.00 lua_register(L, "jointDelete", apiJointDelete); // 3.00 lua_register(L, "jointHinge", apiJointHinge); // 3.00 @@ -6887,6 +7013,20 @@ static void _registerApi(lua_State *L) { lua_register(L, "meshPlane", apiMeshPlane); // 3.00 lua_register(L, "meshSphere", apiMeshSphere); // 3.00 lua_register(L, "meshTorus", apiMeshTorus); // 3.00 + lua_register(L, "micCalibrate", apiMicCalibrate); // 3.00 + lua_register(L, "micCalibration", apiMicCalibration); // 3.00 + lua_register(L, "micClose", apiMicClose); // 3.00 + lua_register(L, "micIsOpen", apiMicIsOpen); // 3.00 + lua_register(L, "micLatency", apiMicLatency); // 3.00 + lua_register(L, "micLevel", apiMicLevel); // 3.00 + lua_register(L, "micList", apiMicList); // 3.00 + lua_register(L, "micMonitor", apiMicMonitor); // 3.00 + lua_register(L, "micOpen", apiMicOpen); // 3.00 + lua_register(L, "micPitch", apiMicPitch); // 3.00 + lua_register(L, "micRead", apiMicRead); // 3.00 + lua_register(L, "micRecordStart", apiMicRecordStart); // 3.00 + lua_register(L, "micRecordStop", apiMicRecordStop); // 3.00 + lua_register(L, "micSetLatency", apiMicSetLatency); // 3.00 lua_register(L, "midiCloseInput", apiMidiCloseInput); // 3.00 lua_register(L, "midiCloseOutput", apiMidiCloseOutput); // 3.00 lua_register(L, "midiControlChange", apiMidiControlChange); // 3.00 @@ -6916,6 +7056,7 @@ static void _registerApi(lua_State *L) { lua_register(L, "mouseSetEnabled", apiMouseSetEnabled); // 3.00 mouseEnable/mouseDisable are framework aliases. lua_register(L, "mouseSetMode", apiMouseSetMode); // 1.18 RDG + lua_register(L, "musicGetPosition", apiMusicGetPosition); // 3.00 lua_register(L, "musicIsPlaying", apiMusicIsPlaying); // Hypseus lua_register(L, "musicLoad", apiMusicLoad); // Hypseus lua_register(L, "musicPause", apiMusicPause); // Hypseus @@ -6975,6 +7116,11 @@ static void _registerApi(lua_State *L) { lua_register(L, "nodeSetSpriteFrame", apiNodeSetSpriteFrame); // 3.00 lua_register(L, "nodeSetText", apiNodeSetText); // 3.00 lua_register(L, "nodeSetVisible", apiNodeSetVisible); // 3.00 + lua_register(L, "opusDecode", apiOpusDecode); // 3.00 + lua_register(L, "opusDecoderNew", apiOpusDecoderNew); // 3.00 + lua_register(L, "opusEncode", apiOpusEncode); // 3.00 + lua_register(L, "opusEncoderNew", apiOpusEncoderNew); // 3.00 + lua_register(L, "opusEncoderSet", apiOpusEncoderSet); // 3.00 lua_register(L, "overlayBanner", apiOverlayBanner); // Hypseus lua_register(L, "overlayBox", apiOverlayBox); // 2.00 lua_register(L, "overlayCircle", apiOverlayCircle); // 2.00 @@ -7146,7 +7292,10 @@ static void _registerApi(lua_State *L) { lua_register(L, "spriteRotateAndScale", apiSpriteRotateAndScale); // 2.10 Handle first since 3.00. lua_register(L, "spriteRotateFrame", apiSpriteRotateFrame); // Hypseus Handle first since 3.00. lua_register(L, "spriteScale", apiSpriteScale); // 2.10 Handle first since 3.00. + lua_register(L, "spriteSetAlpha", apiSpriteSetAlpha); // 3.00 + lua_register(L, "spriteSetBlend", apiSpriteSetBlend); // 3.00 lua_register(L, "spriteSetFrame", apiSpriteSetFrame); // 2.10 Handle first since 3.00. + lua_register(L, "spriteSetTint", apiSpriteSetTint); // 3.00 lua_register(L, "spriteUnload", apiSpriteUnload); // 2.00 lua_register(L, "srtClear", apiSrtClear); // Hypseus @@ -7226,6 +7375,9 @@ static void _registerApi(lua_State *L) { lua_register(L, "vldpSetScale", apiVldpSetScale); // Hypseus lua_register(L, "vldpSetShift", apiVldpSetShift); // 3.00 lua_register(L, "vldpSetVerbose", apiVldpSetVerbose); // 1.xx + lua_register(L, "voiceFree", apiVoiceFree); // 3.00 + lua_register(L, "voiceProcess", apiVoiceProcess); // 3.00 + lua_register(L, "voiceProcessorNew", apiVoiceProcessorNew); // 3.00 } @@ -7613,6 +7765,9 @@ static void _saveMachineSettings(int32_t milliseconds) { if (_global.machineTier != TIER_UNMEASURED) { fprintf(out, "tier = %d\n", _global.machineTier); } + if (micLatency() != MIC_LATENCY_UNKNOWN) { + fprintf(out, "mic = %d\n", micLatency()); + } fclose(out); } else { utilSay("Unable to write %s", path); @@ -8269,6 +8424,29 @@ static void _spriteAdoptAnimation(SpriteT *sprite) { } +// Every sprite draw ends here: the sprite's blend, alpha, and tint are set on the surface being +// drawn (a frame, a turned copy, or the image itself, so they follow every draw of the sprite) and +// it is blitted, stretched into dest or at its own size. SDL only rebuilds its blitter when one of +// them changes, so setting them on every draw costs nothing. +static void _spriteBlit(SpriteT *sprite, SDL_Surface *surface, const SDL_Rect *source, SDL_Rect *dest, bool stretched) { + SDL_BlendMode mode = SDL_BLENDMODE_BLEND; + + if (sprite->blend == SPRITE_ADD) { + mode = SDL_BLENDMODE_ADD; + } else if (sprite->blend == SPRITE_MULTIPLY) { + mode = SDL_BLENDMODE_MUL; + } + SDL_SetSurfaceBlendMode(surface, mode); + SDL_SetSurfaceAlphaMod(surface, sprite->alpha); + SDL_SetSurfaceColorMod(surface, sprite->tintR, sprite->tintG, sprite->tintB); + if (stretched) { + SDL_BlitSurfaceScaled(surface, source, _global.overlay, dest, SDL_SCALEMODE_NEAREST); + } else { + SDL_BlitSurface(surface, source, _global.overlay, dest); + } +} + + static void _spriteDestroy(SpriteT *sprite) { HASH_DEL(_global.spriteList, sprite); _spriteFreeSurface(sprite); @@ -8395,6 +8573,11 @@ static void _spriteRegister(SpriteT *sprite) { sprite->surface = sprite->originalSurface; sprite->scaleX = 1.0; sprite->scaleY = 1.0; + sprite->blend = SPRITE_ALPHA; + sprite->alpha = 255; + sprite->tintR = 255; + sprite->tintG = 255; + sprite->tintB = 255; sprite->frameWidth = sprite->originalSurface->w; sprite->frameHeight = sprite->originalSurface->h; sprite->id = _global.nextSpriteId++; @@ -9107,6 +9290,9 @@ static void _unloadScriptResources(void) { _progTrace("Unloading video handle %d", video->id); _videoDestroy(video); } + // The microphone and every voice object the script made. + micClose(); + voiceFreeAll(); } @@ -9260,6 +9446,32 @@ static void _videoDestroy(VideoT *video) { } +// The handle checks _argHandle takes, one for each kind of voice object. +static bool _voiceIsAny(int32_t handle) { + return voiceKind(handle, VOICE_KIND_ENCODER) || voiceKind(handle, VOICE_KIND_DECODER) || voiceKind(handle, VOICE_KIND_PROCESSOR) || voiceKind(handle, VOICE_KIND_JITTER); +} + + +static bool _voiceIsDecoder(int32_t handle) { + return voiceKind(handle, VOICE_KIND_DECODER); +} + + +static bool _voiceIsEncoder(int32_t handle) { + return voiceKind(handle, VOICE_KIND_ENCODER); +} + + +static bool _voiceIsJitter(int32_t handle) { + return voiceKind(handle, VOICE_KIND_JITTER); +} + + +static bool _voiceIsProcessor(int32_t handle) { + return voiceKind(handle, VOICE_KIND_PROCESSOR); +} + + // Once a second: whether any watched file's modification time moved. static bool _watchedChanged(void) { uint64_t now = utilTicks(); @@ -11123,6 +11335,74 @@ static int32_t apiGuiShow(lua_State *L) { } +// packet, status = jitterGet(jitter [, span]) The packet due for the next span samples (the step +// unless given), or nil, and the buffer moved on; status is "ok", "missing" (conceal the gap), or +// "insertion" (play a little silence while it grows). +static int32_t apiJitterGet(lua_State *L) { + static const char *names[] = { "ok", "missing", "insertion" }; + uint8_t packet[VOICE_PACKET_MAX]; + int32_t handle = 0; + int32_t span = 0; + int32_t bytes = 0; + VoiceJitterE status = VOICE_JITTER_MISSING; + + _argCheck(L, "jitterGet", 1, 2); + handle = _argHandle(L, "jitterGet", 1, _voiceIsJitter, "jitter buffer"); + span = (lua_gettop(L) >= 2) ? _argInteger(L, "jitterGet", 2) : voiceFrame(handle); + bytes = voiceJitterGet(handle, packet, (int32_t)sizeof(packet), span, &status); + if (status == VOICE_JITTER_OK) { + lua_pushlstring(L, (const char *)packet, (size_t)bytes); + } else { + lua_pushnil(L); + } + lua_pushstring(L, names[status]); + + return 2; +} + + +// jitter = jitterNew([step]) A jitter buffer: packets put in by timestamp, taken out in order a +// step at a time (960 samples, 20 ms at 48 kHz, unless given). +static int32_t apiJitterNew(lua_State *L) { + int32_t step = VOICE_DEFAULT_FRAME; + int32_t handle = 0; + + _argCheck(L, "jitterNew", 0, 1); + if (lua_gettop(L) >= 1) { + step = _argInteger(L, "jitterNew", 1); + } + handle = voiceJitterNew(step); + if (handle < 0) { + _luaDie(L, "jitterNew", "%s", voiceError(handle)); + } + _luaTrace(L, "jitterNew", "%d step %d", handle, step); + lua_pushinteger(L, handle); + + return 1; +} + + +// jitterPut(jitter, packet, timestamp [, span]) A packet that arrived, by its timestamp in samples; its +// span is the step unless given. +static int32_t apiJitterPut(lua_State *L) { + const char *packet = NULL; + size_t bytes = 0; + int32_t handle = 0; + int32_t span = 0; + + _argCheck(L, "jitterPut", 3, 4); + handle = _argHandle(L, "jitterPut", 1, _voiceIsJitter, "jitter buffer"); + packet = _argData(L, "jitterPut", 2, &bytes); + span = (lua_gettop(L) >= 4) ? _argInteger(L, "jitterPut", 4) : voiceFrame(handle); + if ((bytes == 0) || (bytes > VOICE_PACKET_MAX)) { + _luaDie(L, "jitterPut", "A packet is 1 to %d bytes: %d", VOICE_PACKET_MAX, (int32_t)bytes); + } + voiceJitterPut(handle, (const uint8_t *)packet, (int32_t)bytes, _argInteger(L, "jitterPut", 3), span); + + return 0; +} + + static int32_t apiJointBall(lua_State *L) { int32_t nodeA; int32_t nodeB; @@ -11904,6 +12184,229 @@ static int32_t apiMeshTorus(lua_State *L) { } +// started = micCalibrate() Plays clicks and times them coming back through the microphone, over a few +// seconds; micCalibration says when it is done. The answer is kept for the machine. +static int32_t apiMicCalibrate(lua_State *L) { + bool started = false; + + _argCheck(L, "micCalibrate", 0, 0); + started = micCalibrate(); + _luaTrace(L, "micCalibrate", "%s", started ? "started" : "no microphone or no speaker"); + lua_pushboolean(L, started); + + return 1; +} + + +// state, latency = micCalibration() "idle", "running", "done", or "failed", and the latency in +// milliseconds once one is known. +static int32_t apiMicCalibration(lua_State *L) { + static const char *names[] = { "idle", "running", "done", "failed" }; + + _argCheck(L, "micCalibration", 0, 0); + lua_pushstring(L, names[micCalibrationState()]); + if (micLatency() == MIC_LATENCY_UNKNOWN) { + lua_pushnil(L); + } else { + lua_pushinteger(L, micLatency()); + } + + return 2; +} + + +// micClose() Stops listening. The microphone also closes when the game ends. +static int32_t apiMicClose(lua_State *L) { + _argCheck(L, "micClose", 0, 0); + micClose(); + _luaTrace(L, "micClose", "Closed."); + + return 0; +} + + +// open = micIsOpen() +static int32_t apiMicIsOpen(lua_State *L) { + _argCheck(L, "micIsOpen", 0, 0); + lua_pushboolean(L, micIsOpen()); + + return 1; +} + + +// milliseconds = micLatency() Between a sound being made and the game hearing it, or nil until a +// calibration (on this machine, at any time) has measured it. +static int32_t apiMicLatency(lua_State *L) { + _argCheck(L, "micLatency", 0, 0); + if (micLatency() == MIC_LATENCY_UNKNOWN) { + lua_pushnil(L); + } else { + lua_pushinteger(L, micLatency()); + } + + return 1; +} + + +// rms, peak = micLevel() How loud the last moment heard was, each 0 to 1. +static int32_t apiMicLevel(lua_State *L) { + float rms = 0.0f; + float peak = 0.0f; + + _argCheck(L, "micLevel", 0, 0); + micLevel(&rms, &peak); + lua_pushnumber(L, rms); + lua_pushnumber(L, peak); + + return 2; +} + + +// names = micList() The microphones this machine has, by name, for micOpen. +static int32_t apiMicList(lua_State *L) { + int32_t count = 0; + int32_t i = 0; + + _argCheck(L, "micList", 0, 0); + count = micDeviceCount(); + lua_createtable(L, count, 0); + for (i = 0; i < count; i++) { + lua_pushstring(L, (micDeviceName(i) != NULL) ? micDeviceName(i) : ""); + lua_rawseti(L, -2, i + 1); + } + + return 1; +} + + +// ok = micMonitor(on [, volume]) Plays what the microphone hears through the speakers, volume 0 to 1. +// Most hardware adds a delay a singer can hear, so it is off until asked for. +static int32_t apiMicMonitor(lua_State *L) { + bool on = false; + float volume = 1.0f; + bool ok = false; + + _argCheck(L, "micMonitor", 1, 2); + on = _argBoolean(L, "micMonitor", 1); + if (lua_gettop(L) >= 2) { + volume = (float)_argNumber(L, "micMonitor", 2); + } + ok = micMonitor(on, volume); + _luaTrace(L, "micMonitor", "%s at %.2f%s", on ? "on" : "off", volume, ok ? "" : ", refused"); + lua_pushboolean(L, ok); + + return 1; +} + + +// opened = micOpen([name]) Starts listening to a microphone by name (micList), or the machine's default. +static int32_t apiMicOpen(lua_State *L) { + const char *name = NULL; + bool opened = false; + + _argCheck(L, "micOpen", 0, 1); + if ((lua_gettop(L) >= 1) && !lua_isnil(L, 1)) { + name = _argString(L, "micOpen", 1); + } + opened = micOpen(name); + _luaTrace(L, "micOpen", "%s %s", (name != NULL) ? name : "default", opened ? "opened" : "failed"); + lua_pushboolean(L, opened); + + return 1; +} + + +// hz, clarity = micPitch() The note being sung, as its fundamental in Hz, and how clearly it is one +// note, 0 to 1; 0 Hz when nothing voiced is heard. +static int32_t apiMicPitch(lua_State *L) { + float hz = 0.0f; + float clarity = 0.0f; + + _argCheck(L, "micPitch", 0, 0); + micPitch(&hz, &clarity); + lua_pushnumber(L, hz); + lua_pushnumber(L, clarity); + + return 2; +} + + +// samples = micRead([max]) What was heard since the last read, as 16-bit mono at 48 kHz in a string +// (two bytes a sample, little endian), at most max samples. +static int32_t apiMicRead(lua_State *L) { + int16_t *samples = NULL; + int32_t max = MIC_RATE * MIC_RING_SECONDS; + int32_t count = 0; + + _argCheck(L, "micRead", 0, 1); + if (lua_gettop(L) >= 1) { + max = _argInteger(L, "micRead", 1); + if ((max < 0) || (max > MIC_RATE * MIC_RING_SECONDS)) { + _luaDie(L, "micRead", "max must be 0 to %d samples: %d", MIC_RATE * MIC_RING_SECONDS, max); + } + } + samples = (int16_t *)malloc((size_t)(max > 0 ? max : 1) * sizeof(int16_t)); + if (samples == NULL) { + _luaDie(L, "micRead", "Out of memory."); + } + count = micRead(samples, max); + lua_pushlstring(L, (const char *)samples, (size_t)count * sizeof(int16_t)); + free(samples); + + return 1; +} + + +// started = micRecordStart(name) Writes everything heard from now on to a WAV file, named like any +// file the game writes, until micRecordStop. +static int32_t apiMicRecordStart(lua_State *L) { + char *path = NULL; + bool started = false; + + _argCheck(L, "micRecordStart", 1, 1); + path = vfsFilePath(_argString(L, "micRecordStart", 1), true); + if (path == NULL) { + _luaDie(L, "micRecordStart", "%s reaches outside the game", lua_tostring(L, 1)); + } + started = micRecordStart(path); + _luaTrace(L, "micRecordStart", "%s %s", path, started ? "recording" : "failed"); + free(path); + lua_pushboolean(L, started); + + return 1; +} + + +// micRecordStop() Finishes the recording. +static int32_t apiMicRecordStop(lua_State *L) { + _argCheck(L, "micRecordStop", 0, 0); + micRecordStop(); + _luaTrace(L, "micRecordStop", "Stopped."); + + return 0; +} + + +// micSetLatency(milliseconds | nil) Sets the microphone's latency for this machine, as a service menu +// does from a measurement taken elsewhere; nil forgets it. +static int32_t apiMicSetLatency(lua_State *L) { + int32_t value = MIC_LATENCY_UNKNOWN; + + _argCheck(L, "micSetLatency", 1, 1); + if (!lua_isnil(L, 1)) { + value = _argInteger(L, "micSetLatency", 1); + if ((value < 0) || (value > MIC_LATENCY_MAX)) { + _luaDie(L, "micSetLatency", "Microphone latency must be 0 to %d milliseconds: %d", MIC_LATENCY_MAX, value); + } + } + micSetLatency(value); + _saveMachineSettings(videoGetAudioCalibration()); + _luaTrace(L, "micSetLatency", "%d", value); + + return 0; +} + + // modelDelete(model): frees its meshes and materials; instances keep their nodes, bare // midiCloseInput() Stops listening to the MIDI input port. static int32_t apiMidiCloseInput(lua_State *L) { @@ -12207,6 +12710,40 @@ static int32_t apiModelLoad(lua_State *L) { } +// seconds = musicGetPosition(id) How far into the track the listener is: the mixer's position less +// what is still on its way to the speakers (the device queue, the machine's calibration, and the +// game's delay), so a picture timed to it lands with the sound. The mixer moves its position a +// buffer at a time, so between moves the answer runs on with the clock, no further than +// MUSIC_GLIDE_MAX_MS, and a paused track holds still. A track that is not playing answers -1. +static int32_t apiMusicGetPosition(lua_State *L) { + MusicT *music = NULL; + Sint64 frames = 0; + uint64_t now = 0; + double seconds = -1.0; + + _argCheck(L, "musicGetPosition", 1, 1); + music = _argMusic(L, "musicGetPosition", 1); + if (MIX_TrackPlaying(music->track) || MIX_TrackPaused(music->track)) { + frames = MIX_GetTrackPlaybackPosition(music->track); + now = utilTicks(); + if (frames != music->heardFrames) { + music->heardFrames = frames; + music->heardTicks = now; + } + seconds = (double)MIX_TrackFramesToMS(music->track, frames); + if (!MIX_TrackPaused(music->track)) { + seconds += (double)SDL_min(now - music->heardTicks, (uint64_t)MUSIC_GLIDE_MAX_MS); + } + seconds -= (double)(videoGetAudioLatency() + videoGetAudioCalibration() + videoGetAudioDelay()); + seconds = SDL_max(seconds, 0.0) / 1000.0; + } + _luaTrace(L, "musicGetPosition", "%d %f", music->id, seconds); + lua_pushnumber(L, seconds); + + return 1; +} + + // playing = musicIsPlaying([id]) Hypseus extension. With no handle, whether any music is playing. static int32_t apiMusicIsPlaying(lua_State *L) { MusicT *music = NULL; @@ -13223,6 +13760,151 @@ static int32_t apiNodeSetVisible(lua_State *L) { } +// samples = opusDecode(decoder, packet | nil) A packet back to 16-bit samples (interleaved when there +// are two channels); nil for a packet that never arrived asks Opus to conceal the gap. +static int32_t apiOpusDecode(lua_State *L) { + int16_t samples[VOICE_FRAME_MAX * 2]; + const char *packet = NULL; + size_t bytes = 0; + int32_t handle = 0; + int32_t channels = 0; + int32_t decoded = 0; + + _argCheck(L, "opusDecode", 2, 2); + handle = _argHandle(L, "opusDecode", 1, _voiceIsDecoder, "Opus decoder"); + channels = voiceChannels(handle); + if (!lua_isnil(L, 2)) { + packet = _argData(L, "opusDecode", 2, &bytes); + } + decoded = voiceDecode(handle, (const uint8_t *)packet, (int32_t)bytes, samples, VOICE_FRAME_MAX); + if (decoded < 0) { + _luaDie(L, "opusDecode", "%s", voiceError(decoded)); + } + lua_pushlstring(L, (const char *)samples, (size_t)decoded * (size_t)channels * sizeof(int16_t)); + + return 1; +} + + +// decoder = opusDecoderNew([rate [, channels]]) 48000 and 1 unless given. +static int32_t apiOpusDecoderNew(lua_State *L) { + int32_t rate = MIC_RATE; + int32_t channels = 1; + int32_t handle = 0; + + _argCheck(L, "opusDecoderNew", 0, 2); + if (lua_gettop(L) >= 1) { + rate = _argInteger(L, "opusDecoderNew", 1); + } + if (lua_gettop(L) >= 2) { + channels = _argInteger(L, "opusDecoderNew", 2); + } + handle = voiceDecoderNew(rate, channels); + if (handle < 0) { + _luaDie(L, "opusDecoderNew", "%s (rate %d, channels %d)", voiceError(handle), rate, channels); + } + _luaTrace(L, "opusDecoderNew", "%d at %d, %d channel(s)", handle, rate, channels); + lua_pushinteger(L, handle); + + return 1; +} + + +// packet = opusEncode(encoder, samples) One frame of 16-bit samples (interleaved when there are two +// channels) -- 2.5, 5, 10, 20, 40, or 60 ms of them -- as one Opus packet. +static int32_t apiOpusEncode(lua_State *L) { + int16_t samples[VOICE_FRAME_MAX * 2]; + uint8_t packet[VOICE_PACKET_MAX]; + const char *data = NULL; + size_t bytes = 0; + int32_t handle = 0; + int32_t channels = 0; + int32_t encoded = 0; + + _argCheck(L, "opusEncode", 2, 2); + handle = _argHandle(L, "opusEncode", 1, _voiceIsEncoder, "Opus encoder"); + channels = voiceChannels(handle); + data = _argData(L, "opusEncode", 2, &bytes); + if ((bytes == 0) || (bytes > sizeof(samples)) || ((bytes % ((size_t)channels * sizeof(int16_t))) != 0)) { + _luaDie(L, "opusEncode", "A frame is whole 16-bit samples for %d channel(s), up to %d: %d bytes", channels, VOICE_FRAME_MAX, (int32_t)bytes); + } + // Copied out of the Lua string, which makes no promise about alignment. + memcpy(samples, data, bytes); + encoded = voiceEncode(handle, samples, (int32_t)(bytes / ((size_t)channels * sizeof(int16_t))), packet, (int32_t)sizeof(packet)); + if (encoded < 0) { + _luaDie(L, "opusEncode", "%s", voiceError(encoded)); + } + lua_pushlstring(L, (const char *)packet, (size_t)encoded); + + return 1; +} + + +// encoder = opusEncoderNew([rate [, channels [, application]]]) 48000, 1, and "voip" unless given; +// application is "voip" (speech), "audio" (music), or "lowdelay". +static int32_t apiOpusEncoderNew(lua_State *L) { + static const char *names[] = { "voip", "audio", "lowdelay" }; + int32_t rate = MIC_RATE; + int32_t channels = 1; + int32_t application = VOICE_APPLICATION_VOIP; + int32_t handle = 0; + int32_t i = 0; + const char *name = NULL; + + _argCheck(L, "opusEncoderNew", 0, 3); + if (lua_gettop(L) >= 1) { + rate = _argInteger(L, "opusEncoderNew", 1); + } + if (lua_gettop(L) >= 2) { + channels = _argInteger(L, "opusEncoderNew", 2); + } + if (lua_gettop(L) >= 3) { + name = _argString(L, "opusEncoderNew", 3); + application = -1; + for (i = 0; i < (int32_t)(sizeof(names) / sizeof(names[0])); i++) { + if (strcmp(name, names[i]) == 0) { + application = i; + } + } + if (application < 0) { + _luaDie(L, "opusEncoderNew", "The application is voip, audio, or lowdelay: %s", name); + } + } + handle = voiceEncoderNew(rate, channels, (VoiceApplicationE)application); + if (handle < 0) { + _luaDie(L, "opusEncoderNew", "%s (rate %d, channels %d)", voiceError(handle), rate, channels); + } + _luaTrace(L, "opusEncoderNew", "%d at %d, %d channel(s), %s", handle, rate, channels, names[application]); + lua_pushinteger(L, handle); + + return 1; +} + + +// opusEncoderSet(encoder, bitrate [, complexity]) Bits a second (0 leaves it as it is), and how much +// work to spend, 0 to 10. +static int32_t apiOpusEncoderSet(lua_State *L) { + int32_t handle = 0; + int32_t bitrate = 0; + int32_t complexity = -1; + + _argCheck(L, "opusEncoderSet", 2, 3); + handle = _argHandle(L, "opusEncoderSet", 1, _voiceIsEncoder, "Opus encoder"); + bitrate = _argInteger(L, "opusEncoderSet", 2); + if (lua_gettop(L) >= 3) { + complexity = _argInteger(L, "opusEncoderSet", 3); + if ((complexity < 0) || (complexity > 10)) { + _luaDie(L, "opusEncoderSet", "Complexity is 0 to 10: %d", complexity); + } + } + if (!voiceEncoderSet(handle, bitrate, complexity)) { + _luaDie(L, "opusEncoderSet", "Opus refused bitrate %d", bitrate); + } + + return 0; +} + + // seconds = os.clock() Replaces Lua's processor-time clock with wall time since the engine started. static int32_t apiOsClock(lua_State *L) { lua_pushnumber(L, (lua_Number)utilTicks() / MS_PER_SECOND_NUMBER); @@ -15442,8 +16124,6 @@ static int32_t apiSoundUnload(lua_State *L) { } -// spriteDraw(id, x, y[, centered]) - Draw at natural size -// spriteDraw(id, x, y, x2, y2[, centered]) - Stretch into the rectangle // spriteBlend(boolean, id) // Accepted and ignored. It is a Hypseus workaround: that engine loads sprites with SDL's blend // mode off, and this turns it back on per sprite. Singe draws every sprite with its alpha already. @@ -15456,6 +16136,8 @@ static int32_t apiSpriteBlend(lua_State *L) { } +// spriteDraw(id, x, y[, centered]) - Draw at natural size +// spriteDraw(id, x, y, x2, y2[, centered]) - Stretch into the rectangle static int32_t apiSpriteDraw(lua_State *L) { int32_t n = lua_gettop(L); bool center = false; @@ -15525,11 +16207,7 @@ static int32_t apiSpriteDraw(lua_State *L) { dest.x -= dest.w / 2; dest.y -= dest.h / 2; } - if (stretched) { - SDL_BlitSurfaceScaled(sprite->surface, NULL, _global.overlay, &dest, SDL_SCALEMODE_NEAREST); - } else { - SDL_BlitSurface(sprite->surface, NULL, _global.overlay, &dest); - } + _spriteBlit(sprite, sprite->surface, NULL, &dest, stretched); _overlayTouched(&dest); _luaTrace(L, "spriteDraw", "%d %d %d %d %d %d", sprite->id, dest.x, dest.y, dest.w, dest.h, center); @@ -15565,14 +16243,14 @@ static int32_t apiSpriteDrawFrame(lua_State *L) { dest.w = source->w; dest.h = source->h; if (n == 4) { - SDL_BlitSurface(source, NULL, _global.overlay, &dest); + _spriteBlit(sprite, source, NULL, &dest, false); } else { scaleX = _argNumber(L, "spriteDrawFrame", 5); scaleY = (n == 6) ? _argNumber(L, "spriteDrawFrame", 6) : scaleX; dest.w = (int32_t)(source->w * scaleX); dest.h = (int32_t)(source->h * scaleY); if ((dest.w > 0) && (dest.h > 0)) { - SDL_BlitSurfaceScaled(source, NULL, _global.overlay, &dest, SDL_SCALEMODE_NEAREST); + _spriteBlit(sprite, source, NULL, &dest, true); } } _overlayTouched(&dest); @@ -15582,15 +16260,20 @@ static int32_t apiSpriteDrawFrame(lua_State *L) { } -// spriteDrawGrid(id, x, y, sourceX, sourceY, width, height) Hypseus extension. Draws one -// rectangle out of the sprite, at its own size, with its top left corner at x, y. The rectangle is -// in the sprite's own pixels and must lie inside it. +// spriteDrawGrid(id, x, y, sourceX, sourceY, width, height[, x2, y2]) Hypseus extension. Draws +// one rectangle out of the sprite with its top left corner at x, y: at its own size, or stretched +// to x2, y2 as spriteDraw stretches, which is the Singe addition. The rectangle is in the sprite's +// own pixels and must lie inside it. A stretch with no width or height draws nothing. static int32_t apiSpriteDrawGrid(lua_State *L) { + int32_t n = lua_gettop(L); SpriteT *sprite = NULL; SDL_Rect source; SDL_Rect dest; - _argCheck(L, "spriteDrawGrid", 7, 7); + _argCheck(L, "spriteDrawGrid", 7, 9); + if (n == 8) { + _luaDie(L, "spriteDrawGrid", "A stretched rectangle needs both x2 and y2."); + } sprite = _argSprite(L, "spriteDrawGrid", 1); dest.x = _argInteger(L, "spriteDrawGrid", 2); dest.y = _argInteger(L, "spriteDrawGrid", 3); @@ -15601,11 +16284,19 @@ static int32_t apiSpriteDrawGrid(lua_State *L) { if ((source.x < 0) || (source.y < 0) || (source.w < 1) || (source.h < 1) || ((source.x + source.w) > sprite->surface->w) || ((source.y + source.h) > sprite->surface->h)) { _luaDie(L, "spriteDrawGrid", "Rectangle %d,%d %dx%d is not inside sprite %d, which is %dx%d.", source.x, source.y, source.w, source.h, sprite->id, sprite->surface->w, sprite->surface->h); } - dest.w = source.w; - dest.h = source.h; - SDL_BlitSurface(sprite->surface, &source, _global.overlay, &dest); + if (n == 9) { + dest.w = _argInteger(L, "spriteDrawGrid", 8) - dest.x + 1; + dest.h = _argInteger(L, "spriteDrawGrid", 9) - dest.y + 1; + if ((dest.w > 0) && (dest.h > 0)) { + _spriteBlit(sprite, sprite->surface, &source, &dest, true); + } + } else { + dest.w = source.w; + dest.h = source.h; + _spriteBlit(sprite, sprite->surface, &source, &dest, false); + } _overlayTouched(&dest); - _luaTrace(L, "spriteDrawGrid", "%d %d %d %d %d %d %d", sprite->id, dest.x, dest.y, source.x, source.y, source.w, source.h); + _luaTrace(L, "spriteDrawGrid", "%d %d %d %d %d %d %d %d %d", sprite->id, dest.x, dest.y, source.x, source.y, source.w, source.h, dest.w, dest.h); return 0; } @@ -15637,11 +16328,7 @@ static int32_t apiSpriteDrawRotatedFrame(lua_State *L) { dest.x -= dest.w / 2; dest.y -= dest.h / 2; if ((dest.w > 0) && (dest.h > 0)) { - if (n == 3) { - SDL_BlitSurface(sprite->rotatedFrame, NULL, _global.overlay, &dest); - } else { - SDL_BlitSurfaceScaled(sprite->rotatedFrame, NULL, _global.overlay, &dest, SDL_SCALEMODE_NEAREST); - } + _spriteBlit(sprite, sprite->rotatedFrame, NULL, &dest, n != 3); } _overlayTouched(&dest); _luaTrace(L, "spriteDrawRotatedFrame", "%d %d %d %d %d", sprite->id, dest.x, dest.y, dest.w, dest.h); @@ -15650,7 +16337,6 @@ static int32_t apiSpriteDrawRotatedFrame(lua_State *L) { } - // spriteFlip(id, horizontal, vertical) Mirrors the sprite: every draw of it, of its frames, and of // its turned frame, until it is called again with false, false. The mirror is applied after the // turn, so a turned frame is just mirrored the other way rather than turned again. @@ -16064,6 +16750,42 @@ static int32_t apiSpriteScale(lua_State *L) { } +// spriteSetAlpha(id, alpha) Multiplies every pixel's alpha by alpha / 255 on every draw of the +// sprite, so it fades with no new image: 255, the default, draws it as it is, 0 not at all. +// Out-of-range values are clamped. +static int32_t apiSpriteSetAlpha(lua_State *L) { + SpriteT *sprite = NULL; + + _argCheck(L, "spriteSetAlpha", 2, 2); + sprite = _argSprite(L, "spriteSetAlpha", 1); + sprite->alpha = (uint8_t)SDL_clamp(_argInteger(L, "spriteSetAlpha", 2), 0, 255); + _luaTrace(L, "spriteSetAlpha", "%d %d", sprite->id, sprite->alpha); + + return 0; +} + + +// spriteSetBlend(id, SPRITE_ALPHA | SPRITE_ADD | SPRITE_MULTIPLY) How every draw of the sprite +// lays it over the overlay: over what is there by its alpha (the default), added to what is there, +// or darkening what is there by its colour. Additive and multiplied pixels keep the overlay's own +// alpha, so they show where the overlay already has something drawn. +static int32_t apiSpriteSetBlend(lua_State *L) { + SpriteT *sprite = NULL; + int32_t blend = 0; + + _argCheck(L, "spriteSetBlend", 2, 2); + sprite = _argSprite(L, "spriteSetBlend", 1); + blend = _argInteger(L, "spriteSetBlend", 2); + if ((blend != SPRITE_ALPHA) && (blend != SPRITE_ADD) && (blend != SPRITE_MULTIPLY)) { + _luaDie(L, "spriteSetBlend", "Blend must be SPRITE_ALPHA, SPRITE_ADD, or SPRITE_MULTIPLY."); + } + sprite->blend = (SpriteBlendE)blend; + _luaTrace(L, "spriteSetBlend", "%d %d", sprite->id, blend); + + return 0; +} + + // spriteSetFrame(id, frame) Ignored for still images and out of range frames. static int32_t apiSpriteSetFrame(lua_State *L) { SpriteT *sprite = NULL; @@ -16084,6 +16806,23 @@ static int32_t apiSpriteSetFrame(lua_State *L) { } +// spriteSetTint(id, r, g, b) Multiplies every pixel's colour by r, g, b / 255 on every draw of the +// sprite: a white sprite drawn in any colour, or any sprite darkened or shifted, with no new image. +// 255, 255, 255, the default, draws it as it is. Out-of-range values are clamped. +static int32_t apiSpriteSetTint(lua_State *L) { + SpriteT *sprite = NULL; + + _argCheck(L, "spriteSetTint", 4, 4); + sprite = _argSprite(L, "spriteSetTint", 1); + sprite->tintR = (uint8_t)SDL_clamp(_argInteger(L, "spriteSetTint", 2), 0, 255); + sprite->tintG = (uint8_t)SDL_clamp(_argInteger(L, "spriteSetTint", 3), 0, 255); + sprite->tintB = (uint8_t)SDL_clamp(_argInteger(L, "spriteSetTint", 4), 0, 255); + _luaTrace(L, "spriteSetTint", "%d %d %d %d", sprite->id, sprite->tintR, sprite->tintG, sprite->tintB); + + return 0; +} + + // spriteUnload(id) static int32_t apiSpriteUnload(lua_State *L) { SpriteT *sprite = NULL; @@ -17345,6 +18084,87 @@ static int32_t apiVldpSetVerbose(lua_State *L) { } +// voiceFree(handle) Releases an Opus encoder or decoder, a voice processor, or a jitter buffer. All of +// them are released when the game ends. +static int32_t apiVoiceFree(lua_State *L) { + int32_t handle = 0; + + _argCheck(L, "voiceFree", 1, 1); + handle = _argHandle(L, "voiceFree", 1, _voiceIsAny, "voice handle"); + voiceFree(handle); + _luaTrace(L, "voiceFree", "%d", handle); + + return 0; +} + + +// cleaned, voiced = voiceProcess(processor, mic [, speaker]) One frame of the microphone with the echo +// of what the speakers played taken out, noise suppressed, and the level evened, and whether it is a +// voice. mic and speaker are the processor's frame of 16-bit samples each. +static int32_t apiVoiceProcess(lua_State *L) { + int16_t mic[VOICE_FRAME_MAX]; + int16_t speaker[VOICE_FRAME_MAX]; + const char *data = NULL; + size_t bytes = 0; + int32_t handle = 0; + size_t frame = 0; + bool heard = false; + bool voiced = false; + + _argCheck(L, "voiceProcess", 2, 3); + handle = _argHandle(L, "voiceProcess", 1, _voiceIsProcessor, "voice processor"); + frame = (size_t)voiceFrame(handle) * sizeof(int16_t); + data = _argData(L, "voiceProcess", 2, &bytes); + if (bytes != frame) { + _luaDie(L, "voiceProcess", "The microphone frame must be %d bytes: %d", (int32_t)frame, (int32_t)bytes); + } + memcpy(mic, data, frame); + if ((lua_gettop(L) >= 3) && !lua_isnil(L, 3)) { + data = _argData(L, "voiceProcess", 3, &bytes); + if (bytes != frame) { + _luaDie(L, "voiceProcess", "The speaker frame must be %d bytes: %d", (int32_t)frame, (int32_t)bytes); + } + memcpy(speaker, data, frame); + heard = true; + } + voiceProcess(handle, mic, heard ? speaker : NULL, &voiced); + lua_pushlstring(L, (const char *)mic, frame); + lua_pushboolean(L, voiced); + + return 2; +} + + +// processor = voiceProcessorNew([frame [, rate [, tailMs]]]) Echo cancellation, noise suppression, +// gain, and voice detection for frames of 960 samples at 48000, against echoes up to 200 ms, unless +// given. +static int32_t apiVoiceProcessorNew(lua_State *L) { + int32_t frame = VOICE_DEFAULT_FRAME; + int32_t rate = MIC_RATE; + int32_t tailMs = VOICE_DEFAULT_TAIL_MS; + int32_t handle = 0; + + _argCheck(L, "voiceProcessorNew", 0, 3); + if (lua_gettop(L) >= 1) { + frame = _argInteger(L, "voiceProcessorNew", 1); + } + if (lua_gettop(L) >= 2) { + rate = _argInteger(L, "voiceProcessorNew", 2); + } + if (lua_gettop(L) >= 3) { + tailMs = _argInteger(L, "voiceProcessorNew", 3); + } + handle = voiceProcessorNew(frame, rate, tailMs); + if (handle < 0) { + _luaDie(L, "voiceProcessorNew", "%s (frame %d, rate %d, tail %d ms)", voiceError(handle), frame, rate, tailMs); + } + _luaTrace(L, "voiceProcessorNew", "%d frame %d at %d, tail %d ms", handle, frame, rate, tailMs); + lua_pushinteger(L, handle); + + return 1; +} + + // ===== Engine entry point ===== @@ -18151,6 +18971,12 @@ void singe(SDL_Window *window, SDL_Renderer *renderer, SDL_GPUDevice *device, Co // drawing: a game that never redraws still has to be given its messages. midiIoPoll(_midiReceived, NULL); + // The microphone's recording written and its calibration stepped; a calibration that has + // just finished is kept for the machine, beside the audio calibration. + if (micUpdate()) { + _saveMachineSettings(videoGetAudioCalibration()); + } + // Timers and tweens, for the same reason. schedulerUpdate(utilTicks(), _scheduleFired, NULL); @@ -18211,6 +19037,9 @@ void singe(SDL_Window *window, SDL_Renderer *renderer, SDL_GPUDevice *device, Co stageStartNS = SDL_GetTicksNS(); _perfCalls.inScript = true; if (!_global.frozen && (utilTicks() >= frameClock)) { + // The next call is due a tick after this one began, so a script's own work is inside the + // tick rather than added to it; after a stall it is due a tick from now, not at once. + frameClock = (utilTicks() >= frameClock + FRAME_TICK_MS) ? utilTicks() + FRAME_TICK_MS : frameClock + FRAME_TICK_MS; intReturn = OVERLAY_NOT_UPDATED; _global.guiDrawCount = 0; _global.overlayLayerCount = 0; @@ -18220,7 +19049,6 @@ void singe(SDL_Window *window, SDL_Renderer *renderer, SDL_GPUDevice *device, Co if (intReturn == OVERLAY_UPDATED) { _global.refreshDisplay = true; } - frameClock = utilTicks() + FRAME_TICK_MS; // Don't eat all the CPU. // Clear per-frame values. _global.keyboardLastDown = SDL_SCANCODE_UNKNOWN; _global.keyboardLastUp = SDL_SCANCODE_UNKNOWN; diff --git a/src/vfs.c b/src/vfs.c index 2b847663f..b2ee90d52 100644 --- a/src/vfs.c +++ b/src/vfs.c @@ -136,9 +136,65 @@ static char *_overlayFor(const char *dataDirBase, const char *dataDir, con static uint8_t *_readAsset(DatabaseT *db, const char *key, size_t *bytes, bool sdlMemory); static bool _readChunk(DatabaseT *db, const char *key, int64_t index, uint8_t *buffer, int64_t capacity, int64_t *length); static bool _resolve(const char *name, TargetT *target); +static int _sqliteAccess(sqlite3_vfs *vfs, const char *name, int flags, int *result); +static int _sqliteCheckReservedLock(sqlite3_file *file, int *result); +static int _sqliteClose(sqlite3_file *file); +static int _sqliteCurrentTime(sqlite3_vfs *vfs, double *now); +static int _sqliteDeviceCharacteristics(sqlite3_file *file); +static void _sqliteDlClose(sqlite3_vfs *vfs, void *handle); +static void _sqliteDlError(sqlite3_vfs *vfs, int bytes, char *out); +static void *_sqliteDlOpen(sqlite3_vfs *vfs, const char *name); +static void (*_sqliteDlSym(sqlite3_vfs *vfs, void *handle, const char *symbol))(void); +static int _sqliteFileControl(sqlite3_file *file, int op, void *arg); +static int _sqliteFileSize(sqlite3_file *file, sqlite3_int64 *size); +static int _sqliteFullPathname(sqlite3_vfs *vfs, const char *name, int bytes, char *out); +static int _sqliteGetLastError(sqlite3_vfs *vfs, int bytes, char *out); +static int _sqliteLock(sqlite3_file *file, int level); +static int _sqliteOpen(sqlite3_vfs *vfs, sqlite3_filename name, sqlite3_file *file, int flags, int *outFlags); +static int _sqliteRandomness(sqlite3_vfs *vfs, int bytes, char *out); +static int _sqliteRead(sqlite3_file *file, void *buffer, int amount, sqlite3_int64 offset); +static int _sqliteSectorSize(sqlite3_file *file); +static int _sqliteSleep(sqlite3_vfs *vfs, int microseconds); +static int _sqliteSync(sqlite3_file *file, int flags); +static int _sqliteTruncate(sqlite3_file *file, sqlite3_int64 size); +static int _sqliteUnlock(sqlite3_file *file, int level); +static int _sqliteWrite(sqlite3_file *file, const void *buffer, int amount, sqlite3_int64 offset); static void _targetFree(TargetT *target); +static char *_uriEncode(const char *text); +// A database packed inside the game, opened by a script through sqlite3.open, is read where it lies +// through this read-only SQLite VFS: each file is a VfsStreamT over the packed asset. Registered +// the first time a script asks (vfsSqliteUri); what it does not do itself goes to the default VFS. +#define VFS_SQLITE_NAME "singePacked" +#define VFS_SQLITE_SECTOR_BYTES 4096 +#define VFS_EXTRACT_BYTES (1024 * 1024) + +typedef struct PackedFileS { + sqlite3_file base; // SQLite's part, first, as a VFS file must begin + VfsStreamT *stream; +} PackedFileT; + +static const sqlite3_io_methods _sqliteFileMethods = { + 1, + _sqliteClose, + _sqliteRead, + _sqliteWrite, + _sqliteTruncate, + _sqliteSync, + _sqliteFileSize, + _sqliteLock, + _sqliteUnlock, + _sqliteCheckReservedLock, + _sqliteFileControl, + _sqliteSectorSize, + _sqliteDeviceCharacteristics, + NULL, NULL, NULL, NULL, NULL, NULL +}; + +static sqlite3_vfs _sqliteVfs; +static sqlite3_vfs *_sqliteDefault = NULL; + static DatabaseT *_databases = NULL; static DatabaseT *_container = NULL; static char *_dataDirBase = NULL; @@ -253,8 +309,6 @@ static DatabaseT *_databaseOpen(const char *path) { char *value = NULL; char *encoded = NULL; char *stem = NULL; - size_t i = 0; - size_t o = 0; int64_t version = 0; for (db = _databases; db != NULL; db = db->next) { @@ -266,20 +320,8 @@ static DatabaseT *_databaseOpen(const char *path) { return NULL; } - // Percent-encode the three characters a URI would misread. - encoded = (char *)calloc(strlen(path) * 3 + 1, 1); - if (encoded == NULL) { - utilDie("Out of memory opening %s.", path); - } - for (i = 0; path[i] != 0; i++) { - if ((path[i] == '?') || (path[i] == '#') || (path[i] == '%')) { - sprintf(encoded + o, "%%%02X", (unsigned char)path[i]); - o += 3; - } else { - encoded[o++] = path[i]; - } - } - uri = utilCreateString("file:%s?immutable=1", encoded); + encoded = _uriEncode(path); + uri = utilCreateString("file:%s?immutable=1", encoded); free(encoded); db = (DatabaseT *)calloc(1, sizeof(DatabaseT)); @@ -755,6 +797,197 @@ static bool _resolve(const char *name, TargetT *target) { } +// The packed-database VFS (see _sqliteVfs). Nothing is ever written, so there is never a journal +// to look for. +static int _sqliteAccess(sqlite3_vfs *vfs, const char *name, int flags, int *result) { + (void)vfs; + (void)name; + (void)flags; + *result = 0; + return SQLITE_OK; +} + + +static int _sqliteCheckReservedLock(sqlite3_file *file, int *result) { + (void)file; + *result = 0; + return SQLITE_OK; +} + + +static int _sqliteClose(sqlite3_file *file) { + PackedFileT *packed = (PackedFileT *)file; + + vfsStreamClose(packed->stream); + packed->stream = NULL; + return SQLITE_OK; +} + + +static int _sqliteCurrentTime(sqlite3_vfs *vfs, double *now) { + (void)vfs; + return _sqliteDefault->xCurrentTime(_sqliteDefault, now); +} + + +static int _sqliteDeviceCharacteristics(sqlite3_file *file) { + (void)file; + return SQLITE_IOCAP_IMMUTABLE; +} + + +// Loading an extension works as it would on any other database: the default VFS does it. +static void _sqliteDlClose(sqlite3_vfs *vfs, void *handle) { + (void)vfs; + _sqliteDefault->xDlClose(_sqliteDefault, handle); +} + + +static void _sqliteDlError(sqlite3_vfs *vfs, int bytes, char *out) { + (void)vfs; + _sqliteDefault->xDlError(_sqliteDefault, bytes, out); +} + + +static void *_sqliteDlOpen(sqlite3_vfs *vfs, const char *name) { + (void)vfs; + return _sqliteDefault->xDlOpen(_sqliteDefault, name); +} + + +static void (*_sqliteDlSym(sqlite3_vfs *vfs, void *handle, const char *symbol))(void) { + (void)vfs; + return _sqliteDefault->xDlSym(_sqliteDefault, handle, symbol); +} + + +static int _sqliteFileControl(sqlite3_file *file, int op, void *arg) { + (void)file; + (void)op; + (void)arg; + return SQLITE_NOTFOUND; +} + + +static int _sqliteFileSize(sqlite3_file *file, sqlite3_int64 *size) { + *size = vfsStreamSize(((PackedFileT *)file)->stream); + return SQLITE_OK; +} + + +// The name is the game's own name for the file, not a path on disk, and is kept as it was given. +static int _sqliteFullPathname(sqlite3_vfs *vfs, const char *name, int bytes, char *out) { + (void)vfs; + if ((int)strlen(name) >= bytes) { + return SQLITE_CANTOPEN; + } + strcpy(out, name); + return SQLITE_OK; +} + + +static int _sqliteGetLastError(sqlite3_vfs *vfs, int bytes, char *out) { + (void)vfs; + return _sqliteDefault->xGetLastError(_sqliteDefault, bytes, out); +} + + +static int _sqliteLock(sqlite3_file *file, int level) { + (void)file; + (void)level; + return SQLITE_OK; +} + + +// Only the main database is opened, and always read only: a packed file cannot be changed. +static int _sqliteOpen(sqlite3_vfs *vfs, sqlite3_filename name, sqlite3_file *file, int flags, int *outFlags) { + PackedFileT *packed = (PackedFileT *)file; + + (void)vfs; + packed->base.pMethods = NULL; + if ((name == NULL) || ((flags & SQLITE_OPEN_MAIN_DB) == 0)) { + return SQLITE_CANTOPEN; + } + packed->stream = vfsStreamOpen(name); + if (packed->stream == NULL) { + return SQLITE_CANTOPEN; + } + packed->base.pMethods = &_sqliteFileMethods; + if (outFlags != NULL) { + *outFlags = SQLITE_OPEN_READONLY; + } + return SQLITE_OK; +} + + +static int _sqliteRandomness(sqlite3_vfs *vfs, int bytes, char *out) { + (void)vfs; + return _sqliteDefault->xRandomness(_sqliteDefault, bytes, out); +} + + +// A read that runs past the end comes back short and zero filled, which is how SQLite expects a +// file to answer it. +static int _sqliteRead(sqlite3_file *file, void *buffer, int amount, sqlite3_int64 offset) { + VfsStreamT *stream = ((PackedFileT *)file)->stream; + int64_t got = 0; + + if (offset < vfsStreamSize(stream)) { + if (vfsStreamSeek(stream, offset, SEEK_SET) < 0) { + return SQLITE_IOERR_READ; + } + got = vfsStreamRead(stream, buffer, amount); + } + if (got < amount) { + memset((uint8_t *)buffer + got, 0, (size_t)(amount - got)); + return SQLITE_IOERR_SHORT_READ; + } + return SQLITE_OK; +} + + +static int _sqliteSectorSize(sqlite3_file *file) { + (void)file; + return VFS_SQLITE_SECTOR_BYTES; +} + + +static int _sqliteSleep(sqlite3_vfs *vfs, int microseconds) { + (void)vfs; + return _sqliteDefault->xSleep(_sqliteDefault, microseconds); +} + + +static int _sqliteSync(sqlite3_file *file, int flags) { + (void)file; + (void)flags; + return SQLITE_OK; +} + + +static int _sqliteTruncate(sqlite3_file *file, sqlite3_int64 size) { + (void)file; + (void)size; + return SQLITE_READONLY; +} + + +static int _sqliteUnlock(sqlite3_file *file, int level) { + (void)file; + (void)level; + return SQLITE_OK; +} + + +static int _sqliteWrite(sqlite3_file *file, const void *buffer, int amount, sqlite3_int64 offset) { + (void)file; + (void)buffer; + (void)amount; + (void)offset; + return SQLITE_READONLY; +} + + static void _targetFree(TargetT *target) { free(target->path); free(target->key); @@ -763,6 +996,29 @@ static void _targetFree(TargetT *target) { } +// Percent-encodes the three characters a SQLite URI would misread. Free the result. +static char *_uriEncode(const char *text) { + char *encoded = NULL; + size_t i = 0; + size_t o = 0; + + encoded = (char *)calloc(strlen(text) * 3 + 1, 1); + if (encoded == NULL) { + utilDie("Out of memory encoding %s.", text); + } + for (i = 0; text[i] != 0; i++) { + if ((text[i] == '?') || (text[i] == '#') || (text[i] == '%')) { + sprintf(encoded + o, "%%%02X", (unsigned char)text[i]); + o += 3; + } else { + encoded[o++] = text[i]; + } + } + + return encoded; +} + + // The path without its database extension, as a new string; unchanged when it has none. char *vfsDatabaseStem(const char *path) { if (_hasDatabaseExtension(path)) { @@ -798,6 +1054,44 @@ bool vfsExists(const char *name) { // anything could read a database row as a stream; everything can now -- vfsStreamOpen and // vfsOpenIO, and the Lua file object built on the first of them -- so a packed name being read // yields the loose candidate, which fails to open like any missing file. Ask for a stream instead. +// Copies a file the game names -- packed or not -- to path on disk, through a temporary name so an +// interrupted copy never leaves a partial file where path is. True when the whole file was written. +bool vfsExtract(const char *name, const char *path) { + VfsStreamT *stream = NULL; + FILE *out = NULL; + uint8_t *buffer = NULL; + char *temporary = NULL; + int64_t got = 0; + int64_t total = 0; + bool good = false; + + stream = vfsStreamOpen(name); + if (stream == NULL) { + return false; + } + temporary = utilCreateString("%s.part", path); + buffer = (uint8_t *)malloc(VFS_EXTRACT_BYTES); + out = (buffer != NULL) ? fopen(temporary, "wb") : NULL; + if (out != NULL) { + good = true; + while (good && ((got = vfsStreamRead(stream, buffer, VFS_EXTRACT_BYTES)) > 0)) { + good = (fwrite(buffer, 1, (size_t)got, out) == (size_t)got); + total += got; + } + good = (fclose(out) == 0) && good && (total == vfsStreamSize(stream)); + good = good && (remove(path) == 0 || !utilFileExists(path)) && (rename(temporary, path) == 0); + if (!good) { + remove(temporary); + } + } + free(buffer); + free(temporary); + vfsStreamClose(stream); + + return good; +} + + char *vfsFilePath(const char *name, bool forWriting) { TargetT target; char *path = NULL; @@ -1062,6 +1356,41 @@ char *vfsReadMeta(struct sqlite3 *db, const char *schema, const char *key) { // Size and modification time, the latter being the database's own for a packed asset. +// The SQLite URI that opens a database packed inside the game where it lies, read only: give it to +// sqlite3_open_v2 with SQLITE_OPEN_READONLY | SQLITE_OPEN_URI. Registers the VFS that reads it the +// first time. Free the result. +char *vfsSqliteUri(const char *name) { + char *encoded = NULL; + char *uri = NULL; + + if (_sqliteDefault == NULL) { + _sqliteDefault = sqlite3_vfs_find(NULL); + memset(&_sqliteVfs, 0, sizeof(_sqliteVfs)); + _sqliteVfs.iVersion = 1; + _sqliteVfs.szOsFile = (int)sizeof(PackedFileT); + _sqliteVfs.mxPathname = _sqliteDefault->mxPathname; + _sqliteVfs.zName = VFS_SQLITE_NAME; + _sqliteVfs.xOpen = _sqliteOpen; + _sqliteVfs.xAccess = _sqliteAccess; + _sqliteVfs.xFullPathname = _sqliteFullPathname; + _sqliteVfs.xDlOpen = _sqliteDlOpen; + _sqliteVfs.xDlError = _sqliteDlError; + _sqliteVfs.xDlSym = _sqliteDlSym; + _sqliteVfs.xDlClose = _sqliteDlClose; + _sqliteVfs.xRandomness = _sqliteRandomness; + _sqliteVfs.xSleep = _sqliteSleep; + _sqliteVfs.xCurrentTime = _sqliteCurrentTime; + _sqliteVfs.xGetLastError = _sqliteGetLastError; + sqlite3_vfs_register(&_sqliteVfs, 0); + } + encoded = _uriEncode(name); + uri = utilCreateString("file:%s?vfs=%s&immutable=1", encoded, VFS_SQLITE_NAME); + free(encoded); + + return uri; +} + + bool vfsStat(const char *name, int64_t *size, int64_t *modified) { TargetT target; bool found = false; diff --git a/src/vfs.h b/src/vfs.h index 2a2603f0c..963ea4e23 100644 --- a/src/vfs.h +++ b/src/vfs.h @@ -63,6 +63,7 @@ typedef struct VfsStreamS VfsStreamT; char *vfsDatabaseStem(const char *path); bool vfsExists(const char *name); +bool vfsExtract(const char *name, const char *path); char *vfsFilePath(const char *name, bool forWriting); void vfsInit(const char *container, const char *dataDirBase, const char *dataDir); bool vfsIsDatabase(const char *path); @@ -75,6 +76,7 @@ SDL_IOStream *vfsOpenIO(const char *name); void vfsQuit(void); char *vfsRead(const char *name, size_t *bytes); // Whole file, NUL terminated, in malloc memory: free() it, not SDL_free() char *vfsReadMeta(struct sqlite3 *db, const char *schema, const char *key); +char *vfsSqliteUri(const char *name); // Read-only URI for a database packed in the game: free() it bool vfsStat(const char *name, int64_t *size, int64_t *modified); void vfsStreamClose(VfsStreamT *stream); VfsStreamT *vfsStreamOpen(const char *name); diff --git a/src/voice.c b/src/voice.c new file mode 100644 index 000000000..5d8635728 --- /dev/null +++ b/src/voice.c @@ -0,0 +1,381 @@ +/* + * + * Singe 3 + * Copyright (C) 2006-2026 Scott Duensing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + + +// Singe: Opus and SpeexDSP behind handles. A handle is an index into one table of objects, each +// marked with its kind; a freed slot is reused. Everything here runs on the engine's thread. + + +#include +#include + +#include +#include +#include +#include + +#include "util.h" +#include "voice.h" + + +#define VOICE_TABLE_GROW 16 + + +typedef struct VoiceObjectS { + VoiceKindE kind; // 0 for a free slot + OpusEncoder *encoder; + OpusDecoder *decoder; + SpeexEchoState *echo; + SpeexPreprocessState *preprocess; + JitterBuffer *jitter; + int16_t *cleaned; // The echo canceller's output, a frame long + int16_t *silence; // The speaker reference when nothing was played + int32_t frame; // A processor's frame, or a jitter buffer's step + int32_t channels; +} VoiceObjectT; + + +static VoiceObjectT *_voiceGet(int32_t handle, VoiceKindE kind); +static int32_t _voiceNew(VoiceKindE kind); +static bool _voiceRateValid(int32_t rate); +static void _voiceRelease(VoiceObjectT *object); + + +static VoiceObjectT *_voiceTable = NULL; +static int32_t _voiceCapacity = 0; + + +int32_t voiceChannels(int32_t handle) { + if ((handle < 1) || (handle > _voiceCapacity)) { + return 0; + } + return _voiceTable[handle - 1].channels; +} + + +int32_t voiceDecode(int32_t handle, const uint8_t *packet, int32_t bytes, int16_t *out, int32_t maxSamples) { + VoiceObjectT *object = _voiceGet(handle, VOICE_KIND_DECODER); + opus_int32 samples = 0; + + if (object == NULL) { + return OPUS_BAD_ARG; + } + if (packet == NULL) { + // Concealment fills exactly the length it is given, so it is given one packet's worth: the + // last one heard, or a usual voice frame before any has been. + opus_decoder_ctl(object->decoder, OPUS_GET_LAST_PACKET_DURATION(&samples)); + if (samples <= 0) { + opus_decoder_ctl(object->decoder, OPUS_GET_SAMPLE_RATE(&samples)); + samples = samples * VOICE_DEFAULT_FRAME_MS / 1000; + } + return opus_decode(object->decoder, NULL, 0, out, (samples < maxSamples) ? samples : maxSamples, 0); + } + return opus_decode(object->decoder, packet, bytes, out, maxSamples, 0); +} + + +int32_t voiceDecoderNew(int32_t rate, int32_t channels) { + VoiceObjectT *object = NULL; + int32_t handle = 0; + int error = OPUS_OK; + + if (!_voiceRateValid(rate) || (channels < 1) || (channels > 2)) { + return OPUS_BAD_ARG; + } + handle = _voiceNew(VOICE_KIND_DECODER); + object = &_voiceTable[handle - 1]; + object->decoder = opus_decoder_create(rate, channels, &error); + if (object->decoder == NULL) { + _voiceRelease(object); + return (error != OPUS_OK) ? error : OPUS_ALLOC_FAIL; + } + object->channels = channels; + + return handle; +} + + +int32_t voiceEncode(int32_t handle, const int16_t *pcm, int32_t samples, uint8_t *packet, int32_t maxBytes) { + VoiceObjectT *object = _voiceGet(handle, VOICE_KIND_ENCODER); + + if (object == NULL) { + return OPUS_BAD_ARG; + } + return opus_encode(object->encoder, pcm, samples, packet, maxBytes); +} + + +int32_t voiceEncoderNew(int32_t rate, int32_t channels, VoiceApplicationE application) { + static const int32_t applications[] = { OPUS_APPLICATION_VOIP, OPUS_APPLICATION_AUDIO, OPUS_APPLICATION_RESTRICTED_LOWDELAY }; + VoiceObjectT *object = NULL; + int32_t handle = 0; + int error = OPUS_OK; + + if (!_voiceRateValid(rate) || (channels < 1) || (channels > 2) || ((int32_t)application < 0) || ((int32_t)application > VOICE_APPLICATION_LOW)) { + return OPUS_BAD_ARG; + } + handle = _voiceNew(VOICE_KIND_ENCODER); + object = &_voiceTable[handle - 1]; + object->encoder = opus_encoder_create(rate, channels, applications[application], &error); + if (object->encoder == NULL) { + _voiceRelease(object); + return (error != OPUS_OK) ? error : OPUS_ALLOC_FAIL; + } + object->channels = channels; + + return handle; +} + + +// bitrate in bits a second (0 leaves it), complexity 0 to 10 (negative leaves it). +bool voiceEncoderSet(int32_t handle, int32_t bitrate, int32_t complexity) { + VoiceObjectT *object = _voiceGet(handle, VOICE_KIND_ENCODER); + + if (object == NULL) { + return false; + } + if ((bitrate > 0) && (opus_encoder_ctl(object->encoder, OPUS_SET_BITRATE(bitrate)) != OPUS_OK)) { + return false; + } + if ((complexity >= 0) && (opus_encoder_ctl(object->encoder, OPUS_SET_COMPLEXITY(complexity)) != OPUS_OK)) { + return false; + } + return true; +} + + +const char *voiceError(int32_t code) { + return opus_strerror(code); +} + + +int32_t voiceFrame(int32_t handle) { + if ((handle < 1) || (handle > _voiceCapacity)) { + return 0; + } + return _voiceTable[handle - 1].frame; +} + + +bool voiceFree(int32_t handle) { + if ((handle < 1) || (handle > _voiceCapacity) || (_voiceTable[handle - 1].kind == 0)) { + return false; + } + _voiceRelease(&_voiceTable[handle - 1]); + + return true; +} + + +// Everything a script made, when the script goes. +void voiceFreeAll(void) { + int32_t i = 0; + + for (i = 0; i < _voiceCapacity; i++) { + if (_voiceTable[i].kind != 0) { + _voiceRelease(&_voiceTable[i]); + } + } + free(_voiceTable); + _voiceTable = NULL; + _voiceCapacity = 0; +} + + +static VoiceObjectT *_voiceGet(int32_t handle, VoiceKindE kind) { + if ((handle < 1) || (handle > _voiceCapacity) || (_voiceTable[handle - 1].kind != kind)) { + return NULL; + } + return &_voiceTable[handle - 1]; +} + + +int32_t voiceJitterGet(int32_t handle, uint8_t *packet, int32_t maxBytes, int32_t span, VoiceJitterE *status) { + VoiceObjectT *object = _voiceGet(handle, VOICE_KIND_JITTER); + JitterBufferPacket out; + int result = 0; + + *status = VOICE_JITTER_MISSING; + if (object == NULL) { + return 0; + } + memset(&out, 0, sizeof(out)); + out.data = (char *)packet; + out.len = (spx_uint32_t)maxBytes; + result = jitter_buffer_get(object->jitter, &out, span, NULL); + jitter_buffer_tick(object->jitter); + if (result == JITTER_BUFFER_OK) { + *status = VOICE_JITTER_OK; + return (int32_t)out.len; + } + if (result == JITTER_BUFFER_INSERTION) { + *status = VOICE_JITTER_INSERTION; + } + return 0; +} + + +// step is the span the buffer moves by each get, in the same units as the packets' timestamps. +int32_t voiceJitterNew(int32_t step) { + VoiceObjectT *object = NULL; + int32_t handle = 0; + + if (step < 1) { + return OPUS_BAD_ARG; + } + handle = _voiceNew(VOICE_KIND_JITTER); + object = &_voiceTable[handle - 1]; + object->frame = step; + object->jitter = jitter_buffer_init(step); + if (object->jitter == NULL) { + _voiceRelease(object); + return OPUS_ALLOC_FAIL; + } + + return handle; +} + + +bool voiceJitterPut(int32_t handle, const uint8_t *packet, int32_t bytes, int32_t timestamp, int32_t span) { + VoiceObjectT *object = _voiceGet(handle, VOICE_KIND_JITTER); + JitterBufferPacket in; + + if ((object == NULL) || (bytes <= 0)) { + return false; + } + memset(&in, 0, sizeof(in)); + // The buffer keeps its own copy, so the packet may be reused once this returns. + in.data = (char *)packet; + in.len = (spx_uint32_t)bytes; + in.timestamp = (spx_uint32_t)timestamp; + in.span = (spx_uint32_t)span; + jitter_buffer_put(object->jitter, &in); + + return true; +} + + +bool voiceKind(int32_t handle, VoiceKindE kind) { + return (_voiceGet(handle, kind) != NULL); +} + + +// A free slot, or a new one at the end, marked with its kind. Returns its handle. +static int32_t _voiceNew(VoiceKindE kind) { + VoiceObjectT *grown = NULL; + int32_t i = 0; + + for (i = 0; i < _voiceCapacity; i++) { + if (_voiceTable[i].kind == 0) { + break; + } + } + if (i == _voiceCapacity) { + grown = (VoiceObjectT *)realloc(_voiceTable, (size_t)(_voiceCapacity + VOICE_TABLE_GROW) * sizeof(VoiceObjectT)); + if (grown == NULL) { + utilDie("Out of memory making a voice object."); + } + memset(grown + _voiceCapacity, 0, VOICE_TABLE_GROW * sizeof(VoiceObjectT)); + _voiceTable = grown; + _voiceCapacity += VOICE_TABLE_GROW; + } + _voiceTable[i].kind = kind; + + return i + 1; +} + + +bool voiceProcess(int32_t handle, int16_t *mic, const int16_t *speaker, bool *voiced) { + VoiceObjectT *object = _voiceGet(handle, VOICE_KIND_PROCESSOR); + + *voiced = false; + if (object == NULL) { + return false; + } + // The canceller always runs, on silence when nothing was played, so it keeps tracking the room + // and the preprocessor's residual echo estimate stays meaningful. + speex_echo_cancellation(object->echo, mic, (speaker != NULL) ? speaker : object->silence, object->cleaned); + memcpy(mic, object->cleaned, (size_t)object->frame * sizeof(int16_t)); + *voiced = (speex_preprocess_run(object->preprocess, mic) != 0); + + return true; +} + + +// frame samples a call (10 to 20 ms is usual: 480 to 960 at 48 kHz), at rate, cancelling echoes up to +// tailMs long (100 to 200 for a room). +int32_t voiceProcessorNew(int32_t frame, int32_t rate, int32_t tailMs) { + VoiceObjectT *object = NULL; + int32_t handle = 0; + int on = 1; + int sample = rate; + + if ((frame < 1) || (frame > VOICE_FRAME_MAX) || !_voiceRateValid(rate) || (tailMs < 1)) { + return OPUS_BAD_ARG; + } + handle = _voiceNew(VOICE_KIND_PROCESSOR); + object = &_voiceTable[handle - 1]; + object->frame = frame; + object->echo = speex_echo_state_init(frame, rate * tailMs / 1000); + object->preprocess = speex_preprocess_state_init(frame, rate); + object->cleaned = (int16_t *)calloc((size_t)frame, sizeof(int16_t)); + object->silence = (int16_t *)calloc((size_t)frame, sizeof(int16_t)); + if ((object->echo == NULL) || (object->preprocess == NULL) || (object->cleaned == NULL) || (object->silence == NULL)) { + _voiceRelease(object); + return OPUS_ALLOC_FAIL; + } + speex_echo_ctl(object->echo, SPEEX_ECHO_SET_SAMPLING_RATE, &sample); + speex_preprocess_ctl(object->preprocess, SPEEX_PREPROCESS_SET_DENOISE, &on); + speex_preprocess_ctl(object->preprocess, SPEEX_PREPROCESS_SET_AGC, &on); + speex_preprocess_ctl(object->preprocess, SPEEX_PREPROCESS_SET_VAD, &on); + speex_preprocess_ctl(object->preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE, object->echo); + + return handle; +} + + +// The rates Opus and the processor both take. +static bool _voiceRateValid(int32_t rate) { + return (rate == 8000) || (rate == 12000) || (rate == 16000) || (rate == 24000) || (rate == 48000); +} + + +static void _voiceRelease(VoiceObjectT *object) { + if (object->encoder != NULL) { + opus_encoder_destroy(object->encoder); + } + if (object->decoder != NULL) { + opus_decoder_destroy(object->decoder); + } + if (object->preprocess != NULL) { + speex_preprocess_state_destroy(object->preprocess); + } + if (object->echo != NULL) { + speex_echo_state_destroy(object->echo); + } + if (object->jitter != NULL) { + jitter_buffer_destroy(object->jitter); + } + free(object->cleaned); + free(object->silence); + memset(object, 0, sizeof(VoiceObjectT)); +} diff --git a/src/voice.h b/src/voice.h new file mode 100644 index 000000000..dc2045935 --- /dev/null +++ b/src/voice.h @@ -0,0 +1,103 @@ +/* + * + * Singe 3 + * Copyright (C) 2006-2026 Scott Duensing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + + +#ifndef VOICE_H +#define VOICE_H + + +#include +#include + + +// The pieces a voice chat stands on, without the network (PLAN.md section 62): an Opus encoder and +// decoder, a voice processor (SpeexDSP's echo cancellation, noise suppression, gain, and voice +// activity), and a jitter buffer. Each lives behind a handle; every call names the kind it wants, +// so a handle of another kind is refused rather than used. + +#define VOICE_PACKET_MAX 4000 // Opus's own ceiling for one packet +#define VOICE_FRAME_MAX 5760 // 120 ms at 48 kHz, the longest frame Opus takes +#define VOICE_DEFAULT_FRAME_MS 20 // The usual voice frame... +#define VOICE_DEFAULT_FRAME 960 // ...in samples at 48 kHz +#define VOICE_DEFAULT_TAIL_MS 200 // The longest echo a room is expected to have + +typedef enum VoiceKindE { + VOICE_KIND_ENCODER = 1, + VOICE_KIND_DECODER = 2, + VOICE_KIND_PROCESSOR = 3, + VOICE_KIND_JITTER = 4 +} VoiceKindE; + +typedef enum VoiceApplicationE { + VOICE_APPLICATION_VOIP = 0, // Speech, tuned for intelligibility + VOICE_APPLICATION_AUDIO = 1, // Music and anything else + VOICE_APPLICATION_LOW = 2 // Lowest delay, at some cost in quality +} VoiceApplicationE; + +typedef enum VoiceJitterE { + VOICE_JITTER_OK = 0, // A packet came out + VOICE_JITTER_MISSING = 1, // None due: conceal the gap + VOICE_JITTER_INSERTION = 2 // The buffer is growing: play a little silence +} VoiceJitterE; + + +// An encoder's or decoder's channels, 0 for anything else. +int32_t voiceChannels(int32_t handle); + +// Decodes a packet into at most maxSamples samples a channel; a NULL packet asks Opus to conceal a +// lost one, as long as the last packet heard. Returns samples a channel, or negative on failure. +int32_t voiceDecode(int32_t handle, const uint8_t *packet, int32_t bytes, int16_t *out, int32_t maxSamples); +int32_t voiceDecoderNew(int32_t rate, int32_t channels); + +// Encodes one frame -- 2.5, 5, 10, 20, 40, or 60 ms of samples a channel -- into a packet. Returns its +// bytes, or negative on failure. +int32_t voiceEncode(int32_t handle, const int16_t *pcm, int32_t samples, uint8_t *packet, int32_t maxBytes); +int32_t voiceEncoderNew(int32_t rate, int32_t channels, VoiceApplicationE application); +bool voiceEncoderSet(int32_t handle, int32_t bitrate, int32_t complexity); + +// Opus's own words for an error code, or SpeexDSP's handle errors. +const char *voiceError(int32_t code); + +// A processor's frame, or a jitter buffer's step, in samples; 0 for anything else. +int32_t voiceFrame(int32_t handle); + +bool voiceFree(int32_t handle); +void voiceFreeAll(void); + +// A packet into the jitter buffer: its timestamp and its span, in samples. +bool voiceJitterPut(int32_t handle, const uint8_t *packet, int32_t bytes, int32_t timestamp, int32_t span); + +// The packet due for the next span samples, if any, and the buffer moved on by one span. Returns +// its bytes, with the status saying whether one came out at all. +int32_t voiceJitterGet(int32_t handle, uint8_t *packet, int32_t maxBytes, int32_t span, VoiceJitterE *status); +int32_t voiceJitterNew(int32_t step); + +// Whether a handle is live and of that kind. +bool voiceKind(int32_t handle, VoiceKindE kind); + +// One frame of the microphone cleaned in place: the echo of speaker (what was played, NULL when +// nothing was) taken out, then noise suppressed and the level evened. Answers whether it is voice. +bool voiceProcess(int32_t handle, int16_t *mic, const int16_t *speaker, bool *voiced); +int32_t voiceProcessorNew(int32_t frame, int32_t rate, int32_t tailMs); + + +#endif // VOICE_H diff --git a/testScripts/micVoice/micVoice.singe b/testScripts/micVoice/micVoice.singe new file mode 100644 index 000000000..d9c1fa4b3 --- /dev/null +++ b/testScripts/micVoice/micVoice.singe @@ -0,0 +1,218 @@ +-- The microphone and the voice pieces (PLAN.md section 62), with no microphone: SDL's disk audio +-- driver reads its "microphone" from a file, which this script writes first -- two seconds of +-- silence, three of a 220 Hz tone at half scale, three of 440 Hz at quarter scale, and silence after. +-- Run it headless from a scratch directory holding this folder: +-- +-- SDL_AUDIO_DRIVER=disk SDL_AUDIO_DISK_INPUT_FILE=micIn.raw SDL_AUDIO_DISK_OUTPUT_FILE=micOut.raw \ +-- SDL_AUDIO_FORMAT=F32 SDL_AUDIO_FREQUENCY=48000 SDL_AUDIO_CHANNELS=1 SDL_VIDEODRIVER=offscreen \ +-- Singe -w micVoice/micVoice.singe +-- +-- It prints one line: MICTEST pass=N fail=0. Every failure prints what it wanted first. What it +-- cannot prove here, and says so: that a real microphone sounds right, monitoring's delay, and a +-- calibration that succeeds -- nothing plays the disk driver's speaker into its microphone, so the +-- calibration must report that it never heard its clicks. +dofile("Singe/Framework.singe") + +local RATE = 48000 +local FRAME = 960 +local INPUT = os.getenv("SDL_AUDIO_DISK_INPUT_FILE") + +local pass = 0 +local fail = 0 + + +local function check(what, got, want) + if got == want then + pass = pass + 1 + else + fail = fail + 1 + debugPrint(string.format("FAIL %s: got %s, wanted %s", what, tostring(got), tostring(want))) + end +end + + +local function near(what, got, want, within) + check(what .. string.format(" (%.3f, wanted %.3f within %.3f)", got, want, within), math.abs(got - want) <= within, true) +end + + +-- 16-bit samples in a string, as micRead and opusDecode give them, and their RMS from 0 to 1. +local function rmsOf(samples) + local sum = 0 + local count = #samples // 2 + + for i = 1, count do + local value = string.unpack("= 1, true) +check("micOpen", micOpen(), true) +check("micIsOpen", micIsOpen(), true) + +local started = singeGetTicks() +local steps = {} + + +local function at(seconds, fn) + steps[#steps + 1] = { at = seconds * 1000, fn = fn, done = false } +end + + +-- Silence first. +at(1.0, function() + local hz = micPitch() + local rms = micLevel() + + check("no pitch in silence", hz, 0) + check("silence is quiet", rms < 0.01, true) +end) + +-- The 220 Hz stretch: a recording of two seconds, a read of one, and the pitch and level. +at(2.5, function() + check("micRecordStart", micRecordStart("micRecording.wav"), true) + micRead() +end) +at(3.5, function() + local samples = micRead() + local hz, clarity = micPitch() + local rms = micLevel() + + near("one second read", #samples / 2, RATE, RATE * 0.1) + near("the read's level", rmsOf(samples), 0.5 / math.sqrt(2), 0.03) + near("220 Hz found", hz, 220, 1.0) + check("220 Hz is clear", clarity > 0.9, true) + near("220 Hz level", rms, 0.5 / math.sqrt(2), 0.03) + + -- Opus round trip on a frame of it, and the decoded frame's level against the original's. + local frame = samples:sub(1, FRAME * 2) + local encoder = opusEncoderNew(RATE, 1, "audio") + local decoder = opusDecoderNew(RATE, 1) + local decoded = nil + + opusEncoderSet(encoder, 64000, 10) + for _ = 1, 5 do + decoded = opusDecode(decoder, opusEncode(encoder, frame)) + end + check("a decoded frame is a frame", #decoded, FRAME * 2) + near("a decoded frame keeps its level", rmsOf(decoded), rmsOf(frame), rmsOf(frame) * 0.25) + check("a lost packet is concealed to a frame", #opusDecode(decoder, nil), FRAME * 2) + voiceFree(encoder) + voiceFree(decoder) + + -- The voice processor on a run of frames of it. + local processor = voiceProcessorNew(FRAME, RATE, 100) + local cleaned = nil + local voiced = nil + + for i = 0, 40 do + local piece = samples:sub((i % 40) * FRAME * 2 + 1, (i % 40 + 1) * FRAME * 2) + + cleaned, voiced = voiceProcess(processor, piece) + end + check("a processed frame is a frame", #cleaned, FRAME * 2) + check("a processed tone is not silenced", rmsOf(cleaned) > 0, true) + check("voiced is a boolean", type(voiced), "boolean") + voiceFree(processor) +end) +at(4.5, function() + micRecordStop() + local file = io.open(singeGetDataPath() .. "files/micRecording.wav", "rb") or io.open("micRecording.wav", "rb") + local data = file and file:read("a") or "" + + if file then + file:close() + end + check("the recording is a WAV", data:sub(1, 4) .. data:sub(9, 12), "RIFFWAVE") + check("the recording is 48 kHz", #data >= 28 and string.unpack("= step.at then + step.done = true + step.fn() + end + end + return OVERLAY_UPDATED +end diff --git a/testScripts/openRoad/art/arch.png b/testScripts/openRoad/art/arch.png new file mode 100644 index 000000000..0b69f1750 --- /dev/null +++ b/testScripts/openRoad/art/arch.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4ec7dc9877fba5af52d9bce395973323a4d4eec90ef7951af262e2818aa85064 +size 466 diff --git a/testScripts/openRoad/art/bush.png b/testScripts/openRoad/art/bush.png new file mode 100644 index 000000000..8674bfb06 --- /dev/null +++ b/testScripts/openRoad/art/bush.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:365607ab6ec9f36c36ccb624370ba6161c9c37ed3637848df966d893268fdea4 +size 227 diff --git a/testScripts/openRoad/art/car.png b/testScripts/openRoad/art/car.png new file mode 100644 index 000000000..d4d30db15 --- /dev/null +++ b/testScripts/openRoad/art/car.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b7fd6cbfe17f926321cd7df54c6fbe103a8c3c1f1d1b7bf5208682b85b7242a +size 417 diff --git a/testScripts/openRoad/art/hills.png b/testScripts/openRoad/art/hills.png new file mode 100644 index 000000000..cbecca64e --- /dev/null +++ b/testScripts/openRoad/art/hills.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49d4b7e96f67a96b64b60b4059119e77ed26ab11420fcfb9a4a56e4557a8a2e0 +size 1012 diff --git a/testScripts/openRoad/art/palm.png b/testScripts/openRoad/art/palm.png new file mode 100644 index 000000000..96ecbceba --- /dev/null +++ b/testScripts/openRoad/art/palm.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:811f27f2712340f1cfc053633dc83d16c9c3cbec33257983dfad813d2cb406aa +size 805 diff --git a/testScripts/openRoad/art/sign.png b/testScripts/openRoad/art/sign.png new file mode 100644 index 000000000..e99149e51 --- /dev/null +++ b/testScripts/openRoad/art/sign.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:30f1adb8828cbd8331fd2ac020f5ce6557c791c064efbdb1e9c340a6e0e91ac3 +size 239 diff --git a/testScripts/openRoad/art/sky.png b/testScripts/openRoad/art/sky.png new file mode 100644 index 000000000..34251ba85 --- /dev/null +++ b/testScripts/openRoad/art/sky.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3ef335927271f70f410f308b1ffbb6299e29a7ccc1f8c3482945d367e0c41430 +size 7552 diff --git a/testScripts/openRoad/art/strip.png b/testScripts/openRoad/art/strip.png new file mode 100644 index 000000000..152606c78 --- /dev/null +++ b/testScripts/openRoad/art/strip.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e4a649068c48d67d7cc3fa8250ab008fcda7b7e48cd011d2da00cb56b601671a +size 453 diff --git a/testScripts/openRoad/art/traffic.png b/testScripts/openRoad/art/traffic.png new file mode 100644 index 000000000..c758a475e --- /dev/null +++ b/testScripts/openRoad/art/traffic.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12cc03689c75fd51c46f88e6b1ba8d953d7fd3ce920ec679ca25cd186b375c14 +size 350 diff --git a/testScripts/openRoad/art/truck.png b/testScripts/openRoad/art/truck.png new file mode 100644 index 000000000..59cfc26a5 --- /dev/null +++ b/testScripts/openRoad/art/truck.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bfbac3ed58013e273db52cdd5baf1e254ccb6125c5b2732844afb5c4bbdcd3 +size 341 diff --git a/testScripts/openRoad/games.dat b/testScripts/openRoad/games.dat new file mode 100644 index 000000000..fa868ff8f --- /dev/null +++ b/testScripts/openRoad/games.dat @@ -0,0 +1,9 @@ +-- Written for testScripts/openRoad/openRoad.singe: a road-racing game drawn a screen row at a time. +GAMES = { + { + TITLE = "Open Road", + SCRIPT = "openRoad/openRoad.singe", + RESOLUTION_X = 640, + RESOLUTION_Y = 480 + } +} diff --git a/testScripts/openRoad/openRoad.singe b/testScripts/openRoad/openRoad.singe new file mode 100644 index 000000000..32dbaf48f --- /dev/null +++ b/testScripts/openRoad/openRoad.singe @@ -0,0 +1,516 @@ +-- Open Road: a road-racing game of the arcade kind, drawn a screen row at a time. There is no 3D +-- here at all. The track is a list of short segments, each with how sharply it bends and how high +-- it is. Every frame projects the segments ahead with one division each, and fills the screen rows +-- between one segment and the next with a cut-out row of road stretched to the road's width there +-- (spriteDrawGrid's stretched form). Bends move each row sideways a little more than the last; +-- hills move rows up or down, and a crest hides what is beyond it, scenery included. +-- +-- Cars and scenery are flat pictures scaled to their distance. The player's car is one picture, +-- leaned into a turn and spun in a crash by turning it. +-- +-- Left and right steer, button 1 (or up) accelerates, button 2 (or down) brakes. Reach the arch +-- before the time runs out for more time. +dofile("Singe/Framework.singe") + +local W = 320 +local H = 240 +local HORIZON_Y = 110 -- Where the horizon sits on a level road; the sky art assumes it +local FOCAL = 160 -- Screen offset = world offset * FOCAL / distance ahead +local CAM_HEIGHT = 60 -- The camera's height over the road under the car +local SEG = 20 -- World units of track in a segment +local DRAW = 150 -- Segments drawn ahead +local NEAR = 1 -- Closer than this, a point is behind the camera +local ROAD_HALF = 100 -- Half a road row in world units, rumble to rumble +local STRIP_W = 256 -- The strip art's width; the art script sets these four +local HAZE = 8 +local ROW_ROAD = 0 -- Row kinds in the strip, each HAZE rows deep +local ROW_GRASS = 2 +local RUMBLE_SEGS = 3 -- Segments from one light band to the next dark one +local LANE = 58 -- World units from one lane's centre to the next +local PLAYER_AHEAD = 80 -- The car is this far ahead of the camera; it is drawn there at its own size +local PLAYER_W = 36 -- And this wide in the world, for hitting things +local PLAYER_BOTTOM = 230 -- Its bottom row on screen: HORIZON_Y + CAM_HEIGHT * FOCAL / PLAYER_AHEAD +local MAX_SPEED = 420 -- World units a second +local ACCEL = 120 +local BRAKE = 320 +local COAST = 50 +local OFFROAD_SPEED = MAX_SPEED / 3 -- Off the road the car slows to this +local OFFROAD_DRAG = 260 +local STEER = 170 -- World units a second across, at full speed +local CENTRIFUGAL = 150 -- How hard a sharp bend at full speed pushes the car out +local CURVE_EASY = 0.2 -- A bend's sharpness: how much each segment turns from the last +local CURVE_MEDIUM = 0.4 +local CURVE_HARD = 0.6 +local HILL_LOW = 120 +local HILL_MEDIUM = 260 +local HILL_HIGH = 420 +local HILLS_SCROLL = 4 -- Pixels the far hills move for each segment of a bend at full sharpness +local LEAN = 6 -- Degrees the car leans into a full turn +local SPIN_SECONDS = 1.2 +local SPIN_TURNS = 2 +local TRAFFIC = 24 +local CAR_LENGTH = 30 -- How close behind a car the player can be before hitting it +local TIME_START = 85 +local TIME_BONUS = 75 +local ARCH_SEGMENT = 8 -- Where the start arch stands, just ahead of the car + +-- What each kind of thing is: its picture, its width in the world (its height follows from the +-- picture), and whether the car hits it. +local KINDS = {} + +local track = {} +local trackLen = 0 +local traffic = {} +local drawn = {} +local held = {} +local strip = nil +local sky = nil +local hills = nil +local hillsW = 0 +local position = 0 -- The camera's distance along the track +local playerX = 0 -- The car's distance across from the road's centre +local speed = 0 +local spin = nil -- Seconds into a crash's spin, or nil +local hillsAt = 0 +local timeLeft = TIME_START +local distance = 0 +local nextLap = 0 +local lap = 1 +local score = 0 +local message = nil +local messageEnd = 0 +local clock = 0 +local lastTicks = nil + + +local function addSegment(curve, y) + local last = track[#track] + + track[#track + 1] = { index = #track, curve = curve, y1 = last and last.y2 or 0, y2 = y, scenery = {}, cars = {} } +end + + +local function easeIn(a, b, t) + return a + (b - a) * t * t +end + + +local function easeInOut(a, b, t) + return a + (b - a) * (0.5 - math.cos(t * math.pi) / 2) +end + + +-- A piece of road: it eases into its bend, holds it, and eases out, climbing or falling by rise +-- over its whole length. +local function addRoad(enter, hold, leave, curve, rise) + local startY = track[#track] and track[#track].y2 or 0 + local endY = startY + rise + local total = enter + hold + leave + + for n = 0, enter - 1 do + addSegment(easeIn(0, curve, n / enter), easeInOut(startY, endY, n / total)) + end + for n = 0, hold - 1 do + addSegment(curve, easeInOut(startY, endY, (enter + n) / total)) + end + for n = 0, leave - 1 do + addSegment(easeInOut(curve, 0, n / leave), easeInOut(startY, endY, (enter + hold + n) / total)) + end +end + + +local function addScenery(index, kind, x) + local segment = track[(index % #track) + 1] + + segment.scenery[#segment.scenery + 1] = { kind = kind, x = x } +end + + +local function buildTrack() + track = {} + addRoad(0, 40, 0, 0, 0) + addRoad(25, 50, 25, CURVE_MEDIUM, 0) + addRoad(30, 40, 30, 0, HILL_MEDIUM) + addRoad(25, 40, 25, -CURVE_EASY, 0) + addRoad(20, 30, 20, -CURVE_MEDIUM, -HILL_LOW) + addRoad(20, 30, 20, CURVE_MEDIUM, HILL_LOW) + addRoad(30, 60, 30, 0, -HILL_HIGH) + addRoad(30, 60, 30, CURVE_HARD, 0) + for _ = 1, 4 do + addRoad(15, 10, 15, 0, HILL_LOW) + addRoad(15, 10, 15, 0, -HILL_LOW) + end + addRoad(25, 50, 25, -CURVE_MEDIUM, HILL_MEDIUM) + addRoad(20, 20, 20, CURVE_EASY, 0) + addRoad(20, 20, 20, -CURVE_EASY, 0) + addRoad(30, 40, 30, -CURVE_HARD, 0) + addRoad(40, 60, 40, CURVE_EASY, -track[#track].y2) + addRoad(0, 30, 0, 0, 0) + trackLen = #track * SEG + + -- Palms along both sides, bushes farther out, a warning board on the outside before each bend + -- (where the car goes if it is taken too fast), and the arch, with nothing hiding it. + for i = 0, #track - 1 do + local segment = track[i + 1] + local nearArch = math.abs(i - ARCH_SEGMENT) < 6 + + if i % 6 == 0 and not nearArch then + addScenery(i, KINDS.palm, -(ROAD_HALF + 35 + math.random(0, 60))) + addScenery(i, KINDS.palm, ROAD_HALF + 35 + math.random(0, 60)) + end + if math.random() < 0.25 then + local side = (math.random() < 0.5) and -1 or 1 + + addScenery(i, KINDS.bush, side * (ROAD_HALF + 90 + math.random(0, 260))) + end + local previous = track[((i - 1) % #track) + 1] + + if previous.curve == 0 and segment.curve ~= 0 then + local outside = (segment.curve > 0) and -1 or 1 + + for back = 25, 5, -5 do + addScenery(i - back, KINDS.sign, outside * (ROAD_HALF + 22)) + end + end + end + addScenery(ARCH_SEGMENT, KINDS.arch, 0) +end + + +local function loadKind(name, width, solid) + local sprite = spriteLoad(DIR .. "art/" .. name .. ".png") + local w = spriteGetWidth(sprite) + local h = spriteGetHeight(sprite) + + return { sprite = sprite, width = width, height = width * h / w, naturalW = w, naturalH = h, solid = solid } +end + + +local function segmentAt(z) + return track[(math.floor(z / SEG) % #track) + 1] +end + + +local function showMessage(text, seconds) + message = text + messageEnd = clock + seconds +end + + +local function reset() + position = 0 + playerX = 0 + speed = 0 + spin = nil + timeLeft = TIME_START + distance = 0 + nextLap = ARCH_SEGMENT * SEG - PLAYER_AHEAD + trackLen + lap = 1 + score = 0 + traffic = {} + for _ = 1, TRAFFIC do + local kind = (math.random() < 0.75) and KINDS.traffic or KINDS.truck + + traffic[#traffic + 1] = { kind = kind, z = math.random(ARCH_SEGMENT + 20, #track - 10) * SEG, x = math.random(-1, 1) * LANE, speed = math.random(120, 260) } + end + showMessage("GO!", 2) +end + + +local function crash() + spin = 0 + speed = 0 +end + + +local function step(dt) + local steer = (held[SWITCH_RIGHT] and 1 or 0) - (held[SWITCH_LEFT] and 1 or 0) + local gas = held[SWITCH_BUTTON1] or held[SWITCH_UP] + local brake = held[SWITCH_BUTTON2] or held[SWITCH_DOWN] + local playerZ = position + PLAYER_AHEAD + local segment = segmentAt(playerZ) + local pace = speed / MAX_SPEED + local offRoad = math.abs(playerX) > ROAD_HALF + + clock = clock + dt + if timeLeft > 0 then + timeLeft = math.max(0, timeLeft - dt) + if timeLeft == 0 then + showMessage("TIME UP", 1000) + end + end + + -- A spin takes the controls away until it is over, and leaves the car on the road's edge. + if spin then + spin = spin + dt + if spin >= SPIN_SECONDS then + spin = nil + playerX = (playerX < 0 and -1 or 1) * (ROAD_HALF - PLAYER_W) + end + steer = 0 + gas = false + end + if timeLeft == 0 then + gas = false + end + + if gas then + speed = speed + ACCEL * dt + elseif brake then + speed = speed - BRAKE * dt + else + speed = speed - COAST * dt + end + if offRoad and speed > OFFROAD_SPEED then + speed = speed - OFFROAD_DRAG * dt + end + speed = math.max(0, math.min(MAX_SPEED, speed)) + + -- Steering moves the car across in proportion to its speed; a bend pushes it outward by the + -- square of it. + playerX = playerX + steer * STEER * pace * dt + playerX = playerX - segment.curve / CURVE_HARD * pace * pace * CENTRIFUGAL * dt + playerX = math.max(-ROAD_HALF * 3, math.min(ROAD_HALF * 3, playerX)) + + position = (position + speed * dt) % trackLen + distance = distance + speed * dt + score = score + math.floor(speed * dt) + hillsAt = (hillsAt + segment.curve / CURVE_HARD * HILLS_SCROLL * speed * dt / SEG) % hillsW + if distance >= nextLap then + nextLap = nextLap + trackLen + lap = lap + 1 + timeLeft = timeLeft + TIME_BONUS + showMessage("EXTENDED TIME", 2) + end + + -- Off the road, anything solid in the car's segment stops it dead. + playerZ = position + PLAYER_AHEAD + segment = segmentAt(playerZ) + if not spin and math.abs(playerX) > ROAD_HALF then + for _, thing in ipairs(segment.scenery) do + if thing.kind.solid and math.abs(thing.x - playerX) < (PLAYER_W + thing.kind.width) * 0.35 then + crash() + break + end + end + end + + -- Traffic keeps its lane at its own speed. Running into the back of a car drops the player to + -- that car's speed, behind it. + for _, car in ipairs(traffic) do + car.z = (car.z + car.speed * dt) % trackLen + local gap = (car.z - playerZ) % trackLen + + if gap < CAR_LENGTH and speed > car.speed and math.abs(car.x - playerX) < (PLAYER_W + car.kind.width) * 0.4 then + speed = car.speed * 0.7 + position = (car.z - CAR_LENGTH - PLAYER_AHEAD) % trackLen + end + end +end + + +-- The far hills, twice the screen's width, drawn round from wherever they have scrolled to. +local function drawHills() + local from = math.floor(hillsAt) + local first = math.min(W, hillsW - from) + local top = HORIZON_Y - spriteGetHeight(hills) + 1 + + spriteDrawGrid(hills, 0, top, from, 0, first, spriteGetHeight(hills)) + if first < W then + spriteDrawGrid(hills, first, top, 0, 0, W - first, spriteGetHeight(hills)) + end +end + + +-- A picture standing on the road at its distance, centred across on x, its foot at bottom. Rows at +-- clip and below are hidden by nearer road, so a thing beyond a crest shows only what is above it: +-- the picture's top part, cut out and stretched to what is left. +local function drawStanding(kind, x, bottom, perUnit, clip) + local w = kind.width * perUnit + local h = kind.height * perUnit + + if w < 1 or x + w / 2 < 0 or x - w / 2 >= W or bottom - h >= clip then + return + end + local left = math.floor(x - w / 2) + local right = math.floor(x + w / 2) + local top = math.floor(bottom - h) + + if bottom <= clip then + spriteDraw(kind.sprite, left, top, right, math.floor(bottom) - 1) + else + local shown = math.min(kind.naturalH, math.max(1, math.floor(kind.naturalH * (clip - (bottom - h)) / h))) + + spriteDrawGrid(kind.sprite, left, top, 0, 0, kind.naturalW, shown, right, clip - 1) + end +end + + +-- The road, nearest segment first. Each segment fills the rows between where its near edge and its +-- far edge land, as far up as the nearest road drawn so far reaches (clip). Each row is one cut-out +-- row of the strip stretched to the road's width there, over one stretched row of grass. +local function drawRoad(camX, camY) + local base = math.floor(position / SEG) + local within = position - base * SEG + local first = track[(base % #track) + 1] + local x = 0 + local dx = -first.curve * within / SEG + local clip = H + local hazeFar = DRAW * SEG + + drawn = {} + for n = 0, DRAW - 1 do + local index = base + n + local segment = track[(index % #track) + 1] + local z1 = math.max(NEAR, n * SEG - within) + local z2 = n * SEG - within + SEG + local scale1 = FOCAL / z1 + local scale2 = FOCAL / z2 + + segment.sx1 = W / 2 + (x - camX) * scale1 + segment.sy1 = HORIZON_Y - (segment.y1 - camY) * scale1 + segment.scale1 = scale1 + segment.sx2 = W / 2 + (x + dx - camX) * scale2 + segment.sy2 = HORIZON_Y - (segment.y2 - camY) * scale2 + segment.scale2 = scale2 + segment.clip = clip + segment.z1 = z1 + x = x + dx + dx = dx + segment.curve + drawn[#drawn + 1] = segment + + if segment.sy2 < clip and segment.sy1 > segment.sy2 then + local top = math.max(0, math.ceil(segment.sy2)) + local bottom = math.min(clip - 1, math.floor(segment.sy1)) + local light = (index // RUMBLE_SEGS) % 2 + local haze = math.min(HAZE - 1, math.floor(z1 / hazeFar * HAZE)) + local road = (ROW_ROAD + light) * HAZE + haze + local grass = (ROW_GRASS + light) * HAZE + haze + local height = segment.sy1 - segment.sy2 + + if top <= bottom then + spriteDrawGrid(strip, 0, top, 0, grass, STRIP_W, 1, W - 1, bottom) + for row = bottom, top, -1 do + local t = (segment.sy1 - row) / height + local cx = segment.sx1 + (segment.sx2 - segment.sx1) * t + local half = ROAD_HALF * (scale1 + (scale2 - scale1) * t) + + spriteDrawGrid(strip, math.floor(cx - half), row, 0, road, STRIP_W, 1, math.floor(cx + half), row) + end + clip = top + end + end + end +end + + +-- Scenery and traffic, farthest first, each clipped by the road nearer than it. +local function drawThings() + for _, car in ipairs(traffic) do + local segment = segmentAt(car.z) + + segment.cars[#segment.cars + 1] = car + end + for i = #drawn, 2, -1 do + local segment = drawn[i] + + for _, thing in ipairs(segment.scenery) do + drawStanding(thing.kind, segment.sx1 + thing.x * segment.scale1, segment.sy1, segment.scale1, segment.clip) + end + for _, car in ipairs(segment.cars) do + local t = (car.z % SEG) / SEG + local perUnit = segment.scale1 + (segment.scale2 - segment.scale1) * t + local sx = segment.sx1 + (segment.sx2 - segment.sx1) * t + car.x * perUnit + local sy = segment.sy1 + (segment.sy2 - segment.sy1) * t + + drawStanding(car.kind, sx, sy, perUnit, segment.clip) + end + end + for _, segment in ipairs(drawn) do + segment.cars = {} + end +end + + +-- The player's car: one picture at its own size, leaned into the turn, shaken on the grass, and +-- spun right round in a crash. +local function drawCar(steer) + local pace = speed / MAX_SPEED + local angle = math.floor(steer * LEAN * pace + 0.5) + local shake = 0 + + if spin then + local t = spin / SPIN_SECONDS + + angle = math.floor(360 * SPIN_TURNS * (1 - (1 - t) * (1 - t))) + end + if math.abs(playerX) > ROAD_HALF and speed > 0 then + shake = math.random(0, 2) + end + -- Turned, the picture grows, so it is drawn by its centre, which stays where the upright one's was. + spriteRotate(KINDS.car.sprite, angle % 360) + spriteDraw(KINDS.car.sprite, W // 2, PLAYER_BOTTOM - KINDS.car.naturalH // 2 - shake, true) +end + + +function onInputPressed(what) + held[what] = true + if what == SWITCH_BUTTON1 and timeLeft == 0 and speed == 0 then + reset() + end +end + + +function onInputReleased(what) + held[what] = false +end + + +function onOverlayUpdate() + local now = singeGetTicks() + local dt = lastTicks and math.min(0.05, (now - lastTicks) / 1000) or 0 + + lastTicks = now + step(dt) + + local playerZ = position + PLAYER_AHEAD + local segment = segmentAt(playerZ) + local t = (playerZ % SEG) / SEG + local camY = segment.y1 + (segment.y2 - segment.y1) * t + CAM_HEIGHT + local steer = (held[SWITCH_RIGHT] and 1 or 0) - (held[SWITCH_LEFT] and 1 or 0) + + spriteDraw(sky, 0, 0) + drawHills() + drawRoad(playerX, camY) + drawThings() + drawCar(steer) + + overlayPrint(1, 0, string.format("TIME %2d", math.ceil(timeLeft))) + overlayPrint(15, 0, string.format("LAP %d", lap)) + overlayPrint(26, 0, string.format("%06d", score // 10)) + overlayPrint(1, 14, string.format("%3d km/h", math.floor(speed * 0.7))) + if message and clock < messageEnd then + overlayPrint(20 - #message // 2, 5, message) + end + if timeLeft == 0 and speed == 0 then + overlayPrint(9, 7, "Button 1 drives again") + end + + return OVERLAY_UPDATED +end + + +overlaySetResolution(W, H) +strip = spriteLoad(DIR .. "art/strip.png") +sky = spriteLoad(DIR .. "art/sky.png") +hills = spriteLoad(DIR .. "art/hills.png") +hillsW = spriteGetWidth(hills) +KINDS.car = loadKind("car", 40, false) +KINDS.traffic = loadKind("traffic", 42, true) +KINDS.truck = loadKind("truck", 46, true) +KINDS.palm = loadKind("palm", 50, true) +KINDS.bush = loadKind("bush", 50, false) +KINDS.sign = loadKind("sign", 40, true) +KINDS.arch = loadKind("arch", ROAD_HALF * 2.3, false) +buildTrack() +reset() diff --git a/testScripts/packedSql/games.dat b/testScripts/packedSql/games.dat new file mode 100644 index 000000000..e6ab81572 --- /dev/null +++ b/testScripts/packedSql/games.dat @@ -0,0 +1,9 @@ +-- Written for testScripts/packedSql/packedSql.singe; see its header for how to run it. +GAMES = { + { + TITLE = "Packed sql", + SCRIPT = "packedSql/packedSql.singe", + RESOLUTION_X = 720, + RESOLUTION_Y = 480 + } +} diff --git a/testScripts/packedSql/levels.db b/testScripts/packedSql/levels.db new file mode 100644 index 0000000000000000000000000000000000000000..8eab1adc5d5e25436b083b79a9345663255385f5 GIT binary patch literal 8192 zcmeI#y=ucS5C`y+RcJB1DI+ zwafmF+(AG90uX=z1Rwwb2tWV=5P$##AaF|{5s&>K5dS@!E(=qbjVYS*?Y+k;)QWZZ z7AZc@c#vm2o@(`>VxGt2Nf;;msgfaAX=zxiAI;O5%kL<9ZvW=e-;;mz53V2}009U< s00Izz00bZa0SG_<0uZ=IfsT~aw|{w^bv;QzV}93F))8*F%In6S0J}>rM*si- literal 0 HcmV?d00001 diff --git a/testScripts/packedSql/packedSql.singe b/testScripts/packedSql/packedSql.singe new file mode 100644 index 000000000..ea1cdee0f --- /dev/null +++ b/testScripts/packedSql/packedSql.singe @@ -0,0 +1,82 @@ +-- sqlite3.open against a database that exists only inside a .game. Asked to read, Singe opens it +-- where it lies, through a read-only SQLite VFS over the packed rows; asked to write, it copies the +-- database once to the game's data directory and opens the copy, then and from then on. +-- +-- It has to be run packed, with no loose copy beside the container -- a loose file shadows the +-- packed one and the whole test then proves nothing -- so from a directory holding this folder: +-- +-- Singe -P packedSql packedSql.game +-- rm -rf packedSql +-- Singe -w -C 720x480 packedSql.game +-- Singe -w -C 720x480 packedSql.game +-- +-- Each run prints one line: SQLTEST pass=N fail=0 count=C. The count is the rows the writable +-- copy holds after this run adds one: 4 the first time, 5 the second, since the copy persists. +-- The .game itself is never written. Every failure prints what it wanted first. +dofile("Singe/Framework.singe") + +local sqlite3 = require("sqlite3") + +local pass = 0 +local fail = 0 + + +local function check(what, got, want) + if got == want then + pass = pass + 1 + else + fail = fail + 1 + debugPrint(string.format("FAIL %s: got %s, wanted %s", what, tostring(got), tostring(want))) + end +end + + +local function count(db) + local n = nil + + for row in db:nrows("SELECT COUNT(*) AS n FROM levels") do + n = row.n + end + return n +end + + +-- Read only: the packed database, read where it lies. On a later run the writable copy exists and +-- is what a name resolves to, as io.open's does; either way the first three rows are the packed ones. +local reader = sqlite3.open("packedSql/levels.db", sqlite3.OPEN_READONLY) +local names = {} + +check("read-only open", reader ~= nil, true) +for row in reader:nrows("SELECT name FROM levels WHERE id <= 3 ORDER BY id") do + names[#names + 1] = row.name +end +check("rows read", table.concat(names, ","), "first,second,third") +check("a read-only open refuses a write", reader:exec("INSERT INTO levels VALUES (99, 'nope')") == sqlite3.OK, false) +reader:close() + +-- Writable: copied out to the data directory the first time, and the copy changed. +local writer = sqlite3.open("packedSql/levels.db") +local before = writer and count(writer) + +check("writable open", writer ~= nil, true) +check("a write", writer:exec("INSERT INTO levels (name) VALUES ('added')"), sqlite3.OK) +local after = count(writer) +check("the write is there", after, before + 1) +writer:close() + +-- The copy is what the name means now, read only or not. +local again = sqlite3.open("packedSql/levels.db", sqlite3.OPEN_READONLY) + +check("the copy is what a read now opens", count(again), after) +again:close() + +-- What is not there, and the names SQLite keeps for itself. +check("a missing packed name does not open", sqlite3.open("packedSql/missing.db", sqlite3.OPEN_READONLY), nil) +local memory = sqlite3.open(":memory:") + +check(":memory: still opens", memory ~= nil, true) +check(":memory: still works", memory:exec("CREATE TABLE t (x)"), sqlite3.OK) +memory:close() + +debugPrint(string.format("SQLTEST pass=%d fail=%d count=%d", pass, fail, after or -1)) +singeQuit() diff --git a/testScripts/skyStrike/art/cloud.png b/testScripts/skyStrike/art/cloud.png new file mode 100644 index 000000000..eda360287 --- /dev/null +++ b/testScripts/skyStrike/art/cloud.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f2ae95dbc52411e5cb1d583c9b26a534b5bc22ab982e0cfa1a96d4471df7111e +size 2686 diff --git a/testScripts/skyStrike/art/enemy.png b/testScripts/skyStrike/art/enemy.png new file mode 100644 index 000000000..956bfb640 --- /dev/null +++ b/testScripts/skyStrike/art/enemy.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f75598d37369fa38172ec297604484dfb3026a0f88ebf582a56e4e28ea04b2dc +size 361 diff --git a/testScripts/skyStrike/art/fireball.png b/testScripts/skyStrike/art/fireball.png new file mode 100644 index 000000000..d6cd887cd --- /dev/null +++ b/testScripts/skyStrike/art/fireball.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:001f95e168100703a00c9f983064b5d3744026f45126939192514b303a1963fb +size 597 diff --git a/testScripts/skyStrike/art/ground.png b/testScripts/skyStrike/art/ground.png new file mode 100644 index 000000000..220837737 --- /dev/null +++ b/testScripts/skyStrike/art/ground.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68699957682e98d9996d1f02149e25e4f6b57e436ba91cbf79579dd95e795ea7 +size 10130 diff --git a/testScripts/skyStrike/art/jet.png b/testScripts/skyStrike/art/jet.png new file mode 100644 index 000000000..2d9916a94 --- /dev/null +++ b/testScripts/skyStrike/art/jet.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:90971415862f30c335e094ec1de1f749a9497c3001260832c2fa2e535c79d411 +size 499 diff --git a/testScripts/skyStrike/art/rock.png b/testScripts/skyStrike/art/rock.png new file mode 100644 index 000000000..0bf4e3a4a --- /dev/null +++ b/testScripts/skyStrike/art/rock.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:148ff82d12288475391f695066792a78d3efd6448c4a991e6a2ffadc69319585 +size 256 diff --git a/testScripts/skyStrike/art/shot.png b/testScripts/skyStrike/art/shot.png new file mode 100644 index 000000000..65cb61add --- /dev/null +++ b/testScripts/skyStrike/art/shot.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ba6d3c6c0fca4bcc7738d211c45a9ed2ee5b35b1b041434bea219cbf3de30dd4 +size 161 diff --git a/testScripts/skyStrike/art/tree.png b/testScripts/skyStrike/art/tree.png new file mode 100644 index 000000000..4d9b4964b --- /dev/null +++ b/testScripts/skyStrike/art/tree.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13367a5cda5965a4a350f41b8f3d0aa6b0f4ecc528814e226ab6d49549f06e81 +size 368 diff --git a/testScripts/skyStrike/games.dat b/testScripts/skyStrike/games.dat new file mode 100644 index 000000000..84dea343e --- /dev/null +++ b/testScripts/skyStrike/games.dat @@ -0,0 +1,9 @@ +-- Written for testScripts/skyStrike/skyStrike.singe: a sprite-scaling flight game. +GAMES = { + { + TITLE = "Sky Strike", + SCRIPT = "skyStrike/skyStrike.singe", + RESOLUTION_X = 640, + RESOLUTION_Y = 480 + } +} diff --git a/testScripts/skyStrike/skyStrike.singe b/testScripts/skyStrike/skyStrike.singe new file mode 100644 index 000000000..d58ec9852 --- /dev/null +++ b/testScripts/skyStrike/skyStrike.singe @@ -0,0 +1,322 @@ +-- Sky Strike: a sprite-scaling flight game, the arcade kind where the world is flat pictures drawn +-- bigger as they come closer. There is no 3D here at all. Every object has a position in a simple +-- world (across, up, and ahead), each frame projects it to the screen with one division, and the +-- sprite is drawn stretched to the size that distance gives it. +-- +-- Turning does the rest, and saves drawing pictures: the jet is one picture, turned for its bank +-- and spun for a barrel roll; the horizon tilts by turning the whole sky and ground, one picture; +-- and everything in the world turns with the horizon, the same picture at the same angle. +-- +-- Arrows steer, button 1 fires, button 2 rolls (and nothing touches you mid-roll). +dofile("Singe/Framework.singe") + +local W = 320 +local H = 240 +local FOCAL = 160 -- Screen offset = world offset * FOCAL / distance ahead +local EYE_HEIGHT = 30 -- The camera's height over the ground; the ground art assumes it +local HORIZON_Y = 100 -- Where the horizon sits when the jet flies level +local NEAR = 8 -- Closer than this ahead, a thing has gone past +local FAR = 1200 -- Scenery appears this far ahead +local SPEED = 260 -- World units a second +local STRIPE = 40 -- The ground art's stripe, in world units +local GROUND_FRAMES = 6 +local BANK_MAX = 35 -- Degrees the jet banks at full turn +local HORIZON_SHARE = 0.6 -- How much of the bank tilts the horizon rather than the jet +local STEER = 120 -- World units a second across at full turn +local CLIMB = 60 -- And up or down +local ALTITUDE_MIN = 12 +local ALTITUDE_MAX = 80 +local ROLL_SECONDS = 0.7 +local FIRE_GAP = 0.08 +local SHOT_SPEED = 900 +local SHOT_RANGE = 900 +local ENEMY_SPEED = 160 -- On top of the jet's own +local SAFE_SECONDS = 2 -- Untouchable after being hit +local START_LIVES = 3 +local JET_X = W / 2 +local JET_Y = 190 +local JET_DROP = 7 -- The jet flies this far below the camera: where it is hit, and its guns +local ENEMY_SPREAD = 12 -- Enemies arrive within this of the jet's height, to come at it + +-- What each kind of thing is: its picture, and its height in the world, which with the distance +-- gives its height on screen. +local KINDS = {} + +local held = {} +local scenery = {} +local enemies = {} +local shots = {} +local explosions = {} +local camX = 0 +local camY = EYE_HEIGHT +local bank = 0 +local pitch = 0 +local roll = nil -- Seconds into a barrel roll, or nil +local rollWay = 1 +local travelled = 0 +local fireWait = 0 +local spawnWait = 0 +local safeUntil = 0 +local score = 0 +local lives = START_LIVES +local clock = 0 +local lastTicks = nil +local ground = nil + + +local function loadKind(name, height) + local sprite = spriteLoad(DIR .. "art/" .. name .. ".png") + + spriteQuality(sprite, RENDER_SMOOTH) + return { sprite = sprite, height = height, natural = spriteGetHeight(sprite), angle = nil } +end + + +local function reset() + scenery = {} + enemies = {} + shots = {} + explosions = {} + camX = 0 + camY = EYE_HEIGHT + bank = 0 + pitch = 0 + roll = nil + score = 0 + lives = START_LIVES + safeUntil = 0 + for _ = 1, 60 do + local thing = { kind = (math.random() < 0.7) and KINDS.tree or KINDS.rock, x = math.random(-600, 600), z = math.random(NEAR, FAR) } + + thing.y = thing.kind.height / 2 + scenery[#scenery + 1] = thing + end + for _ = 1, 12 do + scenery[#scenery + 1] = { kind = KINDS.cloud, x = math.random(-900, 900), y = math.random(110, 220), z = math.random(NEAR, FAR) } + end +end + + +-- Where a point of the world lands on the screen, and how many pixels a world unit is there: the +-- one division, then the turn of the horizon about its own point. nil when it is behind the camera. +local function project(x, y, z, horizonX, horizonY, cosA, sinA) + if z < NEAR then + return nil + end + local perUnit = FOCAL / z + local dx = (x - camX) * perUnit + local dy = (camY - y) * perUnit + + return horizonX + dx * cosA - dy * sinA, horizonY + dx * sinA + dy * cosA, perUnit +end + + +-- A thing drawn at its distance: its kind's picture, turned to the angle (once a frame for all of a +-- kind, since they share it), stretched to its height there. +local function drawThing(kind, sx, sy, perUnit, angle) + if kind.angle ~= angle then + spriteRotate(kind.sprite, angle) + kind.angle = angle + end + local scale = kind.height * perUnit / kind.natural + local w = spriteGetWidth(kind.sprite) * scale + local h = spriteGetHeight(kind.sprite) * scale + + if (sx + w / 2 < 0) or (sx - w / 2 > W) or (sy + h / 2 < 0) or (sy - h / 2 > H) or (w < 1) then + return + end + spriteDraw(kind.sprite, sx - w / 2, sy - h / 2, sx + w / 2, sy + h / 2) +end + + +local function explode(x, y, z) + explosions[#explosions + 1] = { x = x, y = y, z = z, age = 0, spin = math.random(0, 359) } +end + + +local function step(dt) + local across = (held[SWITCH_RIGHT] and 1 or 0) - (held[SWITCH_LEFT] and 1 or 0) + local climb = (held[SWITCH_UP] and 1 or 0) - (held[SWITCH_DOWN] and 1 or 0) + + clock = clock + dt + travelled = travelled + SPEED * dt + camX = camX + across * STEER * dt + camY = math.max(ALTITUDE_MIN, math.min(ALTITUDE_MAX, camY + climb * CLIMB * dt)) + -- The bank and the nose ease toward the stick rather than snapping. + bank = bank + (across * BANK_MAX - bank) * math.min(1, dt * 6) + pitch = pitch + (climb * 18 - pitch) * math.min(1, dt * 5) + if roll then + roll = roll + dt + if roll >= ROLL_SECONDS then + roll = nil + end + end + + -- The world comes toward the jet; what passes goes round to the far end again. + for _, thing in ipairs(scenery) do + thing.z = thing.z - SPEED * dt + if thing.z < NEAR then + thing.z = thing.z + FAR + thing.x = camX + math.random(-600, 600) + ((thing.kind == KINDS.cloud) and math.random(-300, 300) or 0) + end + end + + -- Enemies come in from ahead, weaving, and bank into their weave. + spawnWait = spawnWait - dt + if spawnWait <= 0 and lives > 0 then + spawnWait = 0.8 + math.random() * 1.2 + enemies[#enemies + 1] = { x = camX + math.random(-60, 60), y = math.max(5, camY - JET_DROP + math.random(-ENEMY_SPREAD, ENEMY_SPREAD)), z = SHOT_RANGE, phase = math.random() * 6.28, weave = 20 + math.random() * 30 } + end + for i = #enemies, 1, -1 do + local enemy = enemies[i] + local sway = math.cos(clock * 2 + enemy.phase) + + enemy.z = enemy.z - (SPEED + ENEMY_SPEED) * dt + enemy.x = enemy.x + sway * enemy.weave * dt + enemy.lean = sway * 25 + if enemy.z < NEAR then + -- It reached the jet: a hit unless it is off to one side, or the jet is rolling or safe. + if math.abs(enemy.x - camX) < 14 and math.abs(enemy.y - (camY - JET_DROP)) < 12 and not roll and clock > safeUntil and lives > 0 then + lives = lives - 1 + safeUntil = clock + SAFE_SECONDS + explode(camX, camY - JET_DROP, NEAR + 20) + end + table.remove(enemies, i) + end + end + + -- Shots fly ahead from the jet's guns, and what they meet blows up. + fireWait = fireWait - dt + if held[SWITCH_BUTTON1] and fireWait <= 0 and lives > 0 then + fireWait = FIRE_GAP + shots[#shots + 1] = { x = camX, y = camY - JET_DROP, z = NEAR + 4 } + end + for i = #shots, 1, -1 do + local shot = shots[i] + local hit = false + + shot.z = shot.z + SHOT_SPEED * dt + for j = #enemies, 1, -1 do + local enemy = enemies[j] + + if math.abs(enemy.x - shot.x) < 10 and math.abs(enemy.y - shot.y) < 8 and math.abs(enemy.z - shot.z) < 30 then + explode(enemy.x, enemy.y, enemy.z) + table.remove(enemies, j) + score = score + 1000 + hit = true + break + end + end + if hit or shot.z > SHOT_RANGE then + table.remove(shots, i) + end + end + + for i = #explosions, 1, -1 do + local blast = explosions[i] + + blast.age = blast.age + dt + blast.z = blast.z - SPEED * dt * 0.5 + blast.spin = blast.spin + 400 * dt + if blast.age > 0.6 or blast.z < NEAR then + table.remove(explosions, i) + end + end +end + + +function onInputPressed(what) + held[what] = true + if what == SWITCH_BUTTON2 and not roll and lives > 0 then + roll = 0 + rollWay = (held[SWITCH_LEFT] and -1) or 1 + elseif what == SWITCH_BUTTON1 and lives <= 0 then + reset() + end +end + + +function onInputReleased(what) + held[what] = false +end + + +function onOverlayUpdate() + local now = singeGetTicks() + local dt = lastTicks and math.min(0.05, (now - lastTicks) / 1000) or 0 + + lastTicks = now + step(dt) + + -- The horizon tilts against the bank and drops as the nose comes up. The sky and the ground are + -- one picture turned about the horizon point; the frame is chosen by how far the ground has + -- moved through a stripe, which is what makes it rush past. + local tilt = -bank * HORIZON_SHARE + local radians = math.rad(tilt) + local cosA = math.cos(radians) + local sinA = math.sin(radians) + local horizonX = W / 2 + local horizonY = HORIZON_Y + pitch + local frame = math.floor((travelled % STRIPE) / STRIPE * GROUND_FRAMES) + 1 + + overlayClear() + spriteRotateFrame(ground, tilt, frame) + spriteDrawRotatedFrame(ground, horizonX, horizonY) + + -- Everything in the world, farthest first, so the near hides the far. + local drawn = {} + + for _, thing in ipairs(scenery) do + drawn[#drawn + 1] = { kind = thing.kind, x = thing.x, y = thing.y, z = thing.z, angle = tilt } + end + for _, enemy in ipairs(enemies) do + drawn[#drawn + 1] = { kind = KINDS.enemy, x = enemy.x, y = enemy.y, z = enemy.z, angle = tilt + enemy.lean } + end + for _, shot in ipairs(shots) do + drawn[#drawn + 1] = { kind = KINDS.shot, x = shot.x, y = shot.y, z = shot.z, angle = 0 } + end + for _, blast in ipairs(explosions) do + drawn[#drawn + 1] = { kind = KINDS.fireball, x = blast.x, y = blast.y, z = blast.z, angle = math.floor(blast.spin) % 360, grow = 0.5 + blast.age * 2.5 } + end + table.sort(drawn, function(a, b) return a.z > b.z end) + for _, item in ipairs(drawn) do + local sx, sy, perUnit = project(item.x, item.y, item.z, horizonX, horizonY, cosA, sinA) + + if sx then + drawThing(item.kind, sx, sy, perUnit * (item.grow or 1), item.angle) + end + end + + -- The jet: one picture, turned for its share of the bank, and spun right round for a roll. + -- It blinks while it cannot be hit. + if lives > 0 and (clock > safeUntil or math.floor(clock * 10) % 2 == 0) then + local angle = bank * (1 - HORIZON_SHARE) + + if roll then + angle = angle + rollWay * 360 * (roll / ROLL_SECONDS) + end + spriteRotate(KINDS.jet.sprite, angle) + spriteDraw(KINDS.jet.sprite, JET_X + bank * 0.8, JET_Y - pitch * 0.5, true) + end + + overlayPrint(1, 0, string.format("SCORE %06d", score)) + overlayPrint(1, 1, "LIVES " .. lives) + if lives <= 0 then + overlayPrint(14, 8, "GAME OVER") + overlayPrint(9, 10, "Button 1 flies again") + end + + return OVERLAY_UPDATED +end + + +overlaySetResolution(W, H) +KINDS.tree = loadKind("tree", 22) +KINDS.rock = loadKind("rock", 8) +KINDS.cloud = loadKind("cloud", 40) +KINDS.enemy = loadKind("enemy", 10) +KINDS.shot = loadKind("shot", 3) +KINDS.fireball = loadKind("fireball", 18) +KINDS.jet = loadKind("jet", 40) +ground = spriteLoadFrames(GROUND_FRAMES, DIR .. "art/ground.png") +reset() diff --git a/util/demoCapture.sh b/util/demoCapture.sh new file mode 100755 index 000000000..34623e089 --- /dev/null +++ b/util/demoCapture.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# Captures a stretch of one of the demos headless, frame by frame, and puts the music under it: +# +# util/demoCapture.sh neonCoast 0 30 [every] [out.mp4] +# +# The demos folder is copied to a scratch folder and run from there with a wrapper that sets +# DEMO_CAPTURE (demos/kit.lua), so the clock moves exactly one 20 ms step a frame and every frame +# (or every "every"th) is saved. With every = 1 the frames become out.mp4 at 50 frames a second +# with the same stretch of the demo's music. Nothing appears on screen. The frames are left in +# $SCRATCH/frames for looking at; SCRATCH defaults to a folder under /tmp. +set -euo pipefail + +DEMO=$1 +FROM=$2 +TO=$3 +EVERY=${4:-1} +OUT=${5:-} +# The run changes folder, so a relative output path is made absolute first. +if [ -n "$OUT" ]; then + OUT=$(realpath -m "$OUT") +fi +STEP=20 +REPO=$(cd "$(dirname "$0")/.." && pwd) +BIN=$(ls "$REPO"/.builddir/Singe-v*-Linux-x86_64 | head -1) +SCRATCH=${SCRATCH:-/tmp/demoCapture-$DEMO} + +rm -rf "$SCRATCH" +mkdir -p "$SCRATCH/run" "$SCRATCH/frames" +cp -r "$REPO/demos/." "$SCRATCH/run/" +cat > "$SCRATCH/run/$DEMO/capture.singe" < "$SCRATCH/run.log" 2>&1 || true +grep -E "DEMO|rror" "$SCRATCH/run.log" || true +find "$SCRATCH/data" -name "frame*.png" -exec mv {} "$SCRATCH/frames/" \; +echo "$(ls "$SCRATCH/frames" | wc -l) frames in $SCRATCH/frames" +if [ -n "$OUT" ] && [ "$EVERY" = "1" ]; then + ffmpeg -hide_banner -loglevel error -y -framerate $((1000 / STEP)) -pattern_type glob -i "$SCRATCH/frames/frame*.png" \ + -ss "$FROM" -t "$(echo "$TO - $FROM" | bc)" -i "$REPO/demos/$DEMO/music.mp3" \ + -map 0:v -map 1:a -c:v libx264 -preset medium -crf 18 -pix_fmt yuv420p -c:a aac -b:a 256k -shortest "$OUT" + echo "wrote $OUT" +fi diff --git a/util/demoSync.py b/util/demoSync.py new file mode 100644 index 000000000..c7370750c --- /dev/null +++ b/util/demoSync.py @@ -0,0 +1,212 @@ +# Analyses a demo's music and writes what the demo synchronises to as a Lua data file: the beats, +# where the bars start, envelopes of the drums, the bass, the loudness and the brightness sixty times +# a second, the times of the drum hits, and the pitch class of the strongest note. +# +# The beats come from a fixed grid when the track is on one (a produced track usually is), found by +# folding the whole track's onsets at every candidate period and keeping the sharpest; a track that +# drifts gets the tracker's beats, each moved to the strongest fine onset near it and smoothed through +# its neighbours. Beat one of the bar is where the loudness and the bass jump most often, since a +# song changes section on a downbeat. +# +# Each envelope is a string of base64-alphabet characters, one a frame, 0 to 63, so it sits in a Lua +# long string with no escapes and the demo decodes it once at startup. +# +# Needs librosa, which Singe does not: python3 -m venv env && env/bin/pip install librosa +# +# Usage: env/bin/python util/demoSync.py music.mp3 out.lua +import sys + +import librosa +import numpy as np + +RATE = 60 # Envelope samples a second: one a frame +SR = 22050 +HOP = 256 +LEVELS = 64 +ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +DECAY = 0.86 # Per sample: a hit's envelope halves in about 75 ms +NOTES = "C C# D D# E F F# G G# A A# B".split() + + +def beatGrid(y, yp, dur): + onset = librosa.onset.onset_strength(y=yp, sr=SR, hop_length=HOP) + ot = librosa.frames_to_time(np.arange(len(onset)), sr=SR, hop_length=HOP) + _, b = librosa.beat.beat_track(onset_envelope=onset, sr=SR, hop_length=HOP, tightness=400) + bt = librosa.frames_to_time(b, sr=SR, hop_length=HOP) + w = np.maximum(0, onset - np.median(onset)) + guess = np.median(np.diff(bt)) + best = None + for period in np.arange(guess * 0.97, guess * 1.03, 0.00001): + hist, _ = np.histogram(np.mod(ot, period) / period, bins=100, range=(0, 1), weights=w) + hist = np.convolve(np.r_[hist[-2:], hist, hist[:2]], np.ones(5) / 5, "valid") + if best is None or hist.max() > best[0]: + best = (hist.max(), period, (np.argmax(hist) + 0.5) / 100 * period) + _, period, offset = best + resid = bt - (offset + period * np.round((bt - offset) / period)) + if np.median(np.abs(resid)) <= 0.015: + print(" a fixed grid: %.3f bpm, beat 0 at %.4f s; tracked beats off it by %.1f ms (median)" % (60 / period, offset, np.median(np.abs(resid)) * 1000)) + return offset + period * np.arange(int((dur - offset) / period) + 1) + fine = librosa.onset.onset_strength(y=yp, sr=SR, hop_length=64) + ft = librosa.frames_to_time(np.arange(len(fine)), sr=SR, hop_length=64) + _, b = librosa.beat.beat_track(onset_envelope=onset, sr=SR, hop_length=HOP, tightness=100, start_bpm=60 / period) + ref = [] + for t in librosa.frames_to_time(b, sr=SR, hop_length=HOP): + m = np.where(np.abs(ft - t) < 0.05)[0] + ref.append(ft[m[np.argmax(fine[m])]]) + ref = np.array(ref) + n = np.arange(len(ref)) + smooth = np.empty(len(ref)) + for k in n: + lo = max(0, k - 8) + hi = min(len(ref), k + 9) + smooth[k] = np.polyval(np.polyfit(n[lo:hi], ref[lo:hi], 1), k) + c = np.polyfit(n[-24:], smooth[-24:], 1) + extra = [] + k = len(smooth) + while np.polyval(c, k) < dur: + extra.append(np.polyval(c, k)) + k += 1 + print(" no fixed grid: %d beats tracked and smoothed (%.1f ms median off), %d carried to the end; %.2f to %.2f bpm" % ( + len(smooth), np.median(np.abs(ref - smooth)) * 1000, len(extra), 60 / np.median(np.diff(smooth[:32])), 60 / np.median(np.diff(smooth[-32:])))) + return np.r_[smooth, extra] + + +def flux(M, freqs, lo, hi): + b = np.log1p(M[(freqs >= lo) & (freqs < hi)] * 10) + return np.maximum(0, np.diff(b, axis=1, prepend=b[:, :1])).sum(axis=0) + + +def band(M, freqs, lo, hi): + return np.sqrt((M[(freqs >= lo) & (freqs < hi)] ** 2).sum(axis=0)) + + +def normal(curve): + return np.clip(curve / (np.percentile(curve, 99.5) + 1e-9), 0, 1) + + +# Onto the RATE grid, keeping each sample's peak so a short hit is not averaged away. +def resample(curve, ft, frames): + out = np.zeros(frames) + idx = np.clip((ft * RATE).astype(int), 0, frames - 1) + np.maximum.at(out, idx, curve) + return out + + +def decayed(curve): + out = np.empty_like(curve) + held = 0.0 + for i, v in enumerate(curve): + held = max(v, held * DECAY) + out[i] = held + return out + + +# Hits: local peaks over a moving median, at least gap seconds apart. +def hits(curve, ft, gap, k): + win = int(1.0 * SR / HOP) + pad = np.pad(curve, win // 2, mode="edge") + med = np.array([np.median(pad[i:i + win]) for i in range(len(curve))]) + std = np.array([np.std(pad[i:i + win]) for i in range(len(curve))]) + pick = [] + last = -1.0 + for i in range(1, len(curve) - 1): + if curve[i] >= curve[i - 1] and curve[i] > curve[i + 1] and curve[i] > med[i] + k * std[i] and ft[i] - last >= gap: + pick.append(ft[i]) + last = ft[i] + return np.array(pick) + + +def packed(curve): + q = np.clip(np.round(curve * (LEVELS - 1)), 0, LEVELS - 1).astype(int) + return "".join(ALPHABET[v] for v in q) + + +def numbers(values, fmt): + text = [] + line = [] + for v in values: + line.append(fmt % v) + if len(line) == 12: + text.append("\t" + ", ".join(line) + ",") + line = [] + if line: + text.append("\t" + ", ".join(line) + ",") + return "\n".join(text) + + +def main(): + source, target = sys.argv[1], sys.argv[2] + print(source) + y, _ = librosa.load(source, sr=SR, mono=True) + dur = len(y) / SR + yh, yp = librosa.effects.hpss(y) + grid = beatGrid(y, yp, dur) + + S = np.abs(librosa.stft(y, n_fft=2048, hop_length=HOP)) + Sp = np.abs(librosa.stft(yp, n_fft=2048, hop_length=HOP)) + Sh = np.abs(librosa.stft(yh, n_fft=2048, hop_length=HOP)) + freqs = librosa.fft_frequencies(sr=SR, n_fft=2048) + ft = librosa.frames_to_time(np.arange(S.shape[1]), sr=SR, hop_length=HOP) + + kick = normal(flux(Sp, freqs, 30, 150)) + snare = normal(flux(Sp, freqs, 1500, 5000)) + hat = normal(flux(Sp, freqs, 7000, 11000)) + bass = normal(band(Sh, freqs, 40, 250)) + rms = normal(librosa.feature.rms(y=y, hop_length=HOP)[0]) + cent = librosa.feature.spectral_centroid(S=S, sr=SR)[0] + high = np.clip((cent - 1000) / 3500, 0, 1) + + # Beat one: where loudness and bass jump most often from the beat before. + def over(curve, a, b): + m = (ft >= a) & (ft < b) + return curve[m].mean() if m.any() else 0 + + level = np.array([over(rms, grid[i], grid[i + 1]) + over(bass, grid[i], grid[i + 1]) for i in range(len(grid) - 1)]) + jump = np.r_[0, np.abs(np.diff(level))] + big = jump > np.percentile(jump, 95) + votes = [int(big[p::4].sum()) for p in range(4)] + phase = int(np.argmax(votes)) + print(" beat one is beat %d of the grid (votes %s)" % (phase, votes)) + + # The strongest pitch class in the upper harmonic part, and how clear it is. + chroma = librosa.feature.chroma_stft(S=Sh * (freqs[:, None] > 300), sr=SR) + note = np.argmax(chroma, axis=0) + clear = chroma.max(axis=0) / (chroma.sum(axis=0) + 1e-9) + + frames = int(dur * RATE) + 1 + env = {} + for name, curve, fall in (("kick", kick, True), ("snare", snare, True), ("hat", hat, True), ("bass", bass, False), ("level", rms, False), ("bright", high, False)): + c = resample(curve, ft, frames) + if fall: + c = decayed(c) + else: + c = np.convolve(c, np.ones(5) / 5, "same") + env[name] = c + idx = np.clip(np.round(np.arange(frames) / RATE * SR / HOP).astype(int), 0, len(note) - 1) + noteFrame = note[idx] + clearness = np.clip((clear[idx] - 0.12) / 0.25, 0, 1) + + kickHits = hits(kick, ft, 0.12, 1.5) + snareHits = hits(snare, ft, 0.12, 1.5) + hatHits = hits(hat, ft, 0.07, 1.2) + print(" %d frames; %d kick hits, %d snare hits, %d hat hits; %d beats, %.1f s" % (frames, len(kickHits), len(snareHits), len(hatHits), len(grid), dur)) + + with open(target, "w") as out: + out.write("-- Written by util/demoSync.py from %s: what the demo synchronises to. Times are seconds of\n" % source.split("/")[-1]) + out.write("-- music; envelopes are %d samples a second, one character each, 0 to 63 in the base64 alphabet.\n" % RATE) + out.write("return {\n") + out.write("\tduration = %.3f,\n" % dur) + out.write("\trate = %d,\n" % RATE) + out.write("\tbarStart = %d, -- The beat (counting from 1) that begins the first whole bar\n" % (phase + 1)) + out.write("\tbeats = {\n%s\n\t},\n" % numbers(grid, "%.4f")) + for name, values in (("kicks", kickHits), ("snares", snareHits), ("hats", hatHits)): + out.write("\t%s = {\n%s\n\t},\n" % (name, numbers(values, "%.3f"))) + for name in ("kick", "snare", "hat", "bass", "level", "bright"): + out.write("\t%s = [[%s]],\n" % (name, packed(env[name]))) + out.write("\tnote = [[%s]],\n" % "".join(ALPHABET[v] for v in noteFrame)) + out.write("\tnoteClear = [[%s]],\n" % packed(clearness)) + out.write("}\n") + + +if __name__ == "__main__": + main() diff --git a/util/demoVideo.py b/util/demoVideo.py new file mode 100644 index 000000000..613597cf0 --- /dev/null +++ b/util/demoVideo.py @@ -0,0 +1,144 @@ +# Precalculates the demos' per-pixel effects as videos: the oldest trick in the demoscene, done with +# numpy instead of lookup tables in assembler. Singe then plays them, scrubs them, turns them, and +# puts them on 3D surfaces. +# +# python3 util/demoVideo.py tunnel out.mp4 [palette] [frames] +# python3 util/demoVideo.py plasma out.mp4 [palette] [frames] [fps] +# python3 util/demoVideo.py noise out.mp4 [frames] +# +# tunnel draws exactly one period of travel down a texture-mapped tunnel in frames frames, every one a +# keyframe, so a demo can seek to any frame at once and move through the tunnel at whatever speed the +# music says; the last frame leads back into the first. plasma is an ordinary looping video whose +# every term repeats a whole number of times in its length, so it loops without a seam. noise is a +# tape's snow and tracking bands, also looping. +import math +import subprocess +import sys + +import numpy as np + +W = 640 +H = 480 + +PALETTES = { + # Neon: black, violet, magenta, orange, and a cyan accent. + "neon": [(0.00, (4, 0, 16)), (0.25, (60, 10, 120)), (0.50, (255, 30, 170)), (0.70, (255, 140, 60)), (0.85, (255, 230, 150)), (1.00, (40, 230, 255))], + # Disco: deep red, gold, and white. + "disco": [(0.00, (20, 0, 10)), (0.30, (150, 20, 40)), (0.55, (255, 150, 30)), (0.80, (255, 230, 140)), (1.00, (255, 255, 255))], + # Arcade: blue, green, and yellow. + "arcade": [(0.00, (0, 0, 20)), (0.30, (10, 40, 160)), (0.55, (20, 200, 120)), (0.80, (240, 240, 60)), (1.00, (255, 255, 255))], +} + + +def ramp(name, t): + stops = PALETTES[name] + t = np.clip(t, 0, 1) + out = np.zeros(t.shape + (3,)) + for (t0, c0), (t1, c1) in zip(stops[:-1], stops[1:]): + m = (t >= t0) & (t <= t1) + k = ((t - t0) / (t1 - t0))[m][:, None] + out[m] = np.array(c0) * (1 - k) + np.array(c1) * k + return out + + +def encoder(out, fps, intra): + args = ["ffmpeg", "-hide_banner", "-loglevel", "error", "-y", "-f", "rawvideo", "-pix_fmt", "rgb24", "-s", "%dx%d" % (W, H), "-r", str(fps), "-i", "-", + "-c:v", "libx264", "-preset", "slow", "-crf", "18", "-pix_fmt", "yuv420p", "-an"] + if intra: + args += ["-g", "1", "-keyint_min", "1"] + else: + args += ["-g", str(int(float(fps)))] + return subprocess.Popen(args + [out], stdin=subprocess.PIPE) + + +# Down a tunnel: each pixel's angle round the axis and its depth (inverse distance from the centre) +# index a texture of neon rings and spokes. Depth runs one texture period over the frames. +def tunnel(out, palette="neon", frames=120): + y, x = np.mgrid[0:H, 0:W].astype(np.float64) + x = (x - W / 2 + 0.5) / (H / 2) + y = (y - H / 2 + 0.5) / (H / 2) + r = np.sqrt(x * x + y * y) + 1e-6 + a = np.arctan2(y, x) / (2 * math.pi) + depth = 0.35 / r + shade = np.clip(r * 1.6, 0, 1) ** 0.8 + pipe = encoder(out, 50, True) + RINGS = 4 + SPOKES = 16 + for f in range(frames): + p = f / frames + u = depth + p / RINGS + v = a + depth * 0.15 + ring = 0.5 + 0.5 * np.cos(u * RINGS * 2 * math.pi * RINGS) + edge = np.abs(np.mod(u * RINGS * RINGS, 1.0) - 0.5) * 2 + spoke = np.abs(np.mod(v * SPOKES, 1.0) - 0.5) * 2 + check = ((np.floor(u * RINGS * RINGS) + np.floor(v * SPOKES)) % 2) + glowRing = np.exp(-(1 - edge) * 9) + glowSpoke = np.exp(-(1 - spoke) * 12) + value = 0.18 + 0.22 * check + 0.75 * glowRing + 0.45 * glowSpoke * ring + col = ramp(palette, np.clip(value * shade, 0, 1)) + # Far away the tunnel fades into a hot white core. + core = np.exp(-r * 9)[..., None] + col = col * (1 - core) + core * np.array([255, 235, 255]) + pipe.stdin.write(np.clip(col, 0, 255).astype(np.uint8).tobytes()) + pipe.stdin.close() + pipe.wait() + + +# Plasma: four interfering waves, each a whole number of turns over the loop, run through a palette +# that itself cycles a whole number of times. +def plasma(out, palette="neon", frames=400, fps=50): + y, x = np.mgrid[0:H, 0:W].astype(np.float64) + x /= W + y /= H + pipe = encoder(out, fps, False) + for f in range(frames): + p = f / frames * 2 * math.pi + v = np.sin(x * 9 + p) + v += np.sin((y * 7 + p * 2) * 1.0) + v += np.sin((x * 6 + y * 5) + p * 3) + cx = x - 0.5 + 0.3 * math.sin(p) + cy = y - 0.5 + 0.3 * math.cos(p * 2) + v += np.sin(np.sqrt(cx * cx + cy * cy) * 18 - p * 4) + t = (np.sin(v * math.pi * 0.5 + p) + 1) / 2 + col = ramp(palette, t) + pipe.stdin.write(np.clip(col, 0, 255).astype(np.uint8).tobytes()) + pipe.stdin.close() + pipe.wait() + + +# A tape's snow, with a couple of tracking bands rolling up the picture, at a quarter of the size +# and scaled up by the player. +def noise(out, frames=100): + global W, H + W, H = 320, 240 + rng = np.random.default_rng(11) + pipe = encoder(out, 25, False) + rows = np.arange(H)[:, None] + for f in range(frames): + snow = rng.random((H, W)) ** 1.6 * 200 + # Grain in streaks: each row's noise smeared sideways a little. + snow = (snow + np.roll(snow, 1, axis=1) + np.roll(snow, 2, axis=1)) / 3 + p = f / frames + band = np.exp(-((rows - (H * (1 - p) * 2) % (H + 40) + 20) ** 2) / 60.0) + band2 = np.exp(-((rows - (H * (1 - p) * 2 + H / 2) % (H + 40) + 20) ** 2) / 20.0) + v = snow * (0.55 + 0.45 * band + 0.6 * band2) + band * 60 + col = np.stack([v * 0.95, v * 0.9, v * 1.05], -1) + pipe.stdin.write(np.clip(col, 0, 255).astype(np.uint8).tobytes()) + pipe.stdin.close() + pipe.wait() + + +def main(): + kind = sys.argv[1] + out = sys.argv[2] + if kind == "tunnel": + tunnel(out, sys.argv[3] if len(sys.argv) > 3 else "neon", int(sys.argv[4]) if len(sys.argv) > 4 else 120) + elif kind == "plasma": + plasma(out, sys.argv[3] if len(sys.argv) > 3 else "neon", int(sys.argv[4]) if len(sys.argv) > 4 else 400, sys.argv[5] if len(sys.argv) > 5 else 50) + elif kind == "noise": + noise(out, int(sys.argv[3]) if len(sys.argv) > 3 else 100) + print("wrote", out) + + +if __name__ == "__main__": + main() diff --git a/util/insertCoinArt.py b/util/insertCoinArt.py new file mode 100644 index 000000000..4e2d30b46 --- /dev/null +++ b/util/insertCoinArt.py @@ -0,0 +1,552 @@ +# Draws the art for demos/insertCoin: every picture is made here, so it is ours and can be drawn +# again. The pixel sprites are written out as rows of characters, a character a pixel, the way they +# were drawn on graph paper for the machines that first showed them; the demo scales them up with +# nearest-pixel stretching, so they stay square. +# +# Usage: python3 util/insertCoinArt.py +import math +import os + +import numpy as np +from PIL import Image, ImageDraw + + +REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +OUT = os.path.join(REPO, "demos", "insertCoin", "art") + +# Colours by character for the pixel sprites; "." is transparent. +INK = { + "W": (255, 255, 255), "K": (20, 20, 30), "R": (230, 40, 40), "r": (140, 20, 30), "O": (255, 150, 30), + "Y": (255, 230, 60), "y": (180, 140, 20), "G": (60, 220, 90), "g": (20, 120, 50), "B": (60, 140, 255), + "b": (30, 60, 160), "C": (80, 230, 255), "M": (230, 60, 220), "P": (150, 70, 230), "S": (200, 200, 210), + "s": (120, 120, 135), "T": (240, 190, 140), "t": (170, 110, 70), +} + + +def save(image, name): + image.save(os.path.join(OUT, name)) + print("%-16s %d x %d" % (name, image.width, image.height)) + + +def pixels(rows): + h = len(rows) + w = max(len(r) for r in rows) + img = Image.new("RGBA", (w, h), (0, 0, 0, 0)) + for y, row in enumerate(rows): + for x, c in enumerate(row): + if c in INK: + img.putpixel((x, y), INK[c] + (255,)) + return img + + +# Frames side by side in one sheet, for spriteLoadFrames-free drawing with spriteDrawGrid. +def sheet(frames): + w = max(f.width for f in frames) + h = max(f.height for f in frames) + out = Image.new("RGBA", (w * len(frames), h), (0, 0, 0, 0)) + for i, f in enumerate(frames): + out.paste(f, (i * w, 0)) + return out + + +# Two kinds of alien, two frames each, in white so the demo can tint them: a domed jelly whose +# tentacles sway, and a diamond-backed bug whose legs step. +INVADER_A = [[ + "...WWWWWW...", + ".WWWWWWWWWW.", + "WW.WW..WW.WW", + "WWWWWWWWWWWW", + "..WW.WW.WW..", + ".W..W..W..W.", + "W..W....W..W", + "............", +], [ + "...WWWWWW...", + ".WWWWWWWWWW.", + "WW.WW..WW.WW", + "WWWWWWWWWWWW", + "..WW.WW.WW..", + "..W..W..W...", + ".W..W..W..W.", + "............", +]] +INVADER_B = [[ + ".....WW.....", + "....WWWW....", + "...WW..WW...", + "..WWWWWWWW..", + ".WW.WWWW.WW.", + "WW..W..W..WW", + "W..W....W..W", + "..W......W..", +], [ + ".....WW.....", + "....WWWW....", + "...WW..WW...", + "..WWWWWWWW..", + ".WW.WWWW.WW.", + "WW..W..W..WW", + ".W.W....W.W.", + "W..........W", +]] +CANNON = [ + "......W......", + ".....WWW.....", + "....WWWWW....", + ".WWWWWWWWWWW.", + "WWWWWWWWWWWWW", + "WW.WWWWWWW.WW", + "WWWWWWWWWWWWW", + ".WWW.....WWW.", +] + +# The runner: a kid with green spiky hair and a purple jacket, four frames of a run and one of a +# jump. +RUNNER = [[ + "....G.G.G.......", + "...GGGGGGGG.....", + "...GGTTKTT......", + "...GTTTTTTTTT...", + "...GTTTTTTTTTT..", + "...GTTTTTTTT....", + ".....TTTTTTT....", + "....PPBPPP......", + "...PPPBPPBPPP...", + "..PPPPBBBBPPPP..", + "..TTPBWBBWBPTT..", + "..TTTBBBBBBTTT..", + "..TTBBBBBBBBTT..", + "....BBB..BBB....", + "...WWW....WWW...", + "..WWWW....WWWW..", +], [ + "....G.G.G.......", + "...GGGGGGGG.....", + "...GGTTKTT......", + "...GTTTTTTTTT...", + "...GTTTTTTTTTT..", + "...GTTTTTTTT....", + ".....TTTTTTT....", + "....PPPPBPP.....", + "...PPPPBBPPPT...", + "..TPPPPBWBBBTT..", + "..TTBBBBBBBBT...", + "...BBBBBBBBB....", + "..BBBBBBBBB.....", + ".WBBB...BBB.....", + ".WW......WWW....", + "..........WWW...", +], [ + "....G.G.G.......", + "...GGGGGGGG.....", + "...GGTTKTT......", + "...GTTTTTTTTT...", + "...GTTTTTTTTTT..", + "...GTTTTTTTT....", + ".....TTTTTTT....", + ".....PPBPP......", + "....PPPBBPP.....", + "....PPPBWBB.....", + "....TTBBBBB.....", + ".....TBBBBB.....", + ".....BBBBB......", + "......BBB.......", + "......WWW.......", + "......WWWW......", +], [ + "....G.G.G.......", + "...GGGGGGGG.....", + "...GGTTKTT......", + "...GTTTTTTTTT...", + "...GTTTTTTTTTT..", + "...GTTTTTTTT....", + ".....TTTTTTT....", + "....PPBPPP......", + "...PPPBBPPPP....", + "...PPPBWBBPPT...", + "...TTBBBBBBTT...", + "....BBBBBBBB....", + "...BBBB.BBBB....", + "..WWBB...BBWW...", + "..WWW.....WWW...", + "................", +], [ + "....G.G.G....TT.", + "...GGGGGGGG..TT.", + "...GGTTKTT...PP.", + "...GTTTTTTTTPPP.", + "...GTTTTTTTTPP..", + "...GTTTTTTTPP...", + ".....TTTTTTPP...", + "..PPPPBPPPP.....", + ".PPPPPBBPPP.....", + "TTPPPBWBBB......", + "TT.BBBBBBBB.....", + "...BBBBBBBBB....", + "..BBBB..BBBB....", + "..BBB....BBB....", + ".WWW......WWW...", + "WWW........WWW..", +]] + +COIN = [[ + "..YYYY..", + ".YyyyyY.", + "YyYYYYyY", + "YyYyyYyY", + "YyYyyYyY", + "YyYYYYyY", + ".YyyyyY.", + "..YYYY..", +], [ + "...YY...", + "..YyyY..", + "..YYyY..", + "..YyyY..", + "..YyyY..", + "..YYyY..", + "..YyyY..", + "...YY...", +], [ + "...YY...", + "...yY...", + "...yY...", + "...yY...", + "...yY...", + "...yY...", + "...yY...", + "...YY...", +], [ + "...YY...", + "..YyyY..", + "..YyYY..", + "..YyyY..", + "..YyyY..", + "..YyYY..", + "..YyyY..", + "...YY...", +]] + +SHIP = [ + ".......WW.......", + "......WCCW......", + "......WCCW......", + ".....WSCCSW.....", + ".....WSSSSW.....", + "....WSSBBSSW....", + "R..WSSBCCBSSW..R", + "R.WSSSBCCBSSSW.R", + "WWSSSSSBBSSSSSWW", + "WSSSSSSSSSSSSSSW", + "WSSsSSSSSSSSsSSW", + ".WsssSSSSSSsssW.", + "..W.OO....OO.W..", + ".....OO..OO.....", + "......O..O......", + "................", +] + +KART = [ + "....KKKKKKKK....", + "...KRRRRRRRRK...", + "..KRRWWWWWWRRK..", + "..KRRRRRRRRRRK..", + ".KKKKKRRRRKKKKK.", + "KKKKKRRRRRRKKKKK", + "KsKKRRRRRRRRKKsK", + "KsKKKKKKKKKKKKsK", + "KKK.SSSSSSSS.KKK", + "KKK.........KKKK", +] + + +# The boss, drawn larger and smoothly: a core, an arm, and a turret, each turned by the demo. +def bossCore(size=96): + y, x = np.mgrid[0:size, 0:size] + 0.5 + c = size / 2 + d = np.sqrt((x - c) ** 2 + (y - c) ** 2) / c + a = np.arctan2(y - c, x - c) + img = np.zeros((size, size, 4)) + shell = (d < 1) & (d > 0.55) + ring = 0.5 + 0.5 * np.cos(a * 8) + img[shell, :3] = (np.array([120, 30, 160]) * (0.6 + 0.4 * ring[shell])[:, None]) + np.array([40, 10, 40]) * (1 - d[shell])[:, None] + eye = d <= 0.55 + glow = np.clip(1 - d / 0.55, 0, 1) + img[eye, :3] = np.array([255, 60, 40]) * (0.4 + 0.6 * glow[eye])[:, None] + np.array([255, 220, 120]) * (glow[eye] ** 4)[:, None] + pupil = d < 0.18 + img[pupil, :3] = [20, 0, 0] + img[..., 3] = np.clip((1 - d) * c, 0, 1) * 255 + edge = (d > 0.95) & (d < 1) + img[edge, :3] = [255, 200, 255] + return Image.fromarray(np.clip(img, 0, 255).astype(np.uint8), "RGBA") + + +def bossArm(w=96, h=24): + img = Image.new("RGBA", (w, h), (0, 0, 0, 0)) + d = ImageDraw.Draw(img) + d.polygon([(0, 4), (w - 16, 6), (w - 4, h // 2), (w - 16, h - 6), (0, h - 4)], fill=(90, 40, 130, 255), outline=(220, 160, 255, 255)) + for i in range(4): + d.rectangle([10 + i * 18, 9, 18 + i * 18, h - 9], fill=(255, 120, 40, 255)) + return img + + +def turret(size=28): + img = Image.new("RGBA", (size, size), (0, 0, 0, 0)) + d = ImageDraw.Draw(img) + d.ellipse([2, 2, size - 3, size - 3], fill=(60, 200, 220, 255), outline=(220, 255, 255, 255)) + d.rectangle([size // 2 - 3, size // 2, size // 2 + 2, size - 1], fill=(30, 80, 110, 255)) + d.ellipse([size // 2 - 5, size // 2 - 5, size // 2 + 4, size // 2 + 4], fill=(255, 255, 180, 255)) + return img + + +def bullet(size=12): + y, x = np.mgrid[0:size, 0:size] + 0.5 + d = np.sqrt((x - size / 2) ** 2 + (y - size / 2) ** 2) / (size / 2) + img = np.zeros((size, size, 4)) + img[..., :3] = 255 + img[..., 3] = np.clip(1 - d, 0, 1) ** 0.6 * 255 + core = d < 0.45 + img[~core, 1] = img[~core, 1] * 0.7 + return Image.fromarray(img.astype(np.uint8), "RGBA") + + +# The 8 by 8 font: 5 by 7 capitals, digits, and punctuation drawn here a pixel at a time, laid out +# sixteen to a row for ASCII 32 to 127 with each glyph one pixel in from its cell's left. Lower +# case shares the capitals. +GLYPHS = { + " ": [" "] * 7, + "!": [" # ", " # ", " # ", " # ", " # ", " ", " # "], + "\"": [" # # ", " # # ", " ", " ", " ", " ", " "], + "#": [" # # ", "#####", " # # ", " # # ", " # # ", "#####", " # # "], + "$": [" # ", " ####", "# # ", " ### ", " # #", "#### ", " # "], + "%": ["## ", "## #", " # ", " # ", " # ", "# ##", " ##"], + "&": [" ## ", "# # ", "# # ", " # ", "# # #", "# # ", " ## #"], + "'": [" # ", " # ", " ", " ", " ", " ", " "], + "(": [" # ", " # ", " # ", " # ", " # ", " # ", " # "], + ")": [" # ", " # ", " # ", " # ", " # ", " # ", " # "], + "*": [" ", " # ", "# # #", " ### ", "# # #", " # ", " "], + "+": [" ", " # ", " # ", "#####", " # ", " # ", " "], + ",": [" ", " ", " ", " ", " ## ", " # ", " # "], + "-": [" ", " ", " ", "#####", " ", " ", " "], + ".": [" ", " ", " ", " ", " ", " ## ", " ## "], + "/": [" ", " #", " # ", " # ", " # ", "# ", " "], + "0": [" ### ", "# #", "# ##", "# # #", "## #", "# #", " ### "], + "1": [" # ", " ## ", " # ", " # ", " # ", " # ", " ### "], + "2": [" ### ", "# #", " #", " # ", " # ", " # ", "#####"], + "3": ["#####", " # ", " # ", " # ", " #", "# #", " ### "], + "4": [" # ", " ## ", " # # ", "# # ", "#####", " # ", " # "], + "5": ["#####", "# ", "#### ", " #", " #", "# #", " ### "], + "6": [" ## ", " # ", "# ", "#### ", "# #", "# #", " ### "], + "7": ["#####", " #", " # ", " # ", " # ", " # ", " # "], + "8": [" ### ", "# #", "# #", " ### ", "# #", "# #", " ### "], + "9": [" ### ", "# #", "# #", " ####", " #", " # ", " ## "], + ":": [" ", " ## ", " ## ", " ", " ## ", " ## ", " "], + ";": [" ", " ## ", " ## ", " ", " ## ", " # ", " # "], + "<": [" # ", " # ", " # ", "# ", " # ", " # ", " # "], + "=": [" ", " ", "#####", " ", "#####", " ", " "], + ">": [" # ", " # ", " # ", " #", " # ", " # ", " # "], + "?": [" ### ", "# #", " #", " # ", " # ", " ", " # "], + "@": [" ### ", "# #", "# ###", "# # #", "# ###", "# ", " ####"], + "A": [" ### ", "# #", "# #", "#####", "# #", "# #", "# #"], + "B": ["#### ", "# #", "# #", "#### ", "# #", "# #", "#### "], + "C": [" ### ", "# #", "# ", "# ", "# ", "# #", " ### "], + "D": ["#### ", "# #", "# #", "# #", "# #", "# #", "#### "], + "E": ["#####", "# ", "# ", "#### ", "# ", "# ", "#####"], + "F": ["#####", "# ", "# ", "#### ", "# ", "# ", "# "], + "G": [" ### ", "# #", "# ", "# ###", "# #", "# #", " ####"], + "H": ["# #", "# #", "# #", "#####", "# #", "# #", "# #"], + "I": [" ### ", " # ", " # ", " # ", " # ", " # ", " ### "], + "J": [" ###", " # ", " # ", " # ", " # ", "# # ", " ## "], + "K": ["# #", "# # ", "# # ", "## ", "# # ", "# # ", "# #"], + "L": ["# ", "# ", "# ", "# ", "# ", "# ", "#####"], + "M": ["# #", "## ##", "# # #", "# # #", "# #", "# #", "# #"], + "N": ["# #", "# #", "## #", "# # #", "# ##", "# #", "# #"], + "O": [" ### ", "# #", "# #", "# #", "# #", "# #", " ### "], + "P": ["#### ", "# #", "# #", "#### ", "# ", "# ", "# "], + "Q": [" ### ", "# #", "# #", "# #", "# # #", "# # ", " ## #"], + "R": ["#### ", "# #", "# #", "#### ", "# # ", "# # ", "# #"], + "S": [" ####", "# ", "# ", " ### ", " #", " #", "#### "], + "T": ["#####", " # ", " # ", " # ", " # ", " # ", " # "], + "U": ["# #", "# #", "# #", "# #", "# #", "# #", " ### "], + "V": ["# #", "# #", "# #", "# #", "# #", " # # ", " # "], + "W": ["# #", "# #", "# #", "# # #", "# # #", "# # #", " # # "], + "X": ["# #", "# #", " # # ", " # ", " # # ", "# #", "# #"], + "Y": ["# #", "# #", " # # ", " # ", " # ", " # ", " # "], + "Z": ["#####", " #", " # ", " # ", " # ", "# ", "#####"], + "[": [" ### ", " # ", " # ", " # ", " # ", " # ", " ### "], + "\\": [" ", "# ", " # ", " # ", " # ", " #", " "], + "]": [" ### ", " # ", " # ", " # ", " # ", " # ", " ### "], + "^": [" # ", " # # ", "# #", " ", " ", " ", " "], + "_": [" ", " ", " ", " ", " ", " ", "#####"], +} + + +def font(): + img = Image.new("RGBA", (16 * 8, 6 * 8), (0, 0, 0, 0)) + for code in range(32, 128): + ch = chr(code) + rows = GLYPHS.get(ch.upper()) + if rows is None: + continue + i = code - 32 + x0 = (i % 16) * 8 + 1 + y0 = (i // 16) * 8 + for y, row in enumerate(rows): + for x, c in enumerate(row): + if c == "#": + img.putpixel((x0 + x, y0 + y), (255, 255, 255, 255)) + return img + + +# Parallax layers for the side-scroller, each tiling sideways: far mountains, near hills, and a +# ground strip of grass over brick. +def mountains(w=320, h=110): + img = Image.new("RGBA", (w, h), (0, 0, 0, 0)) + d = ImageDraw.Draw(img) + rng = np.random.default_rng(4) + pts = [(0, h)] + x = 0 + while x <= w: + pts.append((x, int(rng.integers(20, 80)))) + x += int(rng.integers(30, 60)) + pts[-1] = (w, pts[1][1]) + pts.append((w, h)) + d.polygon(pts, fill=(70, 80, 150, 255)) + for px, py in pts[1:-1]: + d.polygon([(px - 8, py + 10), (px, py), (px + 8, py + 10)], fill=(230, 240, 255, 255)) + return img + + +def hills(w=320, h=80): + img = Image.new("RGBA", (w, h), (0, 0, 0, 0)) + d = ImageDraw.Draw(img) + for i in range(-1, 5): + cx = i * 90 + 40 + d.ellipse([cx - 70, 20, cx + 70, 160], fill=(40, 150, 70, 255)) + d.ellipse([cx - 50, 34, cx + 50, 120], fill=(70, 190, 90, 255)) + return img + + +def ground(w=64, h=48): + img = Image.new("RGBA", (w, h), (0, 0, 0, 0)) + d = ImageDraw.Draw(img) + d.rectangle([0, 0, w - 1, 7], fill=(60, 200, 70, 255)) + d.rectangle([0, 6, w - 1, 9], fill=(30, 120, 40, 255)) + for row in range(4): + y = 10 + row * 10 + off = (row % 2) * 8 + for col in range(-1, 5): + x = col * 16 + off + d.rectangle([x, y, x + 14, y + 8], fill=(190, 90, 40, 255), outline=(110, 50, 20, 255)) + return img + + +# The race track, seen from above: grass, a loop of road with a striped kerb, and a +# chequered start line, at a pixel a texel. +def track(size=512): + y, x = np.mgrid[0:size, 0:size] + 0.5 + cx = cy = size / 2 + u = (x - cx) / (size * 0.36) + v = (y - cy) / (size * 0.26) + r = np.sqrt(u * u + v * v) + img = np.zeros((size, size, 3)) + grass = ((np.floor(x / 16) + np.floor(y / 16)) % 2) + img[:] = np.where(grass[..., None] > 0, np.array([60, 170, 60]), np.array([50, 150, 50])) + road = np.abs(r - 1) < 0.16 + kerb = (np.abs(r - 1) >= 0.16) & (np.abs(r - 1) < 0.21) + a = np.arctan2(v, u) + img[road] = [110, 110, 120] + stripes = (np.floor(a / (2 * math.pi) * 64) % 2) == 0 + img[kerb & stripes] = [230, 40, 40] + img[kerb & ~stripes] = [245, 245, 245] + start = road & (np.abs(a) < 0.035) + chk = ((np.floor(x / 4) + np.floor(y / 4)) % 2) == 0 + img[start & chk] = [20, 20, 20] + img[start & ~chk] = [250, 250, 250] + water = (r < 0.55) + img[water] = [40, 100, 220] + img[water & ((np.floor((x + y) / 6) % 5) == 0)] = [90, 160, 255] + return Image.fromarray(img.astype(np.uint8), "RGB") + + +# A sky for the racers, as an equirectangular picture: a gradient and a band of pixel mountains +# all the way round, so turning the camera scrolls them as the old racers scrolled theirs. +def raceSky(w=2048, h=1024): + img = np.zeros((h, w, 3)) + t = (np.arange(h) / (h / 2))[:, None] + top = np.array([40, 80, 220]) + mid = np.array([140, 200, 255]) + img[:] = (top + (mid - top) * np.clip(t, 0, 1)[..., None]) + img[h // 2:] = [60, 170, 60] + rng = np.random.default_rng(9) + x = 0 + ridge = np.zeros(w) + while x < w: + peak = int(rng.integers(20, 70)) + span = int(rng.integers(60, 140)) + for i in range(span): + if x + i < w: + ridge[x + i] = max(ridge[x + i], peak * (1 - abs(i - span / 2) / (span / 2))) + x += span // 2 + for i in range(w): + top_y = h // 2 - int(ridge[i]) + img[top_y:h // 2, i] = [80, 90, 160] + img[top_y:min(top_y + 6, h // 2), i] = [235, 240, 255] + img = np.repeat(np.repeat(img[::4, ::4], 4, axis=0), 4, axis=1) + return Image.fromarray(img.astype(np.uint8), "RGB") + + +# A modern dusk for the chrome to reflect: a deep blue sky warming to orange at a low sun, a dark +# land below, and a few bright city lights. +def duskSky(w=2048, h=1024): + lon = (np.arange(w) + 0.5) / w * 2 * math.pi - math.pi + lat = math.pi / 2 - (np.arange(h) + 0.5) / h * math.pi + LON, LAT = np.meshgrid(lon, lat) + img = np.zeros((h, w, 3)) + up = np.clip(LAT / (math.pi / 2), 0, 1) + img[:] = (np.array([255, 150, 70]) * (1 - up[..., None]) ** 3 + np.array([20, 40, 110]) * (1 - (1 - up[..., None]) ** 3)) + sun = np.exp(-((LON - 0.6) ** 2 + (LAT - 0.08) ** 2) / 0.004) + img += sun[..., None] * np.array([255, 230, 180]) * 1.5 + down = LAT < 0 + img[down] = np.array([18, 16, 26]) + np.array([60, 40, 30]) * np.exp(LAT[down] * 6)[..., None] + rng = np.random.default_rng(2) + for _ in range(400): + x = int(rng.integers(0, w)) + y = int(h / 2 + rng.integers(2, 40)) + img[y, x] = [255, 220, 150] + return Image.fromarray(np.clip(img, 0, 255).astype(np.uint8), "RGB") + + +def scanlines(): + img = Image.new("RGBA", (4, 4), (0, 0, 0, 0)) + for x in range(4): + img.putpixel((x, 1), (0, 0, 0, 110)) + img.putpixel((x, 3), (0, 0, 0, 110)) + return img + + +def main(): + os.makedirs(OUT, exist_ok=True) + save(sheet([pixels(f) for f in INVADER_A]), "invaderA.png") + save(sheet([pixels(f) for f in INVADER_B]), "invaderB.png") + save(pixels(CANNON), "cannon.png") + save(sheet([pixels(f) for f in RUNNER]), "runner.png") + save(sheet([pixels(f) for f in COIN]), "coin.png") + save(pixels(SHIP), "ship.png") + save(pixels(KART), "kart.png") + save(bossCore(), "bossCore.png") + save(bossArm(), "bossArm.png") + save(turret(), "turret.png") + save(bullet(), "bullet.png") + save(font(), "font.png") + save(mountains(), "mountains.png") + save(hills(), "hills.png") + save(ground(), "ground.png") + save(track(), "track.png") + save(raceSky(), "raceSky.png") + save(duskSky(), "duskSky.png") + save(scanlines(), "scanlines.png") + + +if __name__ == "__main__": + main() diff --git a/util/learnKit.py b/util/learnKit.py index 97fcd3b98..095497fa8 100644 --- a/util/learnKit.py +++ b/util/learnKit.py @@ -5,11 +5,13 @@ # shapes rather than painted, so it is ours, it is tiny, and it can be regenerated. The engine # already gives every reader a video, two models, a font, and a click (the Singe folder it unpacks # on the first run), so this kit is only the things a 2D game needs: a ship, a rock, a shot, a -# star, one walk cycle, and two noises. +# star, one walk cycle, and two noises; and one small database, the stages lesson twenty-nine's +# game reads. # # Usage: python3 util/learnKit.py import math import os +import sqlite3 import struct import wave @@ -132,6 +134,30 @@ def boomShape(t, done): return (noise * 0.8 + math.sin(2.0 * math.pi * 70.0 * t) * 0.5) * (1.0 - done) ** 3 +# The stages of lesson twenty-nine's reaction test, as the database a game would ship: a name and +# the shortest and longest wait before "NOW!", in milliseconds. Written fresh each time, so the +# file is the same on every machine. +STAGES = [ + (1, "Easy", 1000, 3000), + (2, "Patient", 3000, 6000), + (3, "Twitchy", 300, 1200), + (4, "Cruel", 200, 8000), +] + + +def stages(): + path = os.path.join(OUT, "stages.db") + if os.path.exists(path): + os.remove(path) + db = sqlite3.connect(path) + db.execute("CREATE TABLE stages (id INTEGER PRIMARY KEY, name TEXT NOT NULL, waitMin INTEGER NOT NULL, waitMax INTEGER NOT NULL)") + db.executemany("INSERT INTO stages VALUES (?, ?, ?, ?)", STAGES) + db.commit() + db.execute("VACUUM") + db.close() + print("stages.db %d stages" % len(STAGES)) + + def main(): os.makedirs(OUT, exist_ok=True) save(ship(), "spaceship.png") @@ -141,6 +167,7 @@ def main(): save(walk(), "walk.png") tone("shoot.wav", 0.18, shootShape) tone("boom.wav", 0.45, boomShape) + stages() if __name__ == "__main__": diff --git a/util/mirrorballArt.py b/util/mirrorballArt.py new file mode 100644 index 000000000..bf2c38bb8 --- /dev/null +++ b/util/mirrorballArt.py @@ -0,0 +1,212 @@ +# Draws the art for demos/mirrorball: every picture is made from shapes and arithmetic here, so it is +# ours and can be drawn again. +# +# The club is an equirectangular picture, the whole room round the camera: the 3D scene lights with +# it and every facet of the mirror ball reflects a piece of it, so it is mostly dark with bright +# coloured lights round the walls and along a truss overhead, which is what makes a mirror ball +# sparkle. The rest are sprites and textures for the oldschool effects. +# +# Usage: python3 util/mirrorballArt.py +import math +import os + +import numpy as np +from PIL import Image, ImageDraw, ImageFont +from scipy import ndimage + + +REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +OUT = os.path.join(REPO, "demos", "mirrorball", "art") + +SS = 4 # Sprites are drawn this many times larger and shrunk, for smooth edges +FONT_WIDE = "/usr/share/fonts/truetype/lato/Lato-BlackItalic.ttf" +GOLD_TOP = np.array([255, 250, 210]) +GOLD_MID = np.array([200, 130, 30]) +GOLD_LOW = np.array([255, 210, 120]) +GOLD_DARK = np.array([90, 40, 10]) +DISCO = [(255, 40, 80), (255, 160, 20), (255, 240, 60), (60, 255, 120), (40, 200, 255), (160, 60, 255)] + + +def save(image, name): + image.save(os.path.join(OUT, name)) + print("%-16s %d x %d" % (name, image.width, image.height)) + + +# The room: near-black walls, a band of coloured lamps round them at eye height and a second band +# higher up, a truss of white lamps across the ceiling, and a floor that faintly carries the colours. +def club(): + w, h = 2048, 1024 + lon = (np.arange(w) + 0.5) / w * 2 * math.pi - math.pi + lat = math.pi / 2 - (np.arange(h) + 0.5) / h * math.pi + LON, LAT = np.meshgrid(lon, lat) + img = np.zeros((h, w, 3)) + img[:] = np.array([8, 6, 16]) + img += (np.clip(LAT, 0, None) / (math.pi / 2))[..., None] * np.array([10, 6, 24]) + + def lamps(count, latDeg, size, bright, colours): + out = np.zeros_like(img) + for i in range(count): + c = np.array(colours[i % len(colours)]) + lo = -math.pi + (i + 0.5) / count * 2 * math.pi + dl = np.angle(np.exp(1j * (LON - lo))) + d = np.sqrt((dl * np.cos(LAT)) ** 2 + (LAT - math.radians(latDeg)) ** 2) / math.radians(size) + out += (np.exp(-d * d * 3) * bright + np.exp(-d * 1.2) * 0.25)[..., None] * c + return out + + img += lamps(24, 4, 2.2, 1.6, DISCO) + img += lamps(16, 28, 3.0, 1.2, DISCO[::-1]) + img += lamps(12, 70, 2.0, 2.0, [(255, 255, 255)]) + floor = LAT < -0.05 + img[floor] = img[floor] * 0.35 + np.array([14, 8, 22]) + return Image.fromarray(np.clip(img, 0, 255).astype(np.uint8), "RGB") + + +# A floor tile: white with a bevelled edge and a dark seam, as both colour and emissive map, so the +# tile's own emissive colour lights it. +def tile(size=128): + y, x = np.mgrid[0:size, 0:size] + 0.5 + d = np.minimum(np.minimum(x, size - x), np.minimum(y, size - y)) + v = np.clip((d - 3) / 10, 0, 1) * 0.8 + 0.2 * (d > 3) + v *= 1 - 0.25 * ((x + y) / (2 * size)) + img = np.zeros((size, size, 4)) + img[..., :3] = (np.clip(v, 0, 1) * 255)[..., None] + img[..., 3] = 255 + return Image.fromarray(img.astype(np.uint8), "RGBA") + + +def chromeText(text, size, pad=24): + f = ImageFont.truetype(FONT_WIDE, size * SS) + box = f.getbbox(text) + w = (box[2] - box[0]) // SS + pad * 2 + h = (box[3] - box[1]) // SS + pad * 2 + mask = Image.new("L", (w * SS, h * SS), 0) + ImageDraw.Draw(mask).text((pad * SS - box[0], pad * SS - box[1]), text, font=f, fill=255) + m = np.array(mask).astype(np.float64) / 255 + rows = np.linspace(0, 1, h * SS) + top = (pad * SS) / (h * SS) + t = np.clip((rows - top) / (1 - 2 * top), 0, 1)[:, None] + upper = GOLD_TOP + (GOLD_MID - GOLD_TOP) * (t / 0.5) + lower = GOLD_DARK + (GOLD_LOW - GOLD_DARK) * ((t - 0.5) / 0.5) + grad = np.repeat(np.where(t < 0.5, upper, lower)[:, None, :], w * SS, axis=1) + outer = ndimage.maximum_filter(m, size=5 * SS) + ring = ndimage.maximum_filter(m, size=2 * SS) + halo = ndimage.gaussian_filter(outer, 7 * SS) + img = np.zeros((h * SS, w * SS, 4)) + img[..., :3] = np.array([255, 160, 40]) + img[..., 3] = np.clip(halo * 1.4, 0, 1) * 170 + img[..., :3] = np.where(outer[..., None] > 0.5, [30, 10, 4], img[..., :3]) + img[..., 3] = np.where(outer > 0.5, 255, img[..., 3]) + img[..., :3] = np.where(ring[..., None] > 0.5, [255, 255, 230], img[..., :3]) + img[..., :3] = np.where(m[..., None] > 0.5, grad, img[..., :3]) + big = Image.fromarray(np.clip(img, 0, 255).astype(np.uint8), "RGBA") + return big.resize((w, h), Image.LANCZOS) + + +# The twister's four faces side by side, 64 pixels each: stripes, a checker, chevrons, and dots, +# each in its own disco colour, so a turning bar shows which face is which. +def twister(): + fw, fh = 64, 64 + img = np.zeros((fh, fw * 4, 4)) + y, x = np.mgrid[0:fh, 0:fw] + 0.5 + pats = [ + ((np.floor(y / 8) % 2) == 0), + ((np.floor(x / 16) + np.floor(y / 16)) % 2 == 0), + ((np.abs((x - 32)) + y) % 32 < 16), + (((x % 16 - 8) ** 2 + (y % 16 - 8) ** 2) < 30), + ] + cols = [DISCO[0], DISCO[2], DISCO[4], DISCO[5]] + for i, (p, c) in enumerate(zip(pats, cols)): + face = np.where(p[..., None], np.array(c), np.array(c) * 0.35) + edge = (x < 2) | (x > fw - 2) + face[edge] = [255, 255, 255] + img[:, i * fw:(i + 1) * fw, :3] = face + img[..., 3] = 255 + return Image.fromarray(img.astype(np.uint8), "RGBA") + + +# One copper bar: a vertical gradient, white in the middle to dark at its edges, tinted per bar. +def copper(h=32): + y = (np.arange(h) + 0.5) / h + v = np.sin(y * math.pi) ** 1.5 + img = np.zeros((h, 4, 4)) + img[..., :3] = (v * 255)[:, None, None] + img[..., 3] = 255 + return Image.fromarray(img.astype(np.uint8), "RGBA") + + +# The rotozoomer's tile: a disco checker with a four-pointed star, colourful enough to read when it +# is turned and squeezed. +def rotoTile(size=128): + y, x = np.mgrid[0:size, 0:size] + 0.5 + c = ((np.floor(x / 64) + np.floor(y / 64)) % 2) + img = np.zeros((size, size, 3)) + img[:] = np.where(c[..., None] > 0, np.array([40, 10, 60]), np.array([255, 120, 30])) + cx = (x % 64) - 32 + cy = (y % 64) - 32 + star = (np.abs(cx) * np.abs(cy) < 30) & (np.abs(cx) + np.abs(cy) < 30) + img[star] = [255, 250, 200] + return Image.fromarray(img.astype(np.uint8), "RGB") + + +# The boing ball's skin: red and white in sixteen by eight, as an equirectangular texture. +def boing(w=256, h=128): + y, x = np.mgrid[0:h, 0:w] + c = ((x // (w // 16)) + (y // (h // 8))) % 2 + img = np.where(c[..., None] > 0, np.array([230, 20, 30]), np.array([250, 250, 250])) + return Image.fromarray(img.astype(np.uint8), "RGB") + + +def bob(size=64): + y, x = np.mgrid[0:size, 0:size] + 0.5 + r = size / 2 - 1 + dx = (x - size / 2) / r + dy = (y - size / 2) / r + d2 = dx * dx + dy * dy + nz = np.sqrt(np.clip(1 - d2, 0, 1)) + light = np.clip(dx * -0.4 + dy * -0.5 + nz * 0.77, 0, 1) + v = 0.18 + 0.7 * light + 0.6 * light ** 24 + a = np.clip((1 - np.sqrt(d2)) * r, 0, 1) * (d2 <= 1) + img = np.zeros((size, size, 4)) + img[..., :3] = np.clip(v, 0, 1)[..., None] * 255 + img[..., 3] = a * 255 + return Image.fromarray(img.astype(np.uint8), "RGBA") + + +def glow(size=128, power=2.2): + y, x = np.mgrid[0:size, 0:size] + 0.5 + d = np.sqrt((x - size / 2) ** 2 + (y - size / 2) ** 2) / (size / 2) + img = np.zeros((size, size, 4)) + img[..., :3] = 255 + img[..., 3] = np.clip(1 - d, 0, 1) ** power * 255 + return Image.fromarray(img.astype(np.uint8), "RGBA") + + +# A star-shaped sparkle, for the light the ball throws. +def sparkle(size=64): + y, x = np.mgrid[0:size, 0:size] + 0.5 + dx = np.abs(x - size / 2) / (size / 2) + dy = np.abs(y - size / 2) / (size / 2) + v = np.exp(-dx * 14) * np.exp(-dy * 2.5) + np.exp(-dy * 14) * np.exp(-dx * 2.5) + np.exp(-(dx * dx + dy * dy) * 18) + img = np.zeros((size, size, 4)) + img[..., :3] = 255 + img[..., 3] = np.clip(v, 0, 1) * 255 + return Image.fromarray(img.astype(np.uint8), "RGBA") + + +def main(): + os.makedirs(OUT, exist_ok=True) + save(club(), "club.png") + save(tile(), "tile.png") + save(chromeText("MIRRORBALL", 96), "logo.png") + save(chromeText("SINGE", 120), "singe.png") + save(twister(), "twister.png") + save(copper(), "copper.png") + save(rotoTile(), "roto.png") + save(boing(), "boing.png") + save(bob(), "bob.png") + save(glow(), "glow.png") + save(sparkle(), "sparkle.png") + + +if __name__ == "__main__": + main() diff --git a/util/neonCoastArt.py b/util/neonCoastArt.py new file mode 100644 index 000000000..696ee58e9 --- /dev/null +++ b/util/neonCoastArt.py @@ -0,0 +1,405 @@ +# Draws the art for demos/neonCoast: every picture is made from shapes and arithmetic here, so it is +# ours and can be drawn again. +# +# The sky is the important one. It is an equirectangular picture, the whole sphere around the +# camera, and the 3D scene both shows it and lights with it: a chrome object reflects whatever is in +# it. So besides the sunset and the stars it carries the striped sun straight ahead (the sky's centre +# faces the camera's default view) and, in the lower half, the neon grid in perspective, as if a +# floor ran to the horizon in every direction. Chrome then reflects the sun and the grid, which is +# the whole look. +# +# Usage: python3 util/neonCoastArt.py +import math +import os + +import numpy as np +from PIL import Image, ImageDraw, ImageFilter, ImageFont + + +REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +OUT = os.path.join(REPO, "demos", "neonCoast", "art") + +SKY_W = 2048 +SKY_H = 1024 +SUN_LAT = 9.0 # Degrees above the horizon of the sun's centre +SUN_RADIUS = 13.0 # Degrees +GRID_CELL = 4.0 # The painted floor grid's cell, in camera heights +FONT_BOLD = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" +FONT_WIDE = "/usr/share/fonts/truetype/lato/Lato-BlackItalic.ttf" + +# The palette: night at the top, through violet and magenta, to orange at the horizon. +SKY_STOPS = [ + (0.00, (6, 3, 22)), + (0.45, (26, 8, 60)), + (0.72, (88, 18, 110)), + (0.88, (200, 40, 120)), + (1.00, (255, 120, 70)), +] +MAGENTA = np.array([255, 40, 200]) +CYAN = np.array([40, 230, 255]) + + +def save(image, name): + image.save(os.path.join(OUT, name)) + print("%-16s %d x %d" % (name, image.width, image.height)) + + +def ramp(stops, t): + t = np.clip(t, 0, 1) + out = np.zeros(t.shape + (3,)) + for (t0, c0), (t1, c1) in zip(stops[:-1], stops[1:]): + m = (t >= t0) & (t <= t1) + k = ((t - t0) / (t1 - t0))[m][:, None] + out[m] = np.array(c0) * (1 - k) + np.array(c1) * k + return out + + +# The sun's own look, wherever it is drawn: yellow at the top to magenta at the bottom, with +# horizontal bands cut out of its lower half that thicken toward the bottom. u, v run -1 to 1. +def sunMask(u, v): + inside = (u * u + v * v) <= 1.0 + band = np.ones_like(u, dtype=bool) + for k in range(7): + centre = 0.12 + k * 0.14 + half = 0.012 + k * 0.009 + band &= ~((v > centre - half) & (v < centre + half)) + return inside & band + + +def sunColour(v): + return ramp([(0.0, (255, 240, 120)), (0.5, (255, 140, 60)), (1.0, (255, 40, 150))], (v + 1) / 2) + + +def sky(): + lon = (np.arange(SKY_W) + 0.5) / SKY_W * 2 * math.pi - math.pi + lat = math.pi / 2 - (np.arange(SKY_H) + 0.5) / SKY_H * math.pi + LON, LAT = np.meshgrid(lon, lat) + img = np.zeros((SKY_H, SKY_W, 3)) + + # Above the horizon: the gradient by height, and stars thinning toward the horizon. + up = LAT >= 0 + img[up] = ramp(SKY_STOPS, 1 - LAT[up] / (math.pi / 2)) + rng = np.random.default_rng(7) + for _ in range(2600): + x = rng.integers(0, SKY_W) + y = int(rng.random() ** 1.8 * SKY_H * 0.42) + b = rng.random() ** 2 * 255 + img[y, x] = np.maximum(img[y, x], [b, b, min(255, b * 1.1)]) + + # Behind the camera, a city's cyan glow along the horizon: the half of the sky a chrome face + # toward the camera reflects, so the chrome shades cyan above and magenta below. + city = np.exp(-np.maximum(LAT, 0) / math.radians(14)) * np.clip(-np.cos(LON), 0, 1) ** 0.7 * up + img = img * (1 - 0.85 * city[..., None]) + city[..., None] * np.array([60, 210, 255]) * 0.95 + + # The sun straight ahead, its glow first. + du = (LON / math.radians(SUN_RADIUS)) + dv = -(LAT - math.radians(SUN_LAT)) / math.radians(SUN_RADIUS) + dist = np.sqrt(du * du + dv * dv) + glow = np.exp(-np.maximum(dist - 1, 0) * 2.2) * (LAT > -0.01) + img += glow[..., None] * np.array([255, 70, 120]) * 0.55 + mask = sunMask(du, dv) + img[mask] = sunColour(dv[mask]) + + # Below the horizon: a dark floor and the grid on it in perspective, fading into haze. + down = LAT < 0 + dirX = np.cos(LAT) * np.sin(LON) + dirZ = -np.cos(LAT) * np.cos(LON) + t = 1.0 / np.maximum(-np.sin(LAT), 1e-4) + # The camera stands in the middle of a cell, so no line runs straight under it. + gx = t * dirX / GRID_CELL + 0.5 + gz = t * dirZ / GRID_CELL + 0.5 + fx = np.abs(gx - np.round(gx)) + fz = np.abs(gz - np.round(gz)) + # Lines a constant width on the floor get thinner with distance; their brightness is kept by + # widening the soft edge as they shrink, then faded into the horizon's haze. + width = 0.03 + 0.002 * t + line = np.clip(1 - np.minimum(fx, fz) / width, 0, 1) ** 1.5 + haze = np.clip((t - 6) / 60, 0, 1) + floor = np.array([14, 4, 30]) * (1 - haze[..., None]) + np.array([120, 30, 110]) * haze[..., None] + lineColour = MAGENTA * (1 - haze[..., None] * 0.7) + below = floor + line[..., None] * lineColour + img[down] = below[down] + img = np.clip(img, 0, 255).astype(np.uint8) + return Image.fromarray(img, "RGB") + + +# The floor tile: a cell of the neon grid, glowing magenta lines on black, with alpha, used as the +# floor's colour and its emissive map at once. Tiled, the line at each edge meets its neighbour's. +def gridTile(colour, size=256, width=5.0, glow=18.0): + y, x = np.mgrid[0:size, 0:size] + 0.5 + d = np.minimum(np.minimum(x, size - x), np.minimum(y, size - y)) + core = np.clip(1 - (d - width / 2), 0, 1) + halo = np.exp(-d / glow) * 0.5 + v = np.clip(core + halo, 0, 1) + img = np.zeros((size, size, 4)) + img[..., :3] = np.array(colour) * v[..., None] + img[..., 3] = 255 + return Image.fromarray(img.astype(np.uint8), "RGBA") + + +# A heightmap for the mountains: a ridge line with a valley in the middle where the sun sits, +# rising toward both ends, with ridged noise for the peaks. Red carries the height. +def mountains(w=256, h=64): + rng = np.random.default_rng(3) + x = np.linspace(-1, 1, w) + z = np.linspace(0, 1, h) + X, Z = np.meshgrid(x, z) + base = np.clip(np.abs(X) * 1.4 - 0.15, 0, 1) + noise = np.zeros_like(X) + amp = 1.0 + freq = 3.0 + for _ in range(5): + phase = rng.random(4) * 10 + n = np.sin(X * freq * 3.1 + phase[0]) * np.sin(Z * freq * 2.3 + phase[1]) + 0.5 * np.sin((X + Z) * freq * 4.7 + phase[2]) + noise += (1 - np.abs(n)) * amp + amp *= 0.5 + freq *= 2.0 + ridge = np.exp(-((Z - 0.5) ** 2) / 0.05) + hgt = np.clip(base * (0.4 + 0.6 * noise / 1.9) * ridge, 0, 1) + img = (hgt * 255).astype(np.uint8) + return Image.fromarray(np.stack([img, img, img], -1), "RGB") + + +SS = 4 # Sprites are drawn this many times larger and shrunk, for smooth edges + + +def big(w, h): + return Image.new("RGBA", (w * SS, h * SS), (0, 0, 0, 0)) + + +def shrink(image, w, h): + return image.resize((w, h), Image.LANCZOS) + + +def pts(points): + return [(x * SS, y * SS) for x, y in points] + + +# The car from behind, low and wide: a black body traced in magenta, a cyan glint on the rear +# window, a full-width taillight bar, and a glow under it on the road. +def car(): + w, h = 176, 80 + im = big(w, h) + d = ImageDraw.Draw(im) + d.ellipse(pts([(6, 64), (170, 80)]), fill=(255, 30, 180, 90)) + d.rectangle(pts([(16, 58), (40, 76)]), fill=(12, 8, 16, 255)) + d.rectangle(pts([(136, 58), (160, 76)]), fill=(12, 8, 16, 255)) + body = [(4, 40), (18, 30), (158, 30), (172, 40), (172, 66), (4, 66)] + d.polygon(pts(body), fill=(18, 12, 30, 255), outline=(255, 40, 200, 255), width=2 * SS) + roof = [(38, 30), (52, 8), (124, 8), (138, 30)] + d.polygon(pts(roof), fill=(26, 16, 44, 255), outline=(255, 40, 200, 255), width=2 * SS) + d.polygon(pts([(46, 28), (57, 12), (119, 12), (130, 28)]), fill=(40, 120, 200, 255)) + d.polygon(pts([(60, 26), (70, 13), (84, 13), (74, 26)]), fill=(150, 240, 255, 255)) + d.rectangle(pts([(10, 42), (166, 50)]), fill=(255, 20, 60, 255)) + d.rectangle(pts([(12, 44), (164, 48)]), fill=(255, 150, 160, 255)) + d.rectangle(pts([(70, 54), (106, 60)]), fill=(230, 230, 240, 255)) + return shrink(im, w, h) + + +def palm(): + w, h = 200, 230 + im = big(w, h) + d = ImageDraw.Draw(im) + trunk = [] + for i in range(41): + t = i / 40 + x = 100 + 18 * math.sin(t * 2.2) - 10 * t + trunk.append((x, 40 + t * 180)) + for (x0, y0), (x1, y1) in zip(trunk[:-1], trunk[1:]): + wdt = 7 + (y0 - 40) / 180 * 5 + d.line(pts([(x0, y0), (x1, y1)]), fill=(10, 4, 16, 255), width=int(wdt * SS)) + top = trunk[0] + dark = (10, 4, 16, 255) + for k in range(9): + ang = -math.pi * 0.98 + k * math.pi * 0.98 / 8 + (0.12 if k % 2 else -0.08) + length = 78 + 12 * math.sin(k * 1.7) + spine = [] + for i in range(17): + t = i / 16 + spine.append((top[0] + math.cos(ang) * length * t, top[1] + math.sin(ang) * length * t * 0.55 + t * t * 52)) + for i, ((x0, y0), (x1, y1)) in enumerate(zip(spine[:-1], spine[1:])): + t = i / 16 + d.line(pts([(x0, y0), (x1, y1)]), fill=dark, width=max(1, int((4 - 3 * t) * SS))) + # Leaflets hang off both sides of the spine, longest near its middle, swept back and down. + dx = x1 - x0 + dy = y1 - y0 + n = math.hypot(dx, dy) + 1e-9 + px, py = -dy / n, dx / n + leaf = 13 * math.sin(math.pi * min(1, t * 1.1)) + 2 + if i % 2: + continue + for side in (-1, 1): + ex = x0 + side * px * leaf + dx / n * leaf * 0.6 + ey = y0 + side * py * leaf + dy / n * leaf * 0.6 + leaf * 0.35 + d.line(pts([(x0, y0), (ex, ey)]), fill=dark, width=int(2.2 * SS)) + d.ellipse(pts([(top[0] - 7, top[1] - 5), (top[0] + 7, top[1] + 7)]), fill=dark) + # A magenta rim on the side away from the viewer's left: the sunset behind it. + a = np.array(im) + alpha = a[..., 3] > 0 + edge = alpha & ~np.roll(alpha, -SS, axis=1) + a[edge] = [230, 40, 160, 255] + return shrink(Image.fromarray(a), w, h) + + +def lamp(): + w, h = 64, 200 + im = big(w, h) + d = ImageDraw.Draw(im) + d.rectangle(pts([(30, 20), (35, 199)]), fill=(20, 14, 30, 255)) + d.line(pts([(33, 22), (8, 14)]), fill=(20, 14, 30, 255), width=4 * SS) + d.ellipse(pts([(0, 8), (18, 20)]), fill=(255, 245, 210, 255)) + return shrink(im, w, h) + + +# A city along the horizon: blocks of every height, lit windows, a few towers with a red light on +# top. It tiles sideways. +def skyline(): + w, h = 1280, 150 + rng = np.random.default_rng(5) + im = Image.new("RGBA", (w, h), (0, 0, 0, 0)) + d = ImageDraw.Draw(im) + x = 0 + while x < w: + bw = int(rng.integers(26, 70)) + bh = int(rng.integers(30, 140)) + shade = int(rng.integers(14, 30)) + d.rectangle([x, h - bh, min(w - 1, x + bw - 3), h - 1], fill=(shade, shade // 2, shade + 16, 255)) + for wy in range(h - bh + 6, h - 6, 7): + for wx in range(x + 4, x + bw - 6, 6): + if rng.random() < 0.35: + c = (255, 210, 120, 255) if rng.random() < 0.7 else (80, 220, 255, 255) + d.rectangle([wx, wy, wx + 2, wy + 3], fill=c) + if bh > 110: + d.rectangle([x + bw // 2 - 1, h - bh - 14, x + bw // 2, h - bh], fill=(30, 20, 40, 255)) + d.ellipse([x + bw // 2 - 3, h - bh - 18, x + bw // 2 + 3, h - bh - 12], fill=(255, 40, 60, 255)) + x += bw + return im + + +# The night road a row at a time, as in the arcade racers: four kinds of row (light and dark road, +# light and dark ground) at HAZE levels each, fading into the violet haze at the horizon. +STRIP_W = 256 +HAZE = 8 +HAZE_RGB = np.array([110, 28, 100]) + + +def roadStrip(): + img = np.zeros((4 * HAZE, STRIP_W, 4), dtype=np.float64) + x = np.arange(STRIP_W) + for kind in range(4): + for level in range(HAZE): + if kind < 2: + row = np.tile(np.array([16, 10, 26], dtype=np.float64), (STRIP_W, 1)) + edge = (x < 10) | (x >= STRIP_W - 10) + row[edge] = [255, 40, 200] + inner = ((x >= 10) & (x < 14)) | ((x >= STRIP_W - 14) & (x < STRIP_W - 10)) + row[inner] = [120, 20, 100] + if kind == 0: + for lane in (1, 2): + c = 10 + (STRIP_W - 20) * lane // 3 + row[(x >= c - 2) & (x < c + 2)] = [40, 230, 255] + else: + row = np.tile(np.array([10, 4, 22] if kind == 2 else [20, 6, 36], dtype=np.float64), (STRIP_W, 1)) + k = level / (HAZE - 1) * 0.8 + row = row * (1 - k) + HAZE_RGB * k + img[kind * HAZE + level, :, :3] = row + img[kind * HAZE + level, :, 3] = 255 + return Image.fromarray(img.astype(np.uint8), "RGBA") + + +# A shaded ball for vector bobs: white and grey, so spriteSetTint colours it. +def bob(size=64): + y, x = np.mgrid[0:size, 0:size] + 0.5 + cx = cy = size / 2 + r = size / 2 - 1 + dx = (x - cx) / r + dy = (y - cy) / r + d2 = dx * dx + dy * dy + inside = d2 <= 1 + nz = np.sqrt(np.clip(1 - d2, 0, 1)) + light = np.clip(dx * -0.4 + dy * -0.5 + nz * 0.77, 0, 1) + spec = np.clip(light, 0, 1) ** 24 + v = 0.18 + 0.7 * light + 0.6 * spec + a = np.clip((1 - np.sqrt(d2)) * r, 0, 1) * inside + img = np.zeros((size, size, 4)) + img[..., :3] = np.clip(v, 0, 1)[..., None] * 255 + img[..., 3] = a * 255 + return Image.fromarray(img.astype(np.uint8), "RGBA") + + +# A soft round glow, white, for additive light: bloom on the overlay. +def glow(size=128, power=2.2): + y, x = np.mgrid[0:size, 0:size] + 0.5 + d = np.sqrt((x - size / 2) ** 2 + (y - size / 2) ** 2) / (size / 2) + v = np.clip(1 - d, 0, 1) ** power + img = np.zeros((size, size, 4)) + img[..., :3] = 255 + img[..., 3] = v * 255 + return Image.fromarray(img.astype(np.uint8), "RGBA") + + +# Lettering in eighties chrome: a sky-to-sunset gradient with a hard horizon line through the middle, +# a white outline, a dark outline outside that, and a soft magenta glow behind. +def chromeText(text, size, font=FONT_WIDE, pad=24): + f = ImageFont.truetype(font, size * SS) + box = f.getbbox(text) + w = (box[2] - box[0]) // SS + pad * 2 + h = (box[3] - box[1]) // SS + pad * 2 + mask = Image.new("L", (w * SS, h * SS), 0) + ImageDraw.Draw(mask).text((pad * SS - box[0], pad * SS - box[1]), text, font=f, fill=255) + m = np.array(mask).astype(np.float64) / 255 + rows = np.linspace(0, 1, h * SS) + top = (pad * SS) / (h * SS) + t = np.clip((rows - top) / (1 - 2 * top), 0, 1)[:, None] + sky = np.array([20, 40, 120]) + (np.array([200, 245, 255]) - np.array([20, 40, 120])) * (t / 0.5) + sunset = np.array([90, 20, 60]) + (np.array([255, 120, 200]) - np.array([90, 20, 60])) * ((t - 0.5) / 0.5) + rowColour = np.where(t < 0.5, sky, sunset) + grad = np.repeat(rowColour[:, None, :], w * SS, axis=1) + from scipy import ndimage + outer = ndimage.maximum_filter(m, size=5 * SS) + ring = ndimage.maximum_filter(m, size=2 * SS) + halo = ndimage.gaussian_filter(outer, 7 * SS) + img = np.zeros((h * SS, w * SS, 4)) + img[..., :3] = np.array([255, 40, 200]) * 1.0 + img[..., 3] = np.clip(halo * 1.4, 0, 1) * 180 + img[..., :3] = np.where(outer[..., None] > 0.5, [20, 4, 30], img[..., :3]) + img[..., 3] = np.where(outer > 0.5, 255, img[..., 3]) + img[..., :3] = np.where(ring[..., None] > 0.5, [255, 255, 255], img[..., :3]) + img[..., :3] = np.where(m[..., None] > 0.5, grad, img[..., :3]) + return shrink(Image.fromarray(np.clip(img, 0, 255).astype(np.uint8), "RGBA"), w, h) + + +def flag(): + w, h = 512, 320 + im = Image.new("RGBA", (w, h), (20, 6, 40, 255)) + d = ImageDraw.Draw(im) + for i in range(8): + y = int(h * 0.62 + i * i * 2.2) + d.rectangle([0, y, w, y + 2], fill=(255, 40, 200, 255)) + d.ellipse([w // 2 - 90, 40, w // 2 + 90, 220], fill=(255, 160, 70, 255)) + logo = chromeText("NEON COAST", 64) + logo = logo.resize((w - 40, int(logo.height * (w - 40) / logo.width)), Image.LANCZOS) + im.alpha_composite(logo, (20, h // 2 - logo.height // 2 + 20)) + return im + + +def main(): + os.makedirs(OUT, exist_ok=True) + save(sky(), "sky.png") + save(gridTile(MAGENTA), "grid.png") + save(gridTile(CYAN, width=3.0, glow=10.0), "gridCyan.png") + save(mountains(), "mountains.png") + save(car(), "car.png") + save(palm(), "palm.png") + save(lamp(), "lamp.png") + save(skyline(), "skyline.png") + save(roadStrip(), "road.png") + save(bob(), "bob.png") + save(glow(), "glow.png") + save(chromeText("NEON COAST", 96), "logo.png") + save(chromeText("SINGE", 120), "singe.png") + save(flag(), "flag.png") + + +if __name__ == "__main__": + main() diff --git a/util/openRoadArt.py b/util/openRoadArt.py new file mode 100644 index 000000000..c940d1449 --- /dev/null +++ b/util/openRoadArt.py @@ -0,0 +1,219 @@ +# Draws the art for testScripts/openRoad, a road-racing game drawn a screen row at a time: every +# picture is made from shapes here, so it is ours, small, and can be drawn again. +# +# The road is not a picture of a road. It is a strip of one-pixel rows, each a whole cross-section +# of road or grass, which the game cuts out and stretches to the road's width at every row of the +# screen. The rows come in four kinds (light road, dark road, light grass, dark grass, alternating +# down the track to show it moving) at HAZE levels each, fading toward the sky's colour, so the far +# road fades with no blending at all. +# +# The cars and the scenery are one picture each. The game leans the player's car into turns and spins +# it in a crash by turning that one picture. +# +# Usage: python3 util/openRoadArt.py +import os + +from PIL import Image, ImageDraw, ImageFilter + + +REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +OUT = os.path.join(REPO, "testScripts", "openRoad", "art") + +W = 320 # The game's overlay +H = 240 +HORIZON_Y = 110 # Where the horizon sits on a level road; the game assumes it +STRIP_W = 256 # A road row's width in pixels, edge of rumble to edge of rumble +RUMBLE_W = 16 # Each rumble strip's share of it +LINE_W = 4 # A lane marking +LANES = 3 +HAZE = 8 # Fade levels for each kind of row, nearest first +HAZE_RGB = (196, 214, 226) # What the far road fades into: the sky at the horizon +KINDS = ( # Each kind of row: the colours across it + {"road": (112, 112, 118), "rumble": (240, 240, 240), "lines": True}, + {"road": (104, 104, 110), "rumble": (200, 40, 40), "lines": False}, + {"grass": (72, 150, 64)}, + {"grass": (62, 134, 56)}, +) + + +def blank(width, height): + return Image.new("RGBA", (width, height), (0, 0, 0, 0)) + + +def faded(colour, level): + t = level / (HAZE - 1) * 0.85 + return tuple(int(colour[c] * (1 - t) + HAZE_RGB[c] * t) for c in range(3)) + (255,) + + +def save(image, name): + image.save(os.path.join(OUT, name)) + print("%-14s %d x %d" % (name, image.width, image.height)) + + +# One row of road: rumble, asphalt with its lane markings, and rumble again. +def roadRow(kind, level): + row = [faded(kind["road"], level)] * STRIP_W + edge = faded(kind["rumble"], level) + for x in range(RUMBLE_W): + row[x] = edge + row[STRIP_W - 1 - x] = edge + if kind["lines"]: + asphalt = STRIP_W - RUMBLE_W * 2 + for lane in range(1, LANES): + centre = RUMBLE_W + asphalt * lane // LANES + for x in range(centre - LINE_W // 2, centre + LINE_W // 2): + row[x] = faded((236, 236, 236), level) + return row + + +# Every row kind at every haze level: row kind * HAZE + level. +def strip(): + image = Image.new("RGBA", (STRIP_W, len(KINDS) * HAZE)) + pixels = image.load() + for k, kind in enumerate(KINDS): + for level in range(HAZE): + row = roadRow(kind, level) if "road" in kind else [faded(kind["grass"], level)] * STRIP_W + for x in range(STRIP_W): + pixels[x, k * HAZE + level] = row[x] + return image + + +# The sky, a sun, and below the horizon the hazy colour of far land, for when the road drops away +# over a crest and leaves the ground beyond it showing. +def sky(): + image = Image.new("RGBA", (W, H)) + draw = ImageDraw.Draw(image) + for y in range(H): + if y <= HORIZON_Y: + t = y / HORIZON_Y + draw.line([(0, y), (W, y)], fill=(int(60 + 136 * t), int(120 + 94 * t), int(210 + 16 * t), 255)) + else: + draw.line([(0, y), (W, y)], fill=faded((72, 150, 64), HAZE - 1)) + draw.ellipse([226, 22, 262, 58], fill=(255, 244, 200, 255)) + clouds = blank(W, H) + cloudy = ImageDraw.Draw(clouds) + for box in ((20, 30, 80, 46), (50, 24, 110, 44), (140, 56, 200, 68), (270, 70, 320, 82)): + cloudy.ellipse(box, fill=(255, 255, 255, 200)) + return Image.alpha_composite(image, clouds.filter(ImageFilter.GaussianBlur(2))) + + +# Hills along the horizon, twice the screen's width so they can scroll round as the road curves, with +# their foot on the picture's bottom row. +def hills(): + width = W * 2 + height = 48 + image = blank(width, height) + draw = ImageDraw.Draw(image) + ranges = ( + (((0, 30), (70, 8), (150, 26), (230, 4), (330, 22), (420, 10), (520, 28), (600, 12), (640, 30)), (120, 150, 170)), + (((0, 40), (40, 30), (110, 38), (190, 24), (260, 36), (360, 28), (440, 40), (500, 26), (580, 34), (640, 40)), (90, 128, 120)), + ) + for peaks, shade in ranges: + draw.polygon([(0, height)] + list(peaks) + [(width, height)], fill=shade + (255,)) + return image + + +# The player's car from behind: body, rear window, lights, and tyres. +def car(): + image = blank(80, 44) + draw = ImageDraw.Draw(image) + draw.rectangle([4, 32, 18, 43], fill=(30, 30, 30, 255)) + draw.rectangle([61, 32, 75, 43], fill=(30, 30, 30, 255)) + draw.polygon([(2, 20), (10, 14), (70, 14), (78, 20), (78, 38), (2, 38)], fill=(210, 30, 30, 255)) + draw.polygon([(16, 14), (22, 2), (58, 2), (64, 14)], fill=(180, 24, 24, 255)) + draw.polygon([(20, 13), (25, 4), (55, 4), (60, 13)], fill=(60, 80, 110, 255)) + draw.rectangle([6, 22, 20, 27], fill=(255, 90, 60, 255)) + draw.rectangle([60, 22, 74, 27], fill=(255, 90, 60, 255)) + draw.rectangle([30, 30, 50, 35], fill=(240, 220, 120, 255)) + draw.line([(2, 38), (78, 38)], fill=(120, 16, 16, 255), width=2) + return image + + +# Traffic from behind: a plainer car, in blue, so it never reads as the player's. +def traffic(): + image = blank(64, 40) + draw = ImageDraw.Draw(image) + draw.rectangle([4, 30, 14, 39], fill=(30, 30, 30, 255)) + draw.rectangle([49, 30, 59, 39], fill=(30, 30, 30, 255)) + draw.polygon([(2, 16), (8, 12), (56, 12), (62, 16), (62, 34), (2, 34)], fill=(50, 90, 190, 255)) + draw.polygon([(12, 12), (17, 1), (47, 1), (52, 12)], fill=(40, 74, 160, 255)) + draw.polygon([(16, 11), (20, 3), (44, 3), (48, 11)], fill=(150, 180, 210, 255)) + draw.rectangle([5, 19, 14, 23], fill=(255, 80, 60, 255)) + draw.rectangle([49, 19, 58, 23], fill=(255, 80, 60, 255)) + return image + + +def truck(): + image = blank(64, 72) + draw = ImageDraw.Draw(image) + draw.rectangle([4, 62, 16, 71], fill=(30, 30, 30, 255)) + draw.rectangle([47, 62, 59, 71], fill=(30, 30, 30, 255)) + draw.rectangle([1, 2, 62, 62], fill=(230, 220, 190, 255), outline=(120, 110, 90, 255)) + draw.line([(32, 4), (32, 60)], fill=(150, 140, 120, 255), width=2) + draw.rectangle([3, 54, 12, 58], fill=(255, 80, 60, 255)) + draw.rectangle([51, 54, 60, 58], fill=(255, 80, 60, 255)) + return image + + +def palm(): + image = blank(56, 112) + draw = ImageDraw.Draw(image) + for i in range(14): + x = 26 + int((i / 13) ** 2 * 6) + draw.rectangle([x, 26 + i * 6, x + 5, 32 + i * 6], fill=(130 - i * 2, 90, 50, 255)) + for points in (((28, 26), (2, 30), (8, 22)), ((28, 26), (54, 30), (48, 22)), ((28, 26), (10, 8), (18, 6)), + ((28, 26), (46, 8), (38, 6)), ((28, 26), (26, 0), (32, 2)), ((28, 26), (0, 44), (6, 36)), ((28, 26), (56, 44), (50, 36))): + draw.polygon(points, fill=(40, 130, 50, 255)) + draw.ellipse([22, 20, 34, 30], fill=(90, 70, 40, 255)) + return image + + +def bush(): + image = blank(48, 24) + draw = ImageDraw.Draw(image) + for box in ((0, 8, 22, 24), (12, 2, 36, 24), (26, 6, 48, 24)): + draw.ellipse(box, fill=(46, 110, 44, 255)) + return image + + +# A curve warning: a board on two posts with a mark that reads the same either way, since the game +# cuts hill-hidden scenery with spriteDrawGrid, which draws the picture unmirrored. +def sign(): + image = blank(56, 56) + draw = ImageDraw.Draw(image) + draw.rectangle([10, 30, 14, 55], fill=(90, 90, 90, 255)) + draw.rectangle([42, 30, 46, 55], fill=(90, 90, 90, 255)) + draw.rectangle([0, 2, 55, 34], fill=(250, 210, 40, 255), outline=(40, 40, 40, 255)) + draw.rectangle([25, 6, 30, 22], fill=(30, 30, 30, 255)) + draw.rectangle([25, 26, 30, 30], fill=(30, 30, 30, 255)) + return image + + +# The start and checkpoint arch over the road: two pillars and a banner, open in between. +def arch(): + image = blank(256, 96) + draw = ImageDraw.Draw(image) + draw.rectangle([0, 0, 15, 95], fill=(220, 220, 220, 255), outline=(80, 80, 80, 255)) + draw.rectangle([240, 0, 255, 95], fill=(220, 220, 220, 255), outline=(80, 80, 80, 255)) + draw.rectangle([0, 0, 255, 22], fill=(30, 30, 30, 255)) + for x in range(0, 256, 16): + draw.rectangle([x, 2 + (x // 16 % 2) * 9, x + 7, 10 + (x // 16 % 2) * 9], fill=(250, 250, 250, 255)) + return image + + +def main(): + os.makedirs(OUT, exist_ok=True) + save(strip(), "strip.png") + save(sky(), "sky.png") + save(hills(), "hills.png") + save(car(), "car.png") + save(traffic(), "traffic.png") + save(truck(), "truck.png") + save(palm(), "palm.png") + save(bush(), "bush.png") + save(sign(), "sign.png") + save(arch(), "arch.png") + + +if __name__ == "__main__": + main() diff --git a/util/renderReel.py b/util/renderReel.py index 85870777f..3dc00e415 100644 --- a/util/renderReel.py +++ b/util/renderReel.py @@ -59,7 +59,7 @@ SHOTS = [ # and are ours. These draw into the overlay, so they are never cleaned. { "caption": "Lesson seven: a game from nothing","lesson": "07-a-game", "frames": 150 }, { "caption": "Lesson eleven: sprites and sound", "lesson": "11-hitting-things", "frames": 150 }, - { "caption": "Thirty lessons from nothing", "lesson": "22-3d", "frames": 150 }, + { "caption": "Thirty-one lessons from nothing", "lesson": "22-3d", "frames": 150 }, ] # The runner every shot goes through: the shot's own script, untouched, with a frame counter that diff --git a/util/skyStrikeArt.py b/util/skyStrikeArt.py new file mode 100644 index 000000000..39442891f --- /dev/null +++ b/util/skyStrikeArt.py @@ -0,0 +1,157 @@ +# Draws the art for testScripts/skyStrike, a sprite-scaling flight game: every picture is made from +# shapes here, so it is ours, small, and can be drawn again. +# +# One picture of each thing and no more. The game turns the jet for its bank and its roll, turns the +# whole sky and ground for the horizon, and scales everything in the distance as it is drawn, so +# nothing here exists in a second size or at a second angle. The only sheet is the ground: six +# frames of perspective stripes, each a sixth of a stripe further on, which cycle to make the ground +# rush past. +# +# Usage: python3 util/skyStrikeArt.py +import math +import os + +from PIL import Image, ImageDraw, ImageFilter + + +REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +OUT = os.path.join(REPO, "testScripts", "skyStrike", "art") + +# The ground sheet. Turned, it must still cover a 320 x 240 screen with the horizon anywhere within +# PITCH of the middle, so it is wider than the screen's diagonal plus that. +GROUND_SIZE = 560 +GROUND_FRAMES = 6 +EYE_HEIGHT = 30.0 # The camera's height over the ground, in the game's world units +FOCAL = 160.0 # The game's projection: screen offset = world offset * FOCAL / distance +STRIPE = 40.0 # World units from one ground stripe to the next of the same colour + + +def blank(width, height): + return Image.new("RGBA", (width, height), (0, 0, 0, 0)) + + +def save(image, name): + image.save(os.path.join(OUT, name)) + print("%-14s %d x %d" % (name, image.width, image.height)) + + +# The player's jet from behind: fuselage, swept wings, tailplanes, a fin, and two glowing exhausts. +def jet(): + image = blank(64, 40) + draw = ImageDraw.Draw(image) + draw.polygon([(2, 24), (32, 16), (62, 24), (62, 27), (32, 22), (2, 27)], fill=(120, 130, 150, 255)) + draw.polygon([(14, 30), (32, 26), (50, 30), (50, 32), (14, 32)], fill=(100, 110, 130, 255)) + draw.polygon([(30, 2), (34, 2), (35, 24), (29, 24)], fill=(140, 150, 170, 255)) + draw.ellipse([22, 14, 42, 34], fill=(160, 170, 190, 255), outline=(60, 65, 80, 255)) + draw.ellipse([25, 23, 31, 29], fill=(255, 170, 60, 255)) + draw.ellipse([33, 23, 39, 29], fill=(255, 170, 60, 255)) + draw.ellipse([27, 25, 29, 27], fill=(255, 250, 200, 255)) + draw.ellipse([35, 25, 37, 27], fill=(255, 250, 200, 255)) + draw.rectangle([29, 15, 35, 18], fill=(70, 110, 160, 255)) + return image + + +# An enemy jet seen head on: darker, with a red nose, so it reads against the sky at any size. +def enemy(): + image = blank(48, 28) + draw = ImageDraw.Draw(image) + draw.polygon([(1, 14), (24, 9), (47, 14), (47, 17), (24, 14), (1, 17)], fill=(70, 70, 80, 255)) + draw.polygon([(23, 0), (25, 0), (26, 14), (22, 14)], fill=(90, 90, 100, 255)) + draw.ellipse([16, 8, 32, 24], fill=(100, 100, 112, 255), outline=(30, 30, 36, 255)) + draw.ellipse([21, 13, 27, 19], fill=(210, 40, 40, 255)) + draw.rectangle([10, 17, 14, 21], fill=(55, 55, 62, 255)) + draw.rectangle([34, 17, 38, 21], fill=(55, 55, 62, 255)) + return image + + +def tree(): + image = blank(32, 56) + draw = ImageDraw.Draw(image) + draw.rectangle([14, 42, 18, 55], fill=(90, 60, 35, 255)) + for top, half, shade in ((2, 8, (30, 110, 45)), (14, 12, (25, 95, 40)), (26, 15, (20, 80, 35))): + draw.polygon([(16, top), (16 + half, top + 18), (16 - half, top + 18)], fill=shade + (255,)) + return image + + +def rock(): + image = blank(40, 24) + draw = ImageDraw.Draw(image) + draw.polygon([(2, 23), (8, 9), (17, 3), (28, 6), (37, 15), (39, 23)], fill=(125, 115, 105, 255)) + draw.polygon([(17, 3), (28, 6), (24, 14), (14, 12)], fill=(160, 150, 140, 255)) + return image + + +def cloud(): + image = blank(96, 40) + draw = ImageDraw.Draw(image) + for box in ((6, 16, 46, 38), (26, 6, 66, 36), (50, 12, 90, 38), (36, 18, 80, 39)): + draw.ellipse(box, fill=(250, 250, 255, 230)) + return image.filter(ImageFilter.GaussianBlur(1.2)) + + +def shot(): + image = blank(12, 12) + draw = ImageDraw.Draw(image) + draw.ellipse([0, 0, 11, 11], fill=(255, 200, 80, 160)) + draw.ellipse([3, 3, 8, 8], fill=(255, 255, 220, 255)) + return image + + +# A fireball: rings from white to dark red, ragged at the edge so it shows when it spins. +def fireball(): + image = blank(48, 48) + draw = ImageDraw.Draw(image) + spikes = [] + for i in range(16): + angle = i * math.pi * 2 / 16 + radius = 23 if i % 2 == 0 else 15 + spikes.append((24 + math.cos(angle) * radius, 24 + math.sin(angle) * radius)) + draw.polygon(spikes, fill=(180, 40, 20, 230)) + draw.ellipse([8, 8, 40, 40], fill=(240, 120, 30, 240)) + draw.ellipse([15, 15, 33, 33], fill=(255, 220, 90, 255)) + draw.ellipse([20, 20, 28, 28], fill=(255, 255, 240, 255)) + return image + + +# The sky and the ground, one square picture with the horizon through its middle, in frames that +# move the stripes a sixth of a stripe on each. A row d pixels below the horizon is ground EYE_HEIGHT +# * FOCAL / d away, which is what spaces the stripes like perspective with no 3D at all. +def ground(): + half = GROUND_SIZE // 2 + sheet = blank(GROUND_SIZE * GROUND_FRAMES, GROUND_SIZE) + for frame in range(GROUND_FRAMES): + image = Image.new("RGBA", (GROUND_SIZE, GROUND_SIZE)) + pixels = image.load() + phase = STRIPE * frame / GROUND_FRAMES + for row in range(GROUND_SIZE): + if row < half: + # Sky: deep blue overhead to pale at the horizon. + t = row / half + colour = (int(40 + 120 * t), int(90 + 110 * t), int(190 + 55 * t), 255) + else: + d = row - half + 0.5 + z = EYE_HEIGHT * FOCAL / d + band = int(math.floor((z + phase) / (STRIPE / 2))) % 2 + haze = min(1.0, z / 1500.0) + base = (70, 140, 60) if band == 0 else (55, 120, 50) + colour = tuple(int(base[c] * (1 - haze) + (150, 185, 210)[c] * haze) for c in range(3)) + (255,) + for column in range(GROUND_SIZE): + pixels[column, row] = colour + sheet.paste(image, (frame * GROUND_SIZE, 0)) + return sheet + + +def main(): + os.makedirs(OUT, exist_ok=True) + save(jet(), "jet.png") + save(enemy(), "enemy.png") + save(tree(), "tree.png") + save(rock(), "rock.png") + save(cloud(), "cloud.png") + save(shot(), "shot.png") + save(fireball(), "fireball.png") + save(ground(), "ground.png") + + +if __name__ == "__main__": + main()