diff --git a/.claude/skills/verify/features/editor-page.md b/.claude/skills/verify/features/editor-page.md index acf6aa5..2e8da84 100644 --- a/.claude/skills/verify/features/editor-page.md +++ b/.claude/skills/verify/features/editor-page.md @@ -1,13 +1,13 @@ # Editor page (docs/editor.html) ## Sub-features -52 presets (load, save, save as, move, factory reset), the current sound (blocks, types, parameters, order by dragging, name), JSON export/import, live follow of changes made on the pedal (WATCH), unsaved-change prompts, phone layout. +52 presets (load, save, save as, move, factory reset), the current sound (blocks, types, parameters, order by dragging, name), JSON export/import, live follow of changes made on the pedal (WATCH), unsaved-change prompts, phone layout; v37: the NAM models panel (A2 `.nam` files into the 16 user slots, `docs/pxnam.js`, protocol 2). ## How to get to it (user POV) Open the editor from the installer page, Connect, edit. ## Driving it with Playwright -`sh .claude/skills/verify/scripts/pages.sh`; `tests/test_editor_page.mjs` talks to `build/edsim` (the real `px_editor.h` and `px_store.h`) through a fake Web MIDI. End state: every line `ok`, `editor page test passed`, `build/editor/editor_1..6*.png`. Protocol only (no browser): `node tools/op.mjs test` runs `tests/test_editor.mjs`. +`sh .claude/skills/verify/scripts/pages.sh`; `tests/test_editor_page.mjs` talks to `build/edsim` (the real `px_editor.h` and `px_store.h`) through a fake Web MIDI. End state: every line `ok`, `editor page test passed`, `build/editor/editor_1..6*.png` (`editor_6_nam.png`: the NAM panel). Protocol only (no browser): `node tools/op.mjs test` runs `tests/test_editor.mjs`. ## Gotchas - Protocol is in `docs/EDITOR-PROTOCOL.md`; a change to a command needs both `px_editor.h` and `docs/pxedit.js`. diff --git a/NOTICE.md b/NOTICE.md index c9a68b7..de5e074 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -8,8 +8,15 @@ OpenPocket is GPL-3.0-only (`LICENSE`), except the parts below, which keep their | `loader/` (update loader) | felucca-bsp `loader/`, changed for the Pocket X flash layout | MPL-2.0 | | `docs/pxota.js`, `docs/pxpkg.js`, `tools/pxpkg.py`, `tools/mkloader.py`, `tools/lz4blk.py` | adapted from [Felucca](https://github.com/hugelton/Felucca)'s web installer and build tools (as used by CLIPPER and SLOOP) | GPL-3.0 | | `firmware/sdk/` (I2S and DAC drivers as LLVM bitcode, SPL, cfg files) | JieLi AC79 SDK V1.2.0 (fw-AC79_AIoT_SDK) | Apache-2.0 (`LICENSES/Apache-2.0.txt`) | +| `firmware/px_cacheram.h` (data-cache ways as RAM, for the NAM network's vector-unit buffers) | [melodee](https://github.com/keremimo/melodee) `firmware/hal/fm1_cache.h`, Kerem Kilic (Ellic Studio), after the AC79 SDK's cache way setup | GPL-3.0 | | `firmware/fonts.h` (bitmaps generated from Inter) | [Inter](https://rsms.me/inter/), Rasmus Andersson | SIL OFL 1.1 (`LICENSES/OFL-1.1-Inter.txt`) | +The factory NAM models (`engine/px_nam_factory.h`, v37) are A2-Lite networks trained by OpenPocket from Neural Amp +Modeler community captures ([pelennor2170/NAM_models](https://github.com/pelennor2170/NAM_models), GPL v3; authors +in `docs/NAM.md`) played with DI guitar from [Alec-Wright/Automated-GuitarAmpModelling](https://github.com/Alec-Wright/Automated-GuitarAmpModelling) +(GPL v3). The NAM A2 architecture is from Neural Amp Modeler (Steven Atkinson, MIT); `engine/px_nam.c`, +`tools/nam_a2.py` and `tools/train_a2.py` are written for OpenPocket from the published architecture. + Sound models: the names refer to the gear that inspired each voicing (circuit analyses published by ElectroSmash, Electric Druid, R.G. Keen / GEOFEX, Rob Robinette, Duncan's Tone Stack Calculator; speaker data sheets; manufacturers' manuals). All trademarks belong to their owners; OpenPocket is not affiliated with Donner, M-VAVE or any gear maker. diff --git a/README.md b/README.md index 5e58bde..580bf78 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ !!! THIS PROJECT IS A PROOF OF CONCEPT, DONT EXPECT FULL FUNCTION AND SOUND QUALITY !!! Install here: https://isod89.github.io/openpocket/ (Donner Pocket X; M-VAVE BlackBox: v31 has the fix for issue #1, being tested) -NEW WEB EDITOR: https://isod89.github.io/openpocket/editor.html · What's new since v33: [docs/WHATS-NEW-v34-v36.md](docs/WHATS-NEW-v34-v36.md) +NEW WEB EDITOR: https://isod89.github.io/openpocket/editor.html · **v37: neural amp models (NAM A2), load your own from TONE3000**: [docs/WHATS-NEW-v37.md](docs/WHATS-NEW-v37.md) · since v33: [docs/WHATS-NEW-v34-v36.md](docs/WHATS-NEW-v34-v36.md) **Open-source guitar multi-effects firmware for the Donner Pocket X and the M-VAVE BlackBox.** Written from scratch for the pedal's own chip (JieLi AC791N, two cores), installable from the browser. @@ -12,11 +12,15 @@ Written from scratch for the pedal's own chip (JieLi AC791N, two cores), install ## What it does -- **12-block chain, 77 models**, in any order you like (double-click PUSH to move a block; the order is saved with +- **12-block chain, 78 models**, in any order you like (double-click PUSH to move a block; the order is saved with the preset): GATE, COMP, PITCH, SPECIAL FX, SYNTH, DRIVE, AMP, CAB, EQ, MOD, DELAY, REVERB - **Synths, keyboards and other guitars** from a normal guitar (no MIDI pickup): organ, church organ, string machine, choir, mono synth with pitch tracking and a resonant ladder filter, PWM synth, bass synth, 12-string, acoustic, sitar (bridge buzz + sympathetic strings), baritone +- **Neural amp models (v37)**: the AMP block's NAM type runs Neural Amp Modeler **A2** networks on the pedal: 12 + factory models trained for it (Twin, AC15, Super 59, Dirty Shirley, JCM900, JCM2000, JVM, Mark IV, Pro Mod, 5150, + 6505+) and 16 user slots you fill from the web editor with A2 captures (TONE3000...). All 24 factory presets use + them. Details: [docs/NAM.md](docs/NAM.md) - **8 amps fitted to captures of the real ones** (v34): Twin Reverb, AC15 Top Boost, JCM900, JCM2000, Mark IV, Dirty Shirley, Pro Mod, 5150. A computer sets the engine's numbers (tube stages oversampled ×4, tone stack, power amp, sag) so that it matches a Neural Amp Modeler capture of each amp on real guitar playing; same CPU cost as a @@ -25,7 +29,7 @@ Written from scratch for the pedal's own chip (JieLi AC791N, two cores), install Greenback, T75, Alnico Blue, Jensen, Cream, DI) with a MIC position - **Pro levels (v36)**: every amp, block and preset at the same loudness (-23 LUFS, measured on real guitar); 24 factory presets round the fitted amps, 28 USER slots; a PRESET LVL per preset; soft output limiter -- What changed since v33: [docs/WHATS-NEW-v34-v36.md](docs/WHATS-NEW-v34-v36.md) +- What changed: [v37](docs/WHATS-NEW-v37.md), [since v33](docs/WHATS-NEW-v34-v36.md) - **New screen (v36)**: a PLAY page readable from a distance (preset number and name, amp, chain in colour) and an EDIT page with big values and bars - **8 reverbs rebuilt in v35**: an 8-line feedback delay network with early reflections and moving lines (no diff --git a/docs/AUDIO-SDK.md b/docs/AUDIO-SDK.md index 3ebe3ad..259b0e8 100644 --- a/docs/AUDIO-SDK.md +++ b/docs/AUDIO-SDK.md @@ -262,3 +262,30 @@ Driver setup: `iis_open` IIS_PORTA, channel_in = BIT(1), channel_out = BIT(0), m - Screen: PLAY (number and name large, amp / cab, the chain in colour, the selected block) and EDIT (the block on its colour, model, 5 settings with value + bar), new Inter fonts (26 and 58 px). `tests/uisim.c` draws every page on the PC and checks that each full page paints every pixel. + +## v37: NAM A2-Lite, user models +- AMP type 8, NAM: a Neural Amp Modeler A2-Lite network (3 channels, 23 dilated layers, LeakyReLU, 16-tap head; + 1871 weights, about 1,730 multiply-adds a sample) in fixed point, `engine/px_nam.c` ([NAM.md](NAM.md)). Activations + Q20, weights Q24, 64-bit sums shifted by a constant. Against the float reference (`tools/nam_a2.py`): 83 to 100 dB + signal to error on the factory models (`tests/test_nam.py`). +- This CPU has no data cache in front of the SRAM, a taken branch costs about 8 cycles, and it issues two + instructions together (a 32-bit multiply-add with a 16-bit load). A first version (a loop over taps per frame, + 16-frame chunks) measured 223 % of real time on the pedal. Now: blocks of 32 frames, layer by layer. Gather: each + frame's inputs to the layer into one row of X (`[u, 1.0, taps x 3 channels]`, 3 words a move), from the layer's + ring (interleaved [time][channel], (kernel - 1) x dilation + 32 frames). Dot: the layer's 3 weight rows against 4 X + rows at a time (`pxn_dot3x4_asm`: a weight read once for 4 frames, 4 multiply-adds paired with 4 loads, 5 issues, + in the hardware loop). Post: LeakyReLU (predicated, no branch), the head sum, the residual 1x1 written straight + into the next layer's ring. The head is a 50-long row (bias, 16 taps x 3) over the head's ring. The hand routines + are in the flash with their callers; `px_nam_check()` compares them with the C ones at boot (pattern with both + signs, rows of 20 and 47, with and without the residual) and keeps C on any difference. +- Memory: the rings (83.4 KB) in the POOL region beside the engine, the model (weights converted, 8 KB) and the + block buffers (7 KB) in RAM. A direct call between the flash (0x02xxxxxx) and the RAM code (0x01C0xxxx) is out of + the call instruction's +-4 MiB: `tools/check_calls.py`, run by `firmware/build.sh` before linking, refuses any such + call and names it (a first v37 build put the audio path in RAM: the linker refused 478 calls, naming only one). +- User models: 16 slots of 8 KiB at 0xC0000 (`firmware/px_models.h`), written by the editor (protocol 2); the update + loader keeps that range (`loader/ldr_core.c`, `LDR_NAM_LO/HI`). The weights are read from the flash (SPI, with the + audio held) when a preset picks the model. +- Level: every model plays at the same loudness: a trim per model (-20 LUFS on `docs/nam_di.wav`, measured by the + editor for user models and by `tools/mk_nam_factory.py` for the factory ones), then one constant that puts NAM + + 1x12 at GAIN noon at the fitted amps' -23 LUFS. +- 24 factory presets rebuilt on the 12 factory NAM models, levelled by `tools/level_presets.py`; USER slots: NAM TWIN. diff --git a/docs/BUILDING.md b/docs/BUILDING.md index de42e5f..bf389a1 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -38,7 +38,13 @@ Apple silicon and other ARM machines Docker emulates it (Rosetta or QEMU); you c `make NATIVE=1 build` skips Docker and uses a toolchain installed on the machine (`sh firmware/setup.sh` installs it in `~/.jieli`; Linux x86-64 only). `tests/run_tests.sh` also runs directly on macOS and Linux with only a C compiler, Node and -Python 3. +Python 3. Its NAM check (`tests/test_nam.py`, the fixed-point network against the float reference) also needs NumPy +and is skipped without it (the container has none). + +The NAM factory models (`engine/px_nam_factory.h`, v37) are generated, not hand-written: `tools/train_a2.py` trains each +A2-Lite network from a capture (needs `pip install jax optax numpy scipy`, about 15 minutes a model on two CPU cores), +then `tools/mk_nam_factory.py LIST.txt DIR docs/nam_di.wav` writes the header with each model's level trim +([NAM.md](NAM.md)). The `.bat` files `makeimage.bat` and `render.bat` only check that Node is installed and call `tools/op.mjs`. `build.bat` does the same when Node and Docker are there, and otherwise builds in WSL (`build.bat docker` or `build.bat wsl` forces one way). `INSTALL-OFFLINE.bat` needs nothing installed: it serves `docs\` with PowerShell (`tools/serve_offline.ps1`), and falls back to Python (`tools/serve.py`) or WSL only if PowerShell cannot open a port. `tests/test_op.mjs` (part of `make test`) checks the Docker command lines, the friendly errors and `make clean` without Docker, using a fake `docker`. `PUBLISH-GITHUB.bat` and `PUBLISH-SOURCE.bat` (PowerShell `tools/publish_github.ps1`) are the maintainer's release tool and still need Windows; nothing else does. diff --git a/docs/EDITOR-PROTOCOL.md b/docs/EDITOR-PROTOCOL.md index 1a7a9c6..f622a23 100644 --- a/docs/EDITOR-PROTOCOL.md +++ b/docs/EDITOR-PROTOCOL.md @@ -1,7 +1,8 @@ # OpenPocket editor protocol (SysEx over USB-MIDI) The web editor (`docs/editor.html`, `docs/pxedit.js`) talks to the pedal with this protocol. The firmware side is -`firmware/px_editor.h`; `tests/edsim.c` runs the same code on a PC for the tests. Protocol version 1 (OpenPocket v32). +`firmware/px_editor.h`; `tests/edsim.c` runs the same code on a PC for the tests. Protocol version 2 (OpenPocket v37; version 1: v32 to v36, +the same without the NAM commands 19..22). ## Framing @@ -42,8 +43,40 @@ The 12 blocks, by index: 0 GATE, 1 COMP, 2 PITCH, 3 SFX, 4 DRIVE, 5 AMP, 6 CAB, | 16 SAVE | slot | slot, rc. Saves the current sound into the slot, writes the flash, the slot becomes the current one (as the pedal's SAVE) | | 17 WATCH | on (0/1) | on. While on, the pedal pushes `STATE` (cmd 5) when the sound, the slot or the focused block changes on the pedal; it stops by itself 5 s after the last request | | 18 PING | — | DSP load % (0..127), flags (bit 0: bypass, bit 1: second core) | +| 19 NAM_LIST | — | factory models (12), user slots (16), then per model (factory first, then the user slots): present (0/1), name string (11 characters at most; an empty user slot reads "U5 EMPTY") | +| 20 NAM_WRITE | piece (2 bytes: bits 0-6, 7-13), 128 packed bytes | the 2 piece bytes, rc (0 ok, 1 invalid). Piece i holds bytes 112 i .. 112 i + 111 of a model (the last piece fewer), packed 7 bit: groups of a byte of high bits (bit j = bit 7 of byte j) then 7 bytes. Stored in RAM only | +| 21 NAM_COMMIT | slot (0..15) | slot, rc (0 ok, 1 invalid: header, a weight that is not a number, CRC; 2 flash). Checks the pieces received and writes them to the user slot | +| 22 NAM_ERASE | slot (0..15) | slot, rc (0 ok, 1 invalid, 2 flash). Empties the user slot | -Writing the flash mutes the sound for a moment, as saving on the pedal does. A whole import sends `SLOT_PUT` without +### NAM models (protocol 2) + +The AMP block's ninth type, `NAM`, plays a neural amp model (NAM A2, its 3-channel "Lite" size, 1871 weights: +`engine/px_nam.h`). Its first parameter, MODEL, picks one of 28 models: 0..11 the factory ones (in the firmware), +12..27 the 16 user slots in the pedal's flash (`firmware/px_models.h`, 0xC0000..0xE0000, kept by firmware updates). +`TEXTS` of AMP type 8, parameter 0 gives each value's model name; the editor asks for it again after a change of +the user slots. + +A user model is 7548 bytes, little endian: a 64-byte header, then the 1871 weights as float32 in the `.nam` +file's order. + +| Offset | Size | Field | +| --- | --- | --- | +| 0 | 4 | magic `0x4D4E504F` ("OPNM") | +| 4 | 2 | version, 1 | +| 6 | 2 | weights, 1871 | +| 8 | 12 | name, ASCII, 0-ended (11 characters at most) | +| 20 | 2 | level trim, int16, 0.01 dB (added to the model's output) | +| 22 | 2 | CRC16 of the weights (polynomial 0x1021, initial value 0) | +| 24 | 40 | 0 | + +The editor (`docs/pxnam.js`) reads a `.nam` file, takes its A2-Lite part (an A2 file is a "SlimmableContainer" +with several sizes; a plain A2-Lite WaveNet also works), measures its loudness on `docs/nam_di.wav` and sets the +level trim so that every model plays at -20 LUFS on that clip, then sends 68 `NAM_WRITE` and one `NAM_COMMIT`. +A1 models (the older "standard" / "lite" / "feather" WaveNets) and other architectures are refused: the pedal's CPU +runs A2-Lite only. + +Writing the flash (`SLOT_PUT` with bit 1, `COMMIT`, `SAVE`, `NAM_COMMIT`, `NAM_ERASE`) mutes the sound for a moment, as +saving on the pedal does. A whole import sends `SLOT_PUT` without bit 1 for every slot, then one `COMMIT`. ## Preset files diff --git a/docs/NAM.md b/docs/NAM.md new file mode 100644 index 0000000..9f4ea72 --- /dev/null +++ b/docs/NAM.md @@ -0,0 +1,125 @@ +# Neural amp models (NAM A2) on the pedal (v37) + +Since v37 the AMP block has a ninth type, **NAM**, that plays a [Neural Amp Modeler](https://www.neuralampmodeler.com/) +network instead of an amp built from circuit stages. It plays the networks of NAM's **A2** architecture, at its +3-channel size, **A2-Lite**. That is the size the pedal's CPU can run. + +## The knobs + +| Knob | What it does | +| --- | --- | +| MODEL | which network: the 12 factory models, then the 16 user slots (`U1 EMPTY` ... until you load one) | +| GAIN | the level into the network, ±12 dB around the level of the captures (noon) | +| BASS, MID, TREBLE | an EQ after the network: ±10 dB at 120 Hz, ±8 dB at 800 Hz, ±10 dB above 2.5 kHz | + +The models are amp captures without a cabinet, so keep a CAB after the AMP. Every model plays at the same loudness +(-20 LUFS on the reference clip `docs/nam_di.wav`), so switching models keeps the volume. + +## Factory models + +Twelve A2-Lite networks, trained for the pedal at 44.1 kHz (`tools/train_a2.py`). Each one learnt to sound like a +community capture of a real amp, playing real DI guitar. Accuracy is ESR, the error on 20 s of guitar the training never +heard: 0.01 is very close, and below about 0.05 the two are hard to tell apart. + +| MODEL | Amp | Capture (author) | ESR | +| --- | --- | --- | --- | +| TWIN | Fender Twin Reverb (normal, bright) | Tim R Fender TwinVerb Norm Bright (Tim R) | 0.006 | +| AC15 | Vox AC15 Top Boost | Phillipe P VOXAC15-TopBoost (Phillipe P) | 0.045 | +| SUPER 59 | Magnatone Super 59 Mk II | Tim R Magnatone Super 59 Mkii Ch1 Br (Tim R) | 0.009 | +| SHIRL CL | Friedman Dirty Shirley Mini, clean | Sascha S DirtyShirleyMini_Clean_B1_M6_T7_MV10_G4 (Sascha S) | 0.014 | +| JCM900 | Marshall JCM900 50 W Dual Verb | Tim R JCM90050WDualVerbCHAG6 (Tim R) | 0.011 | +| SHIRLEY | Friedman Dirty Shirley Mini, crunch | Sascha S DirtyShirleyMini_crunch_G6 (Sascha S) | 0.033 | +| JCM2000 | Marshall JCM2000 DSL, lead | Tim R JCM2000 L2 G6 (Tim R) | 0.042 | +| MARK IV | Mesa Boogie Mark IV | Roman A LT_MESA_MARKIV_1 (Roman A) | 0.041 | +| JVM OD2 | Marshall JVM, OD2 | Phillipe P JVM-OD2-RD-NoDrive-ESR0,003 (Phillipe P) | 0.056 | +| PRO MOD | Splawn Pro Mod, 2nd gear | Tim R Splawn Pro Mod 2nd Gear - G12 (Tim R) | 0.052 | +| 5150 | Peavey 5150 (block letter), boosted | Helga B 5150 BlockLetter - Boosted (Helga B) | 0.064 | +| 6505 RED | Peavey 6505+ red channel, MXR drive | Helga B 6505+ Red ch - MXR Drive (Helga B) | 0.124 | + +High-gain captures are harder for a network this small: their error is higher (the 6505+ most), while the clean +and crunch models are very close. A larger A2 would do better, but would not fit the pedal's CPU. + +The factory presets use them; the fitted amps of v34 are still there as the other 8 AMP types. + +## Your own models (TONE3000 and others) + +1. Get a capture in the **A2** format: on [TONE3000](https://www.tone3000.com/) and in NAM's own trainer, A2 files + are offered beside the older formats. The pedal reads the A2-Lite part of an A2 file. The older A1 files + ("standard", "lite", "feather", "nano") do not run on the pedal and are refused with that reason. +2. Open the web editor (`editor.html`), connect the pedal, and under **NAM models** pick a free slot and the `.nam` file. + The editor checks it, measures its level and sends it to the pedal (about 2 seconds; the sound mutes a moment + while the flash is written). +3. In a preset, set the AMP type to **NAM** and turn **MODEL** to that slot. + +Or press **Browse TONE3000** in the same panel: TONE3000's own tone browser opens in a pop-up (sign in there; it shows +A2 captures only), and the chosen tone comes back with its creator and its A2 models; **Load** puts one into the +user slot chosen beside it. This uses TONE3000's public API ([tone3000.com/api](https://www.tone3000.com/api)), its +"Select" flow: OAuth 2.0 with PKCE and OpenPocket's publishable key (`T3K_CLIENT_ID` in `docs/pxt3k.js`), the sign-in +coming back through `docs/t3k.html`. The access token lives in the page only while it is open. It needs that key and +`https://isod89.github.io/openpocket/t3k.html` registered as a redirect URI in TONE3000's settings. + +The 16 user slots are in the pedal's flash at 0xC0000..0xE0000, outside the area a firmware update rewrites: your +models stay through updates. Clear a slot from the same panel. + +Most captures are made at 48 kHz. The pedal runs at 44.1 kHz, so such a model plays with its tone about 1.5 +semitones lower (the amp's filters sit 8% lower). The editor says so when it loads one. The factory models are +trained at 44.1 kHz and are not affected. + +## How it runs + +- `engine/px_nam.c`: the network in fixed point (activations with 20 fraction bits, weights with 24, 64-bit sums), + checked against a float reference (`tools/nam_a2.py`) for every factory model by `tests/test_nam.py`: about 99 dB + signal to error. +- Blocks of 32 frames, layer by layer. On the CPU, each output channel of a layer is computed for 4 frames at a time + straight from the layer's history ring (`rdot`): for each kernel tap, the 4 frames' 3 channels sit side by side in + the ring (12 words), so a weight is read once for 4 frames and no input is copied (where a tap's 4 frames wrap + round the ring, those 12 words are copied first). Then LeakyReLU, the head sum and the residual (`post`). On the + pedal these are hand-written (pi32v2 assembly: multiply-adds paired with loads, 3 words moved by one instruction, + no branch per sample), because this CPU has no data cache in front of its RAM and a taken branch costs about 8 + cycles. At start-up they are run against the C versions on a test pattern, and the C versions are used if they + differ by a single bit. On this CPU a multiply-add paired with the load of the value it needs next waits for it + (3.2 cycles, against 2.2 without the wait), so the routines for 6, 15 and 16 taps (`rdq`, written by + `tools/gen_rdq.py`) are unrolled with each value loaded 2 to 4 steps before its use. The start-up timing compares + them with the first `rdot` and with gathering each frame's inputs into one row first (then the hardware-loop dot + routine), and keeps the fastest. +- The dot products can also run on the chip's vector unit (in its FFT block: one command computes a row of weights + against many X rows, beside the CPU; each frame's inputs to the layer are then gathered into one X row). The block + is cut in two halves, and half B of a layer never needs the next layer's half A: so while the unit computes one + half, the CPU gathers or posts the other, and may compute the last 4 or 8 frames of a half itself. The unit costs + about 4.8 cycles a multiply-add on the pedal, about as much as the CPU. Its inputs (the X rows and a copy of the + weights, 13 KB) sit in seven of the data-cache ways turned into RAM at boot (`firmware/px_cacheram.h`, melodee's + routine; the data cache only serves the flash), so that it does not read the RAM the CPUs work in; the start-up + check runs the unit there too, and the ordinary RAM is used if it differs. +- Two cores: frame t of a layer needs only frames t and earlier of the layer before. So CPU1 takes the first 12 or 16 + frames of each 32-frame block through all 23 layers without ever waiting, and CPU0 the rest, waiting before each + layer until CPU1 has posted the one before (one counter). With a NAM amp in two-core mode the audio block runs on + CPU0 (in the audio interrupt) as a pipeline (`dsp_pipe` in `firmware/px_audio.h`, `px_engine_part`): CPU1 first runs + the effects after the amp on the previous block's network output while CPU0 runs the effects before the amp on this + block, then both run the network (one block, 2.9 ms, more latency; `tests/engine/pipe_test.c` checks it gives the + one-core output one block later). In the pipeline the roles are the other way round (`pxn_serve`): CPU1 comes to + the network after its effects, so it takes the last frames of each 32-frame block and waits per layer for CPU0, + which takes the first frames and never waits, and up to 12 more of them in the first blocks by how late CPU1 came + in the blocks before. Without a NAM amp the whole block runs on CPU1 as before. +- Each layer's history ring has its first 3 frames mirrored after its end, so 4 frames can be read straight from any + position: the tap pointers just move on by 4 frames per group. On the pedal a layer's whole block of groups runs in one call + (`pxn_rdl6/15/16_asm`, generated by `tools/gen_rdq.py --rdl`), its tap table on the stack. +- At start-up the pedal times the ways to run it (CPU alone; the unit one command after the other; the unit and the + CPU at once, the CPU taking 0, 4 or 8 frames; two cores, with or without the unit) on the first factory model and + keeps the fastest (`pxn_tune`). The PC test runs every mode with a simulated unit that finishes its commands late, + at random, and a simulated second core that moves on only while the first waits for it: the output must be exactly + the CPU's. +- 1,730 multiply-adds per sample in 23 layers; the history buffers take 83 KB of RAM, a model 7.5 KB. +- The load shows at the bottom right of the screen (`C1 nn%`). + +## Training (`tools/train_a2.py`) + +`train_a2.py --capture CAPTURE.nam --di DI.wav --val DI2.wav --out MODEL.nam --name NAME` trains an A2-Lite network +(JAX) on a capture: the DI goes through the capture (resampled to its rate and back), the A2-Lite learns the result at +44.1 kHz. Loss: pre-emphasised ESR plus a multi-resolution spectral term. `tools/mk_nam_factory.py` writes the +factory models into `engine/px_nam_factory.h`, each with its level trim. + +Credits: the captures are from the Neural Amp Modeler community collection +[pelennor2170/NAM_models](https://github.com/pelennor2170/NAM_models) (GNU GPL v3), by the authors named in the +table; the DI guitar is from [Alec-Wright/Automated-GuitarAmpModelling](https://github.com/Alec-Wright/Automated-GuitarAmpModelling) +(GNU GPL v3). The A2 architecture is Steven Atkinson's (Neural Amp Modeler, MIT); the pedal's code is written for +OpenPocket from the published architecture. diff --git a/docs/SOUNDS-AND-CONTROLS.md b/docs/SOUNDS-AND-CONTROLS.md index f1bc9db..f9e52d6 100644 --- a/docs/SOUNDS-AND-CONTROLS.md +++ b/docs/SOUNDS-AND-CONTROLS.md @@ -1,8 +1,8 @@ -# OpenPocket — sounds and controls (v36) +# OpenPocket — sounds and controls (v37) ![OpenPocket screens](ui-v23.png) -## The chain (12 blocks, 77 models) +## The chain (12 blocks, 78 models) Default order: `GT → CMP → PIT → SFX → SYN → DRV → AMP → CAB → EQ → MOD → DLY → REV` Since v29 every preset has its own block order: **double-click PUSH** on the chain to grab the selected block, turn @@ -19,6 +19,12 @@ captures of the real units (v34); the effects follow published circuit analyses R.G. Keen, Boss/Roland/EHX manuals). They are digital models, not copies. The product names are trademarks of their owners, used only to describe the sound. +### AMP — NAM: neural amp models (v37; MODEL, GAIN, BASS, MID, TREBLE) +The ninth AMP type plays Neural Amp Modeler A2 networks: 12 factory models (TWIN, AC15, SUPER 59, SHIRL CL, JCM900, +SHIRLEY, JCM2000, MARK IV, JVM OD2, PRO MOD, 5150, 6505 RED) and 16 user slots filled from the web editor with A2 +captures. MODEL picks the network, GAIN sets the level into it (±12 dB), BASS / MID / TREBLE are an EQ after it. The +models have no cabinet: keep a CAB after the AMP. All the factory presets use NAM. Details: [NAM.md](NAM.md). + ### AMP — 8 amps, fitted to captures of the real ones (GAIN, BASS, MID, TREBLE, PRESENCE) Since v34 there are fewer amps, and each one is fitted by computer to a capture of the real amp (method and references: [FITTED-MODELS.md](FITTED-MODELS.md)). With the knobs at noon it sounds like the capture. @@ -106,8 +112,8 @@ plate). DECAY sets the real decay time (RT60) of the lows: ROOM 0.3–1.2 s, HAL PLATE 0.6–5 s, SPRING 1.5–4 s, SHIMMER 2–8 s, AMBIENT 6–20 s. They run at 22 kHz in 16 bits (like the classic studio units), in a quarter of v34's memory. -## Factory presets (v36): 24 sounds, all at the same loudness, then 28 USER slots -Built round the fitted amps and drives, which sound like their captures near noon. Every preset is levelled to the +## Factory presets (v37): 24 sounds, all at the same loudness, then 28 USER slots +Built round the NAM models (v37; v36's were built round the fitted amps) and the fitted drives. Every preset is levelled to the same loudness (-23 LUFS, EBU R128, measured on real DI guitar by `tools/level_presets.py`): going from a clean to a high-gain preset no longer jumps by 20 dB. @@ -120,7 +126,7 @@ high-gain preset no longer jumps by 20 dB. | | 05 SURF SPRING | 11 70S ROCK | | 21 DOOM | | | | 06 AMBIENT SWELL | 12 BOUTIQUE | | | | -25–52: **USER 25 … USER 52**, a clean TWIN + 1x12 + a little room, to build your own. +25–52: **USER 25 … USER 52**, a clean NAM TWIN + 1x12 + a little room, to build your own. **Levels (v36)**: every amp plays at the same loudness at GAIN noon and moves only +-3 dB over the whole knob; every block type, with its knobs at noon, keeps the loudness when switched on; each preset has its own **PRESET LVL** diff --git a/docs/WHATS-NEW-v37.md b/docs/WHATS-NEW-v37.md new file mode 100644 index 0000000..5e53e3d --- /dev/null +++ b/docs/WHATS-NEW-v37.md @@ -0,0 +1,59 @@ +# What's new in OpenPocket v37: neural amp models (NAM A2) + +## Neural amps on the pedal +- **A new AMP type, NAM**, plays Neural Amp Modeler networks of the **A2** architecture (its "Lite" size) on the pedal + itself. The pedal no longer plays an approximation fitted to a capture: it plays the network. +- **12 factory models**, trained for the pedal from community captures of real amps (Fender Twin Reverb, Vox AC15, + Magnatone Super 59, Friedman Dirty Shirley clean and crunch, Marshall JCM900, JCM2000 and JVM, Mesa Mark IV, Splawn + Pro Mod, Peavey 5150 and 6505+). All at the same loudness. +- **Knobs:** MODEL, GAIN (±12 dB into the network), BASS, MID, TREBLE (an EQ after it). +- Details, accuracy and credits: [NAM.md](NAM.md). + +## Load your own captures (TONE3000) +- The web editor has a **NAM models** panel: pick a user slot, choose an **A2** `.nam` file (from TONE3000, or from + NAM's trainer), and it goes to the pedal in about 2 seconds. 16 user slots, kept through firmware updates. +- The editor checks the file, refuses A1 captures with the reason, and sets the model's level so it plays as loud as + the others. +- On the pedal, MODEL shows the model's name; the PLAY page shows it as the amp. +- **Browse TONE3000 from the editor:** the button opens TONE3000's own tone browser (sign in there, A2 captures only), + then the editor shows the chosen tone (title, gear, creator) and its A2 models, and loads one into a user slot. It + uses TONE3000's public API (its "Select" flow, OAuth with PKCE); nothing is stored by the editor. + +## New factory presets +- **All 24 factory presets are rebuilt around the NAM models**, levelled to the same loudness as before. The 28 USER + slots start from a clean NAM Twin. +- The 8 fitted amps of v34 stay available as AMP types, and your saved presets keep the amp they use. + +## Faster engine +- The NAM network has hand-written routines for the pedal's CPU, checked against the C versions at every start-up: + each layer is read straight from its history ring (no copy), 4 frames at a time, a weight read once for the 4, + multiply-adds paired with loads. +- It can use the chip's **vector unit** (in its FFT block) for the dot products beside the CPU, and the **second + core**: with a NAM amp, CPU0 runs the block and CPU1 takes the first frames of each network block (earlier frames + never need later ones, so CPU1 never waits). At start-up the pedal times the ways it can run the network and keeps + the fastest. +- A NAM amp replaces the fitted amp's ×4-oversampled stages, so it adds less than its own cost. +- Effects run over a whole block, one after another, instead of sample by sample (same output, about 20% cheaper). + In front of a NAM amp the drive runs at ×2 oversampling instead of ×4. +- With a NAM amp the two cores work as a pipeline: CPU1 runs the effects after the amp on the previous block while + CPU0 runs the effects before it, then both run the network. This adds one block of latency (2.9 ms). +- The network reads each layer's history without any per-tap position arithmetic: every ring's first frames are + mirrored after its end, and each layer's whole block runs in one hand-written call. +- In the pipeline CPU1 goes straight from its effects to the network and takes the last frames of each network + block; CPU0 takes more frames when CPU1 comes late, so neither core waits for the other. +- **Load on the pedal** (% of real time, measured): the network alone 66%, the 23 factory presets with a NAM amp + 69–90% (most 75–83%). The status corner shows `2C` and the load while both cores run a NAM preset. Above 93% for + 8 blocks in a row the pedal bypasses the effects (`BYP`) until the next change, as before (85% on one core). + +## For developers +- Editor protocol 2: `NAM_LIST`, `NAM_WRITE`, `NAM_COMMIT`, `NAM_ERASE` ([EDITOR-PROTOCOL.md](EDITOR-PROTOCOL.md)). +- `tools/train_a2.py` (JAX) trains an A2-Lite network from a capture; `tools/mk_nam_factory.py` builds the factory + set; `tests/test_nam.py` checks the fixed-point engine against a float reference. +- Memory: the NAM history buffers (83 KB) sit in the POOL region beside the engine, so that the ordinary RAM keeps + about 47 KB free (for Bluetooth later). +- `tools/check_calls.py` (run by `firmware/build.sh`): refuses a direct call between the flash code and the RAM code, + which is out of the CPU's call range, and names it. + +## Please report +The CPU load cannot be measured off the pedal. Please send the `C1 nn%` shown at the bottom right on a few factory +presets (for example 14 HAIR METAL, 16 SPACE LEAD and 06 AMBIENT SWELL), and say if you hear crackles. diff --git a/docs/editor.html b/docs/editor.html index d56bb47..63af993 100644 --- a/docs/editor.html +++ b/docs/editor.html @@ -74,6 +74,29 @@ .row.cur{background:var(--panel);box-shadow:inset 3px 0 0 var(--acc)} .row.cur .n{color:var(--acc)} .slotbar{display:flex;flex-wrap:wrap;gap:6px;align-items:center} +/* v37: TONE3000 (the Select flow) */ +.t3k{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:6px 0 8px} +.t3k .logo{font-weight:800;letter-spacing:.04em;font-size:15px;color:#fff} +.t3kcard{border:1px solid #2a2e2a;border-radius:10px;padding:10px;margin:0 0 10px;display:grid;gap:8px} +.t3kcard .top{display:grid;grid-template-columns:64px minmax(0,1fr);gap:10px;align-items:center} +.t3kcard .img{width:64px;height:64px;border-radius:8px;object-fit:cover;background:#222} +.t3kcard .ttl{font-weight:700;overflow:hidden;text-overflow:ellipsis} +.t3kcard .sub{color:var(--dim);font-size:12.5px} +.t3kcard .by{display:flex;align-items:center;gap:6px;font-size:13px;min-width:0} +.t3kcard .by img{width:20px;height:20px;border-radius:50%;background:#222} +.t3kcard .mrow{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;font-size:13px} +.t3kcard .mrow span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +.t3kcard .foot{display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:12.5px;color:var(--dim)} +.t3kcard .logo{font-weight:800;letter-spacing:.04em;color:#fff} +.t3kcard select{background:#1c1f1c;color:var(--txt);border:1px solid #333;border-radius:7px;padding:5px} +/* v37: NAM models */ +.namlist{max-height:360px} +.namlist .row{grid-template-columns:34px minmax(0,1fr) auto;cursor:default} +.namlist .row .acts{display:flex;gap:4px} +.namlist .row.empty .nm{color:var(--dim);font-weight:500} +.side .note{margin:0;font-size:12.5px;line-height:1.45;color:var(--dim)} +.side .note code{font-size:12px} +.a2{font-size:10px;letter-spacing:.06em;color:var(--acc);border:1px solid var(--acc);border-radius:4px;padding:0 4px;margin-left:6px;vertical-align:1px} .slotbar .lbl{font-size:12.5px;color:var(--dim);margin-right:auto} /* ---- the screen ---- */ @@ -174,6 +197,15 @@

Presets

+ + + + + +
@@ -216,6 +248,8 @@

Connect your pedal

+ + diff --git a/engine/px_dsp.c b/engine/px_dsp.c index c484937..fcfcdfb 100644 --- a/engine/px_dsp.c +++ b/engine/px_dsp.c @@ -12,6 +12,13 @@ * stacks), Celestion / Jensen / EV / JBL speaker curves, Roland/Boss/Ampeg/Electro-Harmonix manuals. */ #include "px_dsp.h" +#include "px_nam.c" /* v37: NAM A2-Lite (one translation unit: every build gets it) */ +/* The engine runs from the flash (XIP), as in v36: a direct call between the flash (0x02xxxxxx) and the RAM code + * (0x01C0xxxx) is out of the CPU's call range, so code in RAM may call nothing in the flash and the reverse, except + * through a pointer (FL_FAR in fm1_flash.h). Only the NAM layer routine is in RAM (px_nam.c, called through a + * pointer). */ +#define PX_HOT +#define PX_INL #include #include @@ -57,6 +64,176 @@ static inline float bq_run(px_bq *b, float x) b->z2 = b->b2 * x - b->a2 * y; return y; } +/* the same over a buffer, in place: the coefficients and state in registers through the loop (same operations, same + * result as bq_run sample by sample) */ +static void bq_block(px_bq *q, float *b, int n) +{ + const float b0 = q->b0, b1 = q->b1, b2 = q->b2, a1 = q->a1, a2 = q->a2; + float z1 = q->z1, z2 = q->z2; + for (int k = 0; k < n; k++) { + const float x = b[k], y = b0 * x + z1; + z1 = b1 * x - a1 * y + z2; + z2 = b2 * x - a2 * y; + b[k] = y; + } + q->z1 = z1; + q->z2 = z2; +} +/* two filters in series over a buffer, interleaved: the first on sample k while the second does sample k-1, so that + * their two feedback loops overlap in the FPU instead of waiting for each other (same operations per filter, same + * result as bq_block twice) */ +static void bq_block2(px_bq *p, px_bq *q, float *b, int n) +{ + if (n <= 0) return; + const float pb0 = p->b0, pb1 = p->b1, pb2 = p->b2, pa1 = p->a1, pa2 = p->a2; + const float qb0 = q->b0, qb1 = q->b1, qb2 = q->b2, qa1 = q->a1, qa2 = q->a2; + float pz1 = p->z1, pz2 = p->z2, qz1 = q->z1, qz2 = q->z2; + float x = b[0], pend = pb0 * x + pz1; + pz1 = pb1 * x - pa1 * pend + pz2; + pz2 = pb2 * x - pa2 * pend; + for (int k = 1; k < n; k++) { + const float xp = b[k], yp = pb0 * xp + pz1; + pz1 = pb1 * xp - pa1 * yp + pz2; + pz2 = pb2 * xp - pa2 * yp; + const float u = pend, yq = qb0 * u + qz1; + qz1 = qb1 * u - qa1 * yq + qz2; + qz2 = qb2 * u - qa2 * yq; + b[k - 1] = yq; + pend = yp; + } + { + const float u = pend, yq = qb0 * u + qz1; + qz1 = qb1 * u - qa1 * yq + qz2; + qz2 = qb2 * u - qa2 * yq; + b[n - 1] = yq; + } + p->z1 = pz1; p->z2 = pz2; q->z1 = qz1; q->z2 = qz2; +} +/* v37: the same filter in integer arithmetic (the pedal's FPU is slow; its integer multiply-adds are not): the signal in + * Q26 (+-32), the coefficients in Q29 (+-4), direct form I with a 64-bit sum. The float filter's coefficients + * are converted each call (they may change between calls); 0 = a coefficient out of range: not run (use bq_block). */ +typedef struct { int32_t x1, x2, y1, y2; } px_fq; /* (laid out as int32_t[4]) */ +int px_fx_int = 0; +int px_fx_hand; /* the integer filter loop by hand (px_fx_check) */ +#define FQ_CB 29 /* coefficient fraction bits */ +#define FQ_SB 26 /* signal fraction bits (+-32) */ +static int32_t fq_c(float c) { return (int32_t)(c * (float)(1u << FQ_CB) + (c >= 0.0f ? 0.5f : -0.5f)); } +static int fq_ok(const px_bq *f) +{ + const float m = (float)(1u << (31 - FQ_CB)) - 0.01f; + return f->b0 < m && f->b0 > -m && f->b1 < m && f->b1 > -m && f->b2 < m && f->b2 > -m && + f->a1 < m && f->a1 > -m && f->a2 < m && f->a2 > -m; +} +/* the loop, on (b0, b1, b2, a1, a2) in Q29 and the state (x1, x2, y1, y2): the sum's bits 29..60 kept (rounded down, + * no saturation: the signal's range leaves room). By hand on the pedal (checked against this one at start-up) */ +static void fq_loop_c(int32_t *b, int n, const int32_t *c, int32_t *st) +{ + int32_t x1 = st[0], x2 = st[1], y1 = st[2], y2 = st[3]; + for (int k = 0; k < n; k++) { + const int32_t x = b[k]; + int64_t acc = (int64_t)c[0] * x; + acc += (int64_t)c[1] * x1; + acc += (int64_t)c[2] * x2; + acc -= (int64_t)c[3] * y1; + acc -= (int64_t)c[4] * y2; + const int32_t y = (int32_t)(uint32_t)(uint64_t)(acc >> FQ_CB); + x2 = x1; x1 = x; y2 = y1; y1 = y; + b[k] = y; + } + st[0] = x1; st[1] = x2; st[2] = y1; st[3] = y2; +} +#if defined(__PI32V2__) +void px_fq_asm(int32_t *b, int n, const int32_t *c, int32_t *st); +__asm__("\t.text\n" + "\t.global px_fq_asm\n" + "px_fq_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -4\n" + "\t[sp+0] = r3\n" + "\tr4 = [r2+0]\n\tr5 = [r2+4]\n\tr6 = [r2+8]\n\tr7 = [r2+12]\n\tr12 = [r2+16]\n" + "\tr13 = [r3+0]\n\tr14 = [r3+4]\n\tr15 = [r3+8]\n\tr11 = [r3+12]\n" + "\tr1 = r1 >> 1\n" + ".Lpx_fq:\n" + "\tr10 = [r0+0]\n" + "\tr9_r8 = r10 * r4 (s)\n" + "\tr9_r8 += r13 * r5 (s)\n" + "\tr9_r8 += r14 * r6 (s)\n" + "\tr9_r8 -= r15 * r7 (s)\n" + "\tr9_r8 -= r11 * r12 (s)\n" + "\tr9_r8 >>>= 29\n" + "\t[r0++=4] = r8\n" + "\tr14 = [r0+0]\n" + "\tr3_r2 = r14 * r4 (s)\n" + "\tr3_r2 += r10 * r5 (s)\n" + "\tr3_r2 += r13 * r6 (s)\n" + "\tr3_r2 -= r8 * r7 (s)\n" + "\tr3_r2 -= r15 * r12 (s)\n" + "\tr3_r2 >>>= 29\n" + "\t[r0++=4] = r2\n" + "\tr13 = r14\n\tr14 = r10\n\tr15 = r2\n\tr11 = r8\n" + "\tr1 += -1\n" + "\tif (r1 != 0) goto .Lpx_fq\n" + "\tr3 = [sp+0]\n" + "\t[r3+0] = r13\n\t[r3+4] = r14\n\t[r3+8] = r15\n\t[r3+12] = r11\n" + "\tsp += 4\n" + "\t{pc, r15-r4} = [sp++]\n"); +#endif +static void (*fq_loop)(int32_t *, int, const int32_t *, int32_t *) = fq_loop_c; +/* start-up: the hand loop against the C one (1 = in use) */ +int px_fx_check(void) +{ +#if defined(__PI32V2__) + static int32_t a[66], b[66]; + int32_t sa[4] = {1000, -2000, 3000, -4000}, sb[4] = {1000, -2000, 3000, -4000}; + const int32_t c[5] = {fq_c(0.25f), fq_c(-0.4f), fq_c(0.2f), fq_c(-1.6f), fq_c(0.7f)}; + uint32_t r = 777u; + for (int i = 0; i < 66; i++) { r = r * 1103515245u + 12345u; a[i] = b[i] = (int32_t)r >> 5; } + fq_loop_c(a, 66, c, sa); + px_fq_asm(b, 66, c, sb); + for (int i = 0; i < 66; i++) if (a[i] != b[i]) return 0; + for (int i = 0; i < 4; i++) if (sa[i] != sb[i]) return 0; + fq_loop = px_fq_asm; + return 1; +#else + return 0; +#endif +} +static void fq_block(const px_bq *f, px_fq *s, int32_t *b, int n) +{ + if (n <= 0) return; + const int32_t c[5] = {fq_c(f->b0), fq_c(f->b1), fq_c(f->b2), fq_c(f->a1), fq_c(f->a2)}; + if (n & 1) fq_loop_c(b, n, c, &s->x1); /* (the hand loop does 2 samples a turn) */ + else fq_loop(b, n, c, &s->x1); +} +static int32_t px_fqbuf[PX_OVERSAMPLE * PX_MAX_BLOCK]; +static void fq_to(int32_t *q, const float *x, int n) +{ + for (int k = 0; k < n; k++) { + float v = x[k] * (float)(1u << FQ_SB); + q[k] = v >= 2147483520.0f ? 2147483520 : v <= -2147483520.0f ? -2147483520 : (int32_t)v; + } +} +static void fq_from(float *x, const int32_t *q, int n) +{ + for (int k = 0; k < n; k++) x[k] = (float)q[k] * (1.0f / (float)(1u << FQ_SB)); +} +/* a chain of filters over a float buffer: in integer arithmetic if all can be, else as floats */ +static void fq_chain(px_bq *f, px_fq *s, int nf, float *b, int n) +{ + int ok = 1; + for (int c = 0; c < nf; c++) ok &= fq_ok(&f[c]); + if (!ok) { for (int c = 0; c < nf; c++) bq_block(&f[c], b, n); return; } + fq_to(px_fqbuf, b, n); + for (int c = 0; c < nf; c++) fq_block(&f[c], &s[c], px_fqbuf, n); + fq_from(b, px_fqbuf, n); +} +/* a chain of filters over a buffer, two at a time */ +static void bq_chain(px_bq *f, int nf, float *b, int n) +{ + int c = 0; + for (; c + 1 < nf; c += 2) bq_block2(&f[c], &f[c + 1], b, n); + if (c < nf) bq_block(&f[c], b, n); +} static void bq_set(px_bq *b, float b0, float b1, float b2, float a0, float a1, float a2) { float z1 = b->z1, z2 = b->z2; /* keep state: no click on change */ @@ -323,13 +500,14 @@ static const tdef T_REV[PX_REV_COUNT] = { /* ------------------------------------------------------------ catalog API --- */ static const char *const PN_AMP[] = {"GAIN", "BASS", "MID", "TREBLE", "PRESENCE"}; +static const char *const PN_NAM[] = {"MODEL", "GAIN", "BASS", "MID", "TREBLE"}; static const char *const PN_CAB[] = {"BODY", "BRIGHT", "MIC"}; const char *px_block_label(int b) { return (b >= 0 && b < PX_NBLK) ? BLK_LABEL[b] : "?"; } const char *px_block_name(int b) { return (b >= 0 && b < PX_NBLK) ? BLK_NAME[b] : "?"; } int px_ntypes(int b) { - static const uint8_t N[PX_NBLK] = {1, PX_CMP_COUNT, PX_PIT_COUNT, PX_SFX_COUNT, PX_DRV_COUNT, PX_AMP_COUNT, + static const uint8_t N[PX_NBLK] = {1, PX_CMP_COUNT, PX_PIT_COUNT, PX_SFX_COUNT, PX_DRV_COUNT, PX_AMP_NTYPES, PX_CAB_COUNT, PX_EQ_COUNT, PX_MOD_COUNT, PX_DLY_COUNT, PX_REV_COUNT, PX_SYN_COUNT}; return (b >= 0 && b < PX_NBLK) ? N[b] : 1; @@ -353,7 +531,7 @@ const char *px_type_name(int b, int t) { if (t < 0 || t >= px_ntypes(b)) t = 0; if (b == PX_B_DRIVE) return DV[t].name; - if (b == PX_B_AMP) return AV[t].name; + if (b == PX_B_AMP) return t == PX_AMP_NAM ? "NAM" : AV[t].name; if (b == PX_B_CAB) return CV[t].name; const tdef *d = tdef_of(b, t); return d ? d->name : "?"; @@ -372,7 +550,7 @@ const char *px_param_name(int b, int t, int k) if (t < 0 || t >= px_ntypes(b)) t = 0; if (k < 0 || k >= px_nparams(b, t)) return ""; if (b == PX_B_DRIVE) return ROLE_NAME[DV[t].role[k]]; - if (b == PX_B_AMP) return PN_AMP[k]; + if (b == PX_B_AMP) return t == PX_AMP_NAM ? PN_NAM[k] : PN_AMP[k]; if (b == PX_B_CAB) return PN_CAB[k]; return tdef_of(b, t)->pn[k]; } @@ -440,6 +618,16 @@ int px_param_text(int b, int t, int k, int v, char *buf) return 1; } break; + case PX_B_AMP: + if (t == PX_AMP_NAM && k == 0) { /* the model's name */ + char nm[12]; + px_nam_name(px_nam_model(v), nm); + for (int i = 0; i < 9; i++) buf[i] = nm[i]; + buf[8] = 0; + return 1; + } + if (t == PX_AMP_NAM && k == 1) { float db = (x - 0.5f) * 24.0f; put_int(buf, (int)(db + (db >= 0 ? 0.5f : -0.5f)), 1); return 1; } + break; case PX_B_PITCH: if (t == PX_PIT_HARMONY && k == 0) { put_str(buf, HARM_TXT[harm_idx(v)]); return 1; } if (t == PX_PIT_WHAMMY && k == 0) { float st = (x - 0.5f) * 48.0f; put_int(buf, (int)(st + (st >= 0 ? 0.5f : -0.5f)), 1); return 1; } @@ -508,10 +696,13 @@ static void setname(px_preset_t *p, const char *s) } enum { NPRESETS = 52 }; int px_preset_count(void) { return NPRESETS; } -/* v36: 24 factory presets built round the fitted amps and drives (amps near noon, where they match the captures), - * each one levelled (LEVEL, tools/level_presets.py: -20 LUFS on DI guitar); slots 25..52: USER, a clean starting point */ +/* v37: 24 factory presets built round the factory NAM A2 models (NAM(model, gain, bass, mid, treble): knobs at noon + * = the captured amp), each one levelled (LEVEL, tools/level_presets.py: -23 LUFS on DI guitar, as v36); slots 25..52: USER, + * a clean starting point */ #define LVL(v) (p->p[PX_B_GATE][PX_PATCH_LEVEL] = (uint8_t)(v)) #define NOGATE (p->on[PX_B_GATE] = 0) +#define NAM(m, g, b, md, t) blk(p, PX_B_AMP, 1, PX_AMP_NAM, px_nam_knob(m), g, b, md, t) +enum { M_TWIN, M_AC15, M_SUPER59, M_SHIRLCL, M_JCM900, M_SHIRLEY, M_JCM2000, M_MARK4, M_JVM, M_PROMOD, M_5150, M_6505 }; void px_preset_factory(px_preset_t *p, int idx) { base_preset(p); @@ -519,104 +710,104 @@ void px_preset_factory(px_preset_t *p, int idx) p->on[PX_B_AMP] = p->on[PX_B_CAB] = 1; switch (idx) { /* ---- clean ---- */ - case 0: setname(p, "TWIN CLEAN"); blk(p, PX_B_GATE, 1, 0, 15, 50, 50, 0, 0); LVL(44); + case 0: setname(p, "TWIN CLEAN"); blk(p, PX_B_GATE, 1, 0, 15, 50, 50, 0, 0); LVL(54); blk(p, PX_B_COMP, 1, PX_CMP_STUDIO, 30, 50, 50, 50, 0); - blk(p, PX_B_AMP, 1, PX_AMP_TWIN, 45, 50, 50, 55, 50); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 50, 50, 0, 0); + NAM(M_TWIN, 50, 50, 50, 55); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 50, 50, 0, 0); blk(p, PX_B_REVERB, 1, PX_REV_PLATE, 40, 50, 22, 0, 0); break; - case 1: setname(p, "CHORUS CLEAN"); blk(p, PX_B_GATE, 1, 0, 15, 50, 50, 0, 0); LVL(47); - blk(p, PX_B_AMP, 1, PX_AMP_TWIN, 40, 50, 50, 55, 50); blk(p, PX_B_CAB, 1, PX_CAB_212BLUE, 50, 50, 50, 0, 0); + case 1: setname(p, "CHORUS CLEAN"); blk(p, PX_B_GATE, 1, 0, 15, 50, 50, 0, 0); LVL(55); + NAM(M_TWIN, 45, 50, 50, 55); blk(p, PX_B_CAB, 1, PX_CAB_212BLUE, 50, 50, 50, 0, 0); blk(p, PX_B_MOD, 1, PX_MOD_CHORUS, 30, 50, 50, 0, 0); blk(p, PX_B_DELAY, 1, PX_DLY_DIGITAL, 35, 25, 18, 50, 0); blk(p, PX_B_REVERB, 1, PX_REV_HALL, 45, 50, 22, 0, 0); break; - case 2: setname(p, "AC15 CHIME"); blk(p, PX_B_GATE, 1, 0, 20, 50, 50, 0, 0); LVL(42); - blk(p, PX_B_AMP, 1, PX_AMP_AC15, 50, 45, 50, 55, 50); blk(p, PX_B_CAB, 1, PX_CAB_212BLUE, 50, 55, 50, 0, 0); + case 2: setname(p, "AC15 CHIME"); blk(p, PX_B_GATE, 1, 0, 20, 50, 50, 0, 0); LVL(50); + NAM(M_AC15, 50, 48, 50, 52); blk(p, PX_B_CAB, 1, PX_CAB_212BLUE, 50, 55, 50, 0, 0); blk(p, PX_B_REVERB, 1, PX_REV_SPRING, 40, 50, 20, 40, 0); break; - case 3: setname(p, "FUNK WAH"); NOGATE; LVL(41); + case 3: setname(p, "FUNK WAH"); NOGATE; LVL(59); blk(p, PX_B_COMP, 1, PX_CMP_SQUASH, 55, 35, 50, 0, 0); blk(p, PX_B_SFX, 1, PX_SFX_AUTOWAH, 55, 50, 55, 40, 0); - blk(p, PX_B_AMP, 1, PX_AMP_TWIN, 40, 45, 55, 60, 55); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 50, 50, 0, 0); + NAM(M_TWIN, 45, 45, 55, 60); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 50, 50, 0, 0); blk(p, PX_B_REVERB, 1, PX_REV_ROOM, 35, 50, 15, 0, 0); break; - case 4: setname(p, "SURF SPRING"); blk(p, PX_B_GATE, 1, 0, 15, 50, 50, 0, 0); LVL(47); - blk(p, PX_B_AMP, 1, PX_AMP_TWIN, 45, 50, 45, 60, 55); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 55, 50, 0, 0); + case 4: setname(p, "SURF SPRING"); blk(p, PX_B_GATE, 1, 0, 15, 50, 50, 0, 0); LVL(66); + NAM(M_SUPER59, 45, 50, 45, 58); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 55, 50, 0, 0); blk(p, PX_B_DELAY, 1, PX_DLY_TAPE, 7, 10, 15, 50, 20); blk(p, PX_B_REVERB, 1, PX_REV_SPRING, 55, 55, 40, 60, 0); break; - case 5: setname(p, "AMBIENT SWELL"); blk(p, PX_B_GATE, 1, 0, 18, 50, 50, 0, 0); LVL(50); + case 5: setname(p, "AMBIENT SWELL"); blk(p, PX_B_GATE, 1, 0, 18, 50, 50, 0, 0); LVL(68); blk(p, PX_B_COMP, 1, PX_CMP_SWELL, 50, 50, 50, 0, 0); - blk(p, PX_B_AMP, 1, PX_AMP_TWIN, 40, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 45, 50, 0, 0); + NAM(M_TWIN, 45, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 45, 50, 0, 0); blk(p, PX_B_MOD, 1, PX_MOD_CHORUS, 20, 30, 30, 0, 0); blk(p, PX_B_DELAY, 1, PX_DLY_DUAL, 35, 45, 30, 40, 0); blk(p, PX_B_REVERB, 1, PX_REV_AMBIENT, 50, 45, 40, 0, 0); break; /* ---- edge of break-up, crunch ---- */ - case 6: setname(p, "TS BLUES"); blk(p, PX_B_GATE, 1, 0, 18, 50, 50, 0, 0); LVL(46); + case 6: setname(p, "TS BLUES"); blk(p, PX_B_GATE, 1, 0, 18, 50, 50, 0, 0); LVL(64); blk(p, PX_B_DRIVE, 1, PX_DRV_TS9, 35, 50, 50, 0, 0); - blk(p, PX_B_AMP, 1, PX_AMP_TWIN, 55, 50, 50, 55, 50); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 50, 50, 0, 0); + NAM(M_SUPER59, 55, 50, 50, 52); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 50, 50, 0, 0); blk(p, PX_B_REVERB, 1, PX_REV_SPRING, 40, 50, 18, 40, 0); break; - case 7: setname(p, "BLUES BREAKUP"); blk(p, PX_B_GATE, 1, 0, 22, 50, 50, 0, 0); LVL(41); - blk(p, PX_B_AMP, 1, PX_AMP_AC15, 60, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_212BLUE, 50, 50, 50, 0, 0); + case 7: setname(p, "BLUES BREAKUP"); blk(p, PX_B_GATE, 1, 0, 22, 50, 50, 0, 0); LVL(51); + NAM(M_SHIRLCL, 55, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_212BLUE, 50, 50, 50, 0, 0); blk(p, PX_B_DELAY, 1, PX_DLY_ANALOG, 29, 20, 15, 40, 0); blk(p, PX_B_REVERB, 1, PX_REV_ROOM, 40, 50, 18, 0, 0); break; - case 8: setname(p, "KLON CRUNCH"); blk(p, PX_B_GATE, 1, 0, 18, 50, 50, 0, 0); LVL(42); + case 8: setname(p, "KLON CRUNCH"); blk(p, PX_B_GATE, 1, 0, 18, 50, 50, 0, 0); LVL(66); blk(p, PX_B_DRIVE, 1, PX_DRV_KLON, 40, 50, 55, 0, 0); - blk(p, PX_B_AMP, 1, PX_AMP_JCM900, 45, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); + NAM(M_JCM900, 45, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); blk(p, PX_B_REVERB, 1, PX_REV_ROOM, 40, 50, 18, 0, 0); break; - case 9: setname(p, "BRIT CRUNCH"); blk(p, PX_B_GATE, 1, 0, 25, 30, 50, 0, 0); LVL(39); - blk(p, PX_B_AMP, 1, PX_AMP_JCM900, 55, 50, 55, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); + case 9: setname(p, "BRIT CRUNCH"); blk(p, PX_B_GATE, 1, 0, 25, 30, 50, 0, 0); LVL(51); + NAM(M_JCM900, 55, 50, 55, 50); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); blk(p, PX_B_REVERB, 1, PX_REV_ROOM, 35, 50, 15, 0, 0); break; - case 10: setname(p, "70S ROCK"); blk(p, PX_B_GATE, 1, 0, 25, 30, 50, 0, 0); LVL(41); + case 10: setname(p, "70S ROCK"); blk(p, PX_B_GATE, 1, 0, 25, 30, 50, 0, 0); LVL(48); blk(p, PX_B_DRIVE, 1, PX_DRV_M77, 20, 50, 65, 0, 0); - blk(p, PX_B_AMP, 1, PX_AMP_JCM900, 60, 55, 55, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); + NAM(M_AC15, 60, 55, 55, 50); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); blk(p, PX_B_REVERB, 1, PX_REV_PLATE, 35, 50, 15, 0, 0); break; case 11: setname(p, "BOUTIQUE"); blk(p, PX_B_GATE, 1, 0, 25, 30, 50, 0, 0); LVL(40); - blk(p, PX_B_AMP, 1, PX_AMP_SHIRLEY, 50, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 50, 50, 50, 0, 0); + NAM(M_SHIRLEY, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 50, 50, 50, 0, 0); blk(p, PX_B_DELAY, 1, PX_DLY_DIGITAL, 29, 15, 12, 45, 0); blk(p, PX_B_REVERB, 1, PX_REV_ROOM, 40, 50, 15, 0, 0); break; /* ---- lead ---- */ - case 12: setname(p, "BRIT LEAD"); blk(p, PX_B_GATE, 1, 0, 30, 30, 50, 0, 0); LVL(41); - blk(p, PX_B_AMP, 1, PX_AMP_JCM2000, 55, 50, 55, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); + case 12: setname(p, "BRIT LEAD"); blk(p, PX_B_GATE, 1, 0, 30, 30, 50, 0, 0); LVL(50); + NAM(M_JCM2000, 55, 50, 55, 50); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); blk(p, PX_B_DELAY, 1, PX_DLY_ANALOG, 39, 30, 20, 45, 0); blk(p, PX_B_REVERB, 1, PX_REV_HALL, 45, 45, 20, 0, 0); break; - case 13: setname(p, "SMOOTH LEAD"); blk(p, PX_B_GATE, 1, 0, 30, 30, 50, 0, 0); LVL(37); - blk(p, PX_B_AMP, 1, PX_AMP_MARK4, 55, 50, 55, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 50, 50, 50, 0, 0); + case 13: setname(p, "SMOOTH LEAD"); blk(p, PX_B_GATE, 1, 0, 30, 30, 50, 0, 0); LVL(41); + NAM(M_MARK4, 55, 50, 55, 50); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 50, 50, 50, 0, 0); blk(p, PX_B_DELAY, 1, PX_DLY_TAPE, 35, 30, 20, 45, 20); blk(p, PX_B_REVERB, 1, PX_REV_HALL, 45, 45, 18, 0, 0); break; - case 14: setname(p, "HAIR METAL"); blk(p, PX_B_GATE, 1, 0, 35, 30, 50, 0, 0); LVL(45); + case 14: setname(p, "HAIR METAL"); blk(p, PX_B_GATE, 1, 0, 35, 30, 50, 0, 0); LVL(50); blk(p, PX_B_DRIVE, 1, PX_DRV_M77, 25, 55, 60, 0, 0); - blk(p, PX_B_AMP, 1, PX_AMP_JCM2000, 60, 55, 45, 55, 55); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); + NAM(M_JVM, 50, 55, 45, 55); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); blk(p, PX_B_DELAY, 1, PX_DLY_DIGITAL, 33, 25, 15, 50, 0); blk(p, PX_B_REVERB, 1, PX_REV_PLATE, 40, 50, 18, 0, 0); break; - case 15: setname(p, "SPACE LEAD"); blk(p, PX_B_GATE, 1, 0, 30, 30, 50, 0, 0); LVL(42); - blk(p, PX_B_AMP, 1, PX_AMP_PROMOD, 50, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 50, 50, 50, 0, 0); + case 15: setname(p, "SPACE LEAD"); blk(p, PX_B_GATE, 1, 0, 30, 30, 50, 0, 0); LVL(48); + NAM(M_PROMOD, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 50, 50, 50, 0, 0); blk(p, PX_B_DELAY, 1, PX_DLY_DUAL, 29, 40, 25, 40, 0); blk(p, PX_B_REVERB, 1, PX_REV_SHIMMER, 55, 45, 30, 40, 0); break; /* ---- high gain ---- */ - case 16: setname(p, "MODERN ROCK"); blk(p, PX_B_GATE, 1, 0, 40, 30, 50, 0, 0); LVL(37); - blk(p, PX_B_AMP, 1, PX_AMP_PROMOD, 55, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 50, 50, 50, 0, 0); + case 16: setname(p, "MODERN ROCK"); blk(p, PX_B_GATE, 1, 0, 40, 30, 50, 0, 0); LVL(44); + NAM(M_PROMOD, 55, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 50, 50, 50, 0, 0); blk(p, PX_B_REVERB, 1, PX_REV_ROOM, 30, 50, 12, 0, 0); break; - case 17: setname(p, "5150 RHYTHM"); blk(p, PX_B_GATE, 1, 0, 45, 25, 50, 0, 0); LVL(41); + case 17: setname(p, "5150 RHYTHM"); blk(p, PX_B_GATE, 1, 0, 45, 25, 50, 0, 0); LVL(44); blk(p, PX_B_DRIVE, 1, PX_DRV_TS9, 0, 55, 75, 0, 0); - blk(p, PX_B_AMP, 1, PX_AMP_5150, 50, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 50, 50, 50, 0, 0); break; - case 18: setname(p, "TIGHT METAL"); blk(p, PX_B_GATE, 1, 0, 50, 20, 50, 0, 0); LVL(41); - blk(p, PX_B_DRIVE, 1, PX_DRV_TS9, 5, 60, 80, 0, 0); - blk(p, PX_B_AMP, 1, PX_AMP_5150, 60, 55, 40, 55, 55); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 50, 55, 50, 0, 0); break; - case 19: setname(p, "SWEDE DEATH"); blk(p, PX_B_GATE, 1, 0, 55, 25, 50, 0, 0); LVL(32); + NAM(M_5150, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 50, 50, 50, 0, 0); break; + case 18: setname(p, "TIGHT METAL"); blk(p, PX_B_GATE, 1, 0, 50, 20, 50, 0, 0); LVL(42); + NAM(M_6505, 50, 55, 45, 55); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 50, 55, 50, 0, 0); break; + case 19: setname(p, "SWEDE DEATH"); blk(p, PX_B_GATE, 1, 0, 55, 25, 50, 0, 0); LVL(62); blk(p, PX_B_DRIVE, 1, PX_DRV_HM2, 70, 80, 80, 50, 0); - blk(p, PX_B_AMP, 1, PX_AMP_JCM900, 40, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); break; - case 20: setname(p, "DOOM"); blk(p, PX_B_GATE, 1, 0, 40, 35, 50, 0, 0); LVL(27); - blk(p, PX_B_AMP, 1, PX_AMP_5150, 65, 65, 45, 45, 45); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 60, 40, 40, 0, 0); + NAM(M_JCM900, 40, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); break; + case 20: setname(p, "DOOM"); blk(p, PX_B_GATE, 1, 0, 40, 35, 50, 0, 0); LVL(26); + NAM(M_5150, 60, 62, 45, 45); blk(p, PX_B_CAB, 1, PX_CAB_412V30, 60, 40, 40, 0, 0); blk(p, PX_B_DELAY, 1, PX_DLY_ANALOG, 45, 20, 10, 40, 0); blk(p, PX_B_REVERB, 1, PX_REV_HALL, 40, 35, 15, 0, 0); break; /* ---- effects ---- */ - case 21: setname(p, "VIBE ROCK"); blk(p, PX_B_GATE, 1, 0, 18, 50, 50, 0, 0); LVL(37); + case 21: setname(p, "VIBE ROCK"); blk(p, PX_B_GATE, 1, 0, 18, 50, 50, 0, 0); LVL(51); blk(p, PX_B_MOD, 1, PX_MOD_UNIVIBE, 35, 55, 60, 0, 0); - blk(p, PX_B_AMP, 1, PX_AMP_JCM900, 55, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); + NAM(M_JCM900, 55, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_412GB, 50, 50, 50, 0, 0); blk(p, PX_B_REVERB, 1, PX_REV_ROOM, 40, 50, 18, 0, 0); break; - case 22: setname(p, "ORGAN"); NOGATE; LVL(49); + case 22: setname(p, "ORGAN"); NOGATE; LVL(75); blk(p, PX_B_SYN, 1, PX_SYN_ORGAN, 50, 70, 40, 30, 0); - blk(p, PX_B_AMP, 1, PX_AMP_TWIN, 45, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 50, 50, 0, 0); + NAM(M_TWIN, 45, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 50, 50, 0, 0); blk(p, PX_B_MOD, 1, PX_MOD_ROTARY, 30, 60, 50, 0, 0); blk(p, PX_B_REVERB, 1, PX_REV_ROOM, 40, 50, 18, 0, 0); break; - case 23: setname(p, "ACOUSTIC"); NOGATE; LVL(90); + case 23: setname(p, "ACOUSTIC"); NOGATE; LVL(66); blk(p, PX_B_SYN, 1, PX_SYN_ACOUSTIC, 55, 50, 55, 40, 0); blk(p, PX_B_COMP, 1, PX_CMP_STUDIO, 40, 40, 85, 60, 0); p->on[PX_B_AMP] = 0; p->on[PX_B_CAB] = 0; blk(p, PX_B_REVERB, 1, PX_REV_ROOM, 40, 55, 18, 0, 0); break; - /* ---- 25..52: USER, a clean amp to start from ---- */ + /* ---- 25..52: USER, a clean NAM amp to start from ---- */ default: { char n[14] = "USER "; n[5] = (char)('0' + (idx + 1) / 10); n[6] = (char)('0' + (idx + 1) % 10); n[7] = 0; setname(p, n); NOGATE; LVL(50); - blk(p, PX_B_AMP, 1, PX_AMP_TWIN, 45, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 50, 50, 0, 0); + NAM(M_TWIN, 50, 50, 50, 50); blk(p, PX_B_CAB, 1, PX_CAB_112JN, 50, 50, 50, 0, 0); blk(p, PX_B_REVERB, 1, PX_REV_ROOM, 35, 50, 15, 0, 0); } break; } } +#undef NAM #undef LVL #undef NOGATE @@ -800,7 +991,7 @@ static void rc_sfx(px_engine *e) static void rc_drive(px_engine *e) { const px_preset_t *p = &e->cur; - float sr = e->sr, osr = sr * PX_OVERSAMPLE; + float sr = e->sr, osr = sr * (float)(e->drv_os ? e->drv_os : PX_OVERSAMPLE); int t = p->type[PX_B_DRIVE] % PX_DRV_COUNT; const drv_v *d = &DV[t]; #ifdef PX_FIT @@ -881,11 +1072,145 @@ static void rc_drive(px_engine *e) e->drv_level = DRV_TRIM[t] * 2.0f * level * powf(10.0f, DRV_DB[t] * 0.05f); /* (v36 trim: before the amp) */ } +/* ---------------------------------------------------------------- NAM (v37) --- */ +#include "px_nam_factory.h" /* the factory models (tools/mk_nam_factory.py) */ +#if defined(__PI32V2__) && !defined(PX_NAM_POOL) /* the pedal: the big piece in its "POOL" RAM region */ +#define PX_NAM_POOL __attribute__((section(".pool"))) +#endif +#ifndef PX_NAM_POOL +#define PX_NAM_POOL +#endif +/* the rings, all in one piece (83.4 KB): on the pedal in the POOL region beside the engine, so that the ordinary RAM + * stays free (Bluetooth will need it) */ +#define PX_NAM_R0 ((PXN_RING_BYTES + 7u) / 8u * 2u) +static pxn_model px_nam_m; +static int32_t px_nam_r0[PX_NAM_R0] PX_NAM_POOL __attribute__((aligned(8))); +/* no user slots unless the firmware (firmware/px_models.h) or a simulator provides them */ +__attribute__((weak)) int px_nam_user(int slot, char *name12, float *level_db, float *w) +{ + (void)slot; (void)name12; (void)level_db; (void)w; + return 0; +} +int px_nam_model(int v) +{ + if (v < 0) v = 0; + if (v > 100) v = 100; + return v * PX_NAM_N / 101; +} +int px_nam_knob(int m) +{ + if (m < 0) m = 0; + if (m >= PX_NAM_N) m = PX_NAM_N - 1; + for (int v = 0; v <= 100; v++) /* the middle of the model's span of the knob */ + if (px_nam_model(v) == m) { int w = v; while (w < 100 && px_nam_model(w + 1) == m) w++; return (v + w) / 2; } + return 0; +} +int px_nam_name(int m, char *buf) +{ + int i = 0; + if (m >= 0 && m < PX_NAM_NFACT) { + const char *s = PXN_FNAME[m]; + while (s[i] && i < 11) { buf[i] = s[i]; i++; } + buf[i] = 0; + return 1; + } + float lv; + int u = m - PX_NAM_NFACT; + if (u >= 0 && u < PX_NAM_NUSER && px_nam_user(u, buf, &lv, 0)) { buf[11] = 0; return 1; } + buf[i++] = 'U'; + if (u + 1 >= 10) buf[i++] = (char)('0' + (u + 1) / 10); + buf[i++] = (char)('0' + (u + 1) % 10); + const char *e = " EMPTY"; + for (int j = 0; e[j]; j++) buf[i++] = e[j]; + buf[i] = 0; + return 0; +} +/* the NAM ring memory as scratch (the firmware's bench screen; the model's history is lost) */ +int32_t *px_nam_scratch(void) +{ + px_nam_m.ready = 0; + return px_nam_r0; +} +/* model m into the network: factory weights straight from flash, a user slot through the ring memory (free until + * pxn_load clears it). 0 = loaded. */ +static int nam_load(int m, float *level_db) +{ + const float *w = 0; + *level_db = 0.0f; + if (m >= 0 && m < PX_NAM_NFACT) { w = PXN_FW[m]; *level_db = PXN_FLVL[m]; } + else if (m >= PX_NAM_NFACT && m < PX_NAM_N) { + char nm[12]; + float *tmp = (float *)px_nam_r0; + if (px_nam_user(m - PX_NAM_NFACT, nm, level_db, tmp)) w = tmp; + } + if (!w) { px_nam_m.ready = 0; return -1; } + return pxn_load(&px_nam_m, w, px_nam_r0, sizeof px_nam_r0, 0, 0); +} +/* start-up: the hand-written NAM routines checked (in the ring memory), then, given a clock (ticks), the ways of running + * the network timed on the first factory model and the fastest kept (pxn_tune). The model is loaded again by the next + * engine set. */ +static uint32_t px_nam_tt[PXN_MODES]; +int px_nam_check(uint32_t (*ticks)(void)) +{ + typedef char room[sizeof px_nam_r0 >= PXN_TEST_WORDS * 4u ? 1 : -1]; + (void)sizeof(room); + const int ok = pxn_selftest(px_nam_r0); + px_fx_hand = px_fx_check(); + px_nam_m.ready = 0; + if (ticks) { + float lv; + if (!nam_load(0, &lv)) pxn_tune(&px_nam_m, ticks, px_nam_tt); + px_nam_m.ready = 0; + } + return ok; +} +uint32_t px_nam_tuned(int mode) { return mode >= 0 && mode < PXN_MODES ? px_nam_tt[mode] : 0; } +/* the network will run on two cores in this engine's next blocks: the caller must run px_engine_process on the core + * that hands jobs to the other one (pxn_set_helper) */ +int px_nam_dual(const px_engine *e) { return pxn_dual() && e->amp_nam && e->cur.on[PX_B_AMP] && px_nam_m.ready; } +void px_nam_helper(int (*run)(void (*fn)(uint32_t), uint32_t arg), int (*wait)(void)) { pxn_set_helper(run, wait); } +void px_nam_fast(void *base, unsigned bytes) { pxn_set_fast((int32_t *)base, bytes); } +/* every model is trimmed to -20 LUFS on the DI clip (its level trim); this puts NAM + the 1x12 at GAIN noon at the fitted + * amps' -23 LUFS (mean over the factory models, measured by tools/level_presets.py's DI) */ +#define PX_NAM_REF_DB (-6.0f) +static void rc_nam(px_engine *e) +{ + const px_preset_t *p = &e->cur; + const uint8_t *q = p->p[PX_B_AMP]; + float sr = e->sr, lv = 0.0f; + int m = px_nam_model(q[0]); + e->amp_n = 0; + e->amp_nam = 1; + if (m != e->nam_idx || !px_nam_m.ready) { + if (nam_load(m, &lv)) { e->nam_idx = -1; return; } + e->nam_idx = m; + e->nam_out_g = powf(10.0f, (lv + PX_NAM_REF_DB) * 0.05f); + } + /* the pedal's input (hard playing ~ -17 dBFS) -> the captures' DI level (x 1 / 0.15), then GAIN +-12 dB */ + e->nam_in_g = (1.0f / 0.15f) * powf(10.0f, (f01(q[1]) - 0.5f) * 24.0f * 0.05f); + bq_lowshelf(&e->ts_low, sr, 120.0f, (f01(q[2]) - 0.5f) * 20.0f); + bq_peak(&e->ts_mid, sr, 800.0f, 0.7f, (f01(q[3]) - 0.5f) * 16.0f); + bq_highshelf(&e->ts_high, sr, 2500.0f, (f01(q[4]) - 0.5f) * 20.0f); +} +/* the NAM block on n samples of e->nam_buf, in place */ +PX_HOT static void nam_run(px_engine *e, float *b, int n, float trim) +{ + const float gi = e->nam_in_g, go = e->nam_out_g * trim; + for (int k = 0; k < n; k++) b[k] *= gi; + pxn_process(&px_nam_m, b, b, n); + for (int k = 0; k < n; k++) b[k] *= go; + bq_block2(&e->ts_low, &e->ts_mid, b, n); + bq_block(&e->ts_high, b, n); +} + static void rc_amp(px_engine *e) { const px_preset_t *p = &e->cur; float sr = e->sr, osr = sr * PX_OVERSAMPLE; - int t = p->type[PX_B_AMP] % PX_AMP_COUNT; + int t = p->type[PX_B_AMP]; + if (t >= PX_AMP_NTYPES) t = 0; + e->amp_nam = 0; + if (t == PX_AMP_NAM) { rc_nam(e); return; } const amp_v *v = &AV[t]; #ifdef PX_FIT if (px_fit_on) v = &px_fit_amp; /* the fitter's candidate (tests/fit/fitlib.c) */ @@ -928,7 +1253,7 @@ static void rc_amp(px_engine *e) /* cabinet fine structure, one sample: sparse taps on a 64-sample ring + breakup resonators, h[k] = A dec^k sin(kw) * = b z^-1 / (1 - a1 z^-1 - a2 z^-2). The state is passed in so the level normalisation can run its own copy. */ -static inline float cab_detail(const px_engine *e, float x, float *rb, int *rw, float (*ms)[2]) +PX_INL static inline float cab_detail(const px_engine *e, float x, float *rb, int *rw, float (*ms)[2]) { int w = (*rw - 1) & 63; float y = 0.0f, xp; @@ -1435,6 +1760,12 @@ static void px_recalc(px_engine *e) bq_lowpass(&e->osb_up2, osr, sr * 0.47f, 1.31f); bq_lowpass(&e->osb_dn, osr, sr * 0.47f, 0.54f); bq_lowpass(&e->osb_dn2, osr, sr * 0.47f, 1.31f); + bq_lowpass(&e->osc_up, sr * 2.0f, sr * 0.47f, 0.54f); /* set C: x2, for a drive before a NAM amp */ + bq_lowpass(&e->osc_up2, sr * 2.0f, sr * 0.47f, 1.31f); + bq_lowpass(&e->osc_dn, sr * 2.0f, sr * 0.47f, 0.54f); + bq_lowpass(&e->osc_dn2, sr * 2.0f, sr * 0.47f, 1.31f); + /* v37: before a NAM amp the drive runs at x2 (the network does not alias; x4 cost 18% of the CPU) */ + e->drv_os = (e->cur.on[PX_B_AMP] && e->cur.type[PX_B_AMP] == PX_AMP_NAM) ? 2 : PX_OVERSAMPLE; rc_drive(e); rc_amp(e); rc_cab(e); @@ -1461,6 +1792,8 @@ void px_engine_init(px_engine *e, float sr) e->oct_ff = 1.0f; e->oct_ff2 = 1.0f; e->dly_type = -1; e->syn_type = -1; + e->nam_idx = -1; + px_nam_m.ready = 0; px_preset_t p; px_preset_factory(&p, 0); px_engine_set(e, &p); } @@ -1511,7 +1844,7 @@ static inline float drive_pre(px_engine *e, float x) /* base rate */ if (e->drv_pre & 1) x = x * e->drv_shelf_lo + bq_run(&e->drv_shelf, x); return x; } -static inline float drive_run(px_engine *e, float x) /* oversampled */ +PX_INL static inline float drive_run(px_engine *e, float x) /* oversampled */ { float d = clip_run(e, x * e->drv_gain) + e->dn; if (e->drv_dcb) { e->drv_dcs += (d - e->drv_dcs) * e->drv_dck; d -= e->drv_dcs; } @@ -1525,7 +1858,30 @@ static inline float drive_run(px_engine *e, float x) /* oversampled */ if (e->drv_np & 4) d = bq_run(&e->drv_t3, d); return d * e->drv_level + x * e->drv_blend; } -static inline float amp_stage(px_engine *e, int i, float x, int upd) +/* drive_run over n oversampled samples in place, stage by stage (the same operations as drive_run sample by sample); + * the anti-denormal offset follows the base-rate sample (os samples each) */ +static float px_os_t[PX_OVERSAMPLE * PX_MAX_BLOCK], px_os_h[PX_OVERSAMPLE * PX_MAX_BLOCK], px_os_u[PX_OVERSAMPLE * PX_MAX_BLOCK]; +static void drive_block(px_engine *e, float *u, int n, int os) /* (static buffers: off the interrupt's stack) */ +{ + float *t = px_os_t, *h = px_os_h; + for (int i = 0; i < n; i++) { + const float dn = ((i / os) & 1) ? 1e-15f : -1e-15f; + float d = clip_run(e, u[i] * e->drv_gain) + dn; + if (e->drv_dcb) { e->drv_dcs += (d - e->drv_dcs) * e->drv_dck; d -= e->drv_dcs; } + t[i] = d; + } + if (e->drv_tm == TM_MUFF) { + memcpy(h, t, (unsigned)n * sizeof(float)); + bq_block(&e->drv_t1, t, n); + bq_block(&e->drv_t2, h, n); + for (int i = 0; i < n; i++) t[i] = t[i] + (h[i] - t[i]) * e->drv_mix; + } else if (e->drv_np & 2) { + bq_block2(&e->drv_t1, &e->drv_t2, t, n); + } else bq_block(&e->drv_t1, t, n); + if (e->drv_np & 4) bq_block(&e->drv_t3, t, n); + for (int i = 0; i < n; i++) u[i] = t[i] * e->drv_level + u[i] * e->drv_blend; +} +PX_INL static inline float amp_stage(px_engine *e, int i, float x, int upd) { x = op_run(&e->amp_hp[i], x); float u = x * e->amp_g[i] + e->amp_bias[i] - e->amp_env[i]; @@ -1602,7 +1958,7 @@ static inline float rv_lin(const int16_t *m, int at, float k) /* fractional return a + ((float)m[(at + ki + 1) & RV_MASK] - a) * f; } /* pre-delay, early reflections, Dattorro's 4 input diffusers */ -static inline float rv_front(px_engine *e, int16_t *m, int p, const int *b, float rq, float in, float *er) +PX_INL static inline float rv_front(px_engine *e, int16_t *m, int p, const int *b, float rq, float in, float *er) { RV_WR(0, in); float r = 0.0f; @@ -1617,7 +1973,7 @@ static inline float rv_front(px_engine *e, int16_t *m, int p, const int *b, floa t = RV_RD(4, e->rv_n[4]); w = d - 0.625f * t; RV_WR(4, w); d = t + 0.625f * w; return d; } -static float rv_fdn(px_engine *e, float in) +PX_INL static inline float rv_fdn(px_engine *e, float in) { int16_t *m = e->rv_m; const int p = e->rv_ptr, *b = e->rv_b; const float rq = e->rv_rq; float er, d = rv_front(e, m, p, b, rq, in * RV_Q, &er), y[8]; @@ -1643,7 +1999,7 @@ static float rv_fdn(px_engine *e, float in) RV_WR(11, (b2 - b6) * h + d); RV_WR(12, (b3 - b7) * h - d); return (o + er) * (1.0f / RV_Q); } -static float rv_plate(px_engine *e, float in) +PX_INL static inline float rv_plate(px_engine *e, float in) { int16_t *m = e->rv_m; const int p = e->rv_ptr, *b = e->rv_b; const float rq = e->rv_rq; float er, d = rv_front(e, m, p, b, rq, in * RV_Q, &er); @@ -1687,7 +2043,7 @@ static inline float ps_voice(const float *buf, int w, float *ph, float inc, floa return rd_frac(buf, PX_PS_N - 1, pa) * g + rd_frac(buf, PX_PS_N - 1, pb) * (1.0f - g); } #define PS_OFFMAX 512 /* one period of low E */ -static float ps_align(const float *buf, int w, float d_ref, float d_new) +PX_HOT static float ps_align(const float *buf, int w, float d_ref, float d_new) { /* SOLA: offset that puts the fading-in tap in phase */ int r0 = w - (int)d_ref, best = 0; float bc = -1e30f; @@ -1708,7 +2064,7 @@ static float ps_align(const float *buf, int w, float d_ref, float d_new) } return (float)best; } -static inline float ps_voice_al(float *buf, int w, float *ph, float *off, float inc, float W) +PX_INL static inline float ps_voice_al(float *buf, int w, float *ph, float *off, float inc, float W) { float a0 = *ph, a = wrap1(a0 + inc); *ph = a; @@ -1764,7 +2120,7 @@ static inline float syn_keys(px_engine *e, float x) float g = 0.25f / (e->syn_slow + 0.004f); return x * (g > 12.0f ? 12.0f : g); } -static inline float syn_shift(px_engine *e, int v) +PX_INL static inline float syn_shift(px_engine *e, int v) { return ps_voice_al(e->syn_buf, e->syn_w, &e->syn_ph[v], e->syn_off[v], e->syn_inc[v], e->syn_W[v]); } @@ -1799,7 +2155,7 @@ static inline int syn_track(px_engine *e, float x) e->syn_prev = b; return trig; } -static float syn_run(px_engine *e, int t, float x) +PX_INL static inline float syn_run(px_engine *e, int t, float x) { float y = 0.0f; switch (t) { @@ -1972,7 +2328,10 @@ static float syn_run(px_engine *e, int t, float x) } } -void px_engine_process(px_engine *e, const float *in, float *out, int n) +/* part: PX_PART_ALL, or (with a NAM amp: px_nam_dual) one stage of the two-core pipeline: PRE the blocks before the + * amp (in -> out, the network's input), NAM the network and its tone stack (out in place), POST the blocks after it + * (in: the network's output -> out). PRE and POST touch different blocks: they may run at once on the two cores. */ +PX_HOT void px_engine_part(px_engine *e, const float *in, float *out, int n, int part) { const px_preset_t *p = &e->cur; const float osg = (float)PX_OVERSAMPLE, sr = e->sr; @@ -2004,12 +2363,89 @@ void px_engine_process(px_engine *e, const float *in, float *out, int n) /* supply sag: slow (~11 ms), its two divisions once a block (divisions are slow on the pedal's FPU) */ const float sag_pa = 1.0f / (1.0f + e->amp_sag * e->amp_sagk), sag_pre = 1.0f / (1.0f + e->amp_sag * e->amp_sagk * 0.3f); + /* v37: a NAM amp works on whole blocks: the blocks before it run first over the n samples (pass 0), the network + * on them, then the blocks after it (pass 1). Without NAM: one pass, sample by sample, as before. */ + const int nam = amp_on && e->amp_nam && px_nam_m.ready && ip_amp >= 0 && n <= PX_MAX_BLOCK; + if (part != PX_PART_ALL && !nam) { /* (the caller checks px_nam_dual: not reached) */ + if (out != in) for (int k = 0; k < n; k++) out[k] = part == PX_PART_PRE ? in[k] : 0.0f; + return; + } + if (part == PX_PART_NAM) { nam_run(e, out, n, tr[ip_amp]); return; } + int s_lo = 0, s_hi = nam ? ip_amp : ns; + const int p0 = part == PX_PART_POST, p1 = part == PX_PART_PRE ? 1 : nam ? 2 : 1; + for (int pass = p0; pass < p1; pass++) { + if (pass == 1) { + if (part == PX_PART_ALL) nam_run(e, e->nam_buf, n, tr[ip_amp]); + s_lo = ip_amp + 1; + s_hi = ns; + } + /* v37: block by block over the n samples (each block's state stays in registers through its loop; the order of + * each sample's operations is unchanged, so the output is the same as sample by sample) */ + float xb[PX_MAX_BLOCK]; for (int k = 0; k < n; k++) { e->dn = (k & 1) ? 1e-15f : -1e-15f; /* anti-denormal (-300 dB): digital silence never decays */ - float x = in[k] + e->dn; - { float y = x - e->dc_x1 + 0.9995f * e->dc_y1; e->dc_x1 = x; e->dc_y1 = y; x = y; } - - for (int s = 0; s < ns; s++) { switch (st[s]) { + float x; + if (pass == 0) { + x = in[k] + e->dn; + { float y = x - e->dc_x1 + 0.9995f * e->dc_y1; e->dc_x1 = x; e->dc_y1 = y; x = y; } + } else x = part == PX_PART_POST ? in[k] : e->nam_buf[k]; + xb[k] = x; + } + for (int s = s_lo; s < s_hi; s++) { + const int sblk = st[s]; + const float strim = tr[s]; + if (sblk == PX_B_CAB) { /* cabinet: its filters one after the other over the block */ + if (p->on[PX_B_CAB] && e->cab_n) { + if (px_fx_int) fq_chain(e->cab, (px_fq *)e->fq_cab, e->cab_n, xb, n); + else bq_chain(e->cab, e->cab_n, xb, n); + for (int k = 0; k < n; k++) { + float x = xb[k]; + if (e->cab_firon) x = cab_detail(e, x, e->cab_rb, &e->cab_rw, e->cab_ms); + xb[k] = x * e->cab_g * strim; + } + } else for (int k = 0; k < n; k++) xb[k] *= strim; + continue; + } + if (sblk == PX_B_DRIVE && (!pair || !amp_os)) { /* drive without the fitted amp's stages, oversampled: stage by + stage over the block (set A or B as the sample path picks; set + C at x2 before a NAM amp) */ + if (drv_on) { + const int os = e->drv_os == 2 ? 2 : PX_OVERSAMPLE, no = os * n; + const int set = os == 2 ? 2 : (pair || !amp_os) ? 0 : 1; + px_bq *fu = os == 2 ? &e->osc_up : dua, *fu2 = os == 2 ? &e->osc_up2 : dub; + px_bq *fd = os == 2 ? &e->osc_dn : dda, *fd2 = os == 2 ? &e->osc_dn2 : ddb; + float *ub = px_os_u; + const float g = (float)os; + for (int k = 0; k < n; k++) { + e->dn = (k & 1) ? 1e-15f : -1e-15f; + const float x = drive_pre(e, xb[k]); + ub[os * k] = x * g; + for (int o = 1; o < os; o++) ub[os * k + o] = 0.0f; + } + px_fq *fs = (px_fq *)e->fq_os[set]; + if (px_fx_int && fq_ok(fu) && fq_ok(fu2) && fq_ok(fd) && fq_ok(fd2)) { + fq_to(px_fqbuf, ub, no); + fq_block(fu, &fs[0], px_fqbuf, no); + fq_block(fu2, &fs[1], px_fqbuf, no); + fq_from(ub, px_fqbuf, no); + drive_block(e, ub, no, os); + fq_to(px_fqbuf, ub, no); + fq_block(fd, &fs[2], px_fqbuf, no); + fq_block(fd2, &fs[3], px_fqbuf, no); + fq_from(ub, px_fqbuf, no); + } else { + bq_block2(fu, fu2, ub, no); + drive_block(e, ub, no, os); + bq_block2(fd, fd2, ub, no); + } + for (int k = 0; k < n; k++) xb[k] = ub[os * k + os - 1] * strim; + } else for (int k = 0; k < n; k++) xb[k] *= strim; + continue; + } + for (int k = 0; k < n; k++) { + e->dn = (k & 1) ? 1e-15f : -1e-15f; + float x = xb[k]; + switch (sblk) { case PX_B_GATE: /* ---- gate ---- */ if (p->on[PX_B_GATE]) { @@ -2189,7 +2625,7 @@ void px_engine_process(px_engine *e, const float *in, float *out, int n) } x = acc; } - if (amp_on) { + if (amp_on && !e->amp_nam) { /* (NAM without its model: passes through) */ if (!amp_os) x = bq_run(&e->amp_tight, x); x = bq_run(&e->ts_low, x); x = bq_run(&e->ts_mid, x); @@ -2384,8 +2820,17 @@ void px_engine_process(px_engine *e, const float *in, float *out, int n) } break; default: break; - } x *= tr[s]; } - + } + xb[k] = x * strim; + } + } + if (nam && pass == 0) { + float *d = part == PX_PART_PRE ? out : e->nam_buf; + for (int k = 0; k < n; k++) d[k] = xb[k]; + continue; + } + for (int k = 0; k < n; k++) { + float x = xb[k]; { float y = x - e->odc_x1 + 0.9990f * e->odc_y1; e->odc_x1 = x; e->odc_y1 = y; x = y; } x *= pg; { /* v36: soft limiter instead of a hard clip: transparent up to 0.8, then rounds off smoothly to 1.2 */ @@ -2394,4 +2839,6 @@ void px_engine_process(px_engine *e, const float *in, float *out, int n) } out[k] = x; } + } } +void px_engine_process(px_engine *e, const float *in, float *out, int n) { px_engine_part(e, in, out, n, PX_PART_ALL); } diff --git a/engine/px_dsp.h b/engine/px_dsp.h index ea5c4c1..5a7730c 100644 --- a/engine/px_dsp.h +++ b/engine/px_dsp.h @@ -42,6 +42,14 @@ enum { PX_SFX_AUTOWAH, PX_SFX_LFOWAH, PX_SFX_RING, PX_SFX_CRUSH, PX_SFX_SLICER, enum { PX_DRV_TS9, PX_DRV_KLON, PX_DRV_M77, PX_DRV_HM2, PX_DRV_COUNT }; enum { PX_AMP_TWIN, PX_AMP_AC15, PX_AMP_JCM900, PX_AMP_JCM2000, PX_AMP_MARK4, PX_AMP_SHIRLEY, PX_AMP_PROMOD, PX_AMP_5150, PX_AMP_COUNT }; +/* v37: Neural Amp Modeler A2-Lite (px_nam.c) as one more AMP type, after the 8 fitted amps. Its 5 settings: MODEL, + * GAIN (into the model, +-12 dB), BASS, MID, TREBLE (after it). Models: PX_NAM_NFACT in the firmware, PX_NAM_NUSER + * slots the web editor fills with A2 captures (.nam files, e.g. from TONE3000). */ +#define PX_AMP_NAM PX_AMP_COUNT +#define PX_AMP_NTYPES (PX_AMP_COUNT + 1) +#define PX_NAM_NFACT 12 +#define PX_NAM_NUSER 16 +#define PX_NAM_N (PX_NAM_NFACT + PX_NAM_NUSER) enum { PX_CAB_112JN, PX_CAB_212BLUE, PX_CAB_412GB, PX_CAB_412T75, PX_CAB_412V30, PX_CAB_112CREAM, PX_CAB_DI, PX_CAB_COUNT }; enum { PX_SYN_ORGAN, PX_SYN_CHURCH, PX_SYN_STRINGS, PX_SYN_CHOIR, PX_SYN_MONO, PX_SYN_PWM, PX_SYN_BASS, @@ -79,6 +87,19 @@ int px_type_v34(int blk, int old); /* presets saved before v34: old ty int px_dly_time_v35(int type, int v); /* presets saved before v35: delay TIME (20..1000 ms) -> today's knob */ int px_param_text(int blk, int type, int k, int v, char *buf8); int px_preset_count(void); +/* NAM models: the MODEL knob (0..100) <-> model 0..PX_NAM_N-1 (factory first, then the user slots) */ +int px_nam_model(int v); +int px_nam_knob(int model); +int32_t *px_nam_scratch(void); /* bench: the NAM ring memory as scratch (PXN_TEST_WORDS+) */ +int px_nam_check(uint32_t (*ticks)(void)); /* start-up: NAM routines checked, then (ticks given) its + fastest way to run chosen (1 = hand routines in use) */ +uint32_t px_nam_tuned(int mode); /* that timing: ticks for 256 frames, by mode (0 = n/a) */ +void px_nam_helper(int (*run)(void (*fn)(uint32_t), uint32_t arg), int (*wait)(void)); /* the other core */ +void px_nam_fast(void *base, unsigned bytes); /* memory away from the CPUs' RAM, for the vector unit (before px_nam_check) */ +int px_nam_name(int model, char *buf12); /* 1 = the model exists ("U5 EMPTY" otherwise) */ +/* the user slots, provided by the firmware (flash; px_dsp.c has a weak, empty stand-in): + * 1 = slot holds a model; its name (11 chars max), its level trim (dB); w (1871 floats) only if w != 0 */ +int px_nam_user(int slot, char *name12, float *level_db, float *w); void px_preset_factory(px_preset_t *p, int idx); /* ---------------------------------------------------------------- state --- */ @@ -115,6 +136,9 @@ typedef struct { /* oversampling (set A: amp, or drive + amp together; set B: a drive that is not right before the amp) */ px_bq os_up, os_up2, os_dn, os_dn2; px_bq osb_up, osb_up2, osb_dn, osb_dn2; + px_bq osc_up, osc_up2, osc_dn, osc_dn2; /* v37: set C, x2 (a drive before a NAM amp) */ + int drv_os; /* the drive's oversampling: PX_OVERSAMPLE, or 2 before a NAM amp */ + struct { int32_t x1, x2, y1, y2; } fq_cab[8], fq_os[3][4]; /* v37: the integer filters' state (px_fx_int) */ uint8_t ord[PX_NBLK]; /* synth / instrument block (v29) */ float syn_buf[PX_PS_N]; int syn_w; /* shifter source (organ, strings...); sitar: string combs */ @@ -144,6 +168,10 @@ typedef struct { px_op amp_hp[4], amp_lp[4]; px_bq ts_low, ts_mid, ts_high, amp_pres, amp_res, amp_voice; float amp_sag, amp_sagk, amp_pw, amp_pwn, amp_out; + /* NAM (v37): one model at a time (its network and history: px_dsp.c, outside this struct) */ + int amp_nam, nam_idx; /* AMP type is NAM; the model loaded (-1: none) */ + float nam_in_g, nam_out_g; + float nam_buf[PX_MAX_BLOCK]; /* cabinet */ px_bq cab[8]; float cab_g; int cab_n; /* fine structure (v27: same response as v25's 128-tap FIR, ~4x cheaper): sparse taps + breakup resonators */ @@ -183,10 +211,15 @@ typedef struct { float sh_buf[PX_PS_N]; int sh_w; float sh_ph, sh_out, sh_lp, sh_k, rv_shim, sh_hp, sh_hk; px_bq rv_tone, rv_hp; } px_engine; +int px_nam_dual(const px_engine *e); /* 1 = its NAM runs on two cores: process it on the job-giving core */ void px_engine_init(px_engine *e, float sr); void px_engine_set(px_engine *e, const px_preset_t *p); void px_engine_process(px_engine *e, const float *in, float *out, int n); +enum { PX_PART_ALL, PX_PART_PRE, PX_PART_NAM, PX_PART_POST }; /* v37: px_engine_part's stages (see px_dsp.c) */ +void px_engine_part(px_engine *e, const float *in, float *out, int n, int part); +extern int px_fx_int; /* v37: 1 = the cabinet and drive filters in integer arithmetic (off: slower) */ +extern int px_fx_hand; /* v37: their loop by hand (checked at start-up) */ #ifdef __cplusplus } diff --git a/engine/px_nam.c b/engine/px_nam.c new file mode 100644 index 0000000..0ccb816 --- /dev/null +++ b/engine/px_nam.c @@ -0,0 +1,3848 @@ +/* SPDX-License-Identifier: GPL-3.0-only + * OpenPocket — NAM A2-Lite in fixed point (see px_nam.h). Written from the published A2 architecture; checked + * against tools/nam_a2.py (tests/test_nam.py). + * + * How it is computed, for this CPU (no data cache in front of the SRAM, a taken branch costs about 8 cycles, two + * instructions can issue together): a block of up to PXN_N frames goes through the network layer by layer. + * - gather: each frame's inputs to the layer are copied into one row of X: [u, 1.0, then for each kernel tap its 3 + * channels], from the layer's history ring (interleaved [time][channel], 3 words moved by one instruction); + * - dot: each output channel is a dot product of its weight row with the X rows, 4 frames at a time (a weight is read + * once for 4 frames), in the CPU's hardware loop, multiply-adds paired with loads: the 3 conv outputs, then the + * head the same way; + * - post: LeakyReLU, the head sum, the residual 1x1 into the next layer's ring. + * The three inner routines exist twice: by hand for the pedal (pi32v2 assembly), and in C (the reference, used on the + * PC and on the pedal if the start-up check finds the hand ones differ by a single bit). */ +#include "px_nam.h" +#include + +static const uint8_t pxn_k[PXN_NL] = {6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 15, 15, 6, 6, 6, 6, 6, 6, 6}; +static const uint16_t pxn_d[PXN_NL] = {1, 3, 7, 17, 41, 101, 239, 1, 3, 7, 17, 41, 101, 239, 1, 13, + 1, 3, 7, 17, 41, 101, 239}; +#define PXN_ONE (1 << PXN_QA) + +/* the block's work buffers: X rows (+ a row of slack: the dot routines read one word past a row) */ +static int32_t pxn_xs[(PXN_N + 1) * PXN_S]; +static int32_t *pxn_x = pxn_xs; /* the X rows in use: pxn_xs, or for the vector unit's modes + the copy in the fast memory (pxn_set_fast) */ +static int32_t *pxn_xf, *pxn_wf; /* fast memory: X rows, then the weights (wa, head) for the unit */ +static int32_t *pxn_fast; /* offered (pxn_set_fast), checked by pxn_selftest */ +#define PXN_WF_HEAD 1550 /* the head row in pxn_wf */ +#define PXN_FAST_WORDS ((PXN_N + 1) * PXN_S + PXN_WF_HEAD + PXN_S + 4) +static uint8_t pxn_rd = 1; /* the CPU's layers by rdot (1) or gathered X rows (0): timed */ +static uint32_t pxn_rdt[4]; /* that timing (mode 0): [0] gathered, [1] rdot, [2] rdq, [3] rdl */ +static uint8_t pxn_rdq_on = 1; /* rdot's load-ahead versions (rdq) where checked: timed */ +static uint8_t pxn_rdl_on = 1; /* rdl: a layer's groups in one call, where checked: timed */ +uint32_t pxn_rdot_ticks(int rd) { return rd >= 0 && rd < 4 ? pxn_rdt[rd] : 0; } +/* v37 diagnostic 18: where the CPU's time goes (mode 0, timed by pxn_tune): [0] input, [1] layers' 4-frame groups (tap + * tables + kernel), [2] layers' 1..3-frame rests (gathered), [3] post, [4] rings + head copy + output, [5] whole block, + * [6] head groups, [7] head rest, [8] [1] again with the kernel skipped (the tap tables alone) */ +static uint32_t (*pxn_pt)(void); +static uint32_t pxn_prof[9]; +static uint8_t pxn_pskip, pxn_pd = 1; +static uint8_t pxn_p3ok, pxn_pc = 4; /* post3 checked; frames per post call (4 with the vector unit) */ +static uint32_t pxn_ptt[2]; /* mode 0 timed with post2 and post3 */ +uint32_t pxn_post_ticks(int v) { return v >= 0 && v < 2 ? pxn_ptt[v] : 0; } +int pxn_post3_state(void) { return pxn_p3ok ? 1 + (pxn_ptt[1] && pxn_ptt[1] < pxn_ptt[0]) : 0; } +#define PXN_T() (pxn_pt ? pxn_pt() : 0u) +uint32_t pxn_prof_ticks(int k) { return k >= 0 && k < 9 ? pxn_prof[k] : 0; } +static int32_t pxn_z[PXN_N * PXN_C + 4], pxn_hs[PXN_N * PXN_C]; +static int32_t pxn_u[PXN_N + 4]; /* the block's input (Q20), for rdot */ +static const int32_t *pxn_tpt[2][PXN_HK]; /* rdot's tap tables, one per core */ + +/* dot: z[3f] = (w . x_f) >> 24 for ng frames (dot4: ng groups of 4 frames), x_f the X rows sb bytes apart. + * The hand routines read w[T] and x_f[T] (one word past): the buffers have slack. Offsets read by the hand code. */ +typedef struct { + const int32_t *w; /* 0 */ + const int32_t *x; /* 4 */ + int32_t t; /* 8: row length */ + int32_t sb; /* 12: X row stride, bytes */ + int32_t *z; /* 16: output, 3 words a frame */ + int32_t ng; /* 20: groups (> 0) */ +} pxn_dot; +/* post, for n frames (> 0): a = LeakyReLU(z); hs += a; if out: out[3f+o] = x_f[o] + ((rr_o . a) >> 24) + rr_o[3], + * x_f the layer's input in the X row (sb bytes apart) */ +typedef struct { + const int32_t *z; /* 0 */ + const int32_t *x; /* 4 */ + int32_t sb; /* 8 */ + const int32_t *rr; /* 12: 3 x {w0, w1, w2, bias (Q20)} */ + int32_t *hs; /* 16 */ + int32_t *out; /* 20: 0 = none (the last layer) */ + int32_t n; /* 24 */ + const int32_t *rr2; /* 28: the same residual for pxn_post2_asm: w[o][c] by c then o, then 3 biases */ +} pxn_post; + +/* rdot (v37): a layer's rows for 4 frames straight from its history ring, no gather: for each kernel tap k, tp[k] + * points at the 3 channels of the first frame, the next frames following (12 bytes apart). The row is [mixin, bias, + * taps x channels] as for the X rows, against [u, 1.0, taps]: the same sums, so the same result. rows: 3 (a layer, its + * rows contiguous) or 1 (the head). Offsets read by the hand code. */ +typedef struct { + const int32_t *w; /* 0 */ + const int32_t *const *tp; /* 4: K pointers */ + int32_t k; /* 8: taps */ + const int32_t *u; /* 12: the 4 frames' u */ + int32_t *z; /* 16: out, z[3f + o] */ + int32_t rows; /* 20 */ + int32_t ng; /* 24: rdl: groups of 4 frames */ + const int32_t *end; /* 28: rdl: the ring's end (its mirrored frames follow) */ + int32_t nlen; /* 32: rdl: minus the ring's length in bytes */ +} pxn_rdot; + +/* ---- the C versions (the reference) ---- */ +static void pxn_dot4_c(const pxn_dot *j) +{ + const int32_t *x = j->x; + int32_t *z = j->z; + const int s = j->sb / 4; + for (int g = 0; g < j->ng; g++, x += 4 * s, z += 12) { + int64_t a0 = 0, a1 = 0, a2 = 0, a3 = 0; + for (int t = 0; t < j->t; t++) { + const int64_t w = j->w[t]; + a0 += w * x[t]; a1 += w * x[s + t]; a2 += w * x[2 * s + t]; a3 += w * x[3 * s + t]; + } + z[0] = (int32_t)(a0 >> PXN_QW); z[3] = (int32_t)(a1 >> PXN_QW); + z[6] = (int32_t)(a2 >> PXN_QW); z[9] = (int32_t)(a3 >> PXN_QW); + } +} +/* the 3 rows of a layer (contiguous, t each) for groups of 4 frames: z[3f + o] */ +static void pxn_dot3x4_c(const pxn_dot *j) +{ + for (int o = 0; o < PXN_C; o++) { + pxn_dot d = *j; + d.w = j->w + o * j->t; + d.z = j->z + o; + pxn_dot4_c(&d); + } +} +static void pxn_dot1_c(const pxn_dot *j) +{ + const int32_t *x = j->x; + const int s = j->sb / 4; + for (int g = 0; g < j->ng; g++, x += s) { + int64_t a = 0; + for (int t = 0; t < j->t; t++) a += (int64_t)j->w[t] * x[t]; + j->z[3 * g] = (int32_t)(a >> PXN_QW); + } +} +static void pxn_rdot_c(const pxn_rdot *j) +{ + const int T = 3 * j->k + 2; + for (int o = 0; o < j->rows; o++) { + const int32_t *w = j->w + o * T; + int64_t a[4]; + for (int f = 0; f < 4; f++) a[f] = (int64_t)w[0] * j->u[f] + (int64_t)w[1] * PXN_ONE; + for (int k = 0; k < j->k; k++) + for (int c = 0; c < PXN_C; c++) + for (int f = 0; f < 4; f++) a[f] += (int64_t)w[2 + 3 * k + c] * j->tp[k][3 * f + c]; + for (int f = 0; f < 4; f++) j->z[3 * f + o] = (int32_t)(a[f] >> PXN_QW); + } +} +/* rdl: ng groups of rdot, the job's u and z moved on, each tap's pointer 4 frames on (back by the ring past its end) */ +static void pxn_rdl_c(pxn_rdot *j) +{ + const int32_t *tp[PXN_HK]; + for (int k = 0; k < j->k; k++) tp[k] = j->tp[k]; + pxn_rdot q = *j; + q.tp = tp; + for (int g = 0; g < j->ng; g++) { + pxn_rdot_c(&q); + q.u += 4; q.z += 12; + for (int k = 0; k < j->k; k++) { + const int32_t *p = tp[k] + 12; + if (p >= j->end) p = (const int32_t *)((const char *)p + j->nlen); + tp[k] = p; + } + } + j->u = q.u; j->z = q.z; +} +static inline __attribute__((always_inline)) int32_t pxn_lrelu(int32_t z) /* LeakyReLU 0.01 on a Q20 value */ +{ + return z < 0 ? (int32_t)(((int64_t)z * 42949673) >> 32) : z; +} +static void pxn_post_c(const pxn_post *j) +{ + const int32_t *z = j->z, *x = j->x; + int32_t *hs = j->hs, *out = j->out; + for (int f = 0; f < j->n; f++, z += 3, hs += 3, x += j->sb / 4) { + const int32_t a0 = pxn_lrelu(z[0]), a1 = pxn_lrelu(z[1]), a2 = pxn_lrelu(z[2]); + hs[0] += a0; hs[1] += a1; hs[2] += a2; + if (!out) continue; + const int32_t *r = j->rr; + for (int o = 0; o < PXN_C; o++, r += 4) { + const int64_t v = (int64_t)r[0] * a0 + (int64_t)r[1] * a1 + (int64_t)r[2] * a2; + *out++ = x[o] + (int32_t)(v >> PXN_QW) + r[3]; + } + } +} +/* gather: n frames of 3 words, src contiguous -> dst rows sb bytes apart */ +static void pxn_gcopy_c(int32_t *dst, const int32_t *src, int n, int sb) +{ + for (int f = 0; f < n; f++, src += 3, dst += sb / 4) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; } +} + +/* the residual reordered for post2: w[o][c] by c then o, then the 3 biases */ +static void pxn_rr2(const int32_t *rr, int32_t *r2) +{ + for (int c = 0; c < PXN_C; c++) + for (int o = 0; o < PXN_C; o++) r2[3 * c + o] = rr[4 * o + c]; + for (int o = 0; o < PXN_C; o++) r2[9 + o] = rr[4 * o + 3]; +} + +#if defined(__PI32V2__) && !defined(PXN_NO_ASM) +#define PXN_ASM 1 +/* ---- the same, by hand (in the flash, with their callers: no call-range question) ---- */ +void pxn_dot3x4_asm(const pxn_dot *j); +void pxn_dot1_asm(const pxn_dot *j); +void pxn_post_asm(const pxn_post *j); +void pxn_post2_asm(const pxn_post *j); +void pxn_post3_asm(const pxn_post *j); +void pxn_rdot_asm(const pxn_rdot *j); +void pxn_rdot6_asm(const pxn_rdot *j); +void pxn_rdq6_asm(const pxn_rdot *j), pxn_rdq15_asm(const pxn_rdot *j), pxn_rdq16_asm(const pxn_rdot *j); +void pxn_rdl6_asm(pxn_rdot *j), pxn_rdl15_asm(pxn_rdot *j), pxn_rdl16_asm(pxn_rdot *j); +void pxn_gcopy_asm(int32_t *dst, const int32_t *src, int n, int sb); +__asm__( + "\t.text\n" + /* dot3x4: the 3 rows (contiguous) for 4 frames at a time. Locals: [sp+0] x, [sp+4] z, [sp+8] groups left, + * [sp+12] job; r0 runs through the weights (back to the row start each group) */ + "\t.global pxn_dot3x4_asm\n" + "pxn_dot3x4_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -16\n" + "\tr1 = [r0+4]\n\t[sp+0] = r1\n" + "\tr1 = [r0+16]\n\t[sp+4] = r1\n" + "\tr1 = [r0+20]\n\t[sp+8] = r1\n" + "\t[sp+12] = r0\n" + ".Lpxn_d4g:\n" + "\tr0 = [sp+12]\n\tr0 = [r0+0]\n" + "\tr5 = [sp+12]\n" + "\tr12 = [r5+12]\n" + "\tr7 = [r5+8]\n" + "\tr1 = [sp+0]\n" + "\tr2 = r1 + r12\n" + "\tr3 = r2 + r12\n" + "\tr4 = r3 + r12\n" + "\tr9_r8 = 0\n" + "\tr11_r10 = 0\n" + "\tr13_r12 = 0\n" + "\tr15_r14 = 0\n" + "\tr5 = [r0++=4]\n" + "\tr6 = [r1++=4]\n" + ".Lpxn_d4r0:\n" + "\trep r7 {\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r2++=4]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r3++=4]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r4++=4]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1++=4]\n" + "\t}\n" + "\tif (r7 != 0) goto .Lpxn_d4r0\n" + "\tr9_r8 >>= 24\n" + "\tr11_r10 >>= 24\n" + "\tr13_r12 >>= 24\n" + "\tr15_r14 >>= 24\n" + "\tr1 = [sp+4]\n" + "\t[r1+0] = r8\n" + "\t[r1+12] = r10\n" + "\t[r1+24] = r12\n" + "\t[r1+36] = r14\n" + "\tr0 += -4\n" + "\tr5 = [sp+12]\n" + "\tr12 = [r5+12]\n" + "\tr7 = [r5+8]\n" + "\tr1 = [sp+0]\n" + "\tr2 = r1 + r12\n" + "\tr3 = r2 + r12\n" + "\tr4 = r3 + r12\n" + "\tr9_r8 = 0\n" + "\tr11_r10 = 0\n" + "\tr13_r12 = 0\n" + "\tr15_r14 = 0\n" + "\tr5 = [r0++=4]\n" + "\tr6 = [r1++=4]\n" + ".Lpxn_d4r1:\n" + "\trep r7 {\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r2++=4]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r3++=4]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r4++=4]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1++=4]\n" + "\t}\n" + "\tif (r7 != 0) goto .Lpxn_d4r1\n" + "\tr9_r8 >>= 24\n" + "\tr11_r10 >>= 24\n" + "\tr13_r12 >>= 24\n" + "\tr15_r14 >>= 24\n" + "\tr1 = [sp+4]\n" + "\t[r1+4] = r8\n" + "\t[r1+16] = r10\n" + "\t[r1+28] = r12\n" + "\t[r1+40] = r14\n" + "\tr0 += -4\n" + "\tr5 = [sp+12]\n" + "\tr12 = [r5+12]\n" + "\tr7 = [r5+8]\n" + "\tr1 = [sp+0]\n" + "\tr2 = r1 + r12\n" + "\tr3 = r2 + r12\n" + "\tr4 = r3 + r12\n" + "\tr9_r8 = 0\n" + "\tr11_r10 = 0\n" + "\tr13_r12 = 0\n" + "\tr15_r14 = 0\n" + "\tr5 = [r0++=4]\n" + "\tr6 = [r1++=4]\n" + ".Lpxn_d4r2:\n" + "\trep r7 {\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r2++=4]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r3++=4]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r4++=4]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1++=4]\n" + "\t}\n" + "\tif (r7 != 0) goto .Lpxn_d4r2\n" + "\tr9_r8 >>= 24\n" + "\tr11_r10 >>= 24\n" + "\tr13_r12 >>= 24\n" + "\tr15_r14 >>= 24\n" + "\tr1 = [sp+4]\n" + "\t[r1+8] = r8\n" + "\t[r1+20] = r10\n" + "\t[r1+32] = r12\n" + "\t[r1+44] = r14\n" + "\tr0 += -4\n" + "\tr1 = [sp+4]\n\tr1 += 48\n\t[sp+4] = r1\n" + "\tr0 = [sp+12]\n\tr12 = [r0+12]\n\tr12 = r12 << 2\n" + "\tr1 = [sp+0]\n\tr1 += r12\n\t[sp+0] = r1\n" + "\tr1 = [sp+8]\n\tr1 += -1\n\t[sp+8] = r1\n" + "\tif (r1 != 0) goto .Lpxn_d4g\n" + "\tsp += 16\n" + "\t{pc, r15-r4} = [sp++]\n" + /* dot1 */ + "\t.global pxn_dot1_asm\n" + "pxn_dot1_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -16\n" + "\tr1 = [r0+4]\n\t[sp+0] = r1\n" + "\tr1 = [r0+16]\n\t[sp+4] = r1\n" + "\tr1 = [r0+20]\n\t[sp+8] = r1\n" + "\t[sp+12] = r0\n" + ".Lpxn_d1g:\n" + "\tr0 = [sp+12]\n" + "\tr7 = [r0+8]\n" + "\tr1 = [sp+0]\n" + "\tr0 = [r0+0]\n" + "\tr9_r8 = 0\n" + "\tr5 = [r0++=4]\n" + "\tr6 = [r1++=4]\n" + ".Lpxn_d1r:\n" + "\trep r7 {\n" + "\tr9_r8 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1++=4]\n" + "\t}\n" + "\tif (r7 != 0) goto .Lpxn_d1r\n" + "\tr9_r8 >>= 24\n" + "\tr1 = [sp+4]\n\t[r1+0] = r8\n\tr1 += 12\n\t[sp+4] = r1\n" + "\tr0 = [sp+12]\n\tr12 = [r0+12]\n" + "\tr1 = [sp+0]\n\tr1 += r12\n\t[sp+0] = r1\n" + "\tr1 = [sp+8]\n\tr1 += -1\n\t[sp+8] = r1\n" + "\tif (r1 != 0) goto .Lpxn_d1g\n" + "\tsp += 16\n" + "\t{pc, r15-r4} = [sp++]\n" + /* post: r1 z, r2 x, r3 hs, r7 out, r11 rr, r12 the LeakyReLU slope, r13 frames left */ + "\t.global pxn_post_asm\n" + "pxn_post_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tr1 = [r0+0]\n\tr2 = [r0+4]\n\tr11 = [r0+12]\n\tr3 = [r0+16]\n\tr7 = [r0+20]\n\tr13 = [r0+24]\n" + "\tr12 = 42949673\n" + ".Lpxn_pf:\n" + "\tr4 = [r1++=4]\n\tr5 = [r1++=4]\n\tr6 = [r1++=4]\n" + "\tifs (r4 < 0) {\n\tr15_r14 = r4 * r12 (s)\n\tr4 = r15\n\t}\n" + "\tifs (r5 < 0) {\n\tr15_r14 = r5 * r12 (s)\n\tr5 = r15\n\t}\n" + "\tifs (r6 < 0) {\n\tr15_r14 = r6 * r12 (s)\n\tr6 = r15\n\t}\n" + "\tr14 = [r3+0]\n\tr14 += r4\n\t[r3++=4] = r14\n" + "\tr14 = [r3+0]\n\tr14 += r5\n\t[r3++=4] = r14\n" + "\tr14 = [r3+0]\n\tr14 += r6\n\t[r3++=4] = r14\n" + "\tif (r7 == 0) goto .Lpxn_pn\n" + "\tr10 = r11\n\tr15 = 4\n" + "\tr9_r8 = 0\n" + "\tr9_r8 += [r10 ++= r15]*r4 (s)\n\tr9_r8 += [r10 ++= r15]*r5 (s)\n\tr9_r8 += [r10 ++= r15]*r6 (s)\n" + "\tr9_r8 >>= 24\n\tr14 = [r10++=4]\n\tr8 += r14\n\tr14 = [r2+0]\n\tr8 += r14\n\t[r7++=4] = r8\n" + "\tr9_r8 = 0\n" + "\tr9_r8 += [r10 ++= r15]*r4 (s)\n\tr9_r8 += [r10 ++= r15]*r5 (s)\n\tr9_r8 += [r10 ++= r15]*r6 (s)\n" + "\tr9_r8 >>= 24\n\tr14 = [r10++=4]\n\tr8 += r14\n\tr14 = [r2+4]\n\tr8 += r14\n\t[r7++=4] = r8\n" + "\tr9_r8 = 0\n" + "\tr9_r8 += [r10 ++= r15]*r4 (s)\n\tr9_r8 += [r10 ++= r15]*r5 (s)\n\tr9_r8 += [r10 ++= r15]*r6 (s)\n" + "\tr9_r8 >>= 24\n\tr14 = [r10++=4]\n\tr8 += r14\n\tr14 = [r2+8]\n\tr8 += r14\n\t[r7++=4] = r8\n" + ".Lpxn_pn:\n" + "\tr14 = [r0+8]\n\tr2 += r14\n" + "\tr13 += -1\n" + "\tif (r13 != 0) goto .Lpxn_pf\n" + "\t{pc, r15-r4} = [sp++]\n" + /* post2 (v37): the same as post, with fewer memory steps: z, hs and x moved 3 words by one instruction, the + * residual's 9 multiply-adds in 3 accumulators, each weight loaded in the same step as the multiply before it (a + * load paired with a multiply takes r0..r7 only). r1 z, r2 x, r3 hs, r7 out, r5 weights, the activations in + * r4 r14 r15; [sp+0] frames left, [sp+4] x stride - 12 */ + "\t.global pxn_post2_asm\n" + "pxn_post2_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -8\n" + "\tr1 = [r0+0]\n\tr2 = [r0+4]\n\tr3 = [r0+16]\n\tr7 = [r0+20]\n" + "\tr15 = [r0+24]\n\t[sp+0] = r15\n" + "\tr15 = [r0+8]\n\tr15 += -12\n\t[sp+4] = r15\n" + "\tif (r7 == 0) goto .Lpxn_p2h\n" + ".Lpxn_p2f:\n" + "\t{r6-r4} = [r1++]\n" + "\tr14 = 42949673\n" + "\tifs (r4 < 0) {\n\tr9_r8 = r4 * r14 (s)\n\tr4 = r9\n\t}\n" + "\tifs (r5 < 0) {\n\tr9_r8 = r5 * r14 (s)\n\tr5 = r9\n\t}\n" + "\tifs (r6 < 0) {\n\tr9_r8 = r6 * r14 (s)\n\tr6 = r9\n\t}\n" + "\t{r10-r8} = [r3++]\n" + "\tr8 += r4\n\tr9 += r5\n\tr10 += r6\n" + "\t[r3+-12] = r8\n\t[r3+-8] = r9\n\t[r3+-4] = r10\n" + "\tr14 = r5\n\tr15 = r6\n" + "\tr5 = [r0+28]\n" + "\tr6 = [r5++=4]\n" + "\tr9_r8 = r6 * r4 (s) # r6 = [r5++=4]\n" + "\tr11_r10 = r6 * r4 (s) # r6 = [r5++=4]\n" + "\tr13_r12 = r6 * r4 (s) # r6 = [r5++=4]\n" + "\tr9_r8 += r6 * r14 (s) # r6 = [r5++=4]\n" + "\tr11_r10 += r6 * r14 (s) # r6 = [r5++=4]\n" + "\tr13_r12 += r6 * r14 (s) # r6 = [r5++=4]\n" + "\tr9_r8 += r6 * r15 (s) # r6 = [r5++=4]\n" + "\tr11_r10 += r6 * r15 (s) # r6 = [r5++=4]\n" + "\tr13_r12 += r6 * r15 (s) # r6 = [r5++=4]\n" + "\tr9_r8 >>= 24\n\tr11_r10 >>= 24\n\tr13_r12 >>= 24\n" + "\tr8 += r6\n\tr6 = [r5++=4]\n" + "\tr10 += r6\n\tr6 = [r5+0]\n" + "\tr12 += r6\n" + "\t{r6-r4} = [r2++]\n" + "\tr8 += r4\n\tr10 += r5\n\tr12 += r6\n" + "\t[r7++=4] = r8\n\t[r7++=4] = r10\n\t[r7++=4] = r12\n" + "\tr15 = [sp+4]\n\tr2 += r15\n" + "\tr15 = [sp+0]\n\tr15 += -1\n\t[sp+0] = r15\n" + "\tif (r15 != 0) goto .Lpxn_p2f\n" + "\tgoto .Lpxn_p2e\n" + ".Lpxn_p2h:\n" + "\t{r6-r4} = [r1++]\n" + "\tr14 = 42949673\n" + "\tifs (r4 < 0) {\n\tr9_r8 = r4 * r14 (s)\n\tr4 = r9\n\t}\n" + "\tifs (r5 < 0) {\n\tr9_r8 = r5 * r14 (s)\n\tr5 = r9\n\t}\n" + "\tifs (r6 < 0) {\n\tr9_r8 = r6 * r14 (s)\n\tr6 = r9\n\t}\n" + "\t{r10-r8} = [r3++]\n" + "\tr8 += r4\n\tr9 += r5\n\tr10 += r6\n" + "\t[r3+-12] = r8\n\t[r3+-8] = r9\n\t[r3+-4] = r10\n" + "\tr15 = [sp+0]\n\tr15 += -1\n\t[sp+0] = r15\n" + "\tif (r15 != 0) goto .Lpxn_p2h\n" + ".Lpxn_p2e:\n" + "\tsp += 8\n" + "\t{pc, r15-r4} = [sp++]\n" + /* post3 (v37 diagnostic 18): post2 with the three LeakyReLU products computed side by side (one predicated move + * each), the residual's weights at fixed offsets from r0 and loaded two multiply-adds ahead in r4/r5 (activations + * in r14 r15 r6). r1 z, r2 x, r3 hs, r7 out, r0 the rr2 weights; [sp+0] frames left, [sp+4] x stride - 12 */ + "\t.global pxn_post3_asm\n" + "pxn_post3_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -8\n" + "\tr1 = [r0+0]\n\tr2 = [r0+4]\n\tr3 = [r0+16]\n\tr7 = [r0+20]\n" + "\tr15 = [r0+24]\n\t[sp+0] = r15\n" + "\tr15 = [r0+8]\n\tr15 += -12\n\t[sp+4] = r15\n" + "\tr0 = [r0+28]\n" + "\tif (r7 == 0) goto .Lpxn_p3h\n" + ".Lpxn_p3f:\n" + "\t{r6-r4} = [r1++]\n" + "\tr15 = 42949673\n" + "\tr9_r8 = r4 * r15 (s)\n" + "\tr11_r10 = r5 * r15 (s)\n" + "\tr13_r12 = r6 * r15 (s)\n" + "\tifs (r4 < 0) {\n\tr4 = r9\n\t}\n" + "\tifs (r5 < 0) {\n\tr5 = r11\n\t}\n" + "\tifs (r6 < 0) {\n\tr6 = r13\n\t}\n" + "\tr14 = r4\n\tr15 = r5\n" + "\tr4 = [r0+0]\n\tr5 = [r0+4]\n" + "\t{r10-r8} = [r3++]\n" + "\tr8 += r14\n\tr9 += r15\n\tr10 += r6\n" + "\t[r3+-12] = r8\n\t[r3+-8] = r9\n\t[r3+-4] = r10\n" + "\tr9_r8 = r14 * r4 (s) # r4 = [r0+8]\n" + "\tr11_r10 = r14 * r5 (s) # r5 = [r0+12]\n" + "\tr13_r12 = r14 * r4 (s) # r4 = [r0+16]\n" + "\tr9_r8 += r15 * r5 (s) # r5 = [r0+20]\n" + "\tr11_r10 += r15 * r4 (s) # r4 = [r0+24]\n" + "\tr13_r12 += r15 * r5 (s) # r5 = [r0+28]\n" + "\tr9_r8 += r6 * r4 (s) # r4 = [r0+32]\n" + "\tr11_r10 += r6 * r5 (s) # r5 = [r0+36]\n" + "\tr13_r12 += r6 * r4 (s) # r4 = [r0+40]\n" + "\tr9_r8 >>= 24\n\tr11_r10 >>= 24\n\tr13_r12 >>= 24\n" + "\tr8 += r5\n\tr5 = [r0+44]\n" + "\tr10 += r4\n" + "\tr12 += r5\n" + "\t{r6-r4} = [r2++]\n" + "\tr8 += r4\n\tr10 += r5\n\tr12 += r6\n" + "\t[r7++=4] = r8\n\t[r7++=4] = r10\n\t[r7++=4] = r12\n" + "\tr15 = [sp+4]\n\tr2 += r15\n" + "\tr15 = [sp+0]\n\tr15 += -1\n\t[sp+0] = r15\n" + "\tif (r15 != 0) goto .Lpxn_p3f\n" + "\tgoto .Lpxn_p3e\n" + ".Lpxn_p3h:\n" + "\t{r6-r4} = [r1++]\n" + "\tr15 = 42949673\n" + "\tr9_r8 = r4 * r15 (s)\n" + "\tr11_r10 = r5 * r15 (s)\n" + "\tr13_r12 = r6 * r15 (s)\n" + "\tifs (r4 < 0) {\n\tr4 = r9\n\t}\n" + "\tifs (r5 < 0) {\n\tr5 = r11\n\t}\n" + "\tifs (r6 < 0) {\n\tr6 = r13\n\t}\n" + "\t{r10-r8} = [r3++]\n" + "\tr8 += r4\n\tr9 += r5\n\tr10 += r6\n" + "\t[r3+-12] = r8\n\t[r3+-8] = r9\n\t[r3+-4] = r10\n" + "\tr15 = [sp+0]\n\tr15 += -1\n\t[sp+0] = r15\n" + "\tif (r15 != 0) goto .Lpxn_p3h\n" + ".Lpxn_p3e:\n" + "\tsp += 8\n" + "\t{pc, r15-r4} = [sp++]\n" + /* rdot: r0 the weights (row after row), r1 a tap's pointer, r2 the tap table, r3 taps left, r4 u, r5 a weight, + * r6 an x; 4 accumulators. [sp+0] job, [sp+4] rows left, [sp+8] z */ + "\t.global pxn_rdot_asm\n" + "pxn_rdot_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -12\n" + "\t[sp+0] = r0\n" + "\tr7 = [r0+20]\n\t[sp+4] = r7\n" + "\tr7 = [r0+16]\n\t[sp+8] = r7\n" + "\tr0 = [r0+0]\n" + ".Lpxn_rdo:\n" + "\tr4 = [sp+0]\n" + "\tr2 = [r4+4]\n" + "\tr3 = [r4+8]\n" + "\tr4 = [r4+12]\n" + "\tr5 = [r0++=4]\n" + "\tr7 = [r0++=4]\n" + "\tr6 = [r4+0]\n" + "\tr9_r8 = r6 * r5 (s) # r6 = [r4+4]\n" + "\tr11_r10 = r6 * r5 (s) # r6 = [r4+8]\n" + "\tr13_r12 = r6 * r5 (s) # r6 = [r4+12]\n" + "\tr15_r14 = r6 * r5 (s)\n" + "\tr6 = 1048576\n" + "\tr9_r8 += r6 * r7 (s)\n" + "\tr11_r10 += r6 * r7 (s)\n" + "\tr13_r12 += r6 * r7 (s)\n" + "\tr15_r14 += r6 * r7 (s)\n" + "\tr5 = [r0++=4]\n" + ".Lpxn_rdk:\n" + "\tr1 = [r2++=4]\n" + "\tr6 = [r1+0]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+12]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+36]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+4]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+16]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+40]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+8]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+20]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+44]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr3 += -1\n" + "\tif (r3 != 0) goto .Lpxn_rdk\n" + "\tr0 += -4\n" + "\tr9_r8 >>= 24\n\tr11_r10 >>= 24\n\tr13_r12 >>= 24\n\tr15_r14 >>= 24\n" + "\tr4 = [sp+8]\n" + "\t[r4+0] = r8\n\t[r4+12] = r10\n\t[r4+24] = r12\n\t[r4+36] = r14\n" + "\tr4 += 4\n\t[sp+8] = r4\n" + "\tr7 = [sp+4]\n\tr7 += -1\n\t[sp+4] = r7\n" + "\tif (r7 != 0) goto .Lpxn_rdo\n" + "\tsp += 12\n" + "\t{pc, r15-r4} = [sp++]\n" + /* rdot6: the same for 6 taps, unrolled (no branch per tap): most layers */ + "\t.global pxn_rdot6_asm\n" + "pxn_rdot6_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -12\n" + "\t[sp+0] = r0\n" + "\tr7 = [r0+20]\n\t[sp+4] = r7\n" + "\tr7 = [r0+16]\n\t[sp+8] = r7\n" + "\tr0 = [r0+0]\n" + ".Lpxn_r6o:\n" + "\tr4 = [sp+0]\n" + "\tr2 = [r4+4]\n" + "\tr3 = [r4+8]\n" + "\tr4 = [r4+12]\n" + "\tr5 = [r0++=4]\n" + "\tr7 = [r0++=4]\n" + "\tr6 = [r4+0]\n" + "\tr9_r8 = r6 * r5 (s) # r6 = [r4+4]\n" + "\tr11_r10 = r6 * r5 (s) # r6 = [r4+8]\n" + "\tr13_r12 = r6 * r5 (s) # r6 = [r4+12]\n" + "\tr15_r14 = r6 * r5 (s)\n" + "\tr6 = 1048576\n" + "\tr9_r8 += r6 * r7 (s)\n" + "\tr11_r10 += r6 * r7 (s)\n" + "\tr13_r12 += r6 * r7 (s)\n" + "\tr15_r14 += r6 * r7 (s)\n" + "\tr5 = [r0++=4]\n" + "\tr1 = [r2++=4]\n" + "\tr6 = [r1+0]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+12]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+36]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+4]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+16]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+40]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+8]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+20]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+44]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr1 = [r2++=4]\n" + "\tr6 = [r1+0]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+12]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+36]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+4]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+16]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+40]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+8]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+20]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+44]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr1 = [r2++=4]\n" + "\tr6 = [r1+0]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+12]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+36]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+4]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+16]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+40]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+8]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+20]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+44]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr1 = [r2++=4]\n" + "\tr6 = [r1+0]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+12]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+36]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+4]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+16]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+40]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+8]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+20]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+44]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr1 = [r2++=4]\n" + "\tr6 = [r1+0]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+12]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+36]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+4]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+16]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+40]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+8]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+20]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+44]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr1 = [r2++=4]\n" + "\tr6 = [r1+0]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+12]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+36]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+4]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+16]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+40]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr6 = [r1+8]\n" + "\tr9_r8 += r6 * r5 (s) # r6 = [r1+20]\n" + "\tr11_r10 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+44]\n" + "\tr15_r14 += r6 * r5 (s) # r5 = [r0++=4]\n" + "\tr0 += -4\n" + "\tr9_r8 >>= 24\n\tr11_r10 >>= 24\n\tr13_r12 >>= 24\n\tr15_r14 >>= 24\n" + "\tr4 = [sp+8]\n" + "\t[r4+0] = r8\n\t[r4+12] = r10\n\t[r4+24] = r12\n\t[r4+36] = r14\n" + "\tr4 += 4\n\t[sp+8] = r4\n" + "\tr7 = [sp+4]\n\tr7 += -1\n\t[sp+4] = r7\n" + "\tif (r7 != 0) goto .Lpxn_r6o\n" + "\tsp += 12\n" + "\t{pc, r15-r4} = [sp++]\n" + /* rdq6, rdq15, rdq16 (generated by tools/gen_rdq.py): the same as rdot, unrolled for 6, 15 and 16 taps, each + * multiply-add using a value loaded 2 to 4 steps before (a pair whose multiply waits for the load before costs + * 3.2 cycles, without the wait 2.2: diagnostic 12). x values in r3 r4 r6 r7, the weight in r5, the taps' pointers + * in r1 and r2 by turns (the next one loaded during the current tap). [sp+0] job, [sp+4] rows left, [sp+8] z, + * [sp+12] the tap table */ + "\t.global pxn_rdq6_asm\n" + "pxn_rdq6_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -16\n" + "\t[sp+0] = r0\n" + "\tr7 = [r0+20]\n" + "\t[sp+4] = r7\n" + "\tr7 = [r0+16]\n" + "\t[sp+8] = r7\n" + "\tr7 = [r0+4]\n" + "\t[sp+12] = r7\n" + "\tr0 = [r0+0]\n" + ".Lpxn_rdq6_asmo:\n" + "\tr4 = [sp+0]\n" + "\tr7 = [r4+12]\n" + "\tr5 = [r0++=4]\n" + "\tr6 = [r0++=4]\n" + "\tr3 = [r7+0]\n" + "\tr9_r8 = r3 * r5 (s)\n" + "\tr3 = [r7+4]\n" + "\tr11_r10 = r3 * r5 (s)\n" + "\tr3 = [r7+8]\n" + "\tr13_r12 = r3 * r5 (s)\n" + "\tr3 = [r7+12]\n" + "\tr15_r14 = r3 * r5 (s)\n" + "\tr3 = 1048576\n" + "\tr9_r8 += r3 * r6 (s)\n" + "\tr11_r10 += r3 * r6 (s)\n" + "\tr13_r12 += r3 * r6 (s)\n" + "\tr15_r14 += r3 * r6 (s)\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+0]\n" + "\tr5 = [r0++=4]\n" + "\tr3 = [r1+0]\n" + "\tr4 = [r1+12]\n" + "\tr6 = [r1+24]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+4]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+8]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+12]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+16]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+20]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s)\n" + "\tr11_r10 += r4 * r5 (s)\n" + "\tr13_r12 += r6 * r5 (s)\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr0 += -4\n" + "\tr9_r8 >>= 24\n" + "\tr11_r10 >>= 24\n" + "\tr13_r12 >>= 24\n" + "\tr15_r14 >>= 24\n" + "\tr4 = [sp+8]\n" + "\t[r4+0] = r8\n" + "\t[r4+12] = r10\n" + "\t[r4+24] = r12\n" + "\t[r4+36] = r14\n" + "\tr4 += 4\n" + "\t[sp+8] = r4\n" + "\tr7 = [sp+4]\n" + "\tr7 += -1\n" + "\t[sp+4] = r7\n" + "\tif (r7 != 0) goto .Lpxn_rdq6_asmo\n" + "\tsp += 16\n" + "\t{pc, r15-r4} = [sp++]\n" + "\t.global pxn_rdq15_asm\n" + "pxn_rdq15_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -16\n" + "\t[sp+0] = r0\n" + "\tr7 = [r0+20]\n" + "\t[sp+4] = r7\n" + "\tr7 = [r0+16]\n" + "\t[sp+8] = r7\n" + "\tr7 = [r0+4]\n" + "\t[sp+12] = r7\n" + "\tr0 = [r0+0]\n" + ".Lpxn_rdq15_asmo:\n" + "\tr4 = [sp+0]\n" + "\tr7 = [r4+12]\n" + "\tr5 = [r0++=4]\n" + "\tr6 = [r0++=4]\n" + "\tr3 = [r7+0]\n" + "\tr9_r8 = r3 * r5 (s)\n" + "\tr3 = [r7+4]\n" + "\tr11_r10 = r3 * r5 (s)\n" + "\tr3 = [r7+8]\n" + "\tr13_r12 = r3 * r5 (s)\n" + "\tr3 = [r7+12]\n" + "\tr15_r14 = r3 * r5 (s)\n" + "\tr3 = 1048576\n" + "\tr9_r8 += r3 * r6 (s)\n" + "\tr11_r10 += r3 * r6 (s)\n" + "\tr13_r12 += r3 * r6 (s)\n" + "\tr15_r14 += r3 * r6 (s)\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+0]\n" + "\tr5 = [r0++=4]\n" + "\tr3 = [r1+0]\n" + "\tr4 = [r1+12]\n" + "\tr6 = [r1+24]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+4]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+8]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+12]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+16]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+20]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+24]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+28]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+32]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+40]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+48]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+52]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+56]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s)\n" + "\tr11_r10 += r4 * r5 (s)\n" + "\tr13_r12 += r6 * r5 (s)\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr0 += -4\n" + "\tr9_r8 >>= 24\n" + "\tr11_r10 >>= 24\n" + "\tr13_r12 >>= 24\n" + "\tr15_r14 >>= 24\n" + "\tr4 = [sp+8]\n" + "\t[r4+0] = r8\n" + "\t[r4+12] = r10\n" + "\t[r4+24] = r12\n" + "\t[r4+36] = r14\n" + "\tr4 += 4\n" + "\t[sp+8] = r4\n" + "\tr7 = [sp+4]\n" + "\tr7 += -1\n" + "\t[sp+4] = r7\n" + "\tif (r7 != 0) goto .Lpxn_rdq15_asmo\n" + "\tsp += 16\n" + "\t{pc, r15-r4} = [sp++]\n" + "\t.global pxn_rdq16_asm\n" + "pxn_rdq16_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -16\n" + "\t[sp+0] = r0\n" + "\tr7 = [r0+20]\n" + "\t[sp+4] = r7\n" + "\tr7 = [r0+16]\n" + "\t[sp+8] = r7\n" + "\tr7 = [r0+4]\n" + "\t[sp+12] = r7\n" + "\tr0 = [r0+0]\n" + ".Lpxn_rdq16_asmo:\n" + "\tr4 = [sp+0]\n" + "\tr7 = [r4+12]\n" + "\tr5 = [r0++=4]\n" + "\tr6 = [r0++=4]\n" + "\tr3 = [r7+0]\n" + "\tr9_r8 = r3 * r5 (s)\n" + "\tr3 = [r7+4]\n" + "\tr11_r10 = r3 * r5 (s)\n" + "\tr3 = [r7+8]\n" + "\tr13_r12 = r3 * r5 (s)\n" + "\tr3 = [r7+12]\n" + "\tr15_r14 = r3 * r5 (s)\n" + "\tr3 = 1048576\n" + "\tr9_r8 += r3 * r6 (s)\n" + "\tr11_r10 += r3 * r6 (s)\n" + "\tr13_r12 += r3 * r6 (s)\n" + "\tr15_r14 += r3 * r6 (s)\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+0]\n" + "\tr5 = [r0++=4]\n" + "\tr3 = [r1+0]\n" + "\tr4 = [r1+12]\n" + "\tr6 = [r1+24]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+4]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+8]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+12]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+16]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+20]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+24]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+28]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+32]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+40]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+48]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+52]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+12]\n" + "\tr1 = [r1+56]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+12]\n" + "\tr2 = [r2+60]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s)\n" + "\tr11_r10 += r4 * r5 (s)\n" + "\tr13_r12 += r6 * r5 (s)\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr0 += -4\n" + "\tr9_r8 >>= 24\n" + "\tr11_r10 >>= 24\n" + "\tr13_r12 >>= 24\n" + "\tr15_r14 >>= 24\n" + "\tr4 = [sp+8]\n" + "\t[r4+0] = r8\n" + "\t[r4+12] = r10\n" + "\t[r4+24] = r12\n" + "\t[r4+36] = r14\n" + "\tr4 += 4\n" + "\t[sp+8] = r4\n" + "\tr7 = [sp+4]\n" + "\tr7 += -1\n" + "\t[sp+4] = r7\n" + "\tif (r7 != 0) goto .Lpxn_rdq16_asmo\n" + "\tsp += 16\n" + "\t{pc, r15-r4} = [sp++]\n" + /* rdl6, rdl15, rdl16 (tools/gen_rdq.py --rdl): rdq for all the groups of 4 frames of a layer's block in one call + * (diagnostic 20): the tap table on the stack ([sp+20+4k]), the job's u and z moved on, every tap pointer 4 frames + * on after each group, back by the ring's length past its end (the ring's first frames are mirrored after it) */ + "\t.global pxn_rdl6_asm\n" + "pxn_rdl6_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -44\n" + "\t[sp+0] = r0\n" + "\tr7 = [r0+24]\n" + "\t[sp+12] = r7\n" + "\tr1 = [r0+4]\n" + "\tr7 = [r1+0]\n" + "\t[sp+20] = r7\n" + "\tr7 = [r1+4]\n" + "\t[sp+24] = r7\n" + "\tr7 = [r1+8]\n" + "\t[sp+28] = r7\n" + "\tr7 = [r1+12]\n" + "\t[sp+32] = r7\n" + "\tr7 = [r1+16]\n" + "\t[sp+36] = r7\n" + "\tr7 = [r1+20]\n" + "\t[sp+40] = r7\n" + ".Lpxn_rdl6_asmg:\n" + "\tr4 = [sp+0]\n" + "\tr7 = [r4+20]\n" + "\t[sp+4] = r7\n" + "\tr7 = [r4+16]\n" + "\t[sp+8] = r7\n" + "\tr0 = [r4+0]\n" + ".Lpxn_rdl6_asmo:\n" + "\tr4 = [sp+0]\n" + "\tr7 = [r4+12]\n" + "\tr5 = [r0++=4]\n" + "\tr6 = [r0++=4]\n" + "\tr3 = [r7+0]\n" + "\tr9_r8 = r3 * r5 (s)\n" + "\tr3 = [r7+4]\n" + "\tr11_r10 = r3 * r5 (s)\n" + "\tr3 = [r7+8]\n" + "\tr13_r12 = r3 * r5 (s)\n" + "\tr3 = [r7+12]\n" + "\tr15_r14 = r3 * r5 (s)\n" + "\tr3 = 1048576\n" + "\tr9_r8 += r3 * r6 (s)\n" + "\tr11_r10 += r3 * r6 (s)\n" + "\tr13_r12 += r3 * r6 (s)\n" + "\tr15_r14 += r3 * r6 (s)\n" + "\tr1 = [sp+20]\n" + "\tr5 = [r0++=4]\n" + "\tr3 = [r1+0]\n" + "\tr4 = [r1+12]\n" + "\tr6 = [r1+24]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+24]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+28]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+32]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+40]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s)\n" + "\tr11_r10 += r4 * r5 (s)\n" + "\tr13_r12 += r6 * r5 (s)\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr0 += -4\n" + "\tr9_r8 >>= 24\n" + "\tr11_r10 >>= 24\n" + "\tr13_r12 >>= 24\n" + "\tr15_r14 >>= 24\n" + "\tr4 = [sp+8]\n" + "\t[r4+0] = r8\n" + "\t[r4+12] = r10\n" + "\t[r4+24] = r12\n" + "\t[r4+36] = r14\n" + "\tr4 += 4\n" + "\t[sp+8] = r4\n" + "\tr7 = [sp+4]\n" + "\tr7 += -1\n" + "\t[sp+4] = r7\n" + "\tif (r7 != 0) goto .Lpxn_rdl6_asmo\n" + "\tr4 = [sp+0]\n" + "\tr7 = [r4+12]\n" + "\tr7 += 16\n" + "\t[r4+12] = r7\n" + "\tr7 = [r4+16]\n" + "\tr7 += 48\n" + "\t[r4+16] = r7\n" + "\tr2 = [r4+28]\n" + "\tr3 = [r4+32]\n" + "\tr1 = [sp+20]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+20] = r1\n" + "\tr1 = [sp+24]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+24] = r1\n" + "\tr1 = [sp+28]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+28] = r1\n" + "\tr1 = [sp+32]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+32] = r1\n" + "\tr1 = [sp+36]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+36] = r1\n" + "\tr1 = [sp+40]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+40] = r1\n" + "\tr7 = [sp+12]\n" + "\tr7 += -1\n" + "\t[sp+12] = r7\n" + "\tif (r7 != 0) goto .Lpxn_rdl6_asmg\n" + "\tsp += 44\n" + "\t{pc, r15-r4} = [sp++]\n" + "\t.global pxn_rdl15_asm\n" + "pxn_rdl15_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -80\n" + "\t[sp+0] = r0\n" + "\tr7 = [r0+24]\n" + "\t[sp+12] = r7\n" + "\tr1 = [r0+4]\n" + "\tr7 = [r1+0]\n" + "\t[sp+20] = r7\n" + "\tr7 = [r1+4]\n" + "\t[sp+24] = r7\n" + "\tr7 = [r1+8]\n" + "\t[sp+28] = r7\n" + "\tr7 = [r1+12]\n" + "\t[sp+32] = r7\n" + "\tr7 = [r1+16]\n" + "\t[sp+36] = r7\n" + "\tr7 = [r1+20]\n" + "\t[sp+40] = r7\n" + "\tr7 = [r1+24]\n" + "\t[sp+44] = r7\n" + "\tr7 = [r1+28]\n" + "\t[sp+48] = r7\n" + "\tr7 = [r1+32]\n" + "\t[sp+52] = r7\n" + "\tr7 = [r1+36]\n" + "\t[sp+56] = r7\n" + "\tr7 = [r1+40]\n" + "\t[sp+60] = r7\n" + "\tr7 = [r1+44]\n" + "\t[sp+64] = r7\n" + "\tr7 = [r1+48]\n" + "\t[sp+68] = r7\n" + "\tr7 = [r1+52]\n" + "\t[sp+72] = r7\n" + "\tr7 = [r1+56]\n" + "\t[sp+76] = r7\n" + ".Lpxn_rdl15_asmg:\n" + "\tr4 = [sp+0]\n" + "\tr7 = [r4+20]\n" + "\t[sp+4] = r7\n" + "\tr7 = [r4+16]\n" + "\t[sp+8] = r7\n" + "\tr0 = [r4+0]\n" + ".Lpxn_rdl15_asmo:\n" + "\tr4 = [sp+0]\n" + "\tr7 = [r4+12]\n" + "\tr5 = [r0++=4]\n" + "\tr6 = [r0++=4]\n" + "\tr3 = [r7+0]\n" + "\tr9_r8 = r3 * r5 (s)\n" + "\tr3 = [r7+4]\n" + "\tr11_r10 = r3 * r5 (s)\n" + "\tr3 = [r7+8]\n" + "\tr13_r12 = r3 * r5 (s)\n" + "\tr3 = [r7+12]\n" + "\tr15_r14 = r3 * r5 (s)\n" + "\tr3 = 1048576\n" + "\tr9_r8 += r3 * r6 (s)\n" + "\tr11_r10 += r3 * r6 (s)\n" + "\tr13_r12 += r3 * r6 (s)\n" + "\tr15_r14 += r3 * r6 (s)\n" + "\tr1 = [sp+20]\n" + "\tr5 = [r0++=4]\n" + "\tr3 = [r1+0]\n" + "\tr4 = [r1+12]\n" + "\tr6 = [r1+24]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+24]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+28]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+32]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+40]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+48]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+52]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+56]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+60]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+64]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+68]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+72]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+76]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s)\n" + "\tr11_r10 += r4 * r5 (s)\n" + "\tr13_r12 += r6 * r5 (s)\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr0 += -4\n" + "\tr9_r8 >>= 24\n" + "\tr11_r10 >>= 24\n" + "\tr13_r12 >>= 24\n" + "\tr15_r14 >>= 24\n" + "\tr4 = [sp+8]\n" + "\t[r4+0] = r8\n" + "\t[r4+12] = r10\n" + "\t[r4+24] = r12\n" + "\t[r4+36] = r14\n" + "\tr4 += 4\n" + "\t[sp+8] = r4\n" + "\tr7 = [sp+4]\n" + "\tr7 += -1\n" + "\t[sp+4] = r7\n" + "\tif (r7 != 0) goto .Lpxn_rdl15_asmo\n" + "\tr4 = [sp+0]\n" + "\tr7 = [r4+12]\n" + "\tr7 += 16\n" + "\t[r4+12] = r7\n" + "\tr7 = [r4+16]\n" + "\tr7 += 48\n" + "\t[r4+16] = r7\n" + "\tr2 = [r4+28]\n" + "\tr3 = [r4+32]\n" + "\tr1 = [sp+20]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+20] = r1\n" + "\tr1 = [sp+24]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+24] = r1\n" + "\tr1 = [sp+28]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+28] = r1\n" + "\tr1 = [sp+32]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+32] = r1\n" + "\tr1 = [sp+36]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+36] = r1\n" + "\tr1 = [sp+40]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+40] = r1\n" + "\tr1 = [sp+44]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+44] = r1\n" + "\tr1 = [sp+48]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+48] = r1\n" + "\tr1 = [sp+52]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+52] = r1\n" + "\tr1 = [sp+56]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+56] = r1\n" + "\tr1 = [sp+60]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+60] = r1\n" + "\tr1 = [sp+64]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+64] = r1\n" + "\tr1 = [sp+68]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+68] = r1\n" + "\tr1 = [sp+72]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+72] = r1\n" + "\tr1 = [sp+76]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+76] = r1\n" + "\tr7 = [sp+12]\n" + "\tr7 += -1\n" + "\t[sp+12] = r7\n" + "\tif (r7 != 0) goto .Lpxn_rdl15_asmg\n" + "\tsp += 80\n" + "\t{pc, r15-r4} = [sp++]\n" + "\t.global pxn_rdl16_asm\n" + "pxn_rdl16_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tsp += -84\n" + "\t[sp+0] = r0\n" + "\tr7 = [r0+24]\n" + "\t[sp+12] = r7\n" + "\tr1 = [r0+4]\n" + "\tr7 = [r1+0]\n" + "\t[sp+20] = r7\n" + "\tr7 = [r1+4]\n" + "\t[sp+24] = r7\n" + "\tr7 = [r1+8]\n" + "\t[sp+28] = r7\n" + "\tr7 = [r1+12]\n" + "\t[sp+32] = r7\n" + "\tr7 = [r1+16]\n" + "\t[sp+36] = r7\n" + "\tr7 = [r1+20]\n" + "\t[sp+40] = r7\n" + "\tr7 = [r1+24]\n" + "\t[sp+44] = r7\n" + "\tr7 = [r1+28]\n" + "\t[sp+48] = r7\n" + "\tr7 = [r1+32]\n" + "\t[sp+52] = r7\n" + "\tr7 = [r1+36]\n" + "\t[sp+56] = r7\n" + "\tr7 = [r1+40]\n" + "\t[sp+60] = r7\n" + "\tr7 = [r1+44]\n" + "\t[sp+64] = r7\n" + "\tr7 = [r1+48]\n" + "\t[sp+68] = r7\n" + "\tr7 = [r1+52]\n" + "\t[sp+72] = r7\n" + "\tr7 = [r1+56]\n" + "\t[sp+76] = r7\n" + "\tr7 = [r1+60]\n" + "\t[sp+80] = r7\n" + ".Lpxn_rdl16_asmg:\n" + "\tr4 = [sp+0]\n" + "\tr7 = [r4+20]\n" + "\t[sp+4] = r7\n" + "\tr7 = [r4+16]\n" + "\t[sp+8] = r7\n" + "\tr0 = [r4+0]\n" + ".Lpxn_rdl16_asmo:\n" + "\tr4 = [sp+0]\n" + "\tr7 = [r4+12]\n" + "\tr5 = [r0++=4]\n" + "\tr6 = [r0++=4]\n" + "\tr3 = [r7+0]\n" + "\tr9_r8 = r3 * r5 (s)\n" + "\tr3 = [r7+4]\n" + "\tr11_r10 = r3 * r5 (s)\n" + "\tr3 = [r7+8]\n" + "\tr13_r12 = r3 * r5 (s)\n" + "\tr3 = [r7+12]\n" + "\tr15_r14 = r3 * r5 (s)\n" + "\tr3 = 1048576\n" + "\tr9_r8 += r3 * r6 (s)\n" + "\tr11_r10 += r3 * r6 (s)\n" + "\tr13_r12 += r3 * r6 (s)\n" + "\tr15_r14 += r3 * r6 (s)\n" + "\tr1 = [sp+20]\n" + "\tr5 = [r0++=4]\n" + "\tr3 = [r1+0]\n" + "\tr4 = [r1+12]\n" + "\tr6 = [r1+24]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+24]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+28]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+32]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+40]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+48]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+52]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+56]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+60]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+64]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+68]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+72]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr1 = [sp+76]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+40]\n" + "\tr2 = [sp+80]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r1+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r1+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r1+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r1+44]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+0]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+12]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+24]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+36]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+4]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+16]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+28]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+40]\n" + "\tr9_r8 += r3 * r5 (s) # r3 = [r2+8]\n" + "\tr11_r10 += r4 * r5 (s) # r4 = [r2+20]\n" + "\tr13_r12 += r6 * r5 (s) # r6 = [r2+32]\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr7 = [r2+44]\n" + "\tr9_r8 += r3 * r5 (s)\n" + "\tr11_r10 += r4 * r5 (s)\n" + "\tr13_r12 += r6 * r5 (s)\n" + "\tr15_r14 += r7 * r5 (s) # r5 = [r0++=4]\n" + "\tr0 += -4\n" + "\tr9_r8 >>= 24\n" + "\tr11_r10 >>= 24\n" + "\tr13_r12 >>= 24\n" + "\tr15_r14 >>= 24\n" + "\tr4 = [sp+8]\n" + "\t[r4+0] = r8\n" + "\t[r4+12] = r10\n" + "\t[r4+24] = r12\n" + "\t[r4+36] = r14\n" + "\tr4 += 4\n" + "\t[sp+8] = r4\n" + "\tr7 = [sp+4]\n" + "\tr7 += -1\n" + "\t[sp+4] = r7\n" + "\tif (r7 != 0) goto .Lpxn_rdl16_asmo\n" + "\tr4 = [sp+0]\n" + "\tr7 = [r4+12]\n" + "\tr7 += 16\n" + "\t[r4+12] = r7\n" + "\tr7 = [r4+16]\n" + "\tr7 += 48\n" + "\t[r4+16] = r7\n" + "\tr2 = [r4+28]\n" + "\tr3 = [r4+32]\n" + "\tr1 = [sp+20]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+20] = r1\n" + "\tr1 = [sp+24]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+24] = r1\n" + "\tr1 = [sp+28]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+28] = r1\n" + "\tr1 = [sp+32]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+32] = r1\n" + "\tr1 = [sp+36]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+36] = r1\n" + "\tr1 = [sp+40]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+40] = r1\n" + "\tr1 = [sp+44]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+44] = r1\n" + "\tr1 = [sp+48]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+48] = r1\n" + "\tr1 = [sp+52]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+52] = r1\n" + "\tr1 = [sp+56]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+56] = r1\n" + "\tr1 = [sp+60]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+60] = r1\n" + "\tr1 = [sp+64]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+64] = r1\n" + "\tr1 = [sp+68]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+68] = r1\n" + "\tr1 = [sp+72]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+72] = r1\n" + "\tr1 = [sp+76]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+76] = r1\n" + "\tr1 = [sp+80]\n" + "\tr1 += 48\n" + "\tr5 = r1 + r3\n" + "\tif (r1 >= r2) {\n" + "\tr1 = r5\n" + "\t}\n" + "\t[sp+80] = r1\n" + "\tr7 = [sp+12]\n" + "\tr7 += -1\n" + "\t[sp+12] = r7\n" + "\tif (r7 != 0) goto .Lpxn_rdl16_asmg\n" + "\tsp += 84\n" + "\t{pc, r15-r4} = [sp++]\n" + + /* gcopy: r0 dst, r1 src, r2 frames, r3 row stride */ + "\t.global pxn_gcopy_asm\n" + "pxn_gcopy_asm:\n" + "\t[--sp] = {rets, r15-r4}\n" + "\tr3 += -12\n" + ".Lpxn_gc:\n" + "\trep r2 {\n" + "\t{r6-r4} = [r1++]\n" + "\t[r0++] = {r6-r4}\n" + "\tr0 += r3\n" + "\t}\n" + "\tif (r2 != 0) goto .Lpxn_gc\n" + "\t{pc, r15-r4} = [sp++]\n"); +#else +#define PXN_ASM 0 +#endif + +/* the routines in use: C until the start-up check (pxn_selftest) picks the hand ones */ +static void (*pxn_dot3x4)(const pxn_dot *) = pxn_dot3x4_c; +static void (*pxn_dot1)(const pxn_dot *) = pxn_dot1_c; +static void (*pxn_post_f)(const pxn_post *) = pxn_post_c; +static void (*pxn_gcopy)(int32_t *, const int32_t *, int, int) = pxn_gcopy_c; +static void (*pxn_rdot_f)(const pxn_rdot *) = pxn_rdot_c; +static void (*pxn_rdot6_f)(const pxn_rdot *) = pxn_rdot_c; /* for 6 taps */ +static void (*pxn_rdq_f[PXN_HK + 1])(const pxn_rdot *); /* by tap count: the load-ahead routines, if checked */ +static void (*pxn_rdl_f[PXN_HK + 1])(pxn_rdot *); /* by tap count: rdl, if checked */ + +/* ---- the chip's vector unit (in its FFT block, 0x1EE0400): dot products in hardware ---- + * One command computes nloop dot products of nlen 32-bit pairs, z = sum(y * x) >> q, the x, y and z addresses moving by + * their own byte steps between loops: a layer's weight row (y, still) against its X rows (x, one row a loop), into + * pxn_z (z, 3 words a loop). The register layout is the one in JieLi's AC79 SDK (apps/common/jl_math, Apache-2.0): + * control 0xAA1 = dot product, x y z 32 bits; config0 = q << 24 | nloop << 12 | nlen; config1 = z step << 20 | + * y step << 10 | x step; start 0x149, done = bit 7, cleared by setting bit 6. It runs beside the CPU. Used only if + * the start-up check finds it there and within 1 of the C result on every value. */ +static uint8_t pxn_vec_ok, pxn_vfail __attribute__((unused)); +static int32_t pxn_vec_diff = -1; /* the start-up check's largest difference (-1: not run) */ +static int pxn_mode_v; /* see pxn_mode() */ +int pxn_mode(void) { return pxn_mode_v; } +/* a command: nloop n dot products of nlen T: the weight row against x rows xs bytes apart, into z (zs bytes apart) */ +static __attribute__((unused)) void pxn_vfill(volatile uint32_t *c, const int32_t *w32, const int32_t *x, int T, int xs, int zs, int32_t *z, int n) +{ + c[0] = 0xAA1u; /* dot product, x y z 32 bits */ + c[1] = (uint32_t)(uintptr_t)x; + c[2] = (uint32_t)(uintptr_t)w32; + c[3] = (uint32_t)(uintptr_t)z; + c[4] = ((uint32_t)PXN_QW << 24) | ((uint32_t)n << 12) | (uint32_t)T; + c[5] = ((uint32_t)zs << 20) | (uint32_t)xs; + c[6] = 0; + c[7] = 0; +} +#if PXN_ASM +#define PXN_FFT_CON (*(volatile uint32_t *)0x1EE0400u) +#define PXN_FFT_CADR (*(volatile uint32_t *)0x1EE0404u) +#define PXN_FFT_CONST (*(volatile uint32_t *)0x1EE0408u) +static volatile uint32_t pxn_vctx[8] __attribute__((aligned(32))); +/* 0 = done, -1 = no answer (the unit is not there or not clocked) */ +static int pxn_vdot(const int32_t *w, const int32_t *x, int T, int sb, int32_t *z, int n) +{ + pxn_vfill(pxn_vctx, w, x, T, sb, 12, z, n); + __asm__ volatile("csync" ::: "memory"); + PXN_FFT_CONST = 0; + PXN_FFT_CADR = (uint32_t)(uintptr_t)pxn_vctx; + PXN_FFT_CON = 0x149u; + for (uint32_t k = 0; !(PXN_FFT_CON & 0x80u); k++) + if (k > 400000u) { PXN_FFT_CON = 0; return -1; } + PXN_FFT_CON |= 0x40u; + return 0; +} +/* the same, without waiting (the bench: what runs beside it); pxn_vwait waits for it */ +void pxn_vstart(const int32_t *w, const int32_t *x, int T, int sb, int zb, int32_t *z, int n) +{ + pxn_vfill(pxn_vctx, w, x, T, sb, zb, z, n); + __asm__ volatile("csync" ::: "memory"); + PXN_FFT_CONST = 0; + PXN_FFT_CADR = (uint32_t)(uintptr_t)pxn_vctx; + PXN_FFT_CON = 0x149u; +} +void pxn_vwait(void) +{ + for (uint32_t k = 0; !(PXN_FFT_CON & 0x80u); k++) + if (k > 4000000u) { PXN_FFT_CON = 0; return; } + PXN_FFT_CON |= 0x40u; +} +#else +void pxn_vstart(const int32_t *w, const int32_t *x, int T, int sb, int zb, int32_t *z, int n) +{ + (void)w; (void)x; (void)T; (void)sb; (void)zb; (void)z; (void)n; +} +void pxn_vwait(void) { } +#endif +/* the command queue (mode 2): commands wait in their own contexts; pxn_kick, called often by the CPU's work, starts the + * next one as soon as the unit is done. Counters: queued, started, finished. */ +#if PXN_ASM || defined(PXN_EMUVEC) +#define PXN_VQON 1 +#define PXN_VQ 8 +static volatile uint32_t pxn_vq[PXN_VQ][8] __attribute__((aligned(32))); +static uint32_t pxn_vq_in, pxn_vq_st, pxn_vq_done; +#if PXN_ASM +static inline __attribute__((always_inline)) void pxn_kick(void) +{ + if (pxn_vq_st != pxn_vq_done) { + if (!(PXN_FFT_CON & 0x80u)) return; + PXN_FFT_CON |= 0x40u; + pxn_vq_done++; + } + if (pxn_vq_st != pxn_vq_in) { + __asm__ volatile("csync" ::: "memory"); + PXN_FFT_CONST = 0; + PXN_FFT_CADR = (uint32_t)(uintptr_t)pxn_vq[pxn_vq_st % PXN_VQ]; + PXN_FFT_CON = 0x149u; + pxn_vq_st++; + } +} +#define PXN_VSTOP() (PXN_FFT_CON = 0) +#else +/* PC tests (PXN_EMUVEC): a unit that finishes each command at some later kick, at random, with the C dot product + * reading the X rows then: a row overwritten too early shows as a wrong result */ +static struct { const int32_t *w, *x; int32_t *z; } pxn_vqp[PXN_VQ]; +static uint32_t pxn_emu_r = 1u; +static void pxn_kick(void) +{ + if (pxn_vq_st != pxn_vq_done) { + pxn_emu_r = pxn_emu_r * 1103515245u + 12345u; + if ((pxn_emu_r >> 27) & 3u) return; + const int k = (int)(pxn_vq_done % PXN_VQ); + pxn_dot d = {pxn_vqp[k].w, pxn_vqp[k].x, (int32_t)(pxn_vq[k][4] & 0xFFFu), PXN_S * 4, pxn_vqp[k].z, + (int32_t)(pxn_vq[k][4] >> 12 & 0xFFFu)}; + pxn_dot1_c(&d); + pxn_vq_done++; + } + if (pxn_vq_st != pxn_vq_in) pxn_vq_st++; +} +#define PXN_VSTOP() ((void)0) +static int32_t pxn_emu_fast[PXN_FAST_WORDS]; +void pxn_emu_on(int mode) /* (before pxn_load: the unit's fast copies are tested too) */ +{ + pxn_vec_ok = 1; pxn_vfail = 0; pxn_mode_v = mode; + pxn_xf = pxn_emu_fast; pxn_wf = pxn_emu_fast + (PXN_N + 1) * PXN_S; +} +#endif +/* the unit stopped answering: off for good (the CPU does the rest), queue emptied */ +static void pxn_vdead(void) +{ + PXN_VSTOP(); + pxn_vfail = 1; + pxn_vec_ok = 0; + pxn_vq_in = pxn_vq_st = pxn_vq_done = 0; +} +static int pxn_vupto(uint32_t seq) /* waits until `seq` commands are finished; -1 = unit dead */ +{ + for (uint32_t k = 0; (int32_t)(pxn_vq_done - seq) < 0; k++) { + pxn_kick(); + if (k > 2000000u) { pxn_vdead(); return -1; } + } + return 0; +} +static void pxn_venq(const int32_t *w, const int32_t *x, int T, int32_t *z, int n) +{ + if (pxn_vq_in - pxn_vq_done >= PXN_VQ && pxn_vupto(pxn_vq_in - PXN_VQ + 1)) return; + volatile uint32_t *c = pxn_vq[pxn_vq_in % PXN_VQ]; + pxn_vfill(c, w, x, T, PXN_S * 4, 12, z, n); /* (on the PC: pxn_vqp) */ +#if !PXN_ASM + pxn_vqp[pxn_vq_in % PXN_VQ].w = w; pxn_vqp[pxn_vq_in % PXN_VQ].x = x; pxn_vqp[pxn_vq_in % PXN_VQ].z = z; +#endif + pxn_vq_in++; + pxn_kick(); +} +#else +#define PXN_VQON 0 +#define pxn_kick() ((void)0) +#endif +int pxn_vec_check(void) { return pxn_vec_ok ? (int)pxn_vec_diff : -1 - (pxn_vec_diff >= 0 ? (int)pxn_vec_diff : 0); } + +/* ---- start-up check ---- */ +/* the test pattern: X rows (9 of PXN_S + slack), weight rows, residual rows, both signs, values as large as a model + * meets (+-32); scratch: PXN_TEST_WORDS */ +#define PXN_T_X(s) (s) +#define PXN_T_W(s) ((s) + 10 * PXN_S) +#define PXN_T_RR(s) (PXN_T_W(s) + 3 * PXN_S + 4) +#define PXN_T_O(s, k) (PXN_T_RR(s) + 12 + (k) * 64) /* 8 output areas of 64 words */ +static void pxn_test_data_sh(int32_t *s, int sh) +{ + uint32_t r = 12345u; + for (int i = 0; i < 13 * PXN_S + 16; i++) { + r = r * 1103515245u + 12345u; + s[i] = (int32_t)r >> sh; + } + for (int k = 0; k < 8; k++) + for (int i = 0; i < 64; i++) PXN_T_O(s, k)[i] = i * 77 - 1000; +} +static void pxn_test_data(int32_t *s) { pxn_test_data_sh(s, 6); } +int pxn_selftest(int32_t *scratch) +{ +#if PXN_ASM + int32_t *s = scratch, ok = 1, p2ok = 1, p3ok = 1; + for (int pass = 0; pass < 4 && ok; pass++) { + pxn_test_data(s); + const int T = pass & 1 ? 47 : 20, sb = PXN_S * 4; + pxn_dot d = {PXN_T_W(s), PXN_T_X(s), T, sb, PXN_T_O(s, 0), 2}; + pxn_dot3x4_c(&d); + d.z = PXN_T_O(s, 1); pxn_dot3x4_asm(&d); + d.ng = 3; d.x = PXN_T_X(s) + PXN_S; d.z = PXN_T_O(s, 2) + 1; pxn_dot1_c(&d); + d.z = PXN_T_O(s, 3) + 1; pxn_dot1_asm(&d); + pxn_post p = {PXN_T_O(s, 0), PXN_T_X(s) + 2 + pass, sb, PXN_T_RR(s), PXN_T_O(s, 4), pass < 2 ? PXN_T_O(s, 5) : 0, 7}; + pxn_post_c(&p); + p.hs = PXN_T_O(s, 6); if (p.out) p.out = PXN_T_O(s, 7); + pxn_post_asm(&p); + if (memcmp(PXN_T_O(s, 0), PXN_T_O(s, 1), 64 * 4) || memcmp(PXN_T_O(s, 2), PXN_T_O(s, 3), 64 * 4) || + memcmp(PXN_T_O(s, 4), PXN_T_O(s, 6), 64 * 4) || memcmp(PXN_T_O(s, 5), PXN_T_O(s, 7), 64 * 4)) ok = 0; + { /* post2 against the C post (same z, x, residual; hs and out from the same start): z is O0, still + * the C dot's; hs and out in O2 and O3, whose check is done */ + int32_t *r2 = PXN_T_O(s, 8); + pxn_rr2(PXN_T_RR(s), r2); + for (int i = 0; i < 64; i++) PXN_T_O(s, 2)[i] = PXN_T_O(s, 3)[i] = i * 77 - 1000; + pxn_post q = p; + q.hs = PXN_T_O(s, 2); if (q.out) q.out = PXN_T_O(s, 3); + q.rr2 = r2; + pxn_post2_asm(&q); + if (memcmp(PXN_T_O(s, 2), PXN_T_O(s, 4), 64 * 4) || memcmp(PXN_T_O(s, 3), PXN_T_O(s, 5), 64 * 4)) p2ok = 0; + for (int i = 0; i < 64; i++) PXN_T_O(s, 2)[i] = PXN_T_O(s, 3)[i] = i * 77 - 1000; + pxn_post3_asm(&q); /* post3: the same check */ + if (memcmp(PXN_T_O(s, 2), PXN_T_O(s, 4), 64 * 4) || memcmp(PXN_T_O(s, 3), PXN_T_O(s, 5), 64 * 4)) p3ok = 0; + } + pxn_gcopy_c(PXN_T_O(s, 0), PXN_T_W(s) + pass, 5, 40); + pxn_gcopy_asm(PXN_T_O(s, 1), PXN_T_W(s) + pass, 5, 40); + if (memcmp(PXN_T_O(s, 0), PXN_T_O(s, 1), 64 * 4)) ok = 0; + } + { /* rdot: 3 rows of 6 taps, 3 rows of 15, the head's 1 row of 16, against the C one */ + int rok = 1; + for (int pass = 0; pass < 3 && rok; pass++) { + pxn_test_data(s); + const int K = pass == 0 ? 6 : pass == 1 ? 15 : 16, rows = pass == 2 ? 1 : 3; + const int32_t *tp[16]; + for (int k = 0; k < K; k++) tp[k] = PXN_T_X(s) + 3 * (k * 5 + pass); + pxn_rdot j = {PXN_T_W(s), tp, K, PXN_T_X(s) + 400, PXN_T_O(s, 0), rows}; + pxn_rdot_c(&j); + j.z = PXN_T_O(s, 1); + pxn_rdot_asm(&j); + if (memcmp(PXN_T_O(s, 0), PXN_T_O(s, 1), 64 * 4)) rok = 0; + if (K == 6) { + j.z = PXN_T_O(s, 2); + pxn_rdot6_asm(&j); + if (memcmp(PXN_T_O(s, 0), PXN_T_O(s, 2), 64 * 4)) rok = 0; + } + } + pxn_rdot_f = rok ? pxn_rdot_asm : pxn_rdot_c; + pxn_rdot6_f = rok ? pxn_rdot6_asm : pxn_rdot_c; + /* the load-ahead routines: 3 rows of 6 and 15 taps, 1 and 3 rows of 16, each against C */ + static void (*const Q[3])(const pxn_rdot *) = {pxn_rdq6_asm, pxn_rdq15_asm, pxn_rdq16_asm}; + static const uint8_t QK[3] = {6, 15, 16}; + for (int q = 0; q < 3; q++) { + int qok = 1; + for (int pass = 0; pass < 4 && qok; pass++) { + pxn_test_data(s); + const int K = QK[q], rows = pass & 1 ? 1 : 3; + const int32_t *tp[16]; + for (int k = 0; k < K; k++) tp[k] = PXN_T_X(s) + 3 * (k * 5 + pass); + pxn_rdot j = {PXN_T_W(s), tp, K, PXN_T_X(s) + 400, PXN_T_O(s, 0), rows}; + pxn_rdot_c(&j); + j.z = PXN_T_O(s, 1); + Q[q](&j); + if (memcmp(PXN_T_O(s, 0), PXN_T_O(s, 1), 64 * 4)) qok = 0; + } + pxn_rdq_f[QK[q]] = qok ? Q[q] : 0; + } + /* rdl: 3 groups of 3 rows (6, 15 taps) and of 1 row (16), on a "ring" whose end some taps pass (brought back + * by its length), against the C one: outputs, and the job's u and z after */ + static void (*const R[3])(pxn_rdot *) = {pxn_rdl6_asm, pxn_rdl15_asm, pxn_rdl16_asm}; + for (int q = 0; q < 3; q++) { + int lok = 1; + for (int pass = 0; pass < 2 && lok; pass++) { + pxn_test_data(s); + const int K = QK[q], rows = q == 2 ? 1 : 3; + const int32_t *tp[16]; + for (int k = 0; k < K; k++) tp[k] = PXN_T_X(s) + 3 * (k * 5 + pass); + pxn_rdot j = {PXN_T_W(s), tp, K, PXN_T_X(s) + 400, PXN_T_O(s, 0), rows, 3, + PXN_T_X(s) + 3 * (K * 4), -3 * (K * 3) * 4}; + pxn_rdot c = j; + pxn_rdl_c(&c); + j.z = PXN_T_O(s, 1); + R[q](&j); + if (memcmp(PXN_T_O(s, 0), PXN_T_O(s, 1), 64 * 4) || j.u != c.u || j.z - PXN_T_O(s, 1) != c.z - PXN_T_O(s, 0)) + lok = 0; + } + pxn_rdl_f[QK[q]] = lok && pxn_rdq_f[QK[q]] ? R[q] : 0; + } + } + if (ok) { + pxn_dot3x4 = pxn_dot3x4_asm; pxn_dot1 = pxn_dot1_asm; pxn_gcopy = pxn_gcopy_asm; + pxn_post_f = p2ok ? pxn_post2_asm : pxn_post_asm; + pxn_p3ok = (uint8_t)(p2ok && p3ok); /* pxn_tune times post3 against post2 */ + } + /* the vector unit: rows of 20 and 47 over 8 X rows, against the C dot */ + { + int vok = 1; + int32_t maxd = 0; + for (int pass = 0; pass < 2 && vok; pass++) { + pxn_test_data_sh(s, 9); /* +-4 (the z values a model gives fit in 32 bits) */ + const int T = pass ? 47 : 20; + pxn_dot d = {PXN_T_W(s), PXN_T_X(s), T, PXN_S * 4, PXN_T_O(s, 0), 8}; + pxn_dot1_c(&d); + if (pxn_vdot(PXN_T_W(s), PXN_T_X(s), T, PXN_S * 4, PXN_T_O(s, 1), 8)) { vok = 0; maxd = 99999; break; } + for (int f = 0; f < 8; f++) { + int32_t df = PXN_T_O(s, 0)[3 * f] - PXN_T_O(s, 1)[3 * f]; + if (df < 0) df = -df; + if (df > maxd) maxd = df; + } + } + pxn_vec_diff = maxd; + pxn_vec_ok = (uint8_t)(vok && maxd <= 1); + pxn_vfail = 0; + pxn_mode_v = pxn_vec_ok ? 1 : 0; + } + /* the fast memory offered (pxn_set_fast): the unit reading X rows and weights there, against the C dot */ + pxn_xf = pxn_wf = 0; + if (pxn_fast && pxn_vec_ok) { + int32_t *xf = pxn_fast, *wf = pxn_fast + (PXN_N + 1) * PXN_S, fok = 1; + for (int pass = 0; pass < 2 && fok; pass++) { + pxn_test_data_sh(s, 9); + const int T = pass ? 47 : 20; + memcpy(xf, PXN_T_X(s), 9u * PXN_S * 4u); + memcpy(wf, PXN_T_W(s), (unsigned)T * 4u + 4u); + pxn_dot d = {PXN_T_W(s), PXN_T_X(s), T, PXN_S * 4, PXN_T_O(s, 0), 8}; + pxn_dot1_c(&d); + if (pxn_vdot(wf, xf, T, PXN_S * 4, PXN_T_O(s, 1), 8)) { fok = 0; break; } + for (int f = 0; f < 8; f++) { + int32_t df = PXN_T_O(s, 0)[3 * f] - PXN_T_O(s, 1)[3 * f]; + if (df < -1 || df > 1) fok = 0; + } + } + if (fok) { pxn_xf = xf; pxn_wf = wf; } + } + return ok; +#else + (void)scratch; + return 0; +#endif +} +int pxn_post2_in_use(void) +{ +#if PXN_ASM + return pxn_post_f == pxn_post2_asm || pxn_post_f == pxn_post3_asm; +#else + return 0; +#endif +} +void pxn_set_fast(int32_t *base, unsigned bytes) { pxn_fast = bytes >= PXN_FAST_WORDS * 4u ? base : 0; } +int pxn_fast_in_use(void) { return pxn_xf != 0; } +int pxn_rdot_chosen(void) { return pxn_rd; } +int pxn_rdq_in_use(void) { return pxn_rdq_on && pxn_rdq_f[6]; } +int pxn_rdl_state(void) { return pxn_rdl_f[6] && pxn_rdl_f[15] && pxn_rdl_f[16] ? 1 + (pxn_rdl_on != 0) : 0; } +int pxn_rdq_checked(void) { return pxn_rdq_f[6] && pxn_rdq_f[15] && pxn_rdq_f[16]; } +int pxn_rdot_in_use(void) +{ +#if PXN_ASM + return pxn_rdot_f == pxn_rdot_asm; +#else + return 0; +#endif +} +int pxn_asm_in_use(void) +{ +#if PXN_ASM + return pxn_dot3x4 == pxn_dot3x4_asm; +#else + return 0; +#endif +} + +/* ---- measurements for the firmware's bench screen (BENCH_AT_BOOT) ---- */ +/* ticks for `reps` runs of the work of one kernel-6 layer over 32 frames (gather 6 taps, 3 dot rows of 20, post with + * the residual): 1,920 multiply-adds a run. hand: the hand routines (if any), else C. scratch: PXN_TEST_WORDS */ +uint32_t pxn_bench_layer(int32_t *scratch, uint32_t (*ticks)(void), int hand, int reps) +{ + static int32_t ring[3 * 64]; + int32_t *s = scratch; + void (*d4)(const pxn_dot *) = pxn_dot3x4_c; + void (*po)(const pxn_post *) = pxn_post_c; + void (*gc)(int32_t *, const int32_t *, int, int) = pxn_gcopy_c; +#if PXN_ASM + if (hand) { d4 = pxn_dot3x4_asm; po = pxn_post_asm; gc = pxn_gcopy_asm; } +#else + (void)hand; +#endif + pxn_test_data(s); + uint32_t t0 = ticks(); + for (int r = 0; r < reps; r++) { + for (int k = 0; k < 6; k++) gc(pxn_x + 2 + 3 * k, ring + 3 * k, 32, PXN_S * 4); + pxn_dot d = {PXN_T_W(s), pxn_x, 20, PXN_S * 4, pxn_z, 8}; + d4(&d); + pxn_post p = {pxn_z, pxn_x + 17, PXN_S * 4, PXN_T_RR(s), pxn_hs, ring, 32, 0}; + po(&p); + } + return ticks() - t0; +} + +/* ticks for `reps` runs of one part of that layer work, by hand (C without hand code): 0 the dot (3 rows of 20 for + * 32 frames: 1,920 multiply-adds), 1 the gather (6 taps x 32 frames), 2 the post (32 frames, with the residual) */ +uint32_t pxn_bench_part(int32_t *scratch, uint32_t (*ticks)(void), int part, int reps) +{ + static int32_t ring[3 * 64]; + int32_t *s = scratch; + pxn_test_data(s); + pxn_dot d = {PXN_T_W(s), pxn_x, 20, PXN_S * 4, pxn_z, 8}; + pxn_post p = {pxn_z, pxn_x + 17, PXN_S * 4, PXN_T_RR(s), pxn_hs, ring, 32, 0}; + uint32_t t0 = ticks(); + for (int r = 0; r < reps; r++) { +#if PXN_ASM + if (part == 3) { for (int o = 0; o < 3; o++) pxn_vdot(d.w + 20 * o, pxn_x, 20, PXN_S * 4, pxn_z + o, 32); } + else if (part == 0) pxn_dot3x4_asm(&d); + else if (part == 1) for (int k = 0; k < 6; k++) pxn_gcopy_asm(pxn_x + 2 + 3 * k, ring + 3 * k, 32, PXN_S * 4); + else pxn_post_asm(&p); +#else + if (part == 0) pxn_dot3x4_c(&d); + else if (part == 1) for (int k = 0; k < 6; k++) pxn_gcopy_c(pxn_x + 2 + 3 * k, ring + 3 * k, 32, PXN_S * 4); + else pxn_post_c(&p); +#endif + } + return ticks() - t0; +} + +/* ticks for `reps` runs of a layer's dot work over 32 frames (3 rows of 20: 1,920 multiply-adds), on buffers given + * (x: 33 rows of PXN_S words, w: 64 words, z: 100 words), by the CPU routine (vec 0) or the vector unit (vec 1); + * then of the post over 32 frames on one buffer (4,000 words: z, X rows, rr, hs, out). For the bench screen: + * where the data sits changes the cost on this chip. */ +uint32_t pxn_bench_dot(int32_t *x, int32_t *w, int32_t *z, int vec, uint32_t (*ticks)(void), int reps) +{ + uint32_t r = 777u; + for (int i = 0; i < 33 * PXN_S; i++) { r = r * 1103515245u + 12345u; x[i] = (int32_t)r >> 10; } + for (int i = 0; i < 64; i++) { r = r * 1103515245u + 12345u; w[i] = (int32_t)r >> 10; } + pxn_dot d = {w, x, 20, PXN_S * 4, z, 8}; + uint32_t t0 = ticks(); + for (int k = 0; k < reps; k++) { +#if PXN_ASM + if (vec) { for (int o = 0; o < 3; o++) pxn_vdot(w + 20 * o, x, 20, PXN_S * 4, z + o, 32); } + else pxn_dot3x4_asm(&d); +#else + (void)vec; + pxn_dot3x4_c(&d); +#endif + } + return ticks() - t0; +} +uint32_t pxn_bench_post(int32_t *b, uint32_t (*ticks)(void), int reps, int v2) +{ + int32_t *z = b, *x = b + 100, *rr = b + 100 + 33 * PXN_S, *rr2 = rr + 12, *hs = rr + 32, *out = hs + 100; + uint32_t r = 99u; + for (int i = 0; i < 4000; i++) { r = r * 1103515245u + 12345u; b[i] = (int32_t)r >> 10; } + pxn_rr2(rr, rr2); + pxn_post p = {z, x + 17, PXN_S * 4, rr, hs, out, 32, rr2}; + uint32_t t0 = ticks(); + for (int k = 0; k < reps; k++) { +#if PXN_ASM + if (v2) pxn_post2_asm(&p); else pxn_post_asm(&p); +#else + (void)v2; + pxn_post_c(&p); +#endif + } + return ticks() - t0; +} +/* ticks for `reps` vector commands of nloop dot products of nlen words (x moving xs bytes and z zs bytes a loop), + * each waited for; start_only: only the CPU's part of starting one (it is waited for outside the timing). + * buf: 40,000 words (x from 0, the weights at 30,000, z at 31,000) */ +uint32_t pxn_bench_vcmd(int32_t *buf, uint32_t (*ticks)(void), int nlen, int nloop, int xs, int zs, int reps, int start_only) +{ +#if PXN_ASM + int32_t *x = buf, *w = buf + 30000, *z = buf + 31000; + for (int i = 0; i < 1000; i++) { w[i] = i * 13 - 6000; x[i] = 3000 - i * 7; } + uint32_t dt = 0; + if (start_only) { + for (int k = 0; k < reps; k++) { + uint32_t t0 = ticks(); + pxn_vstart(w, x, nlen, xs, zs, z, nloop); + dt += ticks() - t0; + pxn_vwait(); + } + return dt; + } + uint32_t t0 = ticks(); + for (int k = 0; k < reps; k++) { pxn_vstart(w, x, nlen, xs, zs, z, nloop); pxn_vwait(); } + return ticks() - t0; +#else + (void)buf; (void)ticks; (void)nlen; (void)nloop; (void)xs; (void)zs; (void)reps; (void)start_only; + return 0; +#endif +} + +/* the vector unit's speed by shape (v37 diagnostic 11): one command of nloop dot products of 20 words, waited for; + * ticks. v: 0 1000 loops, x step 0, z step 0, x and weights at one address, small values (an earlier measurement gave + * 1.5 cycles a multiply-add like this); 1 the same with 32 loops; 2 z step 12; 3 x and weights apart; 4 large values; + * 5 the network's shape (500 loops, x step 80, z step 12, apart, large values); 6 the same, the CPU not reading the + * unit's register for the first half (a loop on registers only); 7 as 5 with the engine's X row stride (200 bytes). + * buf: 21,000 words */ +#if PXN_ASM +static void __attribute__((noinline)) pxn_spin(uint32_t n) { for (uint32_t i = 0; i < n; i++) __asm__ volatile(""); } +#endif +uint32_t pxn_bench_vfast(int32_t *buf, uint32_t (*ticks)(void), int v) +{ +#if PXN_ASM + int32_t *x = buf, *w = v == 3 || v >= 5 ? buf + 12000 : buf, *z = buf + 13000; + const int big = v >= 4, nloop = v == 1 ? 32 : v == 7 ? 200 : v >= 5 ? 500 : 1000; + const int xs = v == 7 ? 200 : v >= 5 ? 80 : 0, zs = v == 2 || v >= 5 ? 12 : 0; + uint32_t r = 2468u; + for (int i = 0; i < 12100; i++) { + r = r * 1103515245u + 12345u; + buf[i] = big ? (int32_t)r >> 6 : 3000 - (i % 1000) * 7; + } + if (v == 6) { + uint32_t t0 = ticks(); + pxn_spin(100000u); + const uint32_t per = ticks() - t0; /* ticks for 100,000 turns of the register loop */ + t0 = ticks(); + pxn_vstart(w, x, 20, xs, zs, z, nloop); + pxn_vwait(); + const uint32_t whole = ticks() - t0; + t0 = ticks(); + pxn_vstart(w, x, 20, xs, zs, z, nloop); + pxn_spin(per ? (uint32_t)((uint64_t)whole * 100000u / per / 2u) : 0u); + pxn_vwait(); + return ticks() - t0; + } + uint32_t t0 = ticks(); + pxn_vstart(w, x, 20, xs, zs, z, nloop); + pxn_vwait(); + return ticks() - t0; +#else + (void)buf; (void)ticks; (void)v; + return 0; +#endif +} +int pxn_vfast_macs(int v) { return 20 * (v == 1 ? 32 : v == 7 ? 200 : v >= 5 ? 500 : 1000); } + +#if PXN_ASM +/* one instruction (or pair) n times in the hardware loop: what each kind costs on this CPU */ +#define PXN_UB(name, body) \ + "\t.global " name "\n" name ":\n\t[--sp] = {rets, r15-r4}\n" \ + "\tr4 = 0\n\tr5 = 0\n\tr6 = 0\n\tr7 = 0\n\tr3 = 5\n\tr10 = 3\n\tr12 = 4\n\tr2 = r0\n\tr11 = r1\n" \ + ".L" name ":\n\trep r11 {\n" body "\t}\n\tif (r11 != 0) goto .L" name "\n" \ + "\t{pc, r15-r4} = [sp++]\n" +__asm__("\t.text\n" + PXN_UB("pxn_ub_ld", "\tr3 = [r2++=4]\n") + PXN_UB("pxn_ub_ldd", "\tr5_r4 = d[r2++=8]\n") + PXN_UB("pxn_ub_ldm3", "\t{r6-r4} = [r2++]\n") + PXN_UB("pxn_ub_st", "\t[r2++=4] = r3\n") + PXN_UB("pxn_ub_rmac", "\tr5_r4 += r3 * r10 (s)\n") + PXN_UB("pxn_ub_pair", "\tr5_r4 += r3 * r10 (s) # r3 = [r2++=4]\n") + PXN_UB("pxn_ub_fmac", "\tr5_r4 += [r2 ++= r12]*r10 (s)\n") + PXN_UB("pxn_ub_rmac2", "\tr5_r4 += r3 * r10 (s)\n\tr7_r6 += r3 * r10 (s)\n") + /* diagnostic 12: a multiply-add paired with a load whose value it does not use (nd), 2 or 4 accumulators, with + * and without each multiply using the value the pair before loaded (the hand routines do) */ + PXN_UB("pxn_ub_pnd", "\tr5_r4 += r3 * r10 (s) # r6 = [r2++=4]\n") + PXN_UB("pxn_ub_p2nd", "\tr5_r4 += r3 * r10 (s) # r6 = [r2++=4]\n\tr9_r8 += r3 * r10 (s) # r7 = [r2++=4]\n") + PXN_UB("pxn_ub_p4dep", "\tr5_r4 += r3 * r10 (s) # r3 = [r2++=4]\n\tr9_r8 += r3 * r10 (s) # r3 = [r2++=4]\n" + "\tr15_r14 += r3 * r10 (s) # r3 = [r2++=4]\n\tr7_r6 += r3 * r10 (s) # r3 = [r2++=4]\n") + PXN_UB("pxn_ub_p4nd", "\tr5_r4 += r3 * r10 (s) # r1 = [r2++=4]\n\tr9_r8 += r3 * r10 (s) # r1 = [r2++=4]\n" + "\tr15_r14 += r3 * r10 (s) # r1 = [r2++=4]\n\tr7_r6 += r3 * r10 (s) # r1 = [r2++=4]\n")); +void pxn_ub_ld(const int32_t *, int), pxn_ub_ldd(const int32_t *, int), pxn_ub_ldm3(const int32_t *, int), + pxn_ub_st(const int32_t *, int), pxn_ub_rmac(const int32_t *, int), pxn_ub_pair(const int32_t *, int), + pxn_ub_fmac(const int32_t *, int), pxn_ub_rmac2(const int32_t *, int), pxn_ub_pnd(const int32_t *, int), + pxn_ub_p2nd(const int32_t *, int), pxn_ub_p4dep(const int32_t *, int), pxn_ub_p4nd(const int32_t *, int); +#endif +/* ticks for reps x n loops of `kind`: 0 load, 1 64-bit load, 2 3-word load, 3 store, 4 multiply-add (registers), + * 5 multiply-add paired with a load, 6 multiply-add with its load, 7 two multiply-adds; buf: 1024 words. n: the + * loop count used (written). 0 without hand code. */ +uint32_t pxn_bench_ops(int kind, int32_t *buf, int reps, int *n, uint32_t (*ticks)(void)) +{ +#if PXN_ASM + static void (*const F[12])(const int32_t *, int) = {pxn_ub_ld, pxn_ub_ldd, pxn_ub_ldm3, pxn_ub_st, + pxn_ub_rmac, pxn_ub_pair, pxn_ub_fmac, pxn_ub_rmac2, + pxn_ub_pnd, pxn_ub_p2nd, pxn_ub_p4dep, pxn_ub_p4nd}; + static const int N[12] = {1024, 512, 340, 1024, 1024, 1024, 1024, 1024, 1024, 512, 256, 256}; + static const int P[12] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 4}; /* loads (pairs) a loop */ + if (kind < 0 || kind > 11) kind = 0; + *n = N[kind] * P[kind]; + uint32_t t0 = ticks(); + for (int r = 0; r < reps; r++) F[kind](buf, N[kind]); + return ticks() - t0; +#else + (void)kind; (void)buf; (void)reps; (void)ticks; + *n = 1; + return 0; +#endif +} + +/* ---- loading ---- */ +static int pxn_finite(float x) +{ + union { float f; uint32_t u; } v; + v.f = x; + return (v.u & 0x7F800000u) != 0x7F800000u; +} +/* to fixed point with q fraction bits, rounded and clamped (real A2 weights stay below 2) */ +static int32_t pxn_toq(float x, int32_t q) +{ + float v = x * (float)(1u << q); + if (v >= 2147483520.0f) return 2147483647; + if (v <= -2147483520.0f) return -2147483647; + return (int32_t)(v < 0.0f ? v - 0.5f : v + 0.5f); +} + +/* the rings, largest first, each into the piece where it fits best (the smaller leftover) */ +static int pxn_rings(pxn_model *m, int32_t *r0, unsigned n0, int32_t *r1, unsigned n1) +{ + unsigned need[PXN_NL + 1]; + for (int i = 0; i < PXN_NL; i++) need[i] = (unsigned)(m->L[i].len + PXN_MIR) * PXN_C * 4u; + need[PXN_NL] = (unsigned)(m->hlen + PXN_MIR) * PXN_C * 4u; + uint32_t done = 0; + for (int t = 0; t <= PXN_NL; t++) { + int b = -1; + for (int i = 0; i <= PXN_NL; i++) + if (!(done >> i & 1u) && (b < 0 || need[i] > need[b])) b = i; + done |= 1u << b; + int32_t **pp; unsigned *pn; + const int f0 = n0 >= need[b], f1 = n1 >= need[b]; + if (!f0 && !f1) return -2; + if (f0 && (!f1 || n0 <= n1)) { pp = &r0; pn = &n0; } else { pp = &r1; pn = &n1; } + if (b == PXN_NL) m->hring = *pp; else m->L[b].ring = *pp; + *pp += need[b] / 4u; + *pn -= need[b]; + } + return 0; +} + +int pxn_load(pxn_model *m, const float *w, int32_t *r0, unsigned n0, int32_t *r1, unsigned n1) +{ + m->ready = 0; +#if !PXN_ASM + pxn_rdl_f[6] = pxn_rdl_f[15] = pxn_rdl_f[16] = pxn_rdl_c; /* the PC: the one-call path, by the C routine */ +#endif + for (int i = 0; i < PXN_NW; i++) + if (!pxn_finite(w[i])) return -1; + const float *p = w; + for (int c = 0; c < PXN_C; c++) m->rech[c] = pxn_toq(p[c], PXN_QW); + p += PXN_C; + int32_t off = 0; + for (int i = 0; i < PXN_NL; i++) { + pxn_layer *L = &m->L[i]; + const int K = pxn_k[i], T = 3 * K + 2; + const float *conv = p, *cb = p + 9 * K, *mix = cb + 3, *one = mix + 3, *ob = one + 9; + /* row o: [mixin, bias, then for each kernel tap k its 3 input channels], as the X rows. File: conv [o][c][k] */ + for (int o = 0; o < PXN_C; o++) { + int32_t *d = m->wa + off + o * T; + d[0] = pxn_toq(mix[o], PXN_QW); + d[1] = pxn_toq(cb[o], PXN_QW); + for (int k = 0; k < K; k++) + for (int c = 0; c < PXN_C; c++) d[2 + 3 * k + c] = pxn_toq(conv[(o * PXN_C + c) * K + k], PXN_QW); + for (int c = 0; c < PXN_C; c++) L->rr[o * 4 + c] = pxn_toq(one[o * PXN_C + c], PXN_QW); + L->rr[o * 4 + 3] = pxn_toq(ob[o], PXN_QA); + } + pxn_rr2(L->rr, L->rr2); + L->k = (int16_t)K; + L->d = (int16_t)pxn_d[i]; + L->off = off; + L->len = (K - 1) * pxn_d[i] + PXN_N; + off += 3 * T; + p = ob + 3; + } + /* head row: [u (0), bias, then for each of its 16 taps the 3 channels]. File: head [c][k], bias, scale */ + m->head[0] = 0; + m->head[1] = pxn_toq(p[PXN_C * PXN_HK], PXN_QW); + for (int k = 0; k < PXN_HK; k++) + for (int c = 0; c < PXN_C; c++) m->head[2 + 3 * k + c] = pxn_toq(p[c * PXN_HK + k], PXN_QW); + m->out_gain = p[PXN_C * PXN_HK + 1] * (1.0f / 1048576.0f); + m->hlen = (PXN_HK - 1) + PXN_N; + if (pxn_wf) { /* the vector unit's copy */ + memcpy(pxn_wf, m->wa, sizeof m->wa); + memcpy(pxn_wf + PXN_WF_HEAD, m->head, sizeof m->head); + } + if (pxn_rings(m, r0, n0, r1, n1)) return -2; + pxn_reset(m); + m->ready = 1; + return 0; +} + +void pxn_reset(pxn_model *m) +{ + for (int i = 0; i < PXN_NL; i++) { + pxn_layer *L = &m->L[i]; + memset(L->ring, 0, (unsigned)(L->len + PXN_MIR) * PXN_C * 4u); + L->w = 0; + } + memset(m->hring, 0, (unsigned)(m->hlen + PXN_MIR) * PXN_C * 4u); + m->hw = 0; +} + +/* the vector unit's copy of a weight row: in the fast memory if in use (pxn_set_fast), else the row itself */ +static __attribute__((unused)) const int32_t *pxn_uw(const pxn_model *m, const int32_t *w) +{ + if (!pxn_wf) return w; + if (w >= m->head && w < m->head + PXN_S + 4) return pxn_wf + PXN_WF_HEAD + (w - m->head); + return pxn_wf + (w - m->wa); +} +/* ---- one block ---- */ +/* how each mode runs (pxn_tune picks one): h > 0: two cores, the helper core takes frames 0 .. h-1 (it never waits: + * earlier frames never need later ones), the calling core the rest; pipe: the vector unit beside the calling core + * (block or range in two halves), the CPU taking c frames of each half's dot products itself */ +static const struct { uint8_t h, pipe, c; } PXN_MC[PXN_MODES] = { + {0, 0, 0}, {0, 0, 0}, {0, 1, 0}, {0, 1, 4}, {0, 1, 8}, {16, 0, 0}, {12, 1, 0}, {16, 1, 0}, {12, 1, 4}, + {20, 0, 0}, {24, 0, 0}}; +/* the K taps (dilation d) of frames f0 .. f0+n-1 of the block (the block starts at ring position w) into X columns 2..; + * kick: this core drives the vector unit */ +static void pxn_gather(const int32_t *ring, int32_t len, int32_t w, int K, int d, int f0, int n, int kick) +{ + for (int k = 0; k < K; k++) { + int32_t s = w + f0 - (K - 1 - k) * d; + if (s < 0) s += len; + if (s >= len) s -= len; + int n1 = len - s; + if (n1 > n) n1 = n; + int32_t *x = pxn_x + f0 * PXN_S + 2 + 3 * k; + pxn_gcopy(x, ring + 3 * s, n1, PXN_S * 4); + if (n1 < n) pxn_gcopy(x + n1 * PXN_S, ring, n - n1, PXN_S * 4); + if (kick) pxn_kick(); + } +} +/* rows weight rows (1, or the 3 of a layer, contiguous) over X rows f0 .. f0+n-1 -> pxn_z, by the CPU */ +static void pxn_rows_cpu(const int32_t *w, int T, int rows, int f0, int n) +{ + const int n4 = rows == PXN_C ? n & ~3 : 0; + pxn_dot d = {w, pxn_x + f0 * PXN_S, T, PXN_S * 4, pxn_z + 3 * f0, n4 >> 2}; + if (n4) pxn_dot3x4(&d); + if (n4 < n) + for (int o = 0; o < rows; o++) { + d.w = w + o * T; d.x = pxn_x + (f0 + n4) * PXN_S; d.z = pxn_z + 3 * (f0 + n4) + o; d.ng = n - n4; + pxn_dot1(&d); + } +} +/* the same, on the vector unit one command after the other if mode 1 or more */ +static void pxn_rows(const pxn_model *m, const int32_t *w, int T, int rows, int n) +{ +#if PXN_ASM + if (pxn_mode_v && pxn_vec_ok) { + for (int o = 0; o < rows; o++) + if (pxn_vdot(pxn_uw(m, w + o * T), pxn_x, T, PXN_S * 4, pxn_z + o, n)) { pxn_vec_ok = 0; break; } + if (pxn_vec_ok) return; + } +#else + (void)m; +#endif + pxn_rows_cpu(w, T, rows, 0, n); +} +/* a ring's first PXN_MIR frames are mirrored after its end, so that 4 frames from any position read straight on: the + * frames p .. p+c-1 just written, those of them below PXN_MIR copied (only those: the other core may be writing the + * others) */ +static inline void pxn_mir(int32_t *ring, int32_t len, int32_t p, int c) +{ + for (; c > 0 && p < PXN_MIR; c--, p++) { + int32_t *a = ring + 3 * p, *b = ring + 3 * (len + p); + b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; + } +} +/* layer i's post for frames f0 .. f0+n-1: LeakyReLU, head sum, residual into the next layer's ring (its block starts + * at its write position, still the one before this block); in pieces of 4 frames, the vector unit kicked between */ +static void pxn_post_part(pxn_model *m, int i, int f0, int n, int kick, int ring) +{ + pxn_layer *L = &m->L[i]; + const int K = L->k; + pxn_post p = {pxn_z + 3 * f0, pxn_x + f0 * PXN_S + 2 + 3 * (K - 1), PXN_S * 4, L->rr, pxn_hs + 3 * f0, 0, 0, L->rr2}; + pxn_layer *N = i < PXN_NL - 1 ? &m->L[i + 1] : 0; + int32_t w = N ? N->w + f0 : 0, r = L->w + f0; /* r: the layer's own input in its ring (ring = 1) */ + if (N && w >= N->len) w -= N->len; + if (r >= L->len) r -= L->len; + if (ring) p.sb = 12; + while (n > 0) { + int c = n < pxn_pc ? n : pxn_pc; + if (N) { + if (c > N->len - w) c = N->len - w; + p.out = N->ring + 3 * w; + } + if (ring) { + if (c > L->len - r) c = L->len - r; + p.x = L->ring + 3 * r; + r += c; + if (r == L->len) r = 0; + } + const int32_t wc = w; + if (N) { w += c; if (w == N->len) w = 0; } + p.n = c; + pxn_post_f(&p); + if (N && wc < PXN_MIR) pxn_mir(N->ring, N->len, wc, c); + if (kick) pxn_kick(); + p.z += 3 * c; p.x += c * (p.sb / 4); p.hs += 3 * c; + n -= c; + } +} +static void pxn_layer_block(pxn_model *m, int i, int n) +{ + pxn_layer *L = &m->L[i]; + const int K = L->k, T = 3 * K + 2; + pxn_gather(L->ring, L->len, L->w, K, L->d, 0, n, 1); + pxn_rows(m, m->wa + L->off, T, PXN_C, n); + pxn_post_part(m, i, 0, n, 1, 0); +} +/* rows weight rows (3 of a layer, or the head's 1) for frames f0 .. f0+n-1 by the CPU straight from a ring (its block + * starting at position w): groups of 4 frames by rdot, a rest of 1 .. 3 frames gathered. core: whose tables (0 the + * calling core, 1 the helper) */ +static void pxn_direct(const int32_t *ring, int32_t len, int32_t w, int K, int d, const int32_t *wr, int rows, int f0, + int n, int core, int kick) +{ + const int32_t **tp = pxn_tpt[core]; + const int n4 = pxn_rd ? n & ~3 : 0; + uint32_t t0 = PXN_T(); + if (n4) { + /* each tap's first 4 frames, then 4 frames on per group: read straight on past the end (the mirrored frames), + * the pointer brought back by the ring's length once past it (diagnostic 19: no position arithmetic per tap) */ + const int32_t *const end = ring + 3 * len; + for (int k = 0; k < K; k++) { + int32_t s = w + f0 - (K - 1 - k) * d; + while (s < 0) s += len; + while (s >= len) s -= len; + tp[k] = ring + 3 * s; + } + void (*const q)(const pxn_rdot *) = pxn_rdq_on && pxn_rdq_f[K] ? pxn_rdq_f[K] : K == 6 ? pxn_rdot6_f : pxn_rdot_f; + pxn_rdot j = {wr, tp, K, pxn_u + f0, pxn_z + 3 * f0, rows, n4 / 4, end, -3 * len * 4}; + if (pxn_rdl_on && pxn_rdl_f[K] && pxn_pc != 4) { /* the whole block in one call (no unit to kick) */ + if (!pxn_pskip) pxn_rdl_f[K](&j); + } else + for (int g = 0; g < n4; g += 4) { + if (!pxn_pskip) q(&j); + if (kick) pxn_kick(); + j.u += 4; j.z += 12; +#define PXN_ADV(k) do { const int32_t *p_ = tp[k] + 12; if (p_ >= end) p_ -= 3 * len; tp[k] = p_; } while (0) + if (K == 6) { PXN_ADV(0); PXN_ADV(1); PXN_ADV(2); PXN_ADV(3); PXN_ADV(4); PXN_ADV(5); } /* (no loop branch) */ + else for (int k = 0; k < K; k++) PXN_ADV(k); +#undef PXN_ADV + } + } + uint32_t t1 = PXN_T(); + if (n4 < n) { + pxn_gather(ring, len, w, K, d, f0 + n4, n - n4, kick); + pxn_rows_cpu(wr, 3 * K + 2, rows, f0 + n4, n - n4); + } + if (pxn_pt) { pxn_prof[pxn_pd] += t1 - t0; pxn_prof[pxn_pd + 1] += PXN_T() - t1; } +} +/* layer i for frames f0 .. f0+n-1, by the CPU alone */ +static void pxn_range_cpu(pxn_model *m, int i, int f0, int n, int kick, int core) +{ + pxn_layer *L = &m->L[i]; + pxn_direct(L->ring, L->len, L->w, L->k, L->d, m->wa + L->off, PXN_C, f0, n, core, kick); + uint32_t t0 = PXN_T(); + pxn_post_part(m, i, f0, n, kick, 1); + if (pxn_pt) pxn_prof[3] += PXN_T() - t0; +} + +/* ---- two cores: the helper (the other core, through the caller's job functions) takes the first h frames ---- */ +static int (*pxn_hrun)(void (*fn)(uint32_t), uint32_t arg); /* 1 = the other core has the job */ +static int (*pxn_hwait)(void); /* 0 = done, -1 = dropped */ +void pxn_set_helper(int (*run)(void (*fn)(uint32_t), uint32_t arg), int (*wait)(void)) { pxn_hrun = run; pxn_hwait = wait; } +static struct { pxn_model *m; int32_t h; volatile int32_t done; } pxn_hj; /* done: layers the helper has posted */ +static uint8_t pxn_hon, pxn_hdead; +#define PXN_SYNC() __asm__ volatile("" ::: "memory") +#if PXN_ASM +#undef PXN_SYNC +#define PXN_SYNC() __asm__ volatile("csync" ::: "memory") +#endif +static void pxn_help_job(uint32_t arg) /* on the helper core */ +{ + (void)arg; + for (int i = 0; i < PXN_NL; i++) { + pxn_range_cpu(pxn_hj.m, i, 0, pxn_hj.h, 0, 1); + PXN_SYNC(); + pxn_hj.done = i + 1; + PXN_SYNC(); + } +} +#ifdef PXN_EMUVEC +/* PC tests: a helper that moves on by one layer only while the calling core waits for it (as late as it can be: a + * frame read before it is ready shows) */ +static uint8_t pxn_emu_hjob; +static int pxn_emu_hrun(void (*fn)(uint32_t), uint32_t arg) { (void)fn; (void)arg; pxn_emu_hjob = 1; return 1; } +static void pxn_emu_hstep(void) +{ + if (pxn_emu_hjob && pxn_hj.done < PXN_NL) { pxn_range_cpu(pxn_hj.m, pxn_hj.done, 0, pxn_hj.h, 0, 1); pxn_hj.done++; } +} +static int pxn_emu_hwait(void) { while (pxn_hj.done < PXN_NL) pxn_emu_hstep(); pxn_emu_hjob = 0; return 0; } +void pxn_emu_helper(void) { pxn_hrun = pxn_emu_hrun; pxn_hwait = pxn_emu_hwait; } +void pxn_emu_gather(void) { pxn_rd = 0; } /* the CPU's layers through gathered X rows */ +#endif +/* the calling core: wait until the helper has posted layer j-1 (layer j's ring holds its frames); if the helper is + * gone, its frames are done here */ +static void pxn_hneed(int j) +{ + if (!pxn_hon) return; + for (uint32_t k = 0; pxn_hj.done < j && !pxn_hdead; ) { + PXN_SYNC(); +#ifdef PXN_EMUVEC + pxn_emu_hstep(); +#endif + if (++k > 400000u) { /* very late: its job API's own wait (and time limit) */ + if (pxn_hwait() < 0) pxn_hdead = 1; /* dropped: never runs again */ + k = 0; + } + } + if (pxn_hdead) + while (pxn_hj.done < j) { pxn_range_cpu(pxn_hj.m, pxn_hj.done, 0, pxn_hj.h, 1, 0); pxn_hj.done++; } +} +static void pxn_hstart(pxn_model *m, int h) +{ + pxn_hj.m = m; + pxn_hj.h = h; + pxn_hj.done = 0; + PXN_SYNC(); + pxn_hon = 1; + pxn_hdead = 0; + if (!pxn_hrun || !pxn_hrun(pxn_help_job, 0)) pxn_hdead = 1; /* no helper: its frames here, layer by layer */ +} +static void pxn_hend(void) +{ + pxn_hneed(PXN_NL); + if (!pxn_hdead && pxn_hwait) pxn_hwait(); + pxn_hon = 0; +} + +#if PXN_VQON +/* the vector unit beside the CPU, over frames fa .. fb-1 in two halves. Half B of layer i, and layer i+1's half A, + * never need each other, so while the vector unit does one half's 3 dot products, the CPU gathers or posts the other: + * unit: D(i,A) D(i,B) D(i+1,A) ... + * CPU: G(i,B) P(i,A) G(i+1,A) P(i,B) G(i+1,B) ... + * (G gather, D dot, P post). Each half has its own X rows and z, so nothing is overwritten while the unit reads it. */ +static uint32_t pxn_issue(pxn_model *m, int i, int f0, int n, int c) /* the 3 dot products of layer i, frames f0.. */ +{ + const pxn_layer *L = &m->L[i]; + const int T = 3 * L->k + 2; + if (!pxn_vec_ok) { pxn_rows_cpu(m->wa + L->off, T, PXN_C, f0, n); return 0; } + const int nv = n - c; /* the CPU takes the last c frames itself, meanwhile */ + for (int o = 0; o < PXN_C && nv > 0; o++) + pxn_venq(pxn_uw(m, m->wa + L->off + o * T), pxn_x + f0 * PXN_S, T, pxn_z + 3 * f0 + o, nv); + const uint32_t seq = nv > 0 ? pxn_vq_in : 0; + if (c > 0) pxn_rows_cpu(m->wa + L->off, T, PXN_C, f0 + (nv > 0 ? nv : 0), nv > 0 ? c : n); + return seq; +} +static void pxn_need(pxn_model *m, uint32_t seq, int i, int f0, int n, int c) +{ + if (!seq) return; + if (!pxn_vfail && !pxn_vupto(seq)) return; + const pxn_layer *L = &m->L[i]; /* the unit died: the CPU does its part (X rows intact) */ + pxn_rows_cpu(m->wa + L->off, 3 * L->k + 2, PXN_C, f0, n - c); +} +static void pxn_layers_pipe(pxn_model *m, int fa, int fb, int c) +{ + const int h = ((fb - fa) >> 1) & ~3, f0[2] = {fa, fa + h}, nf[2] = {h, fb - fa - h}; + uint32_t seq[2]; + pxn_layer *L = &m->L[0]; + for (int s = 0; s < 2; s++) { + pxn_gather(L->ring, L->len, L->w, L->k, L->d, f0[s], nf[s], 1); + seq[s] = pxn_issue(m, 0, f0[s], nf[s], c); + } + for (int i = 0; i < PXN_NL; i++) + for (int s = 0; s < 2; s++) { + pxn_need(m, seq[s], i, f0[s], nf[s], c); + pxn_post_part(m, i, f0[s], nf[s], 1, 0); + if (i < PXN_NL - 1) { + pxn_hneed(i + 1); + L = &m->L[i + 1]; + pxn_gather(L->ring, L->len, L->w, L->k, L->d, f0[s], nf[s], 1); + seq[s] = pxn_issue(m, i + 1, f0[s], nf[s], c); + } + } +} +#endif + +/* v37 diagnostic 22: the helper as a server for the whole audio block, the roles the other way round. In the two-core + * pipeline CPU1 first runs the effects after the amp (POST), which often take longer than CPU0's effects before it + * (PRE): CPU1 comes late to the network. So for each 32-frame block CPU0 takes the first hs frames and never waits, and + * CPU1 the last n-hs frames, waiting before layer i until CPU0 has posted layer i-1 (frame t needs only frames t and + * earlier). The lateness the firmware measured (ticks) gives CPU0 more frames (hs up to 28) in the first blocks: + * frames moved = lateness / 2 per-frame costs. pxn_serve runs on CPU1 (after POST) until pxn_srv_end. */ +static struct { + pxn_model *m; + volatile int32_t seq, hs, n, mdone, hlay, hdone, stop; /* mdone: layers CPU0 has posted; hlay: layers CPU1 has */ +} pxn_sv; +static uint8_t pxn_sv_on, pxn_sv_dead; +static int32_t pxn_sv_late, pxn_sv_c; /* CPU1's lateness left (ticks); one frame's cost, one core */ +uint32_t pxn_frame_ticks(void) { return (uint32_t)pxn_sv_c; } +#ifdef PXN_EMUVEC +static uint8_t pxn_emu_eager; /* PC: CPU1 runs each layer as soon as allowed, or only when waited for */ +static void pxn_emu_sstep(int waited) +{ + if (pxn_sv.hdone == pxn_sv.seq || (!waited && !pxn_emu_eager)) return; + while (pxn_sv.hlay < PXN_NL && pxn_sv.hlay <= pxn_sv.mdone) { + pxn_range_cpu(pxn_sv.m, pxn_sv.hlay, pxn_sv.hs, pxn_sv.n - pxn_sv.hs, 0, 1); + pxn_sv.hlay++; + } + if (pxn_sv.hlay == PXN_NL) pxn_sv.hdone = pxn_sv.seq; +} +void pxn_emu_srv(int eager) { pxn_emu_eager = (uint8_t)eager; pxn_sv_c = 1; } /* (lateness then in frames x 2) */ +#define PXN_SSTEP(w) pxn_emu_sstep(w) +#else +#define PXN_SSTEP(w) ((void)0) +#endif +void pxn_srv_begin(int32_t late) /* CPU0, before starting CPU1's job */ +{ + pxn_sv.seq = pxn_sv.hdone = pxn_sv.stop = pxn_sv.hlay = 0; + pxn_sv.mdone = 0; + pxn_sv_late = late; + PXN_SYNC(); + pxn_sv_on = (uint8_t)(!pxn_sv_dead && PXN_MC[pxn_mode_v].h && !PXN_MC[pxn_mode_v].pipe); +} +void pxn_srv_end(void) /* CPU0: CPU1 leaves pxn_serve (then wait for its job) */ +{ + PXN_SYNC(); + pxn_sv.stop = 1; + PXN_SYNC(); + pxn_sv_on = 0; +} +int pxn_srv_active(void) { return pxn_sv_on; } +void pxn_serve(void) /* CPU1 */ +{ + int32_t done = 0; + for (;;) { + while (pxn_sv.seq == done && !pxn_sv.stop) PXN_SYNC(); + if (pxn_sv.seq == done) return; + const int32_t q = pxn_sv.seq; + PXN_SYNC(); + for (int i = 0; i < PXN_NL; i++) { + while (pxn_sv.mdone < i) PXN_SYNC(); + pxn_range_cpu(pxn_sv.m, i, pxn_sv.hs, pxn_sv.n - pxn_sv.hs, 0, 1); + PXN_SYNC(); + pxn_sv.hlay = i + 1; + } + PXN_SYNC(); + pxn_sv.hdone = done = q; + } +} +static void pxn_srv_block(pxn_model *m, int n) /* CPU0: the layers of one block with CPU1 serving */ +{ + int x = 0; + if (pxn_sv_late > 0 && pxn_sv_c > 0) { + x = (int)(pxn_sv_late / (2 * pxn_sv_c) + 2) & ~3; + if (x > 12) x = 12; + pxn_sv_late -= x * 2 * pxn_sv_c; + } + const int hs = 16 + x; + pxn_sv.m = m; pxn_sv.hs = hs; pxn_sv.n = n; + pxn_sv.mdone = 0; pxn_sv.hlay = 0; + PXN_SYNC(); + const int32_t q = pxn_sv.seq + 1; + pxn_sv.seq = q; + PXN_SYNC(); + PXN_SSTEP(0); + for (int i = 0; i < PXN_NL; i++) { + pxn_range_cpu(m, i, 0, hs, 1, 0); + PXN_SYNC(); + pxn_sv.mdone = i + 1; + PXN_SSTEP(0); + } + for (uint32_t k = 0; pxn_sv.hdone != q; ) { + PXN_SYNC(); + PXN_SSTEP(1); + if (++k > 8000000u) { /* (CPU1 gone for ~0.1 s: its layers here, from where it was) */ + pxn_sv_dead = 1; + for (int i = pxn_sv.hlay; i < PXN_NL; i++) pxn_range_cpu(m, i, hs, n - hs, 1, 0); + pxn_sv.hdone = q; + pxn_sv_on = 0; + } + } +} +static void pxn_block(pxn_model *m, const float *in, float *out, int n) +{ + pxn_layer *L0 = &m->L[0]; + int32_t w0 = L0->w; + const uint32_t tb = PXN_T(); + for (int f = 0; f < n; f++) { /* Q20, clamped to +-64 (far above any guitar) */ + float v = in[f] * 1048576.0f; + const int32_t u = v >= 67108864.0f ? 67108864 : v <= -67108864.0f ? -67108864 : (int32_t)v; + int32_t *x = pxn_xs + f * PXN_S, *r = L0->ring + 3 * w0; + x[0] = u; + x[1] = PXN_ONE; + pxn_u[f] = u; + for (int c = 0; c < PXN_C; c++) r[c] = (int32_t)(((int64_t)m->rech[c] * u) >> PXN_QW); + if (w0 < PXN_MIR) pxn_mir(L0->ring, L0->len, w0, 1); + if (++w0 == L0->len) w0 = 0; + } + memset(pxn_hs, 0, (unsigned)n * PXN_C * 4u); + const int h = PXN_MC[pxn_mode_v].h, pipe = PXN_MC[pxn_mode_v].pipe && pxn_vec_ok, c = PXN_MC[pxn_mode_v].c; + pxn_pc = (uint8_t)(pipe || (pxn_mode_v == 1 && pxn_vec_ok) ? 4 : PXN_N); /* post in 4-frame steps only to kick the unit */ + { /* the X rows: in the fast memory when the vector unit reads them (input columns copied over) */ + int32_t *xb = (pipe || pxn_mode_v == 1) && pxn_vec_ok && pxn_xf ? pxn_xf : pxn_xs; + if (xb != pxn_xs) for (int f = 0; f < n; f++) { xb[f * PXN_S] = pxn_xs[f * PXN_S]; xb[f * PXN_S + 1] = PXN_ONE; } + pxn_x = xb; + } + if (pxn_pt) pxn_prof[0] += PXN_T() - tb; + if (h && n == PXN_N && pxn_sv_on && !pipe) pxn_srv_block(m, n); /* two cores, CPU1 serving (the pipeline) */ + else if (h && n == PXN_N) { /* two cores */ + pxn_hstart(m, h); +#if PXN_VQON + if (pipe) pxn_layers_pipe(m, h, n, c); + else +#endif + for (int i = 0; i < PXN_NL; i++) { pxn_hneed(i); pxn_range_cpu(m, i, h, n - h, 1, 0); } + pxn_hend(); + } +#if PXN_VQON + else if (pipe && n >= 16) pxn_layers_pipe(m, 0, n, c); +#endif + else if (pxn_mode_v == 1 && pxn_vec_ok) for (int i = 0; i < PXN_NL; i++) pxn_layer_block(m, i, n); + else for (int i = 0; i < PXN_NL; i++) pxn_range_cpu(m, i, 0, n, 1, 0); + (void)pipe; (void)c; + const uint32_t th = PXN_T(); + for (int i = 0; i < PXN_NL; i++) { /* every ring moves on by the block */ + pxn_layer *L = &m->L[i]; + L->w += n; + if (L->w >= L->len) L->w -= L->len; + } + /* head: the activation sums into its ring, 16 taps gathered, one row */ + int n1 = m->hlen - m->hw; + if (n1 > n) n1 = n; + memcpy(m->hring + 3 * m->hw, pxn_hs, (unsigned)n1 * PXN_C * 4u); + if (n1 < n) memcpy(m->hring, pxn_hs + 3 * n1, (unsigned)(n - n1) * PXN_C * 4u); + if (n1 < n || m->hw < PXN_MIR) pxn_mir(m->hring, m->hlen, 0, PXN_MIR); /* (this core alone writes it) */ + int32_t hw = m->hw; + m->hw += n; + if (m->hw >= m->hlen) m->hw -= m->hlen; + if ((pxn_mode_v == 1 || PXN_MC[pxn_mode_v].pipe) && pxn_vec_ok) { + pxn_gather(m->hring, m->hlen, hw, PXN_HK, 1, 0, n, 1); + pxn_rows(m, m->head, PXN_S, 1, n); + } else { + pxn_pd = 6; + pxn_direct(m->hring, m->hlen, hw, PXN_HK, 1, m->head, 1, 0, n, 0, 1); + pxn_pd = 1; + } + const float g = m->out_gain; + for (int f = 0; f < n; f++) out[f] = (float)pxn_z[3 * f] * g; + pxn_x = pxn_xs; + if (pxn_pt) { + const uint32_t te = PXN_T(); + pxn_prof[5] += te - tb; + pxn_prof[4] += te - th; /* (the head's groups and rest taken out by the caller) */ + } +} +int pxn_dual(void) { return PXN_MC[pxn_mode_v].h != 0; } + +/* times the modes on the loaded model (8 blocks of 32 frames of a test signal each), keeps the fastest: the modes + * with the vector unit only if it is there, the two-core ones only with a helper */ +int pxn_tune(pxn_model *m, uint32_t (*ticks)(void), uint32_t t[PXN_MODES]) +{ + static float in[PXN_N], out[PXN_N]; + int best = 0; + for (int k = 0; k < PXN_MODES; k++) t[k] = 0; + if (!m->ready) return pxn_mode_v; + for (int rd = 3; rd >= 0; rd--) { /* the CPU's way: rdl, rdq, rdot or gathered X rows (mode 0) */ + if (rd == 3 && !pxn_rdl_f[6]) { pxn_rdt[3] = 0; continue; } + pxn_rd = (uint8_t)(rd > 0); + pxn_rdq_on = (uint8_t)(rd >= 2); + pxn_rdl_on = (uint8_t)(rd == 3); + pxn_mode_v = 0; + pxn_reset(m); + uint32_t r = 4321u, dt = 0; + for (int b = 0; b < 10; b++) { + for (int f = 0; f < PXN_N; f++) { r = r * 1103515245u + 12345u; in[f] = (float)((int32_t)r >> 8) * (0.5f / 8388608.0f); } + uint32_t t0 = ticks(); + pxn_block(m, in, out, PXN_N); + if (b >= 2) dt += ticks() - t0; + } + pxn_rdt[rd] = dt; + } + { + int b = 0; + for (int rd = 1; rd < 4; rd++) if (pxn_rdt[rd] && pxn_rdt[rd] < pxn_rdt[b]) b = rd; + pxn_rd = (uint8_t)(b > 0); + pxn_rdq_on = (uint8_t)(b >= 2); + pxn_rdl_on = (uint8_t)(b == 3); + pxn_sv_c = (int32_t)(pxn_rdt[b] / (8u * PXN_N)); /* one frame through every layer, one core (ticks) */ + } +#if PXN_ASM + if (pxn_p3ok) for (int v = 0; v < 2; v++) { /* post2 or post3: the faster */ + pxn_post_f = v ? pxn_post3_asm : pxn_post2_asm; + pxn_mode_v = 0; + pxn_reset(m); + uint32_t r = 4321u, dt = 0; + for (int b = 0; b < 10; b++) { + for (int f = 0; f < PXN_N; f++) { r = r * 1103515245u + 12345u; in[f] = (float)((int32_t)r >> 8) * (0.5f / 8388608.0f); } + uint32_t t0 = ticks(); + pxn_block(m, in, out, PXN_N); + if (b >= 2) dt += ticks() - t0; + } + pxn_ptt[v] = dt; + } + if (pxn_p3ok) pxn_post_f = pxn_ptt[1] < pxn_ptt[0] ? pxn_post3_asm : pxn_post2_asm; +#endif + for (int pass = 0; pass < 2; pass++) { /* the profile (mode 0, the chosen way), then without kernel */ + uint32_t keep[9]; + memcpy(keep, pxn_prof, sizeof keep); + pxn_mode_v = 0; + pxn_reset(m); + pxn_pskip = (uint8_t)pass; + uint32_t r = 4321u; + for (int b = 0; b < 10; b++) { + for (int f = 0; f < PXN_N; f++) { r = r * 1103515245u + 12345u; in[f] = (float)((int32_t)r >> 8) * (0.5f / 8388608.0f); } + if (b == 2 && !pass) for (int k = 0; k < 9; k++) pxn_prof[k] = 0; + if (b == 2 && pass) pxn_prof[1] = 0; + pxn_pt = b >= 2 ? ticks : 0; + pxn_block(m, in, out, PXN_N); + } + pxn_pt = 0; + pxn_pskip = 0; + if (pass) { const uint32_t t1 = pxn_prof[1]; memcpy(pxn_prof, keep, sizeof keep); pxn_prof[8] = t1; } + else pxn_prof[4] -= pxn_prof[6] + pxn_prof[7]; + } + for (int mode = 0; mode < PXN_MODES; mode++) { + const int unit = mode == 1 || PXN_MC[mode].pipe; + if ((unit && !pxn_vec_ok) || (PXN_MC[mode].h && !pxn_hrun)) continue; + pxn_mode_v = mode; + pxn_reset(m); + uint32_t r = 4321u, dt = 0; + for (int b = 0; b < 10; b++) { + for (int f = 0; f < PXN_N; f++) { r = r * 1103515245u + 12345u; in[f] = (float)((int32_t)r >> 8) * (0.5f / 8388608.0f); } + uint32_t t0 = ticks(); + pxn_block(m, in, out, PXN_N); + if (b >= 2) dt += ticks() - t0; + } + if ((unit && !pxn_vec_ok) || (PXN_MC[mode].h && pxn_hdead)) continue; /* failed on the way */ + t[mode] = dt; + if (dt < t[best]) best = mode; + } + pxn_mode_v = best; + pxn_reset(m); + return best; +} + +void pxn_process(pxn_model *m, const float *in, float *out, int n) +{ + if (!m->ready) { + if (out != in) memcpy(out, in, (unsigned)n * sizeof(float)); + return; + } + while (n > 0) { + const int c = n < PXN_N ? n : PXN_N; + pxn_block(m, in, out, c); + in += c; + out += c; + n -= c; + } +} diff --git a/engine/px_nam.h b/engine/px_nam.h new file mode 100644 index 0000000..06d1c0c --- /dev/null +++ b/engine/px_nam.h @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-3.0-only + * OpenPocket — Neural Amp Modeler A2-Lite on the pedal, in fixed point. + * + * The network (NAM "A2", 2026, the 3-channel "Lite" size; tools/nam_a2.py is the float reference): + * x = rechannel * u 1 -> 3 + * 23 layers, kernel 6 (15 for layers 14 and 15), dilations 1 3 7 17 41 101 239 | x2 | 1 13 | 1 .. 239: + * z = conv(x) + bias + mixin * u ; a = LeakyReLU(z, 0.01) ; head += a ; x += layer1x1(a) + bias + * y = head_scale * (conv16(head) + bias) 3 -> 1 + * 1871 weights, read in the .nam file's order (pxn_load). About 1,730 multiply-adds per sample. + * + * Fixed point: activations are int32 with 20 fraction bits (range +-2048, step 1e-6), weights int32 with 24 (+-128), + * products summed in int64 then shifted back by a constant (one instruction on the pedal). + * Samples go through in blocks of up to PXN_N frames (px_nam.c: gather, dot, post). Each layer keeps its input history + * in a ring of (kernel - 1) x dilation + PXN_N frames, the 3 channels side by side. The rings take 83.4 KB, the + * weights 6.2 KB, the block buffers 7 KB. + */ +#pragma once +#include + +#define PXN_C 3 +#define PXN_NL 23 +#define PXN_HK 16 +#define PXN_NW 1871 /* A2-Lite weights, head_scale included */ +#define PXN_N 32 /* frames per block */ +#define PXN_S 50 /* a block row: u, 1.0, then up to 16 taps x 3 channels */ +#define PXN_QA 20 /* activations: fraction bits */ +#define PXN_QW 24 /* weights: fraction bits */ +#define PXN_LOOK 6331 /* sum of (kernel - 1) x dilation */ +#define PXN_MIR 3 /* each ring's first frames mirrored after its end (4-frame reads) */ +#define PXN_RING (PXN_LOOK + (PXN_HK - 1) + (PXN_NL + 1) * (PXN_N + PXN_MIR)) /* frames in all rings (head included) */ + + +typedef struct { + int32_t *ring; /* len frames x PXN_C channels, interleaved */ + int32_t len, w; /* ring length (lookback + PXN_N), where the next block is written */ + int16_t k, d; /* kernel, dilation */ + int32_t off; /* this layer's weight rows in pxn_model.wa */ + int32_t rr[12]; /* its residual 1x1: 3 x {w[o][0..2] Q24, bias[o] Q20} */ + int32_t rr2[12]; /* the same for the pedal's post2: w[o][c] by c then o, then the 3 biases */ +} pxn_layer; + +typedef struct { + int32_t wa[1542 + 4]; /* each layer's 3 rows [mixin, bias, taps x channels], Q24 (+ slack) */ + int32_t rech[PXN_C]; + int32_t head[PXN_S + 4]; /* [0, bias, 16 taps x 3 channels] Q24 (+ slack) */ + float out_gain; /* head_scale / 2^20 */ + pxn_layer L[PXN_NL]; + int32_t hlen, hw; /* head ring */ + int32_t *hring; + int ready; +} pxn_model; + +/* Converts 1871 float weights (the .nam file's order) into the model. 0 = ok, -1 = a weight is not finite, -2 = the + * ring memory is too small. The rings (PXN_RING_BYTES in all) come from the caller in up to two pieces (r0 of n0 + * bytes, r1 of n1 bytes: one RAM region may not hold them all); they are cleared. */ +int pxn_load(pxn_model *m, const float *w, int32_t *r0, unsigned n0, int32_t *r1, unsigned n1); +#define PXN_RING_BYTES ((unsigned)PXN_RING * PXN_C * 4u) +/* the pedal's hand-written routines: checked once against the C ones (1 = in use); call before audio starts. + * scratch: PXN_TEST_WORDS words (the ring memory will do: reset the model after) */ +int pxn_selftest(int32_t *scratch); +#define PXN_TEST_WORDS 1280 +int pxn_asm_in_use(void); +/* the vector unit: its start-up check's largest difference with C if in use (>= 0), else -1 - that difference (or -1) */ +int pxn_vec_check(void); +void pxn_vstart(const int32_t *w, const int32_t *x, int T, int sb, int zb, int32_t *z, int n); /* bench */ +void pxn_vwait(void); +/* measurements for the firmware's bench screen (px_audio.h, BENCH_AT_BOOT): ticks, see px_nam.c */ +uint32_t pxn_bench_layer(int32_t *scratch, uint32_t (*ticks)(void), int hand, int reps); +uint32_t pxn_bench_dot(int32_t *x, int32_t *w, int32_t *z, int vec, uint32_t (*ticks)(void), int reps); +uint32_t pxn_bench_post(int32_t *b, uint32_t (*ticks)(void), int reps, int v2); +uint32_t pxn_bench_vcmd(int32_t *buf, uint32_t (*ticks)(void), int nlen, int nloop, int xs, int zs, int reps, int start_only); +/* how the blocks run: 0 the CPU alone, 1 each dot product on the vector unit in turn, 2..4 the vector unit and the + * CPU at once (half a block on the unit while the CPU prepares or finishes the other half; the CPU also takes 0, 4 or + * 8 frames of each half's dot products itself), 5..10 two cores (the other core takes the block's first 12 to 24 + * frames; with or without the vector unit beside this one). pxn_tune times them on a loaded model and keeps the + * fastest (ticks for 256 frames in t[], 0 = not available); the model is cleared after. */ +#define PXN_MODES 11 +/* the other core, for modes 5..8: run(fn, arg) hands it fn(arg) (1 = taken, 0 = do it yourself), wait() waits for it + * (0 = done, -1 = dropped). Without it those modes are not used. */ +void pxn_set_helper(int (*run)(void (*fn)(uint32_t), uint32_t arg), int (*wait)(void)); +/* the two-core pipeline (v37): CPU1 serves the network's blocks after its own work, the roles the other way round + * (see px_nam.c): pxn_srv_begin(lateness in ticks) on CPU0 before starting CPU1's job, pxn_serve() at the end of that + * job, pxn_srv_end() on CPU0 after the network, then wait for the job */ +void pxn_srv_begin(int32_t late); +void pxn_serve(void); +void pxn_srv_end(void); +int pxn_srv_active(void); +uint32_t pxn_frame_ticks(void); /* one frame through every layer on one core (ticks, timed by pxn_tune) */ +int pxn_dual(void); /* 1 = the mode in use wants the other core (the caller must not be it) */ +int pxn_tune(pxn_model *m, uint32_t (*ticks)(void), uint32_t t[PXN_MODES]); +int pxn_mode(void); +int pxn_post2_in_use(void); +int pxn_rdot_in_use(void); +/* fast memory for the vector unit's inputs (X rows, a copy of the weights: PXN_FAST_BYTES), away from the RAM the CPUs + * work in: offered before pxn_selftest, which checks the unit there and then uses it */ +void pxn_set_fast(int32_t *base, unsigned bytes); +#define PXN_FAST_BYTES (((PXN_N + 1) * PXN_S + 1550 + PXN_S + 4) * 4u) +int pxn_fast_in_use(void); +int pxn_rdot_chosen(void); /* the CPU's layers: 1 rdot, 0 gathered X rows (timed by pxn_tune) */ +uint32_t pxn_rdot_ticks(int rd); /* that timing, mode 0: 0 gathered, 1 rdot, 2 rdq (load-ahead rdot) */ +uint32_t pxn_prof_ticks(int k); +int pxn_rdl_state(void); /* rdl (a layer's groups in one call): 0 failed its check, 1 slower, 2 in use */ +uint32_t pxn_post_ticks(int v); /* mode 0 timed with post2 (0) and post3 (1) */ +int pxn_post3_state(void); /* 0 post3 failed its check, 1 slower than post2, 2 in use */ /* where mode 0's time goes (pxn_tune): see px_nam.c */ +int pxn_rdq_in_use(void); +int pxn_rdq_checked(void); /* all three passed the start-up check */ +uint32_t pxn_bench_part(int32_t *scratch, uint32_t (*ticks)(void), int part, int reps); +uint32_t pxn_bench_vfast(int32_t *buf, uint32_t (*ticks)(void), int v); /* v 0..7, see px_nam.c */ +int pxn_vfast_macs(int v); +uint32_t pxn_bench_ops(int kind, int32_t *buf, int reps, int *n, uint32_t (*ticks)(void)); +/* clears the histories (silence in) */ +void pxn_reset(pxn_model *m); +/* n frames (any n): in -> out, float, in place allowed */ +void pxn_process(pxn_model *m, const float *in, float *out, int n); diff --git a/engine/px_nam_factory.h b/engine/px_nam_factory.h new file mode 100644 index 0000000..b71bcf2 --- /dev/null +++ b/engine/px_nam_factory.h @@ -0,0 +1,2278 @@ +/* SPDX-License-Identifier: GPL-3.0-only + * OpenPocket — the factory NAM models (generated by tools/mk_nam_factory.py: do not edit). + * A2-Lite networks trained by tools/train_a2.py on real DI guitar (Alec-Wright/Automated-GuitarAmpModelling, + * GPL v3) through NAM community captures (pelennor2170/NAM_models, GPL v3), at 44.1 kHz: + * TWIN Tim R Fender TwinVerb Norm Bright.nam (val ESR 0.00622) + * AC15 Phillipe P VOXAC15-TopBoost.nam (val ESR 0.0453) + * SUPER 59 Tim R Magnatone Super 59 Mkii Ch1 Br.nam (val ESR 0.00923) + * SHIRL CL Sascha S DirtyShirleyMini_Clean_B1_M6_T7_MV10_G4.nam (val ESR 0.01417) + * JCM900 Tim R JCM90050WDualVerbCHAG6.nam (val ESR 0.01143) + * SHIRLEY Sascha S DirtyShirleyMini_crunch_G6.nam (val ESR 0.03285) + * JCM2000 Tim R JCM2000 L2 G6.nam (val ESR 0.04219) + * MARK IV Roman A LT_MESA_MARKIV_1.nam (val ESR 0.04099) + * JVM OD2 Phillipe P JVM-OD2-RD-NoDrive-ESR0,003.nam (val ESR 0.05616) + * PRO MOD Tim R Splawn Pro Mod 2nd Gear - G12.nam (val ESR 0.05162) + * 5150 Helga B 5150 BlockLetter - Boosted.nam (val ESR 0.06356) + * 6505 RED Helga B 6505+ Red ch - MXR Drive.nam (val ESR 0.12384) + */ +#pragma once +static const char *const PXN_FNAME[PX_NAM_NFACT] = {"TWIN", "AC15", "SUPER 59", "SHIRL CL", "JCM900", "SHIRLEY", "JCM2000", "MARK IV", "JVM OD2", "PRO MOD", "5150", "6505 RED"}; +static const float PXN_FLVL[PX_NAM_NFACT] = {15.52f, 4.40f, 16.54f, -1.64f, 8.43f, -7.97f, -6.51f, -10.75f, 0.15f, -3.39f, 5.11f, 2.29f}; +static const float PXN_FW[PX_NAM_NFACT][PXN_NW] = { + {0.320002794f, 0.727935612f, 0.238266841f, -0.294501394f, 0.221699819f, 0.104392655f, -0.128418848f, 0.144016638f, 0.101290569f, 0.0822667405f, + 0.0152568799f, 0.128478527f, -0.174938768f, -0.03103997f, -0.0981253907f, 0.154792517f, 0.0195958018f, -0.0653405264f, -0.181042448f, -0.0504140742f, + 0.0183058865f, -0.0916420296f, 0.247081414f, 0.201894924f, -0.719463229f, -0.53177017f, 0.0184677504f, -0.126764014f, -0.00687608216f, 0.0156425256f, + 0.420173645f, -0.347761035f, -0.0340246633f, 0.456002206f, 0.100207433f, 0.122930154f, -0.192029804f, -0.465934485f, 0.0745655969f, 0.0532701015f, + -0.263561964f, -0.159334973f, -0.0143990805f, -0.164026037f, 0.0974085331f, 0.051251173f, 0.033373829f, -0.118478425f, 0.142390504f, 0.269288689f, + 0.197429761f, -0.162272394f, 0.201181158f, -0.110113233f, 0.216591671f, -0.196128488f, 0.323289543f, -0.0252455547f, 0.0993641391f, -0.0346511155f, + 0.00503816549f, -0.563742161f, -0.0324353464f, 0.0706069618f, 0.215851128f, -0.559211791f, -0.621891499f, 0.134683162f, -0.337736517f, 0.137799785f, + 0.410406828f, -1.05721986f, -0.0127586899f, -0.0262720603f, 0.0521447025f, -0.0152240191f, 0.246549338f, -0.0257569235f, -0.12116006f, 0.0307621304f, + 0.109530061f, 0.0464904308f, -0.176881284f, -0.32212925f, -0.00227459334f, -0.297868758f, 0.200276911f, 0.189926267f, -0.273637027f, -0.255514145f, + 0.302535236f, 0.289970249f, -0.062493369f, -0.0178196281f, -0.0663246289f, 0.14788036f, 0.118426472f, -0.175300553f, -0.0600616932f, 0.0131231463f, + 0.0145234345f, -0.486900628f, -0.0919932425f, -0.218039855f, -0.447236508f, 0.0505323894f, 0.00663054595f, 0.293269426f, 0.00799008366f, 0.250583768f, + 0.507222831f, 0.131466553f, -0.159615785f, -0.315812618f, 0.460827798f, 0.0245637484f, -0.116886303f, 0.0765883029f, 0.00776308356f, 0.24579902f, + 0.0582570545f, 0.0551543422f, -0.117907256f, 0.0611371547f, -0.30954212f, 0.102774739f, 0.305877835f, -0.410342783f, -0.643392742f, 0.0481229015f, + 0.0355304331f, -0.0356179997f, 0.311238766f, 1.12574863f, -0.447806716f, -0.681138575f, 0.278553128f, -0.450490177f, -0.43198511f, -0.23908706f, + 0.337415218f, -0.278194219f, 0.129682869f, -0.0790919438f, -0.0225018729f, -0.0104843974f, 0.0446419641f, -0.159577727f, -0.0137874614f, -0.172769129f, + 0.041802194f, -0.205231622f, -0.207288012f, 0.346252441f, 0.0426046997f, 0.00666930433f, 0.147833884f, -0.0369464979f, 0.00181085453f, 0.0672910064f, + 0.0219754037f, -0.282444149f, 0.127130985f, -0.195996031f, -0.294043273f, -0.241320997f, -0.191948742f, 0.332392186f, 0.0722167641f, 0.248396412f, + -0.318528533f, -0.127425611f, 0.0334078968f, -0.0743197501f, -0.0487778634f, 0.00103084568f, 0.153441861f, 0.16111581f, 0.306441158f, -0.0161492098f, + 0.0604530163f, 0.11396303f, -0.00662915362f, -0.0742837489f, -0.0416792333f, 0.0666100457f, -0.38005501f, 0.210701153f, -0.345546335f, -0.371328056f, + 0.0171439629f, 0.166849792f, 0.0401930138f, -0.0240467321f, -0.405817807f, 0.593822122f, 0.25163579f, -0.127797648f, -0.0769951716f, 0.0511766113f, + -0.409496516f, -0.0299271885f, 0.0323981717f, 0.0292824656f, 0.147891685f, -0.194810256f, 0.398428321f, 0.6430071f, -1.45392609f, 0.0709634051f, + -0.878020763f, 0.579480469f, -0.0281858891f, 0.113544352f, -0.504832745f, 0.683281481f, -0.0429000743f, -0.00206970726f, 0.0270704702f, 0.540376902f, + -0.191310152f, 0.146080971f, -0.10047438f, 0.0421313047f, -0.272222251f, 0.411978781f, -0.232192516f, -0.0656728595f, 0.12510936f, -0.149254411f, + -0.0906135961f, -0.200680047f, -0.122976363f, -0.369376838f, -0.19224371f, -0.138621107f, -0.165644184f, 0.0731152147f, -0.0173074473f, 0.225308478f, + -0.027622452f, 0.0267966297f, -0.0876654387f, -0.128174528f, -0.294355333f, 0.137662798f, -0.238469288f, -0.130840331f, 0.141685262f, 0.01705545f, + -0.162940696f, -0.514827311f, 0.0759900659f, 0.0559914522f, -0.319205821f, -0.016560223f, -0.257945567f, -0.264920056f, 0.0101437513f, -0.0534790531f, + 0.0880148038f, -0.417727768f, 0.238673404f, -0.254578292f, -0.377836674f, 0.211919218f, -0.0344717614f, 0.0332916901f, -0.0576109327f, 0.0406780466f, + 0.106088862f, -0.125937566f, 0.185775802f, -0.0148367165f, -0.0409304462f, 0.0486571379f, -0.240917355f, -0.359464586f, 0.147706226f, 0.261364073f, + -0.116930939f, -0.592162669f, 0.366903543f, -0.979997873f, -0.352478474f, 0.043261569f, -0.765983582f, -0.0801936835f, -0.0327976756f, 0.00344138872f, + -0.0197854117f, -0.154816523f, 0.169537723f, -0.137233987f, -0.112292238f, -0.0252265818f, -0.580140293f, 0.316705912f, -0.231947005f, -0.0933478996f, + 0.221392319f, -0.156037241f, -0.333965838f, 0.0729784817f, 0.120149583f, -0.080131501f, -0.0241976846f, 0.074344717f, -0.401305854f, 0.0193682779f, + -0.00803659204f, -0.194800198f, -0.452858865f, -0.0937628523f, -0.101308048f, -0.0118359029f, -0.0701310486f, -0.0135800652f, -0.163697287f, -0.0580080114f, + -0.147485554f, 0.0780391321f, 0.244432911f, -0.114997923f, -0.268026918f, -0.0129966037f, -0.0709751844f, -0.162322447f, 0.0344978832f, -0.0759400725f, + 0.318007737f, -0.0167786293f, 0.0797265694f, 0.204898536f, -0.083638303f, 0.314746916f, -0.173922837f, -0.214675382f, -0.102284722f, -0.0595818162f, + -0.358969182f, -0.0370458812f, -0.426881611f, 0.298076004f, -0.043575678f, 0.0123004029f, 0.000284876645f, 0.0073229745f, -0.258349776f, -0.406277061f, + -0.19405359f, -0.0488906913f, -0.576096952f, -0.520151734f, -0.0574315302f, -0.278035551f, 0.572334051f, 0.601548254f, 0.0192571301f, 0.275804788f, + -0.0357486121f, -0.0026895029f, -0.00638304744f, -0.261505425f, 0.105444096f, -0.01616586f, 0.109752521f, 0.494069159f, -0.584600687f, 0.135217816f, + -0.222836092f, 0.0553883947f, -0.289294749f, 0.0754005089f, 0.113033384f, 0.113942586f, 0.00492773252f, -0.126614287f, -0.0970381796f, 0.207256362f, + -0.00682878681f, -0.335137129f, 0.187242761f, 0.112018444f, 0.279060125f, -0.0304795057f, 0.228536695f, -0.198877677f, 0.0865274519f, -0.153108925f, + 0.194333613f, 0.276584923f, -0.183604062f, -0.0832636952f, -0.0460950918f, 0.233211234f, 0.115993865f, -0.344297945f, 0.0594771095f, 0.246814728f, + 0.561287105f, -0.306759089f, -0.0547386669f, 0.366040736f, -0.250159025f, -0.244459316f, 0.0845491812f, 0.265848458f, -0.12129119f, 0.0862684175f, + 0.0698148683f, 0.286801249f, -0.0613340884f, 0.15287292f, -0.287336618f, -0.111791015f, -0.107560113f, 6.81929741e-05f, -0.0456131287f, -0.050002031f, + 0.521864951f, 0.257501155f, -0.310510218f, 0.28786701f, 0.402625889f, -0.103886977f, 0.0425702073f, -0.0701063052f, -0.93487519f, 0.0324090682f, + 0.118950255f, -0.452989966f, -0.0290757958f, -0.00198609685f, 0.0147935804f, 0.0596355312f, -0.318430036f, -0.0882511064f, -0.102662861f, 0.310698807f, + -0.423990339f, -0.0770069361f, 0.206660151f, 0.0944473371f, 0.0999624282f, -0.205198243f, -0.54408735f, 0.170801759f, -0.273319513f, 0.0169180352f, + -0.25457868f, 0.272094607f, 0.199749738f, -0.120463543f, 0.149006158f, -0.040559072f, -0.0523554273f, 0.0379892886f, -0.0746313483f, 0.0818328112f, + -0.0465595126f, -0.183399945f, 0.0784317553f, -0.0329172388f, 0.0699358359f, 0.0239772201f, 0.311165839f, -0.0244213156f, 0.313508809f, 0.0342346616f, + -0.0343389548f, -0.0754749626f, 0.108617447f, 0.0493116081f, -0.243414134f, -0.149915785f, -0.107825086f, -0.0736621097f, 0.181917682f, 0.382621199f, + 0.182711661f, 0.145676866f, -0.141762882f, -0.038060125f, 0.171391919f, 0.4376674f, 0.196767882f, -0.114851251f, 0.0110788103f, 0.0686115548f, + 0.0227040797f, -0.0370920002f, -0.379986018f, -0.509422421f, -0.0121140825f, 0.136875138f, 0.86446178f, -0.0677354708f, 0.813054383f, 1.01785576f, + 0.0643896163f, 0.780335009f, 0.476904899f, -0.222717494f, -0.031733878f, 0.00140565902f, 0.0214189999f, 0.0988452435f, 0.0431881063f, -0.0136906458f, + 0.00123600033f, 0.0916183963f, 0.16348134f, -0.209540114f, 0.00239260797f, -0.351962328f, 0.0621864684f, 0.136941403f, 0.0237927455f, 0.0295623373f, + 0.104942612f, -0.189774469f, -0.0968532786f, 0.0665237829f, 0.175493807f, 0.0595969036f, 0.569206655f, -0.0521111712f, 0.204016134f, 0.265283793f, + -0.0657563135f, -0.233701959f, -0.317906767f, 0.000894171302f, 0.23384653f, 0.0366723984f, 0.0092264805f, -0.135675818f, 0.0844440386f, -0.550518751f, + 0.0197029896f, -0.0236755442f, -0.357204616f, 0.522541761f, -0.294396162f, -0.208078116f, -0.257401526f, 0.256916553f, -0.21552752f, 0.109098405f, + 0.0877898112f, -0.00758853927f, -0.387047827f, -0.203556567f, 0.351177841f, -0.303477585f, -0.20878619f, -0.0840715691f, 0.13074939f, 0.0212625265f, + 0.15493907f, -0.0281743761f, -0.03384104f, -0.0250720363f, -0.466245174f, 0.44826889f, 0.214388251f, -0.851495683f, 0.88083452f, 0.866199434f, + -0.383589774f, 0.0368302725f, 0.534557581f, -0.872038901f, -1.12196648f, -0.396844864f, -0.014328355f, 0.00166004337f, 0.0175180808f, -0.0957099795f, + -0.0583343655f, 0.239026517f, 0.0588663183f, -0.332332522f, 0.315371275f, 0.283738613f, 0.317093521f, 0.221017227f, 0.000919329817f, 0.390480608f, + -0.283429652f, 0.0825110823f, -0.0643859655f, 0.250869811f, 0.0815078244f, -0.143051356f, -0.0222078227f, 0.314124674f, -0.105842113f, 0.0282360446f, + -0.113176391f, -0.332099587f, 0.307134807f, 0.144448951f, 0.179990053f, -0.0171661004f, -0.143977314f, 0.2733334f, -0.126580685f, 0.109768085f, + 0.159542128f, 0.129058555f, -0.24877499f, 0.144703925f, 0.00163456507f, 0.447044015f, 0.0685276091f, -0.415035754f, 0.119498402f, 0.468353093f, + 0.192951366f, 0.21645695f, 0.0294794943f, -0.445398211f, -0.402517796f, -0.267334878f, -0.0106207784f, 0.0462955385f, 0.141573459f, -0.102678426f, + 0.208805203f, -0.0755669847f, -0.19355391f, -0.0695272088f, -0.0473123565f, -0.0310575422f, 0.505506158f, -0.347351193f, -1.33151555f, -0.6290223f, + 0.0440548398f, -1.74882686f, -0.347440183f, -0.256283849f, -0.764552832f, -0.750802219f, -0.126139015f, -0.291707277f, 0.0137333078f, 0.065734677f, + 0.0331367441f, 0.247845545f, -0.0540053956f, -0.470580876f, -0.329841852f, 0.0795188248f, 0.368202478f, 0.190783635f, 0.0700106397f, 0.511546612f, + -0.0431035422f, 0.0614454225f, -0.315362155f, -0.158082694f, 0.440606296f, -0.241824254f, -0.103895672f, -0.23736608f, -0.0581941605f, 0.222253427f, + -0.0323104523f, 0.198297828f, 0.180266395f, 0.133024827f, 0.441116512f, 0.103443183f, -0.151767731f, -0.242113546f, -0.289402246f, 0.0486540683f, + -0.136479437f, 0.582120538f, 0.377949774f, -0.10405504f, -0.136076719f, 0.37007913f, -0.441757649f, -0.0396250375f, 0.279574513f, -0.159419641f, + -0.0613110065f, -0.0320004635f, 0.209606186f, -0.00474839937f, 0.0535671562f, 0.108059518f, -0.0305782985f, 0.225557685f, -0.194655567f, -0.297121108f, + -0.374176562f, -0.336623996f, -0.134913787f, 0.206215873f, -0.00810150057f, 0.00999673735f, -0.0519903637f, -0.0599969327f, -0.302498609f, -0.469799846f, + -0.258007139f, -0.12572825f, -0.378005743f, -0.791505277f, -0.0580756217f, 0.528974593f, -1.20989561f, 0.157907084f, -1.15543008f, 0.10329432f, + 0.0285686702f, 0.0709906295f, -0.0189741738f, -0.0827316418f, -0.417886555f, 0.0737546086f, 0.430135638f, 0.0405062921f, 0.272363722f, -0.0487547666f, + -0.531473339f, 0.0753807873f, -0.172660559f, -0.390263021f, 0.131527901f, 0.0326949693f, -0.144981742f, 0.213018656f, -0.265681088f, 0.193237633f, + -0.151091725f, 0.158346772f, -0.228344694f, 0.380951881f, 0.081983f, 0.351329207f, -0.203432769f, -0.0841938332f, 0.221505523f, -0.62310195f, + -0.23818773f, 0.252021879f, 0.113434009f, 0.279121637f, -0.0495694056f, 0.139120847f, -0.14690654f, -0.281981707f, -0.369015098f, -0.26502651f, + -0.194555134f, -0.107396439f, -0.694717288f, -0.426235318f, -0.063681528f, 0.00958946999f, -0.164178729f, -0.170916229f, -0.339674264f, 0.524144948f, + -0.208976731f, 0.238468632f, 0.234342307f, 0.106406674f, 0.088305518f, 0.0205128696f, -0.481847137f, -0.0557736121f, -0.0289304368f, -0.0444393866f, + 0.0390480794f, -0.0318123661f, 0.411561161f, 0.513020575f, 0.979109704f, -0.262236208f, 0.564525008f, -0.421708703f, -0.311959505f, -0.334863186f, + -0.55592227f, 0.123110987f, -0.0381749421f, 0.074725531f, -0.0190737713f, 0.21356909f, 0.297855109f, 0.0549441427f, 0.121302299f, -0.0707401261f, + -0.21862337f, 0.0522237532f, -0.0219318531f, -0.272730529f, 0.0920793116f, -0.379290015f, -0.0254803319f, -0.160382703f, -0.127773985f, -0.286016196f, + 0.160298839f, 0.0748135f, 0.235303923f, 0.106611483f, -0.237715885f, -0.0270974468f, -0.228146479f, 0.160703748f, 0.33747533f, 0.0726386607f, + -0.0942120105f, -0.0503520221f, 0.0761879086f, -0.335950613f, 0.0526137687f, -0.0391252078f, -0.181290001f, -0.15414694f, 0.00574185094f, -0.230331719f, + -0.253739476f, 0.201259062f, 0.0921022967f, 0.379425347f, -0.219840243f, -0.405094951f, 0.251530975f, 0.241785735f, -0.134766564f, -0.34202677f, + 0.00379340444f, -0.405860037f, -0.0559564568f, -0.492168397f, -0.0547218286f, -0.509858131f, -0.0515021272f, 0.32810843f, -0.106005065f, -0.0583298095f, + -0.036849957f, -0.0274443626f, 0.336404204f, -0.376512885f, -0.434760481f, -0.838715911f, 0.549667418f, -0.020962771f, 0.865067244f, -0.713208616f, + -0.129544809f, 0.0144371241f, 0.772616208f, 1.0080725f, -0.0154628083f, 0.0328557417f, -0.0354825146f, -0.179818556f, -0.276158512f, -0.414324969f, + 0.21490328f, -0.00820116047f, -0.172608986f, 0.0899692029f, -0.367011458f, -0.279750705f, 0.105710201f, 0.0325534269f, 0.169232056f, -0.181302786f, + 0.166743517f, 0.36113742f, -0.253517836f, -0.00474567851f, -0.024939144f, -0.00596407615f, 0.00795338396f, 0.0268483385f, -0.172426492f, 0.00318273343f, + -0.149795651f, 0.0654482916f, 0.219352499f, 0.110920571f, -0.0217606183f, -0.0190845206f, 0.637979746f, 0.0672781393f, -0.0200622305f, 0.0241881404f, + 0.0894083157f, -0.0175152831f, 0.344773024f, -0.133356974f, 0.124639675f, 0.174598411f, 0.0743934214f, -0.414395571f, 0.0211903322f, 0.0237194747f, + 0.0537813418f, -0.00622186577f, -0.239280403f, 0.346199483f, -0.00684237108f, 0.129447803f, 0.0607083924f, 0.0981191024f, 0.2065254f, -0.185048252f, + 0.122076333f, 0.0338343941f, 0.0661867931f, -0.00738086645f, -1.59812844f, -0.679577589f, 0.213638887f, 0.478158623f, 0.985541403f, -0.383156151f, + 0.23053512f, 0.0768726319f, 0.751086593f, 0.790887475f, -0.114043467f, 1.88371968f, 0.010422389f, 0.0332279839f, -0.0560950786f, 0.0451607928f, + -0.0968486145f, 0.0893956348f, 0.115075879f, 0.171518281f, -0.0963892862f, 0.255946219f, -0.0540995374f, 0.262730032f, 0.248091996f, -0.363642961f, + -0.236176401f, -0.31515944f, -0.00251664664f, -0.0714586303f, 0.0262390934f, -0.258696079f, 0.0417376384f, -0.0701360703f, -0.125176534f, -0.0905520469f, + -0.0698385015f, -0.168205261f, 0.306394935f, 0.180792496f, 0.252962708f, 0.121805713f, -0.302771956f, 0.342272162f, 0.212041587f, -0.085814625f, + -0.0766337365f, -0.0255873799f, 0.366674989f, 0.0822694823f, 0.0266864784f, -0.450952351f, 0.151637584f, -0.160945669f, -0.178467706f, 0.16578427f, + -0.214175701f, 0.132469997f, 0.208800703f, -0.483698815f, -0.0809172243f, -0.463492304f, -0.0596344396f, 0.151856348f, -0.376855165f, 0.359063506f, + -0.134733588f, -0.34635374f, -0.0891275033f, -0.0415380448f, 0.0129466504f, -0.0513411686f, 0.345792532f, -1.14577508f, 0.0394139588f, -0.808116615f, + 0.66803509f, 0.108936563f, -0.29552266f, 0.593446553f, -0.70717293f, -0.242042899f, 0.841962695f, -0.107531764f, 0.000926714041f, 0.0852836668f, + -0.0921941996f, 0.200303867f, 0.0529267862f, -0.152158111f, -0.180311024f, -0.0799054652f, -0.0628844872f, -0.145738885f, -0.29520005f, -0.299493879f, + 0.259081274f, 0.303479075f, 0.0451451279f, -0.615664721f, -0.0403953046f, 0.127399012f, -0.29616642f, -0.0539320298f, 0.0234511718f, -0.0598459877f, + -0.0050708144f, 0.0641707107f, 0.0434160568f, -0.159044608f, -0.407733113f, -0.0600728616f, 0.100125775f, -0.179697528f, -0.143094346f, -0.0350803435f, + -0.00481863879f, 0.222673252f, -0.183074579f, 0.0917387605f, -0.149485528f, -0.195946187f, 0.0258023031f, -0.148412228f, 0.0498001352f, -0.219201609f, + 0.0373454355f, -0.102115318f, -0.103859432f, -0.214986309f, -0.288288355f, 0.053918764f, -0.244836465f, -0.26550132f, -0.00168398547f, -0.0347548947f, + -0.114063255f, -0.219881549f, 0.069473587f, -0.35421598f, -0.00882569142f, 0.0328616537f, 0.359401137f, -0.110123463f, -0.0324427746f, 0.280836105f, + 0.0890353918f, -0.244091853f, -0.283525437f, 0.210731432f, 0.000730477972f, -0.09614072f, -0.288608432f, -0.274063379f, -0.227396429f, -0.0317098908f, + -0.275611997f, 0.0837779716f, -0.225940108f, -0.18747513f, 0.0103117879f, 0.118430041f, -0.161751702f, -0.0466530882f, -0.567460835f, -0.41640681f, + -0.0434406139f, -0.491296351f, -0.318130881f, -0.105452664f, -0.203037411f, 0.0601230823f, -0.277426034f, -0.564400017f, -0.574883044f, -0.502787054f, + -0.245825991f, -0.041782245f, 0.0877745599f, -0.179995924f, 0.268962055f, -0.0852335021f, 0.00621272344f, 0.0506004132f, -0.0971327946f, -0.109765336f, + 0.0365844071f, 0.16344285f, -0.0153219784f, -0.0794168115f, -0.13280198f, -0.0226649772f, 0.246028945f, -0.0593289472f, -0.0211467277f, -0.0685695112f, + 0.0692618489f, -0.256377518f, -0.131709173f, -0.14928171f, -0.0958701149f, -0.399491847f, -0.0686315224f, -0.614136457f, -0.222711891f, -0.0194156282f, + 0.0999355689f, -0.208292261f, 0.137100771f, -0.146627992f, -0.229359373f, -0.184306338f, -0.138746843f, 0.00311749568f, 0.0888340175f, -0.328191668f, + -0.0826627612f, 0.133920103f, -0.00996457133f, 0.00176426326f, -0.250971794f, 0.154616252f, -0.0401207693f, -0.0415579751f, -0.0390620306f, -1.15519655f, + -0.215280816f, 0.593551576f, 1.41964471f, 0.348625183f, 0.497001708f, -0.240724668f, -0.290100783f, 0.645548165f, 0.488691509f, 0.0818741843f, + -0.665020764f, -0.00036877711f, 0.0818009526f, -0.0994826183f, -0.0790214837f, 0.024444269f, -0.164537683f, -0.113262899f, 0.197103739f, 0.000169705236f, + -0.0692830011f, -0.177846298f, -0.0822940469f, -0.0197301544f, 0.215602741f, -0.0676476955f, 0.277163923f, -0.135592803f, -0.091607675f, 0.0378600769f, + -0.10084793f, -0.171629936f, -0.05746888f, 0.0247162469f, -0.289851189f, -0.0774754286f, -0.0566865802f, -0.10109932f, 0.0656537861f, -0.128677025f, + -0.0981626585f, -0.0339667946f, 0.070148997f, -0.0847533047f, 0.179516166f, -0.17532523f, 0.148237586f, -0.169818088f, -0.0751874894f, -0.00145684613f, + 0.242101297f, 0.0691361949f, -0.123409636f, 0.131296217f, -0.0819166154f, -0.159384966f, 0.0331388377f, -0.00851295795f, 0.125817835f, -0.122829095f, + 0.0788533464f, 0.0795873553f, -0.249470636f, -0.183947936f, -0.271617234f, -0.0214255322f, -0.164119825f, 0.0315094963f, -0.217496216f, -0.0438018478f, + -0.328969032f, -0.352339417f, 0.0825408697f, 0.0904301181f, 0.0652124211f, -0.0278453939f, 0.135250345f, -0.198932752f, -0.348944217f, -0.0618232302f, + -0.162864357f, -0.372509897f, -0.00999633316f, -0.187597424f, -0.0886586383f, -0.27198568f, -0.298573792f, -0.093272604f, 0.207878605f, -0.139668852f, + -0.0867923051f, -0.0166914426f, -0.39126119f, -0.358095556f, 0.196745038f, -0.434817374f, -0.106974803f, -0.226963505f, -0.296442777f, -0.449791342f, + -0.313701302f, -0.0756079331f, -0.293213636f, 0.021066647f, 0.033039052f, 0.28603676f, -0.0168675352f, 0.229473442f, 0.187415794f, -0.0236471947f, + -0.218633249f, 0.24284479f, -0.197397113f, -0.0828920752f, 0.12698172f, 0.121630482f, -0.10588558f, -0.00033191478f, -0.0618540421f, 0.152890563f, + 0.350695103f, -0.260760933f, 0.140502438f, -0.396948576f, -0.00834110472f, -0.154257491f, 0.271454453f, -0.0226850975f, -0.185989931f, -0.144636646f, + -0.169718787f, -0.0307236407f, -0.0853279606f, 0.0399151109f, 0.215855971f, 0.0941276103f, -0.181828037f, -0.245152295f, -0.101008765f, 0.142085582f, + -0.0569081493f, -0.11334575f, -0.0059307632f, -0.239880323f, -0.198954716f, 0.0404747166f, -0.0688926801f, -0.0826343745f, 0.0489392206f, -0.0151519692f, + -0.0839022174f, -0.00577921141f, -0.379413158f, -0.699541271f, -0.0949917212f, 0.316457778f, 0.0934711695f, -0.683368385f, -0.203845769f, 0.436182499f, + 1.04791176f, -0.675518751f, 0.29669407f, -0.0745671839f, -0.00116188661f, 0.0571228452f, -0.129394129f, -0.0542831421f, -0.157754317f, 0.313790619f, + 0.348781973f, -0.0519376434f, -0.636682034f, 0.0266690943f, 0.00843314733f, 0.558970332f, 0.508355319f, -0.206397235f, -0.0844501257f, -0.276875347f, + -0.381188154f, 0.203778103f, 0.192978799f, -0.207665786f, 0.333311617f, -0.198825032f, -0.358826488f, 0.1085077f, 0.347107649f, 0.364807338f, + -0.204113513f, 0.0916816145f, -0.0537360609f, -0.0570641495f, -0.315438658f, -0.12315999f, 0.136113241f, -0.13791205f, 0.112091064f, 0.2560139f, + -0.0704316646f, 0.101182923f, 0.427031279f, -0.552460909f, 0.556045353f, 0.70171839f, -0.219150975f, -0.534155488f, -0.272778302f, -0.615203083f, + 0.339515686f, 0.43809858f, -0.168065831f, -0.0895660222f, -0.269120902f, 0.0377679802f, 0.0505856425f, 0.136624336f, -0.0908491388f, -0.155028597f, + 0.583257735f, 0.0116753401f, 0.000876878679f, 0.136744902f, -0.183319479f, 0.269755036f, 0.830802262f, 0.378539324f, -0.188007712f, 1.06142509f, + -0.519577444f, -0.744766116f, 0.408011347f, -0.741570294f, -1.27765477f, 0.495514452f, -0.00937539898f, 0.101118363f, -0.103055269f, 0.059950646f, + 0.101199329f, -0.109977752f, -0.0573159121f, -0.133595794f, 0.445373684f, 0.15000473f, 0.279574662f, -0.249145642f, 0.181714147f, 0.563862622f, + -0.00439061504f, 0.0419037901f, 0.0258011352f, 0.0930103511f, -0.00443388568f, 0.163302779f, -0.228125021f, -0.0677218214f, 0.383806169f, -0.319216162f, + -0.263668984f, 0.0608730689f, 0.176480278f, 0.050158482f, 0.420219451f, -0.0488052778f, -0.0204592124f, 0.496525407f, -0.271960914f, -0.0770587772f, + 0.225930333f, 0.145449936f, 0.433174908f, 0.0869830176f, -0.366774559f, -0.592608809f, -0.0263784919f, 0.0909157991f, 0.10609144f, -0.0585011095f, + 0.107543975f, 0.195686072f, -0.139314443f, 0.263174951f, -0.516120315f, -0.333524585f, -0.26690957f, -0.557095289f, -0.218039408f, 0.27526775f, + 0.286979318f, 0.0228182599f, 0.406089306f, 0.0571791977f, 0.0699024647f, -0.0331161618f, 0.336949974f, 0.0430967771f, 0.160424218f, -0.147005126f, + 0.340254068f, -0.719981611f, 0.513058841f, -0.284326732f, 0.559920132f, -0.569148302f, 0.0894708484f, -0.0463323258f, -0.0180383567f, 0.0521842092f, + -0.111619569f, 0.165742949f, -0.214235336f, 0.352604359f, 0.125896886f, -0.0286869854f, 0.402697951f, -0.00535626663f, 0.207202092f, 0.421059042f, + 0.0959834382f, -0.0968295783f, -0.226889729f, 0.0983363464f, -0.162348539f, -0.223985612f, -0.230892882f, 0.112910762f, -0.161302492f, -0.600236535f, + 0.0811172128f, -0.116535388f, 0.131094575f, 0.126875505f, -0.0473274328f, -0.244132116f, -0.297251582f, -0.479590535f, 0.181458101f, -0.143222183f, + -0.240144163f, -0.063987568f, -0.241627499f, -0.0521522835f, 0.236889914f, 0.269735456f, -0.454293966f, 0.292024672f, -0.135803267f, -0.385483742f, + -0.247320056f, -0.244748116f, 0.0369249247f, -0.315586954f, -0.424419016f, -0.0915979668f, 0.390432805f, -0.228138626f, 0.115203463f, 0.179089308f, + 0.748564124f, -0.237653077f, 0.337761164f, -0.189138994f, 0.099142842f, 0.0112606827f, -0.0915880576f, -0.0219361112f, -0.171286881f, 1.28796887f, + -0.276818335f, -1.07646894f, 0.679676831f, -0.399518847f, -0.134240597f, -0.000716817507f, 0.0358600244f, -0.117341079f, 0.119422801f, 0.182410136f, + -0.0218682829f, 0.0256534088f, -0.0942742825f, 0.0351673029f, 0.0758332238f, -0.0704390034f, -0.0646369234f, -0.073464781f, 0.358791113f, 0.088503249f, + 0.146917224f, 0.468065977f, 0.0824491978f, 0.122947365f, -0.461115062f, -0.136030659f, 0.0259315092f, -0.0662572905f, 0.0759087577f, -0.25495252f, + -0.466526866f, -0.0944550782f, 0.0370809734f, -0.0962131768f, -0.105866015f, -0.223298714f, 0.123263322f, 0.175803795f, 0.131272018f, 0.025415279f, + -0.10711202f, -0.29799062f, 0.113237008f, -0.0269872677f, -0.151539341f, -0.143276826f, 0.07303188f, 0.0929697976f, -0.518299341f, -0.0368588679f, + 0.431161731f, 0.129989758f, 0.0888010114f, 0.0856963173f, 0.299928904f, -0.210380226f, -0.231081709f, 0.0630718172f, -0.163724303f, 0.0697069913f, + -0.414506227f, 0.133196816f, 0.17183581f, 0.0179266371f, 0.0773292929f, 0.415877908f, -0.224390998f, 0.063989006f, 0.0683998689f, -0.0303310677f, + -0.36361438f, -0.387215525f, -0.121823348f, -0.635597229f, -0.134966493f, -0.392721415f, -0.719002903f, -0.627922893f, 0.643933237f, -0.152195275f, + -0.0924756378f, 0.0479475334f, -0.0315041766f, -0.0169432573f, -0.059510652f, 0.0200484879f, 0.211313993f, 0.153515488f, -0.0291435122f, -0.0951273739f, + -0.151882336f, -0.214013472f, 0.374437124f, -0.0679607913f, -0.345841169f, -0.15261735f, -0.203756496f, 0.163882568f, -0.12344908f, 0.218043074f, + 0.173156649f, 0.30874449f, 0.437124401f, 0.642759979f, 0.291895479f, -0.228181109f, -0.0193584841f, 0.0820774063f, 0.449491888f, 0.116115861f, + 0.248559296f, 0.00681480858f, 0.184873432f, 0.224606693f, -0.128282413f, 0.236130014f, 0.291825682f, 0.015695462f, 0.31003508f, 0.470903456f, + 0.0588748045f, 0.067117013f, -0.0175605565f, -0.0855088085f, 0.080020465f, -0.0231959093f, 0.0564044788f, -0.15192242f, -0.332757562f, -0.198643833f, + 0.0704269484f, -0.226353124f, -0.0778084621f, 0.408074409f, 0.258671492f, -0.127795011f, 0.17264995f, -0.0679947138f, 0.418509632f, -0.0639230087f, + -0.0540482886f, -0.016626073f, -0.408160836f, -0.00156273821f, 0.799812317f, -0.419457376f, 0.722188711f, -0.356472313f, 0.145347685f, -0.179951221f, + -0.140388459f, 0.0684301779f, 0.000922316394f, -0.538544595f, -0.0319256037f, -0.0781605318f, -0.00262406934f, 0.191325232f, 0.167186514f, 0.285945326f, + 0.30341652f, -0.238022849f, 0.350381523f, 0.275618374f, -0.0838561505f, 0.192660391f, 0.341756254f, -0.0317622982f, -0.279077917f, -0.0242220983f, + 0.709514141f, 0.0785572007f, -0.223170489f, 0.0414261706f, -0.184083745f, -0.0790363327f, -0.0755218267f, -0.181758821f, 0.00738642085f, 0.0592964552f, + -0.0663597509f, 0.0127031533f, 0.145218357f, 0.11033655f, -0.13129504f, -0.166355252f, -0.192510575f, 0.0718062967f, -0.101126343f, 0.00869054906f, + 0.0840429068f, 0.143499628f, -0.3279154f, -0.0382677019f, 0.165857777f, -0.301145047f, -0.0507232621f, -0.116687365f, 0.0660524741f, -0.317248255f, + -0.256876856f, 0.31446144f, 0.227873117f, -0.167415306f, 0.257640958f, 0.114550903f, -0.0918739662f, 0.00284876022f, -0.201383308f, -0.0990986377f, + 0.0434153974f, -0.0714030936f, 0.173617989f, 0.0188739151f, -0.251626879f, -1.00330877f, 0.127476901f, 0.114293382f, 0.176429674f, -0.69107759f, + 0.155755252f, 0.102089025f, -1.08716333f, -1.22878575f, 0.375104994f, -0.432537377f, -0.00320134684f, -0.0318307132f, -0.0121608749f, 0.208828673f, + 0.467383176f, -0.0843178704f, -0.0982475579f, 0.054304447f, 0.215642869f, -0.229237929f, 0.270063162f, 0.2673935f, 0.214516446f, -0.0591908246f, + 0.175329939f, 0.253942311f, -0.230741277f, 0.559158206f, -0.0180195756f, 0.142454609f, -0.0929456055f, 0.214900583f, 0.340125114f, -0.0882830098f, + -0.303573072f, -0.00106275163f, -0.16494827f, -0.0839601085f, -0.0883156359f, 0.0478671305f, 0.359185487f, -0.177741483f, 0.189078733f, -0.0246234983f, + 0.342583507f, 0.641370952f, 0.162700146f, 0.480004638f, -0.0806799233f, -0.178320855f, -0.177639127f, -0.250833482f, -0.178985834f, -0.0281072911f, + 0.496237785f, 0.110640571f, 0.0328890607f, 0.0214015022f, 0.038102299f, -0.00157501164f, 0.321196526f, -0.0217496082f, 0.0432562977f, -0.0270059109f, + -0.262441635f, -0.217480227f, -0.0548459813f, -0.0589241385f, -0.0961484537f, 0.00491823908f, 0.78938514f, -0.305812448f, 0.493680209f, 0.845378458f, + 0.1924676f, -0.226778314f, -0.169291228f, -0.590278685f, 0.176980317f, 0.65129143f, 0.328980774f, 0.445320189f, 0.0f, 0.0f, + 0.0f, 0.0794823095f, 0.276787847f, -0.0654815584f, 0.057262592f, 0.107872523f, 0.185422033f, -0.325238824f, -0.0297511704f, -0.00732802646f, + -0.1617845f, 0.126082554f, 0.120474435f, -0.0112138372f, -0.324396163f, -0.251926988f, -0.114226915f, 0.081903711f, -0.134992197f, -0.212048694f, + -0.139029488f, -0.0760293528f, 0.225661367f, 0.377456933f, -0.0109266117f, 0.179618061f, 0.201336771f, 0.147556171f, -0.00154567359f, -0.20832634f, + -0.228691846f, -0.301034778f, 0.129740372f, 0.135804504f, -0.245617837f, 0.0250728931f, 0.0677641332f, 0.178723559f, 0.177599907f, 0.12528646f, + -0.07665243f, -0.0475598536f, 0.159861743f, -0.0527207442f, 0.0772747099f, 0.307238698f, 0.0391237922f, -0.243029863f, -0.0177469514f, 0.0330559798f, + 0.0199999996f}, + {0.437204927f, 0.79582274f, 0.439064384f, -0.318116665f, 0.210035652f, 0.116235256f, -0.105440304f, 0.157740995f, 0.0980156064f, 0.0609955005f, + 0.00584362447f, 0.141818374f, -0.150975555f, -0.0161989387f, -0.0998102352f, 0.127917647f, 0.00318227196f, -0.0594566017f, -0.162914738f, -0.0389257111f, + 0.0144801028f, -0.30896014f, 0.171051815f, 0.199362472f, -0.591514051f, -0.3572115f, 0.0526762567f, -0.32841292f, -0.0788461417f, 0.00997200701f, + 0.537830412f, -0.185120851f, -0.00492082164f, 0.209314898f, 0.00114865077f, 0.112247527f, -0.0689580366f, -0.290129095f, 0.14530693f, 0.0346103087f, + -0.218552917f, -0.0778238475f, 0.0314404741f, -0.22525543f, -0.074223116f, 0.0335750356f, 0.0794392899f, -0.0364088863f, 0.188962713f, 0.209601656f, + 0.0283250306f, -0.175100625f, 0.248916432f, -0.0308014192f, 0.259750456f, -0.249616817f, 0.170496985f, -0.0262443814f, -0.0445671082f, -0.08149416f, + 0.00276159542f, -0.538915753f, -0.203989133f, -0.224677116f, -0.0434034243f, -0.603021681f, -0.53718698f, 0.0859901756f, -0.161466852f, 0.112695746f, + 0.359769404f, -0.867479861f, 0.0117676109f, 0.00195443537f, 0.000167080696f, -0.131897643f, 0.208628118f, -0.112089969f, -0.230808839f, 0.157877877f, + 0.189489692f, 0.0646149889f, -0.136951625f, -0.375457823f, -0.0618972406f, -0.134124622f, 0.270433724f, -0.070038639f, -0.409796417f, -0.324191511f, + 0.0890914723f, 0.000282544264f, -0.1629242f, -0.0469530337f, 0.0223895386f, 0.159633949f, -0.0784210041f, -0.184251443f, -0.0581217371f, -0.0969130471f, + 0.169221327f, -0.468679428f, -0.287555814f, -0.195945635f, -0.3093099f, 0.0988243371f, -0.16969876f, 0.290478766f, -0.217072442f, -0.000144212609f, + 0.287388086f, 0.275752962f, 0.0640206784f, -0.333787739f, 0.632495582f, 0.10763637f, -0.342576116f, 0.184521317f, 0.187465891f, 0.212962225f, + 0.211490899f, 0.135699421f, -0.32622394f, 0.232900068f, -0.0314855427f, 0.132072672f, 0.519425809f, -0.254401296f, -0.767059565f, -0.0187393092f, + 0.0261123516f, 0.014153895f, 0.408510208f, 1.27107072f, -0.619752944f, -0.961148381f, 0.246000469f, -0.956831932f, -0.179458722f, -0.179612324f, + 0.569737017f, 0.0463690832f, 0.23216261f, 0.185151234f, 0.0266659055f, 0.0193214156f, 0.0164687894f, -0.0924596936f, -0.01836822f, 0.0675220266f, + -0.0991237983f, -0.398966998f, -0.444152176f, 0.35833925f, 0.122865774f, 0.012667235f, 0.143872768f, -0.0209947694f, -0.145522371f, 0.23681806f, + 0.392379522f, 0.000461632822f, 0.176877126f, 0.175560176f, -0.456174672f, -0.0640411898f, 0.0260694344f, 0.191827968f, -0.0115754716f, 0.222096413f, + -0.817447364f, 0.229900956f, 0.269959271f, 0.091646716f, -0.0446379445f, 0.0322227292f, 0.0995288715f, 0.291982263f, 0.44018358f, 0.015326607f, + -0.0680046976f, -0.125337273f, -0.243480608f, -0.0795179158f, -0.121940807f, 0.0402282998f, -0.358597517f, -0.0799888968f, -0.191677764f, -0.40844062f, + 0.0308474097f, 0.202336535f, 0.0364707932f, 0.00381973688f, -0.302411467f, 0.540955126f, 0.0795237422f, -0.338397563f, -0.215792924f, -0.0511936657f, + -0.444079399f, -0.0145637924f, 0.00985581335f, -0.124927118f, -0.0440857336f, -0.334484428f, 0.534409702f, 1.14385688f, -1.75340009f, 0.0411479697f, + -0.738750219f, 0.72059232f, 0.0683893561f, -0.143516898f, -0.185418397f, 0.975314021f, 0.0311414488f, 0.0250676088f, 0.0722995624f, 0.250212401f, + 0.0174462683f, 0.167295009f, -0.200926557f, -0.182624638f, -0.274597943f, 0.53572464f, -0.154471993f, 0.117295898f, 0.208155677f, -0.224626496f, + -0.212155312f, -0.215472862f, 0.0450192355f, -0.268397301f, -0.196485758f, -0.511081934f, -0.249315381f, 0.021206988f, -0.0343645141f, 0.0856001973f, + -0.0627486557f, -0.0118940435f, -0.231373176f, 0.00634664111f, -0.161051959f, 0.340791494f, -0.158978194f, 0.00342110661f, 0.36792025f, 0.104889713f, + -0.0583028533f, -0.421093732f, 0.158379376f, 0.154374659f, -0.199948385f, -0.167289943f, -0.00780764362f, -0.195486531f, -0.140795037f, -0.15402776f, + -0.0781054795f, -0.00519254431f, 0.419491589f, 0.0147678433f, -0.0543500669f, 0.39348194f, 0.274362236f, 0.0734272748f, 0.0360517204f, 0.145456001f, + 0.156595379f, -0.00501923775f, 0.265857279f, -0.0906987786f, -0.0633318797f, 0.0239553172f, -0.261930168f, -0.295215338f, 0.161255151f, 0.322144002f, + 0.516429842f, -0.471345603f, 0.496557266f, -0.869234741f, -0.448264688f, 0.21391362f, -0.808695436f, -0.0492781475f, 0.0120117096f, 0.0159573015f, + -0.0237108357f, -0.0044144569f, -0.0312706418f, -0.0773130804f, -0.107828312f, -0.160694987f, -0.885372341f, 0.277538061f, 0.180453807f, 0.0131255239f, + -0.0262788683f, -0.153998792f, 0.147916839f, 0.0833770335f, 0.214652717f, 0.180694714f, 0.0856525376f, 0.286176205f, -0.0086038867f, 0.0475435294f, + 0.0279090293f, 0.0775384232f, 0.0266226232f, -0.116497234f, -0.296959549f, 0.101202592f, 0.034839578f, 0.231224313f, 0.34472546f, 0.123053193f, + -0.0634378716f, 0.0632224306f, 0.310016602f, 0.202677265f, 0.481300026f, 0.117524952f, -0.230984181f, -0.201067656f, -0.0245771073f, -0.0514651313f, + 0.222741693f, 0.00648321817f, 0.0892841518f, -0.0335169137f, -0.152456149f, 0.323998749f, -0.0766943693f, -0.185653076f, -0.0925968438f, -0.187476248f, + -0.384664655f, -0.0279040523f, -0.385762513f, 0.357629091f, -0.0352133252f, 0.0596358553f, -0.0242723934f, 0.00103412697f, -0.227633849f, -0.550111532f, + -0.206933782f, -0.197246999f, -0.601865649f, -0.119970605f, 0.0665813759f, -0.177619979f, 0.289925009f, 0.660419047f, 0.0502083637f, 0.190039054f, + 0.0331769548f, 0.00424856646f, -0.0255700275f, -0.012655152f, -0.0139397103f, -0.0598135106f, -0.041135598f, 0.0517171994f, -0.902633369f, 0.026271224f, + 0.0466000997f, 0.128850713f, 0.144802228f, -0.0736828148f, 0.340815961f, -0.104140721f, -0.0547395907f, -0.228682578f, -0.139112666f, 0.0886177197f, + 0.0684123486f, -0.0265315305f, -0.0410673991f, 0.000926051114f, -0.0339116231f, -0.06805823f, 0.717036903f, -0.135824025f, -0.12975955f, -0.190833971f, + -0.0630182102f, -0.113672026f, -0.405785024f, 0.0887649581f, 0.100552276f, 0.434857041f, 0.277235985f, -0.331707567f, -0.0656862333f, 0.245650366f, + 0.2173094f, -0.101742685f, 0.0924894065f, 0.261599779f, -0.335499465f, -0.269426376f, -0.0904110745f, 0.178140879f, -0.155383095f, 0.0408210233f, + 0.102776013f, 0.255029142f, -0.0905911028f, -0.0025189009f, -0.427269548f, -0.235211104f, -0.107454814f, -0.125259772f, 0.0363325067f, -0.102107666f, + 0.235813096f, -0.00616228953f, -0.301057667f, 0.834364891f, 0.66138643f, -0.218125165f, -0.208107889f, -0.0404892489f, -0.756763518f, 0.155948028f, + -0.101058178f, -0.509505153f, -0.0187548678f, 0.0046321936f, -0.0270413384f, 0.00684362231f, -0.0294409487f, 0.01972734f, -0.0832930729f, 0.136030927f, + -0.7397241f, -0.000855609425f, 0.00704781106f, -0.0106868949f, -0.037713889f, -0.0218205657f, -0.27939266f, -0.0235267095f, -0.138728738f, -0.0103448993f, + -0.256322533f, 0.0434292294f, 0.265551537f, -0.0111555597f, 0.0457777604f, -0.0215223432f, 0.0191988479f, -0.0537123643f, -0.233186215f, 0.0453603268f, + -0.0303911604f, 0.000457061367f, -0.0299746562f, 0.0090396069f, 0.130080491f, 0.0175366998f, 0.188177913f, 0.0597376302f, 0.13145192f, -0.00428146403f, + 0.17717506f, -0.111255214f, 0.255440533f, -0.0922052041f, -0.100453116f, 0.355357349f, -0.110357217f, 0.0313351676f, -0.0838082209f, 0.138499185f, + 0.171381921f, 0.143688232f, -0.296086997f, -0.0647244453f, 0.295913815f, 0.433998168f, 0.138618574f, -0.26061362f, 0.0438039042f, 0.0587544814f, + 0.0195482709f, 0.00914085191f, -0.0912326947f, -0.292975068f, -0.0064786463f, 0.188055113f, 0.838496983f, -0.0217055045f, 0.750575364f, 1.07065356f, + 0.019794669f, 0.814243138f, 0.637595177f, -0.146046594f, -0.00986132585f, 0.0124552259f, -0.00711993081f, 0.045911409f, 0.034395583f, -0.0150525067f, + 0.000188192716f, 0.0182128549f, -0.0269282945f, -0.183880597f, -0.00749045657f, -0.373938501f, 0.0367912874f, 0.161211833f, 0.132423088f, 0.0414499268f, + 0.105077818f, -0.171453595f, -0.0453410223f, 0.199608698f, 0.411384374f, -0.00425420562f, 0.518677771f, -0.0981346965f, 0.151687533f, 0.197260901f, + -0.126710638f, -0.279440641f, -0.383345842f, -0.0924815089f, 0.120708421f, -0.0823969617f, -0.13636969f, -0.126484856f, 0.0669008046f, -0.594268382f, + -0.0402190536f, -0.0783136189f, -0.421521276f, 0.30497703f, -0.324276984f, -0.195804641f, -0.43621847f, -0.0723127946f, -0.505071998f, 0.18664223f, + 0.101815164f, 0.0445570424f, -0.21854727f, -0.031351272f, 0.44050619f, -0.246105954f, -0.251094848f, -0.129033297f, 0.169337481f, 0.0908023268f, + 0.180644631f, 0.0175932255f, -0.0601568632f, -0.00539110694f, -0.28662172f, 0.491552979f, 0.141408294f, -1.05429101f, 0.88877219f, 0.761699438f, + -0.489248395f, -0.0187334809f, 1.15207744f, -0.887617469f, -1.1354233f, -0.615501285f, 0.0243814718f, 0.0273358375f, 0.0119783413f, -0.0656412095f, + -0.0130682383f, 0.195327997f, 0.109376192f, -0.315242916f, 0.31200543f, 0.261328012f, 0.24281019f, 0.285560191f, -0.0330663621f, 0.13028565f, + -0.168115497f, 0.0980092064f, -0.156669244f, 0.130135447f, 0.0390744768f, -0.228509352f, 0.0337741002f, 0.371700555f, -0.0759292766f, 0.1639871f, + -0.206469983f, 0.178323001f, 0.338605195f, 0.0355383754f, 0.225867137f, -0.332366526f, -0.0431966186f, 0.207721084f, -0.350248992f, 0.16101113f, + 0.266590953f, 0.264059842f, -0.214305505f, 0.0517612062f, 0.331683934f, 0.506731808f, -0.0159028601f, -0.369549274f, 0.218311816f, 0.511536479f, + 0.150484785f, 0.117995024f, -0.0172271878f, -0.4786897f, -0.462191075f, -0.309032291f, 0.009379589f, -0.0362872481f, 0.0607356355f, -0.197480515f, + 0.107059181f, -0.162535295f, -0.250479907f, -0.0500157624f, 0.0471333377f, -0.122950517f, 0.460064352f, -0.0354562588f, -1.23151135f, -0.582033813f, + 0.22173667f, -1.75913727f, -0.103309952f, -0.318009645f, -0.841539443f, -0.604349911f, -0.0700794905f, -0.239072785f, 0.059796121f, 0.133416802f, + 0.00424249051f, -0.0159196556f, -0.199197739f, -0.447804958f, -0.159147054f, 0.146522492f, 0.508974731f, 0.188236117f, 0.11172618f, 0.477228016f, + 0.151487112f, 0.0316795111f, -0.16831024f, -0.111620136f, 0.422439396f, -0.481061041f, -0.0750201195f, -0.549474716f, -0.0481238179f, 0.148784623f, + 0.095758222f, 0.188192189f, 0.20636481f, 0.0972981602f, 0.54026562f, -0.0438451208f, -0.139772534f, -0.1628021f, -0.164808288f, 0.23127608f, + -0.191793442f, 0.272009492f, 0.275795132f, 0.181642935f, 0.0900303274f, 0.450233161f, -0.691934049f, 0.0897538587f, 0.118153028f, 0.114937194f, + 0.0515132658f, -0.0338343494f, 0.352510005f, -0.0101657044f, 0.0065090768f, 0.0527077466f, 0.00624680426f, 0.261403382f, -0.374205738f, -0.10629198f, + -0.100339688f, -0.0848261043f, 0.046789851f, 0.371177346f, 0.210783347f, 0.146754727f, -0.0251764841f, 0.0580669381f, -0.356600761f, -0.3284702f, + -0.0765896291f, -0.428460777f, -0.333272636f, -0.606867135f, -0.164290056f, 0.654930949f, -1.140203f, 0.377478212f, -0.581717253f, 0.127559394f, + 0.00148013805f, 0.0369090885f, 0.0425331295f, -0.075351119f, -0.338502675f, 0.0418923497f, 0.382629216f, 0.093639262f, 0.850303531f, 0.0519182608f, + -0.0281527825f, 0.00638820278f, -0.220494732f, -0.337825209f, 0.267760187f, 0.183828294f, -0.172142491f, -0.0605346859f, -0.277975619f, 0.0466986746f, + -0.271914572f, 0.361469477f, -0.109448314f, 0.403345019f, -0.0749114826f, -0.2375357f, -0.541667521f, -0.118084013f, -0.047225181f, -0.444193006f, + -0.153183028f, 0.101787664f, 0.251794428f, -0.0136765363f, -0.0990717262f, 0.0184011031f, -0.228260726f, 0.0796486214f, -0.0966077819f, -0.10936676f, + -0.158265263f, -0.16103442f, -0.703488111f, -0.468880028f, -0.139403448f, 0.15372318f, 0.125109792f, 0.289350599f, -0.0851558223f, 0.288414568f, + -0.517732918f, 0.172060505f, 0.218181744f, -0.057513047f, 0.115281545f, -0.256504834f, -0.114084937f, -0.126609385f, -0.0158536453f, 0.0556809977f, + 0.0957602784f, -0.545142531f, 0.229531869f, 0.315052688f, 0.535269022f, -0.28667593f, 0.753713071f, -0.279542178f, -0.231547594f, -0.609377801f, + 0.430329263f, 0.473323196f, 0.2094789f, 0.0357725509f, 0.00691400142f, -0.0235712677f, 0.111615196f, 0.0457599834f, 0.0118661439f, -0.0103898728f, + -0.234043717f, -0.00320127932f, -0.0345160104f, -0.0262892935f, 0.0145881828f, -0.135338202f, -0.0999391824f, -0.202305079f, 0.0493233018f, -0.180068165f, + 0.117133692f, 0.0125291785f, 0.209591925f, -0.0330353454f, -0.286343664f, -0.0274254102f, -0.093415387f, 0.239284277f, 0.358053356f, 0.1204786f, + 0.0206479151f, -0.107977122f, 0.0183981769f, -0.152393147f, 0.134020045f, 0.12451832f, -0.14776285f, -0.0421854332f, -0.0328442119f, -0.25116533f, + -0.248759642f, 0.122176088f, -0.0626464039f, 0.239674821f, -0.245420232f, -0.37092039f, 0.19287774f, 0.159705609f, -0.130282953f, -0.44689548f, + -0.0460084639f, -0.143176809f, -0.12962234f, -0.57937938f, -0.207303196f, -0.508513153f, -0.0894829184f, 0.24970752f, -0.147371739f, -0.116439782f, + -0.00667855097f, -0.0334443748f, 0.384568542f, -0.570515454f, -0.593942225f, -0.190094277f, 0.338099599f, 0.0641652867f, 0.607566893f, -0.677459359f, + 0.0792442709f, -0.0324935205f, 0.586153686f, 0.881305933f, 0.245909095f, 0.00204892876f, 0.040681053f, -0.106683031f, -0.0589009598f, -0.0172515325f, + 0.133113712f, 0.00978616346f, -0.211729527f, -0.134621933f, -0.143738165f, -0.0793402717f, 0.062640734f, -0.121376798f, 0.0490164869f, -0.256971896f, + -0.0422468558f, 0.197242215f, -0.421860605f, -0.0684353784f, -0.284424305f, -0.0493882447f, -0.0486044623f, -0.111324489f, -0.0110259699f, -0.0330088772f, + -0.172578901f, 0.0226928145f, 0.0450545326f, 0.119282208f, 0.0686789751f, -0.13824138f, 0.749154806f, 0.0107145887f, 0.0259693544f, 0.11137148f, + 0.13250652f, -0.051894486f, 0.129033864f, 0.0435151234f, 0.160235927f, 0.374913663f, 0.335426152f, -0.26821962f, -0.0380645692f, -0.0182602666f, + -0.0899389461f, -0.0876597464f, -0.0921502486f, 0.156635836f, -0.0435665809f, 0.000709626707f, 0.0325670429f, 0.176450402f, 0.0233280081f, -0.378230304f, + 0.0197206773f, -0.0555212274f, -0.0182300769f, 0.105109826f, -0.900954723f, -0.638811052f, 0.159612596f, 0.471157432f, 0.997592807f, -0.432789475f, + 0.114172071f, -0.126879141f, 0.728739917f, 0.845168889f, -0.21356754f, 1.73358381f, 0.0469382145f, 0.037104059f, 0.0964882001f, -0.0808945224f, + -0.141636893f, -0.119319752f, 0.0420427993f, 0.0472231954f, -0.0504945517f, 0.189153954f, -0.00595333194f, 0.15952599f, 0.13030377f, -0.339119107f, + -0.274458855f, -0.255216449f, -0.0412813574f, -0.0528396294f, 0.0484906547f, -0.248627678f, -0.0200746693f, -0.0101936357f, -0.0670499951f, -0.0738818869f, + 0.20208925f, 0.0004609561f, -0.0566869117f, 0.00723310607f, 0.0748960003f, 0.0658851713f, -0.151808947f, 0.0378854461f, 0.433700532f, -0.0242372155f, + -0.0399040207f, -0.0476308353f, 0.141772494f, -0.0569795668f, -0.214303866f, -0.539144635f, 0.0317048579f, -0.377322823f, -0.18466033f, 0.12157996f, + -0.163917586f, 0.125608385f, -0.052598197f, -0.403110713f, 0.126826853f, -0.397970855f, -0.126324862f, 0.145840004f, -0.53964293f, 0.377859026f, + -0.234488368f, -0.582030952f, -0.15637134f, -0.0803310573f, 0.0792386457f, -0.118860975f, 0.420768976f, -0.729546309f, -0.0807428733f, -0.673920989f, + 0.503868103f, 0.0587886684f, -0.176585123f, 0.321871698f, -0.805839002f, -0.269420177f, 0.841467321f, 0.128658101f, 0.0496603139f, -0.0280974321f, + 0.0903837606f, 0.241852239f, 0.0803140998f, -0.0806611851f, -0.0472782739f, -0.0236918516f, -0.0680459663f, -0.103055127f, -0.121188276f, -0.226161331f, + -0.00356430141f, -0.0410319269f, 0.00866157189f, -0.353968769f, -0.107852623f, -0.496339709f, -0.0789892152f, 0.137530178f, 0.191725388f, 0.0933030248f, + 0.0848814473f, 0.11169374f, 0.107222289f, -0.015081089f, -0.257021427f, -0.0211021975f, 0.1352714f, 0.0292856582f, 0.212389052f, 0.184346989f, + -0.041199144f, 0.29289037f, -0.126963854f, 0.157084912f, -0.0473913103f, -0.0841825381f, 0.119899482f, -0.0629543513f, 0.16554518f, -0.125119895f, + 0.046672307f, -0.0880546868f, -0.000180973395f, -0.0331940874f, -0.160248473f, 0.104236148f, 0.0677120239f, -0.0601180829f, -0.0359042957f, -0.0663314387f, + -0.0792668015f, -0.0874824822f, 0.258325756f, -0.324056119f, -0.238125369f, -0.413353264f, -0.104998775f, 0.163062274f, 0.482768863f, 0.576492488f, + 0.117119715f, -0.219789639f, -0.421689332f, -0.0654301792f, -0.211120188f, -0.244646057f, -0.310426235f, -0.246039569f, -0.35420388f, -0.281715304f, + -0.606658757f, -0.0519394539f, 0.306495011f, 0.605208576f, 0.543184996f, 0.169343218f, 0.0914866179f, 0.241796061f, -0.153908551f, 0.131120771f, + 0.54209429f, 0.141373768f, 0.250706166f, 0.32151264f, 0.0502307415f, 0.327134103f, 0.0384770781f, -0.0417864509f, 0.0175834317f, -0.221825778f, + -0.0245760139f, -0.0296537988f, -0.0122212972f, -0.249944687f, 0.302532107f, -0.0347554423f, 0.0377319865f, 0.163671181f, 0.0247077122f, -0.0994052738f, + -0.0392172337f, 0.0257011354f, -0.00611363305f, 0.090088658f, -0.11986056f, -0.179029837f, 0.328462452f, -0.0876445547f, -0.0180254262f, 0.0393130668f, + 0.200249091f, -0.1419328f, 0.0413908921f, 0.0343342647f, 0.0170187876f, -0.331970185f, -0.0211289395f, -0.426801324f, 0.0923058912f, 0.130113274f, + 0.100663304f, -0.30815202f, 0.0420131274f, -0.202209577f, -0.224648878f, -0.172304511f, -0.1637934f, -0.0346921235f, 0.0698224753f, -0.356757879f, + -0.127298236f, 0.112603024f, 0.0218678061f, 0.0513769649f, -0.267565608f, 0.0941419974f, -0.0395812541f, 0.0656734407f, -0.0161141641f, -0.469859391f, + -0.224421948f, 0.776326418f, 0.930440247f, 0.140589461f, 0.465662092f, 0.0313122347f, -0.0285378341f, 0.570697784f, -0.0772327706f, -0.141918615f, + -0.766513526f, 0.046136681f, -0.0235099662f, 0.127764776f, 0.0522216782f, -0.100201599f, -0.128371343f, -0.0138462475f, 0.0925395042f, -0.0833251402f, + -0.107175395f, -0.262622088f, -0.0652637631f, -0.144909814f, 0.205392852f, 0.076639384f, 0.0854952484f, -0.0157191195f, 0.157067224f, 0.0575216934f, + -0.11482358f, -0.153082609f, 0.0751532167f, 0.0592754632f, -0.250453979f, -0.0926636308f, -0.168894395f, -0.21708864f, -0.0445020646f, -0.0343646407f, + -0.0490053445f, -0.2621108f, -0.0446094796f, -0.0811311305f, 0.253372192f, -0.0537946858f, 0.223791122f, -0.0828495175f, 0.00577329053f, 0.0577865876f, + 0.292222261f, 0.110374384f, -0.0755676776f, 0.149264082f, -0.0327544659f, -0.14888379f, 0.0501760878f, -0.0325772651f, 0.0236100443f, 0.190217733f, + -0.0663645566f, -0.161954775f, 0.26661548f, 0.0702954084f, -0.679474473f, -0.122369893f, -0.547751069f, 0.204742134f, -0.159490243f, -0.639323175f, + 0.100854337f, 0.0207304787f, 0.0255491808f, -0.012624409f, 0.442319453f, -0.0208961945f, 0.217082247f, 0.360432774f, -0.093110837f, 0.145095319f, + 0.0513334088f, -0.199895963f, 0.619706929f, 0.311651379f, 0.00832941011f, 0.610411048f, -0.0496487468f, -0.0402017012f, 0.22110562f, -0.2664617f, + -0.121841691f, 0.016269302f, -0.314571232f, -0.367803842f, 0.411577523f, -0.209634468f, 0.185652211f, -0.0450404659f, -0.0723086819f, -0.0869112015f, + -0.167939007f, -0.000639556325f, -0.26600489f, -0.113191314f, 0.0398609713f, 0.109824285f, -0.162542999f, 0.223154336f, 0.111721009f, -0.280608177f, + -0.358966887f, -0.0820543319f, -0.310728967f, -0.187736005f, -0.0798193067f, 0.006557588f, -0.15935953f, -0.122656927f, -0.174115211f, 0.3137348f, + 0.275268793f, -0.189874455f, 0.333319694f, -0.228954211f, 0.0829796046f, -0.00907284208f, 0.148601755f, 0.192993313f, 0.00243610982f, -0.0109275896f, + -0.100769579f, 0.0649416447f, -0.039608445f, -0.0225007199f, 0.194825381f, 0.140112653f, -0.180895224f, -0.279672801f, -0.114936851f, 0.228404105f, + -0.0101221371f, -0.0401500426f, 0.0516131409f, -0.208658203f, -0.131037995f, 0.0977391079f, -0.116534874f, -0.130121022f, -0.039123524f, 0.0487441085f, + -0.0353913866f, -0.0661854073f, -0.135960519f, -0.0286061559f, -0.117337666f, 0.306724489f, 0.130002603f, -0.661184013f, -0.160297021f, 0.671203554f, + 1.06287968f, -0.633021414f, 0.303659022f, -0.116227493f, 0.0910732672f, 0.0864962339f, 0.0708205104f, 0.239345282f, 0.206805438f, 0.433172226f, + 0.199774697f, -0.0594713651f, -0.258696049f, 0.425626963f, 0.357470483f, 0.56701088f, 0.367864728f, -0.237356082f, -0.0380746312f, -0.163435549f, + -0.30730024f, 0.201757893f, 0.187952772f, -0.195334241f, 0.498011291f, -0.293749809f, -0.238899603f, 0.202281088f, 0.0851788893f, -0.0310569499f, + -0.101801418f, 0.176978812f, 0.101736508f, 0.0632714927f, -0.277675748f, -0.167538896f, 0.179806694f, -0.0875898823f, 0.125575453f, 0.251111776f, + -0.0632151663f, 0.0999829322f, 0.537501931f, 0.0737130567f, 0.304624289f, 0.26849702f, 0.122650646f, -0.0946496502f, -0.36781624f, 0.0141618634f, + 0.20005095f, 0.0652295128f, -0.160327181f, 0.0521822684f, -0.356350094f, 0.264112025f, -0.00252836547f, -0.0151875392f, -0.0204058848f, -0.108307898f, + 0.493457079f, 0.0505603105f, 0.0512197949f, 0.188380986f, -0.506324589f, -0.065375559f, 0.548281133f, 0.405731112f, -0.325132608f, 0.915298879f, + -0.532431126f, -0.927089214f, 0.217877433f, -0.73468703f, -1.15329421f, 0.506840706f, 0.122758307f, 0.0959179923f, -0.10831257f, 0.160929382f, + 0.158527762f, -0.0618149266f, 0.080697991f, -0.256186545f, 0.327245861f, 0.184408069f, 0.473689497f, -0.244641632f, 0.176285744f, 0.476413995f, + 0.346344441f, 0.010140799f, -0.0436002351f, -0.131097093f, -0.019206956f, 0.123071142f, 0.258684456f, -0.129381433f, 0.33104375f, -0.341267228f, + -0.137878612f, -0.268448651f, 0.0924073234f, 0.252439916f, 0.237682194f, 0.101451941f, -0.228486508f, 0.45285812f, 0.251062304f, -0.135159269f, + -0.117859423f, -0.0534324758f, 0.0970708355f, 0.0516291521f, 0.0331727453f, -0.499438822f, 0.0685870796f, 0.1490684f, 0.16390349f, 0.0256691501f, + 0.188646361f, 0.312956601f, -0.175986305f, 0.305218279f, -0.423205882f, -0.324310392f, -0.307620436f, -0.323511451f, -0.200964689f, 0.290852845f, + 0.403992236f, 0.0729630589f, 0.360960662f, 0.151030973f, -0.111167744f, -0.00472199172f, 0.23211965f, -0.122441009f, -0.459585369f, -0.110370338f, + 0.326464236f, -1.04497194f, 0.377578467f, -0.186828464f, 0.435137302f, -0.57999897f, -0.132276699f, -0.022682609f, 0.109127022f, -0.019786628f, + -0.138101757f, 0.242186636f, -0.150408655f, 0.332499325f, 0.129083961f, 0.0483900942f, 0.53597039f, -0.048942253f, 0.188986763f, 0.3709701f, + 0.256798983f, 0.165140703f, 0.0988404006f, 0.0723534301f, -0.135145962f, -0.258737773f, -0.152767375f, -0.0177989863f, 0.395112574f, -0.628078938f, + -0.12186233f, -0.144693404f, 0.0905231759f, 0.0095616756f, -0.0761535168f, -0.14643693f, -0.0802358016f, -0.462305725f, 0.343319118f, -0.0164435282f, + -0.0843435377f, 0.15140529f, -0.117182598f, 0.256911278f, 0.36117956f, 0.461465925f, -0.17121923f, 0.202422529f, 0.00927488413f, -0.258064568f, + -0.209873959f, -0.158593461f, -0.194038317f, -0.444462657f, -0.56509608f, -0.289964348f, -0.0405572206f, -0.453288376f, -0.211590424f, 0.277116477f, + 0.676387846f, -0.154339045f, 0.218910277f, -0.421596467f, 0.406989217f, -0.0151179023f, -0.1469547f, 0.207232073f, -0.0529554114f, 1.54851294f, + -0.44691661f, -1.00676203f, 0.636529803f, -0.283339679f, -0.168019861f, 0.0161710493f, -0.0792540684f, -0.305472612f, 0.144976348f, 0.455419272f, + 0.0863018408f, -0.0409479029f, -0.116321281f, -0.0584555455f, 0.161194041f, -0.0391042233f, -0.127018675f, -0.277980626f, 0.473977536f, 0.0681830272f, + 0.0597782508f, 0.182397857f, 0.0106854346f, 0.286231369f, 0.0582272187f, -0.16172035f, -0.0791217834f, -0.248234808f, -0.0173476059f, -0.439119607f, + -0.258945137f, 0.0462844558f, -0.0709895343f, -0.122178949f, 0.0727157071f, -0.0653003603f, -0.0361779295f, 0.193643823f, 0.144540876f, -0.228686363f, + -0.223871231f, -0.233999968f, 0.467419058f, 0.108618386f, -0.113583185f, -0.126810879f, -0.0104047507f, 0.121974871f, -0.66479367f, -0.0291346014f, + 0.101771519f, 0.113461874f, 0.161271453f, 0.0705547109f, 0.391627848f, 0.0709073246f, -0.219815642f, -0.0736673772f, -0.20226042f, -0.0584522374f, + -0.879622221f, -0.0692324042f, 0.0892744511f, 0.0548123904f, 0.144684345f, 0.265032083f, -0.364700705f, 0.11765404f, 0.0484449789f, 0.283504605f, + -0.395945132f, -0.931214333f, -0.461022556f, -0.590534806f, -0.411395729f, -0.375968844f, -0.790080905f, -0.601462543f, 0.89890188f, -0.0500652604f, + 0.417472869f, 0.278125614f, -0.0255045276f, -0.011283909f, -0.245328784f, -0.027925944f, 0.0663387999f, 0.321386129f, 0.0885890052f, -0.0711879805f, + -0.127079546f, -0.162997276f, 0.263899207f, -0.0473732427f, -0.22637023f, -0.0279280543f, -0.0761625096f, 0.120013557f, -0.0775053799f, 0.278116196f, + 0.26710856f, 0.446065575f, 0.640398443f, 0.360335559f, 0.482204378f, 0.0297843125f, -0.26621455f, 0.00509508187f, 0.417411745f, 0.274341345f, + 0.219139844f, 0.117519915f, 0.118119851f, -0.0121751744f, -0.0191419274f, 0.244258359f, 0.0862509459f, 0.137203738f, 0.0280260183f, 0.175285131f, + 0.0642229095f, -0.0638982803f, -0.0980459824f, -0.259306014f, 0.0287448745f, 0.0897846073f, 0.108326755f, -0.207421824f, -0.411147833f, -0.285041869f, + -0.156959981f, -0.289423764f, -0.0981746987f, 0.17475912f, 0.131084636f, -0.168592617f, 0.00573371118f, -0.12352892f, 0.44233948f, -0.106773756f, + -0.146531999f, 0.0568572506f, -0.222767174f, 0.265371591f, 0.35611847f, -0.451033801f, 0.730029225f, -0.41636914f, 0.19999215f, -0.351690739f, + 0.172555417f, 0.0856927857f, -0.0282244012f, -0.455689311f, -0.0489625037f, 0.0425077267f, -0.0709517822f, 0.0674823895f, 0.166347384f, 0.0985849574f, + 0.170120329f, -0.244002029f, 0.335761905f, 0.186425045f, -0.0310981423f, -0.0472115725f, 0.345500827f, 0.0930226967f, -0.235647753f, -0.024434017f, + 0.706020236f, 0.0673754066f, -0.289297044f, 0.0148709342f, -0.118887357f, 0.266848564f, -0.141114742f, -0.172013104f, 0.236132488f, 0.620805204f, + 0.0370628722f, 0.251287073f, 0.0781477913f, 0.126722842f, -0.125769541f, -0.386906207f, 0.088503927f, 0.197281793f, 0.0448846593f, 0.35948804f, + 0.471869528f, 0.385189146f, -0.0948050618f, 0.0212395657f, 0.146379381f, -0.11350216f, 0.0334931053f, -0.147426739f, -0.0243513696f, -0.270552129f, + -0.248792231f, 0.426191777f, 0.146247491f, -0.36377725f, -0.0813077018f, 0.110728674f, -0.133676842f, 0.0878243819f, -0.183538482f, -0.135560647f, + -0.0564778633f, -0.0796944425f, -0.168943569f, 0.152806088f, -0.0179360583f, -1.17363477f, 0.350322604f, 0.206194639f, 0.28059873f, -0.478562772f, + 0.149106368f, 0.100343391f, -1.08175004f, -1.18695176f, 0.384449154f, -0.414048433f, 0.02662329f, 0.0308128558f, 0.0147187319f, 0.20435968f, + 0.430234194f, -0.182383597f, -0.167862535f, -0.0633655116f, 0.175263971f, -0.199302524f, 0.340236217f, 0.0880362391f, 0.250785559f, -0.221097946f, + 0.224512428f, 0.279809564f, -0.29004246f, 0.554240823f, -0.0405951664f, 0.0948179066f, -0.0656798035f, 0.260405213f, 0.455765963f, 0.0607664324f, + -0.251911193f, 0.0621386617f, -0.0464355871f, -0.146952987f, -0.117524207f, 0.0713930279f, 0.411964834f, 0.137857154f, 0.328662574f, -0.0612290241f, + 0.242327452f, 0.794129372f, 0.162459761f, 0.625458181f, -0.0496782102f, -0.148081303f, -0.162492976f, -0.172442824f, -0.0462583527f, 0.0311205499f, + 0.335303277f, 0.115909874f, 0.00255033723f, 0.0875154361f, -0.0142915957f, 0.208244979f, 0.011003809f, 0.0473537073f, 0.150348648f, -0.0611767545f, + -0.285184056f, -0.126191571f, -0.0609769262f, -0.035876777f, -0.0681206882f, 0.00639729016f, 0.941052794f, 0.0845582038f, 0.208714455f, 0.845378458f, + 0.1924676f, -0.226778314f, -0.169291228f, -0.590278685f, 0.176980317f, 0.65129143f, 0.328980774f, 0.445320189f, 0.0f, 0.0f, + 0.0f, 0.0112649826f, 0.171688899f, -0.0953749865f, 0.0361875333f, 0.0626384988f, 0.133241206f, -0.289227217f, -0.0478978157f, -0.014137092f, + -0.0985466689f, 0.137593433f, 0.0176389795f, -0.0880499333f, -0.336937636f, -0.331006408f, -0.287988782f, 0.130898893f, -0.094566904f, -0.133188024f, + -0.0628890172f, 0.0261573177f, 0.241381556f, 0.407820225f, 0.0259183962f, 0.174384937f, 0.0260221213f, -0.0387244597f, -0.202165768f, -0.312292576f, + -0.17975913f, -0.152651578f, 0.283849537f, 0.149789527f, -0.127689406f, 0.060863141f, 0.0064349561f, 0.0812200978f, 0.0782844648f, 0.0358283222f, + -0.0329459459f, 0.0156202642f, 0.242898732f, 0.0611717328f, 0.0845263079f, 0.199475944f, 0.0741161779f, -0.0982123986f, 0.0210540164f, -0.00615544664f, + 0.0199999996f}, + {0.347829491f, 0.896825016f, 0.228995472f, -0.425543219f, 0.244013935f, 0.261297405f, 0.0499458276f, 0.14161472f, 0.0419562124f, -0.0522208288f, + 0.041781757f, 0.29276368f, 0.00936574861f, -0.0339858942f, -0.160748035f, 0.0294843875f, 0.0389059484f, 0.0758989975f, -0.0227518361f, -0.0556363538f, + -0.0429842658f, -0.189893633f, 0.186301112f, 0.161526576f, -0.611897588f, -0.316239357f, 0.1184837f, -0.231246501f, -0.0742645785f, -0.0263487566f, + 0.532484114f, -0.122621164f, 0.0817085728f, 0.352759987f, 0.0347844325f, 0.0832168087f, -0.0987690538f, -0.27720353f, 0.17833975f, -0.0425624549f, + -0.251707107f, 0.059914086f, 0.194601849f, -0.336133391f, -0.10377273f, -0.0449788235f, 0.0534170903f, 0.110356808f, 0.354106635f, 0.086406149f, + -0.0152471671f, -0.245034888f, 0.22103703f, 0.0856627151f, 0.394683927f, -0.348822176f, 0.134680435f, 0.0676391348f, -0.0962649435f, 0.0866020396f, + -0.0563473292f, -0.461460799f, -0.244852483f, -0.100106694f, 0.12479423f, -0.786077857f, -0.543236136f, 0.00934056751f, -0.343111932f, -0.166839883f, + 0.407239348f, -0.902566373f, 0.0700233728f, -0.0272308048f, 0.167871401f, -0.0849308148f, 0.437565953f, -0.0829480812f, -0.251949072f, 0.600114048f, + -0.0798675194f, 0.101578228f, -0.21730496f, -0.489234954f, -0.126192346f, 0.262612373f, 0.144644588f, 0.0425582007f, 0.0162403472f, -0.0813646317f, + 0.26758647f, 0.428203642f, -0.30355528f, -0.169204623f, -0.109554745f, -0.194621608f, 0.00716137001f, 0.382607996f, 0.0796287805f, -0.172216371f, + 0.139905646f, -0.794648588f, -0.363355309f, 0.154461905f, -0.184114367f, 0.0942273811f, -0.184314191f, 0.187316328f, 0.182515055f, 0.544964731f, + 0.433675081f, 0.0734698549f, -0.139548257f, -0.314803094f, 0.426348329f, 0.0629405528f, -0.11808636f, 0.0551142432f, 0.00703255739f, 0.25234884f, + 0.0474335738f, 0.0779756829f, -0.108815856f, 0.00395154068f, -0.264480799f, 0.107284985f, 0.274748415f, -0.378739417f, -0.643070698f, 0.127984449f, + 0.100384384f, -0.046582751f, 0.311144829f, 1.45004952f, -0.441186488f, -0.888648868f, 0.252565265f, -0.456906796f, -0.523245215f, -0.285202801f, + 0.313959718f, -0.333286941f, -0.0277237371f, -0.0673194826f, 0.0116979424f, 0.0231112204f, 0.0877679214f, -0.17902106f, -0.0472341441f, -0.18293038f, + 0.00272879913f, -0.225582182f, -0.219950646f, 0.383755356f, 0.0300158225f, 0.0356073566f, 0.142228588f, -0.048188705f, -0.000435415539f, 0.0244731586f, + 0.0321909525f, -0.275125086f, 0.0881301835f, -0.161260396f, -0.278055072f, -0.117421411f, -0.153603122f, 0.276117057f, -0.0737173632f, 0.14777182f, + -0.541110933f, -0.114910409f, -0.0338362418f, -0.142474458f, -0.0304052886f, 0.0387434587f, 0.128355503f, 0.26129517f, 0.392793775f, -0.0914428234f, + -0.0635547414f, 0.00382663356f, -0.264196992f, 0.00684118085f, -0.109270521f, -0.0289789401f, -0.407222599f, 0.126567185f, -0.0918096751f, -0.233674809f, + 0.123271026f, 0.275621355f, 0.110055029f, -0.00532453647f, -0.196108893f, 0.548845887f, 0.048320815f, -0.412984133f, -0.28330484f, -0.118563749f, + -0.442242742f, -0.032542292f, 0.0183882713f, -0.12124081f, 0.101070754f, 0.00276302313f, 0.461780012f, 0.576388061f, -1.51740062f, 0.0565155372f, + -0.90323174f, 0.317659914f, -0.0129406843f, 0.325528562f, -0.453612089f, 0.803968787f, -0.0360982083f, 0.0227638278f, 0.0729184598f, 0.469468862f, + -0.163325384f, 0.108963981f, -0.0870644376f, -0.000855660241f, -0.250427306f, 0.443867654f, -0.10407009f, 0.00543069746f, 0.191723272f, -0.137264267f, + -0.0727986544f, -0.231745884f, -0.0971060991f, -0.377975613f, -0.178353712f, -0.15188697f, -0.148313433f, 0.076997757f, -0.011758063f, 0.240197957f, + -0.0242683999f, 0.0280354619f, -0.100606106f, -0.0815167204f, -0.275723159f, 0.157025531f, -0.195126906f, -0.0975112692f, 0.167800635f, 0.0152143687f, + -0.151855916f, -0.50646323f, 0.0564852394f, 0.0391732678f, -0.358813256f, 0.0955376029f, -0.0188017152f, -0.0838183314f, 0.194900349f, 0.0490096919f, + -0.153385207f, -0.390047699f, 0.209796116f, -0.253625959f, -0.354935676f, 0.195386454f, -0.128548324f, 0.0515489206f, 0.0633615404f, 0.199599251f, + 0.225772202f, -0.0598585531f, 0.0430381484f, -0.0308059603f, -0.0491709448f, 0.00487765204f, -0.284453154f, -0.353396356f, 0.170876905f, 0.260935962f, + -0.103943728f, -0.445237875f, 0.351095468f, -0.976388574f, -0.353180766f, 0.0766528845f, -0.754648149f, -0.285340339f, -0.0389314629f, 0.0089914063f, + 0.0175842103f, -0.196561038f, 0.000451742177f, 0.0115896082f, -0.0870815143f, 0.0745170116f, -0.931385219f, 0.419157147f, -0.0764471665f, -0.11962235f, + 0.135723948f, -0.0275045428f, -0.475885063f, 0.053675916f, 0.030060228f, 0.114761934f, 0.00955091696f, 0.156225815f, -0.55660975f, 0.036079295f, + -0.116895385f, -0.00550436554f, -0.092190586f, 0.118967816f, -0.383370787f, 0.241222069f, 0.0227138195f, 0.127095327f, 0.0487856939f, 0.0397894122f, + -0.278570056f, 0.120322205f, 0.234932899f, 0.0176874045f, 0.0223366059f, 0.179116264f, -0.240858674f, -0.117619202f, 0.0889054611f, -0.0741809756f, + 0.320755094f, -0.0811053291f, 0.0561013222f, 0.248349532f, -0.0531567223f, 0.303633451f, -0.201356158f, -0.264540613f, -0.146623656f, -0.0353382863f, + -0.321276635f, -0.0271309856f, -0.399995655f, 0.265215188f, -0.0642426312f, 0.0847379491f, 0.0299517214f, 0.0029484001f, -0.230010256f, -0.205718085f, + -0.240651205f, -0.0563175417f, -0.460392982f, -0.6369735f, -0.194931969f, -0.269018799f, 0.547484636f, 0.665968657f, -0.0718654543f, 0.232947528f, + -0.0041759517f, -0.00162059278f, 0.0195881259f, -0.111245662f, 0.136168256f, -0.0971392095f, 0.1378396f, 0.328131914f, -0.764108956f, 0.210464895f, + -0.21480155f, -0.13117826f, -0.281255543f, -0.113206834f, -0.0825911909f, 0.0433119871f, -0.0654882863f, -0.128118724f, -0.106925614f, 0.151851073f, + -0.0246165451f, -0.327192962f, 0.135212064f, 0.128254786f, 0.284134477f, -0.0511767268f, 0.209623799f, -0.184007123f, 0.0765315592f, -0.122190885f, + 0.208753958f, 0.265983284f, -0.130088031f, -0.0886714756f, -0.0392897651f, 0.212304264f, 0.106418863f, -0.363296539f, 0.0603333153f, 0.241204664f, + 0.546214163f, -0.33513236f, -0.0572449975f, 0.335251182f, -0.26474902f, -0.224597484f, 0.105726227f, 0.27281329f, -0.0902684107f, 0.0882825553f, + 0.0718556046f, 0.288435161f, -0.0630472526f, 0.158843011f, -0.28886342f, -0.112639129f, -0.102861479f, -0.0319195986f, -0.0500557497f, -0.0508012995f, + 0.832639992f, 0.32457f, -0.320375741f, 0.299996346f, 0.386223733f, -0.111778587f, -0.042507723f, -0.0723694116f, -0.93681699f, 0.0701726228f, + 0.0979098529f, -0.456549942f, 0.00304931565f, -0.00545037724f, 0.0348754637f, 0.0748499036f, -0.245772302f, -0.0888876319f, -0.193029329f, 0.315224618f, + -0.47481367f, 0.00634377124f, 0.123364791f, 0.0534588471f, 0.132591039f, -0.218004003f, -0.590728879f, 0.20184359f, -0.20827429f, -0.0235928167f, + -0.21540907f, 0.234757781f, 0.155550584f, -0.099625513f, 0.168945953f, 0.0512675717f, -0.0703281015f, -0.0325747877f, -0.0998474285f, 0.125609294f, + 0.00263838796f, -0.0746104792f, 0.14224197f, -0.0756623223f, 0.00223151688f, 0.0594903342f, 0.293356568f, -0.0655791536f, 0.336459965f, 0.0123342043f, + -0.0734266043f, -0.00486698933f, 0.0341428854f, 0.0644143522f, -0.227263927f, -0.143805265f, 0.00485472381f, -0.0746490806f, 0.151623264f, 0.37496525f, + 0.214656457f, 0.181464225f, -0.165040553f, -0.083394669f, 0.144281223f, 0.429285377f, 0.145462379f, -0.151077852f, -0.0042624916f, 0.0513807051f, + 0.00718373898f, -0.0480037965f, -0.454432577f, -0.32288456f, 0.259657174f, 0.182371482f, 0.890510499f, 0.00662379432f, 0.722578347f, 0.965156198f, + 0.005645236f, 0.890723169f, 0.603856564f, -0.152596399f, -0.000892390788f, 7.9380181e-05f, 0.0417672545f, 0.0630773827f, -0.0371674672f, -0.0980680361f, + -0.0454574786f, -0.070249781f, 0.0835869312f, -0.133979216f, 0.0631383508f, -0.378569365f, 0.0741070285f, 0.290653229f, 0.0956470072f, 0.062734127f, + 0.119653292f, -0.19259505f, -0.101225577f, 0.208231315f, 0.335147917f, 0.0637331903f, 0.570227325f, -0.0551926345f, 0.198545247f, 0.256811887f, + -0.080113031f, -0.230126783f, -0.316172719f, -0.00353696919f, 0.218664169f, 0.0212419964f, -0.00235945615f, -0.158873603f, 0.071373485f, -0.559451044f, + 0.0044489773f, -0.0380211398f, -0.350197405f, 0.490884125f, -0.323572278f, -0.22293061f, -0.247425571f, 0.287647039f, -0.197298169f, 0.113376729f, + 0.0957916677f, 0.0171877258f, -0.355009407f, -0.200645179f, 0.331895977f, -0.362054646f, -0.254710257f, -0.102201208f, 0.122500114f, -0.0154508688f, + 0.0984075665f, 0.0299932417f, -0.0351433009f, -0.0402560644f, -0.414569139f, 0.467767268f, 0.283491641f, -0.904856265f, 0.889073789f, 1.32088482f, + -0.586711109f, 0.0127553595f, 0.699023306f, -0.786315382f, -1.11005771f, -0.823616743f, 0.00368113816f, 0.0103874383f, 0.0247410312f, -0.0913214758f, + -0.043281503f, 0.11361818f, 0.112395264f, -0.182678148f, -0.0412037f, 0.443201184f, 0.204474866f, 0.236076564f, -0.0483018793f, 0.102456301f, + -0.352495551f, 0.10961768f, -0.0765077025f, 0.196107283f, 0.0393401831f, -0.267034948f, 0.0676220208f, -0.166445628f, -0.118211836f, -0.0722328052f, + -0.169764057f, 0.330435097f, 0.129785061f, 0.237407923f, 0.170490682f, 0.174217984f, 0.201930583f, 0.122434668f, -0.477833241f, 0.29344812f, + 0.0731907636f, 0.150264889f, -0.281004637f, -0.232548952f, 0.329873145f, 0.448203474f, 0.074813202f, -0.412824243f, 0.123855613f, 0.47787714f, + 0.195870861f, 0.215879843f, 0.0211352967f, -0.447488129f, -0.409330994f, -0.274398118f, -0.0120197525f, 0.0412981585f, 0.123603933f, -0.120183446f, + 0.192120492f, -0.0970369652f, -0.203877583f, -0.0358764902f, -0.054178454f, -0.0341593064f, 0.297811061f, 0.191227719f, -1.32838511f, -0.553884327f, + 0.139373273f, -1.75632238f, -0.151789457f, -0.254019231f, -0.790824354f, -0.788568854f, -0.13267751f, -0.291931123f, 0.0313553698f, 0.0518225655f, + 0.0346974917f, 0.326392829f, 0.0961077437f, -0.332481384f, -0.179078683f, 0.217695341f, 0.470980436f, 0.0710727796f, 0.0570358969f, 0.420509726f, + -0.0205584764f, -0.0496891811f, -0.32084766f, -0.184427455f, 0.508876443f, -0.371765673f, -0.0488311462f, -0.379932135f, 0.0220791418f, 0.309932113f, + 0.0541258678f, 0.245268151f, 0.248356551f, 0.194652289f, 0.453225434f, 0.119033188f, -0.129096076f, -0.216725364f, -0.263886541f, 0.0437593013f, + -0.13895306f, 0.540519476f, 0.321530312f, -0.151273102f, -0.186017081f, 0.273163915f, -0.523132563f, -0.0700922236f, 0.251682341f, -0.182646275f, + -0.0898947269f, -0.0504489355f, 0.190546364f, 0.0175719149f, 0.0824321955f, 0.132170364f, -0.00318061979f, 0.260862648f, -0.164046571f, -0.316240788f, + -0.375522971f, -0.346502513f, -0.0973384827f, 0.241404012f, 0.04867924f, -0.0235450491f, -0.0661618412f, -0.0461932831f, -0.289997697f, -0.547706246f, + -0.248350874f, -0.277301371f, -0.339369178f, -0.793692887f, -0.282827079f, 0.529408395f, -1.21667194f, -0.0861817226f, -1.13362288f, 0.10430713f, + 0.0555061325f, 0.0473684259f, 0.0184515566f, -0.0848278999f, -0.422404975f, 0.0501114056f, 0.406353891f, 0.0276410896f, 0.251672655f, -0.049474258f, + -0.521245122f, 0.0868787989f, -0.14654398f, -0.381638676f, 0.127665743f, -0.0729293153f, -0.250967979f, 0.113258921f, -0.274566352f, 0.0662784725f, + -0.270049095f, 0.156320065f, -0.234967008f, 0.385404557f, 0.0669647455f, 0.29846549f, -0.212570652f, -0.0917858928f, 0.225032091f, -0.622130513f, + -0.23269321f, 0.228270277f, 0.105190158f, 0.250284582f, -0.0464922078f, 0.138486326f, -0.144485191f, -0.282615751f, -0.370280266f, -0.116512954f, + -0.113064244f, -0.0491220877f, -0.594477832f, -0.36671555f, -0.118638895f, 0.135506988f, -0.0459745117f, -0.221383631f, -0.328963459f, 0.387095809f, + -0.315988451f, 0.405363947f, 0.378755867f, -0.0322778299f, -0.253150731f, -0.0468353964f, -0.317884952f, -0.0637997016f, -0.028500475f, -0.0337896161f, + 0.0422018245f, 0.00284788967f, 0.605356216f, 0.520802498f, 0.96897918f, -0.234244898f, 0.563585818f, -0.45257023f, -0.350486368f, -0.332197905f, + -0.520320356f, 0.327311516f, 0.132605359f, 0.0397002324f, 0.0185869969f, 0.222038403f, 0.305836916f, 0.089075461f, 0.150847808f, -0.0444059856f, + -0.214028567f, 0.0626966134f, 0.00245273812f, -0.284404278f, 0.117325701f, -0.369130939f, -0.030085789f, -0.241759837f, -0.171236813f, -0.342866093f, + 0.12297307f, 0.0239823256f, 0.179172948f, 0.048873648f, -0.279249489f, -0.075848721f, -0.264297128f, 0.119598702f, 0.280439198f, 0.10196127f, + -0.106343471f, -0.0655127391f, 0.0674425885f, -0.315034986f, 0.0678373054f, 0.0323062912f, -0.164387301f, -0.115098126f, 0.0208095871f, -0.196604282f, + -0.243394017f, 0.195819378f, 0.092114009f, 0.386374891f, -0.228982493f, -0.402503222f, 0.256475598f, 0.235694662f, -0.144470766f, -0.334392905f, + -0.00279010972f, -0.397365004f, -0.057816796f, -0.528236687f, -0.128943175f, -0.495592773f, -0.0707376972f, 0.333336204f, -0.118751541f, -0.076935932f, + -0.0196604766f, -0.0222474914f, 0.317931145f, -0.279982299f, -0.391336381f, -0.851924121f, 0.545413733f, -0.0465218499f, 0.856529474f, -0.707003117f, + -0.167013019f, 0.013569613f, 0.771060824f, 0.9990955f, 0.163387612f, -0.00805820059f, 0.00671994127f, -0.081872113f, -0.213249922f, -0.352507174f, + 0.0787476823f, 0.0678673387f, -0.105533876f, -0.0356768556f, -0.3005642f, -0.29054004f, -0.0100659756f, -0.00980375241f, -0.157956645f, -0.227980345f, + 0.110995337f, 0.367617697f, -0.201098129f, 0.040140681f, -0.131244734f, 0.0489144288f, -0.0417681895f, 0.0147907501f, -0.0959879458f, 0.102464467f, + 0.030522421f, -0.0202007648f, -0.0309543405f, 0.0313200131f, -0.14778246f, -0.182958245f, 0.0599847026f, -0.0157731026f, -0.00506313378f, 0.242181987f, + 0.0316433422f, 0.0280085746f, 0.0391543433f, 0.0364214852f, 0.0992968231f, 0.230371639f, 0.0844202936f, -0.31195569f, 0.0743078142f, -0.00518577034f, + 0.0819934234f, 0.092488043f, -0.0739047974f, 0.190118238f, -0.273027956f, 0.111147597f, 0.120675907f, 0.18058145f, 0.197077736f, -0.215678424f, + 0.0540064611f, 0.0290654041f, 0.0384150073f, 0.044564493f, -0.186466664f, 0.212716639f, 0.920222402f, 0.224227905f, 0.736055732f, -0.050527785f, + 0.0914015323f, 0.0724036098f, 0.683608234f, 0.438395977f, -0.333264619f, 2.07156968f, 0.0602503866f, 0.0178847201f, -0.0100434227f, 0.0164561253f, + -0.0741465613f, 0.152925193f, 0.119969442f, 0.136440814f, -0.129019529f, 0.30379954f, -0.0310005005f, 0.302003562f, 0.288311958f, -0.341981769f, + -0.258527011f, -0.285557121f, 0.0108165387f, -0.0368242115f, 0.0491894335f, -0.237718895f, 0.0679496154f, 0.204723582f, -0.239233285f, -0.0698686466f, + -0.0217859801f, -0.0557185411f, -0.131441727f, 0.22780104f, 0.260199577f, 0.183825284f, -0.245929837f, 0.343363166f, -0.0745784193f, -0.252882451f, + -0.160105929f, -0.211306006f, 0.392108142f, -0.103612982f, -0.0750142708f, -0.456344932f, 0.0963185206f, -0.196087614f, -0.208726674f, 0.165333003f, + -0.220038667f, 0.153866276f, 0.195420831f, -0.485715091f, -0.0769660547f, -0.417747319f, -0.0516913347f, 0.153356969f, -0.384601951f, 0.359993935f, + -0.139579475f, -0.344844639f, -0.0859261379f, -0.0433508344f, -0.057422474f, -0.04916621f, 0.33526516f, -0.470401406f, 0.0435397662f, -0.770296454f, + 0.575440407f, 0.0879566222f, -0.235913426f, 0.478823632f, -0.717184186f, -0.188801765f, 1.00773764f, -0.101590663f, 0.0466010757f, 0.0861076862f, + -0.0373706557f, 0.195164666f, 0.0126482816f, -0.165871233f, -0.145033821f, -0.0623252764f, -0.0201574136f, -0.0380369648f, -0.0901542827f, -0.227438182f, + 0.0951462612f, 0.234152064f, 0.22012566f, -0.27561757f, 0.0665173754f, -0.00396204274f, -0.227110624f, -0.0185771789f, 0.0965266079f, 0.0497610793f, + 0.0710849762f, 0.12517637f, 0.135817632f, -0.0149636213f, -0.332056344f, -0.110991634f, 0.0895683169f, -0.0400689989f, 0.0799629539f, 0.0685975626f, + -0.00411364809f, 0.267962039f, -0.154316947f, 0.128811359f, -0.080035679f, -0.139413074f, 0.0304237064f, -0.170164645f, 0.0576586723f, -0.22578007f, + -0.050246615f, -0.183625668f, -0.0682284534f, -0.064207077f, -0.178829566f, 0.0717483312f, -0.487565756f, -0.461943954f, -0.0401230566f, 0.10167861f, + 0.141518727f, 0.0351641439f, 0.37810269f, -0.0846708268f, -0.0110072903f, 0.00586596224f, 0.297942549f, 0.134728909f, 0.0764279515f, 0.0393605344f, + -0.373840511f, -0.0904598311f, -0.173017085f, 0.291241825f, 0.0973844528f, 0.0411487035f, -0.112999663f, -0.0632430166f, -0.0369872749f, 0.0345334187f, + -0.269166559f, 0.081595473f, 0.000700441538f, -0.013368031f, -0.0270271804f, 0.0479038581f, 0.0519456714f, 0.125008047f, -0.478331745f, -0.358023465f, + -0.0311135631f, -0.501711726f, -0.370038778f, -0.218204334f, -0.392247647f, -0.0672186166f, -0.299360365f, -0.293968081f, -0.130605265f, -0.183587924f, + 0.111008257f, 0.0128890919f, 0.113802843f, -0.170476601f, 0.303711891f, -0.0427424125f, 0.0149607267f, 0.0642828718f, -0.083123453f, -0.102279752f, + 0.0606542118f, 0.184832916f, 0.0933540985f, 0.102333397f, -0.059556473f, -0.0293583833f, 0.304752678f, -0.0164759252f, 0.0918334424f, 0.106746182f, + 0.202500865f, -0.190793201f, -0.0752491802f, -0.10760688f, -0.0730718896f, -0.349114597f, 0.0180732924f, -0.402307153f, 0.0471143275f, 0.0594122857f, + 0.0830638781f, -0.138001591f, 0.177193046f, -0.0870023519f, -0.136983663f, -0.120312966f, -0.123772696f, 0.052254539f, 0.196991161f, -0.261632651f, + -0.0962040499f, 0.108098798f, 0.0507183708f, 0.120816976f, -0.192660183f, 0.163091794f, 0.00290290802f, -0.0550516732f, 0.00306833326f, -0.642281651f, + 0.546678841f, 0.695992112f, 1.12366664f, 0.331959337f, 0.475854844f, -0.357824773f, -0.306469619f, 0.678329766f, -0.0587933548f, 0.115944631f, + -0.742132366f, 0.0460594147f, 0.0863636881f, -0.0395578742f, -0.134101555f, -0.10918577f, -0.170853153f, -0.102628842f, 0.026754532f, -0.0179449208f, + 0.0200446919f, -0.245781615f, -0.140404984f, -0.0677445456f, 0.179762542f, -0.00773310568f, 0.393228829f, -0.0270723961f, -0.072360836f, 0.00971974991f, + -0.129901335f, -0.18842715f, -0.0634235591f, -0.0155574707f, -0.315278769f, -0.0921552926f, -0.0876452774f, -0.109573327f, 0.0776367337f, -0.101509191f, + -0.0527765676f, -0.00802092534f, 0.0655215606f, -0.0617186092f, 0.202959388f, -0.121114261f, 0.157303184f, -0.132700026f, -0.0175535008f, 0.0370068923f, + 0.240016669f, 0.0954563096f, -0.100407086f, 0.142186448f, -0.0573429838f, -0.133583009f, 0.0278537963f, -0.01638088f, 0.107562095f, -0.292474687f, + -0.0370637588f, 0.0249175169f, -0.143545076f, 0.0680733398f, -0.331947148f, -0.0126976511f, 0.0506766662f, 0.065375112f, 0.106667973f, 0.232000083f, + -0.125294149f, -0.0104689673f, 0.0412461348f, -0.159488291f, 0.05722389f, 0.0149713214f, 0.172336936f, -0.0945723429f, -0.279494703f, 0.0183742233f, + 0.0529774837f, -0.107851915f, 0.100547075f, 0.00809857715f, 0.0999323651f, -0.0641398877f, 0.0191784985f, 0.0226321481f, 0.149528354f, -0.0967241824f, + -0.0686425865f, 0.101002097f, -0.209407583f, -0.273127496f, 0.346816897f, -0.202341899f, 0.0900800228f, -0.163366288f, -0.160167783f, -0.45090273f, + -0.24714762f, 0.0724510923f, -0.264945298f, 0.0882803723f, 0.0634144396f, 0.293975115f, -0.0402587466f, 0.217927411f, 0.147317111f, -0.0102889929f, + -0.226812348f, 0.23031798f, -0.194503054f, -0.0723710209f, 0.147908896f, 0.187989682f, -0.126105592f, 0.0521292724f, -0.0279709473f, 0.167263404f, + 0.351183802f, -0.264301091f, 0.149293959f, -0.408907205f, -0.0168118887f, -0.160249442f, 0.265703738f, -0.00415859278f, -0.13312307f, -0.108208843f, + -0.122927383f, -0.00843925308f, -0.0489528663f, 0.0488418415f, 0.2205991f, 0.102420308f, -0.176109776f, -0.223663479f, -0.104740158f, 0.162607908f, + -0.0538728572f, -0.123013645f, -0.0163850486f, -0.217110366f, -0.206955224f, 0.0340815149f, -0.052480232f, -0.0812721774f, 0.0415275469f, -0.0204980467f, + -0.0413506217f, -0.0130159892f, -0.612777174f, 0.201380879f, -0.19039242f, 0.323714942f, 0.00861529168f, -0.745500207f, -0.199030906f, 0.355426818f, + 1.0027914f, -0.584811807f, 0.212044895f, -0.100639343f, 0.0334720723f, 0.0257377941f, 0.00209837127f, 0.213636667f, 0.190770254f, 0.532970726f, + 0.154921472f, -0.330324441f, -0.306645423f, 0.157530457f, 0.0417827852f, 0.564030051f, 0.422576338f, -0.254995048f, 0.0812658966f, -0.195228934f, + -0.314569265f, 0.197429985f, 0.201564938f, -0.139765158f, 0.470490634f, -0.168624803f, -0.234372556f, 0.208961487f, 0.0469165742f, -0.0301592425f, + -0.0832379684f, 0.132875726f, -0.0166728217f, -0.0253250692f, -0.447962999f, -0.28779307f, 0.141266912f, -0.126526192f, 0.149032533f, 0.294086426f, + -0.0544269569f, 0.110347152f, 0.539247513f, 0.0658296719f, 0.466452509f, 0.362081498f, -0.0935750529f, -0.369758487f, -0.223375589f, -0.321485192f, + 0.133142143f, 0.163076103f, -0.0838514268f, -0.0234215409f, -0.302799076f, 0.244368315f, 0.0149699459f, 0.0111578954f, 0.0335813537f, -0.000760606432f, + 0.511158347f, 0.0515028685f, 0.025528064f, 0.0303084627f, -0.656382263f, 0.470634729f, 1.06368828f, 0.302953333f, -0.161250725f, 0.985926867f, + -0.650554478f, -0.773719668f, 0.277138144f, -0.691946268f, -1.32905483f, 0.456345946f, 0.0542916246f, 0.0300052576f, -0.0422878936f, 0.226664528f, + 0.158782065f, -0.124195151f, 0.0373629704f, -0.143856645f, 0.411760509f, 0.0840357915f, 0.20945847f, -0.34250778f, 0.253611416f, 0.206222236f, + 0.169208959f, 0.0486866608f, -0.102341212f, -0.0380329378f, 0.064715676f, -0.106136292f, -0.115690984f, -0.113579109f, 0.348598897f, -0.327859193f, + -0.0545125715f, -0.182900161f, 0.189069495f, 0.269955605f, 0.259337693f, 0.157300264f, -0.356326431f, 0.437784016f, 0.0956551209f, -0.050417304f, + -0.00739003578f, -0.0785496384f, 0.0910924375f, 0.0680354834f, -0.0692989379f, -0.549835205f, 0.0400051065f, 0.207733154f, 0.141211614f, -0.041969955f, + 0.285626978f, 0.137944624f, -0.141844526f, 0.304119885f, -0.418546826f, -0.282031834f, -0.202486008f, -0.335424483f, -0.235032633f, 0.264964253f, + 0.51328522f, 0.0792668834f, 0.603937268f, 0.149910986f, -0.0587027334f, 0.01436086f, 0.561232626f, -0.198243245f, 0.549475491f, -0.203241155f, + 0.3905316f, -0.731481075f, 0.426308811f, -0.260858089f, 0.467693835f, -1.02524793f, -0.211585417f, -0.267748892f, 0.0104008242f, 0.00966152735f, + -0.0834355652f, 0.170456365f, -0.185552821f, 0.38905251f, 0.0976222381f, 0.0145774502f, 0.279756755f, 0.00200369162f, 0.138040036f, 0.280859917f, + 0.310875922f, -0.150497273f, -0.456274688f, 0.0847987086f, -0.100773588f, -0.225781873f, -0.103654549f, -0.0968824476f, 0.540662944f, -0.176461428f, + 0.0253521316f, 0.0897697732f, 0.00566751743f, 0.292973906f, 0.111151315f, 0.0252633858f, -0.300030887f, 0.0373926982f, -0.104106151f, -0.142940819f, + -0.587317169f, -0.228284374f, 0.0157731436f, -0.0559487566f, 0.194775894f, 0.0565060563f, -0.368914694f, 0.241809085f, -0.250789404f, -0.504554927f, + -0.298701435f, -0.285782754f, 0.00630647037f, -0.329998493f, -0.43660742f, -0.129076779f, 0.341857076f, -0.21878694f, 0.0536873117f, 0.0254951958f, + 0.617454529f, -0.417251348f, 0.247386619f, -0.271980882f, -0.105030753f, 0.0180559605f, 0.0948672295f, -0.00604635151f, -0.145953566f, 2.26762438f, + -0.428158164f, -1.04516208f, 0.609328032f, -0.460243255f, -0.130432591f, 0.207470119f, -0.0896816105f, -0.261838853f, 0.00879556872f, 0.211604714f, + 0.00471465616f, -0.0060906657f, -0.0693282783f, 0.0650085956f, 0.0472484678f, -0.0881269723f, -0.0591743514f, 0.12727429f, 0.188300654f, 0.280399144f, + 0.259611845f, 0.490713269f, 0.14908351f, 0.244944021f, -0.406245321f, -0.133407637f, -0.152303144f, -0.372388124f, -0.0214249194f, -0.374765277f, + -0.0223537646f, -0.590657771f, -0.332865924f, -0.124654219f, -0.136009067f, -0.423913151f, -0.0610302761f, 0.141722113f, 0.0848094225f, -0.174542844f, + -0.157540232f, -0.297639519f, 0.170472205f, 0.425481886f, -0.0551521927f, -0.328256786f, 0.131904617f, 0.251726955f, -0.552623451f, 0.0133723281f, + 0.301479518f, 0.106053233f, 0.0601636246f, 0.18647784f, 0.484560579f, -0.160641149f, -0.163124487f, 0.0657425672f, 0.038640976f, 0.156343624f, + -0.446300358f, 0.0644065142f, 0.146046877f, -0.026477633f, 0.0822978243f, 0.34897694f, -0.384570241f, 0.0524303317f, -0.0407978892f, 0.00886274502f, + -0.422366112f, -0.42067647f, 0.288094938f, -0.550019801f, -0.0275960993f, -0.334507197f, -0.737837434f, -0.898159206f, 0.637625158f, -0.0260510631f, + -0.164081767f, 0.148940191f, -0.0266860556f, -0.0383486375f, -0.0704965293f, 0.0389235392f, 0.0152392704f, 0.328681856f, 0.105329335f, -0.123407118f, + -0.157165378f, -0.0841090158f, 0.28895849f, 0.0216392223f, -0.165659949f, -0.199016124f, -0.28243503f, 0.260077864f, -0.00234235637f, 0.2448311f, + 0.163242996f, 0.251133174f, 0.468998134f, 0.619557917f, 0.270569265f, -0.239975974f, -0.0329946764f, 0.0441796742f, 0.446100771f, 0.105266184f, + 0.242329955f, -0.00515836058f, 0.168752506f, 0.242376879f, -0.112327322f, 0.262533963f, 0.297452658f, 0.01219559f, 0.300668865f, 0.472462952f, + 0.0772388875f, 0.202601179f, 0.0265024342f, -0.223762169f, 0.0745374486f, -0.312136471f, 0.483436316f, -0.194459915f, -0.261464983f, -0.245254681f, + -0.0881014913f, -0.233919054f, -0.186446115f, 0.258105636f, 0.128656223f, -0.271979272f, 0.0119167008f, -0.172048882f, 0.258601427f, -0.123525657f, + -0.0642806962f, 0.0612154789f, -0.244050816f, 0.176006645f, 1.14404762f, -0.455936164f, 0.725523949f, -0.369399697f, 0.183714405f, -0.194300979f, + 0.0941615626f, 0.0312694646f, -0.00353009673f, -0.43523258f, -0.0208604578f, 0.0140751544f, -0.0529478043f, 0.147495285f, 0.159753889f, 0.198991954f, + 0.194594458f, -0.209394604f, 0.181255281f, 0.204057872f, -0.0902258381f, 0.161365896f, 0.17984423f, 0.106060207f, -0.431699693f, -0.0114347627f, + 0.727928758f, 0.150984377f, -0.143741071f, 0.0195611399f, -0.169746414f, -0.032253474f, -0.0531137846f, -0.473776847f, 0.0556001551f, 0.28430301f, + -0.0641033798f, 0.00126469042f, 0.103436418f, -0.171852916f, -0.203560919f, -0.336109906f, 0.0389311202f, 0.220483452f, 0.123829544f, 0.252859294f, + 0.322677583f, 0.246889949f, -0.068520993f, 0.0838966146f, 0.199971929f, -0.197190389f, -0.139091611f, -0.0672390461f, 0.239880294f, -0.143297493f, + -0.201202795f, 0.145910129f, 0.1806245f, -0.227773443f, -0.0350743122f, 0.115108885f, -0.123335607f, 0.043775931f, -0.196144611f, -0.144055724f, + -0.0730374679f, -0.0948513746f, -0.0969018191f, 0.0526694395f, -0.213613629f, -1.06916976f, 0.356532037f, 0.156216934f, 0.23943679f, -0.536308825f, + 0.259225398f, 0.0849249735f, -0.798145771f, -1.18776095f, 0.260326058f, -0.260783613f, 0.00125792436f, -0.0385306999f, -0.0227774493f, 0.199077308f, + 0.45185563f, -0.0983593911f, -0.132034525f, 0.00445087859f, 0.104933709f, -0.20069018f, 0.294136465f, 0.264953166f, 0.195390895f, -0.0751130804f, + 0.119392902f, 0.282816648f, -0.195846394f, 0.57405287f, -0.020493079f, 0.173270762f, -0.0659952462f, 0.123844653f, 0.258594841f, -0.0731057003f, + -0.329120755f, -0.0914134979f, -0.249435529f, -0.157788783f, 0.00123534526f, 0.0813608021f, 0.382171512f, -0.238835916f, 0.1404403f, -0.0669482723f, + 0.399963588f, 0.637601495f, 0.208955839f, 0.542083561f, -0.0668655708f, -0.169451177f, -0.123954251f, -0.136665002f, -0.148362875f, -0.00433115102f, + 0.680287838f, 0.0979960561f, 0.014628063f, -0.00647194451f, -0.0428764783f, -0.0232417211f, 0.124079496f, 0.0139583023f, 0.00528632058f, -0.0459940694f, + -0.258338273f, -0.230906576f, -0.203986272f, -0.0845730752f, -0.0476759039f, 0.00647225603f, 0.760889769f, 0.179511935f, 0.700923443f, 0.845378458f, + 0.1924676f, -0.226778314f, -0.169291228f, -0.590278685f, 0.176980317f, 0.65129143f, 0.328980774f, 0.445320189f, 0.0f, 0.0f, + 0.0f, 0.0459140874f, 0.261406302f, -0.065033786f, 0.0329310708f, 0.0813694596f, 0.141434669f, -0.344511032f, -0.0634308606f, -0.0722451508f, + -0.154095307f, 0.22232908f, 0.210300729f, 0.0247619301f, -0.273060113f, -0.25493598f, -0.120055817f, 0.0756186768f, -0.138403505f, -0.235315144f, + -0.155292496f, -0.0606597587f, 0.263878226f, 0.409165174f, -0.00141678727f, 0.210421517f, 0.215366587f, 0.187555045f, 0.0250068475f, -0.203405038f, + -0.152894855f, -0.341794372f, 0.0228320453f, 0.117863551f, -0.253799558f, 0.022391472f, 0.0704579279f, 0.173994809f, 0.209082112f, 0.166899905f, + -0.00334456889f, 0.0597272478f, 0.173001558f, -0.145600855f, -0.0470812693f, 0.168006554f, -0.067152828f, -0.284583509f, -0.104366273f, 0.0184687451f, + 0.0199999996f}, + {0.350155771f, 0.773833334f, 0.232930019f, -0.304400176f, 0.215443313f, 0.114444807f, -0.11515566f, 0.150520712f, 0.10041634f, 0.0735829026f, + 0.0103407418f, 0.139094725f, -0.161260322f, -0.0240950063f, -0.0985336453f, 0.14503935f, 0.0126021653f, -0.0593839549f, -0.171996504f, -0.0460245684f, + 0.0171544645f, 0.0174358208f, 0.406454146f, 0.378448635f, -0.509303451f, -0.400580466f, -0.0765143707f, -0.0269919094f, 0.142656729f, 0.184161112f, + 0.623825788f, -0.217563361f, -0.120381445f, 0.556905985f, 0.244772449f, 0.284563184f, -0.00199747249f, -0.342808336f, 0.0191135686f, 0.0650187433f, + -0.255667984f, -0.146420136f, -0.00593222072f, -0.215688631f, -0.0140288007f, 0.0584330224f, 0.0391540304f, -0.105686083f, 0.150432304f, 0.217026919f, + 0.0846060067f, -0.158866897f, 0.202102944f, -0.1033528f, 0.21919179f, -0.243549749f, 0.22615473f, -0.0228708405f, -0.039623227f, -0.0320061333f, + 0.00461264001f, -0.657070875f, -0.148249656f, -0.0229328014f, 0.361913115f, -0.479527354f, -0.608754992f, 0.216900632f, -0.268104821f, 0.155897304f, + 0.176685363f, -0.939413846f, -0.0228265356f, 0.00132535165f, 0.0428172834f, 0.0499661602f, 0.426714092f, 0.195683435f, -0.0886379108f, 0.242035553f, + 0.0735411122f, 0.19659026f, 0.0295962375f, -0.135196403f, 0.0456926748f, -0.0692876652f, 0.172623917f, -0.0156501383f, -0.370913476f, -0.209575355f, + 0.212289572f, 0.14202112f, -0.191902056f, -0.0865070596f, 0.0445087515f, 0.179706082f, -0.128611565f, -0.532389641f, -0.0331286825f, -0.100117378f, + 0.232022643f, -0.403915435f, -0.340827554f, -0.434988707f, -0.296909451f, 0.0493630357f, -0.141530335f, 0.242092997f, -0.133389428f, -0.119107284f, + 0.29484883f, 0.0629642308f, -0.160573885f, -0.367080599f, 0.510788739f, 0.303208649f, -0.193003356f, 0.0055692615f, 0.0270872843f, 0.165325448f, + 0.151283532f, 0.236740619f, -0.15728277f, 0.150520876f, -0.176618218f, 0.222618505f, 0.46262747f, -0.0362936743f, -0.578089118f, -0.0673340857f, + 0.0136053273f, 0.0443176366f, 0.29613319f, 1.29145563f, -0.46549964f, -0.301421583f, 0.51594758f, -0.492872179f, -0.491807759f, -0.155936509f, + 0.292166799f, 0.103900164f, 0.0454499759f, -0.0774596781f, -0.0049527986f, 0.00183203968f, 0.0469964109f, -0.169319451f, 0.0719326809f, -0.1612553f, + 0.0125987101f, -0.0877535641f, -0.324067205f, 0.379539013f, 0.00224056025f, -0.0607294179f, 0.0409555435f, -0.0898024365f, -0.0718947425f, 0.122993588f, + 0.140495628f, -0.287683636f, 0.114185512f, -0.0619179793f, -0.327983141f, -0.102559283f, -0.0745484531f, 0.113932006f, 0.01629382f, 0.0231048055f, + -0.667959034f, 0.0109063676f, 0.196877107f, -0.068584539f, -0.0729782283f, 0.0797958449f, 0.146384463f, 0.206126601f, 0.473516196f, -0.0330840237f, + -0.02057443f, -0.0171461124f, -0.140495807f, -0.00556226959f, -0.0822988972f, -0.0206514727f, -0.465510815f, 0.160803989f, -0.178855106f, -0.305258483f, + 0.107214779f, 0.24727653f, 0.0386788286f, -0.0384776741f, -0.279454559f, 0.622283161f, 0.14169462f, -0.333460122f, -0.253938377f, -0.0472973511f, + -0.435898572f, -0.0438693278f, 0.0154743493f, -0.0475152545f, 0.0386370793f, -0.247702524f, 0.545254171f, 0.565954983f, -1.41220808f, 0.00536204735f, + -0.682302237f, 0.572230756f, 0.00493590534f, 0.261217952f, -0.503560901f, 1.01910901f, -0.0554300956f, 0.0144271813f, 0.0862311646f, 0.328843921f, + -0.181393117f, 0.0308611766f, -0.227453813f, -0.127659544f, -0.332675546f, 0.400237769f, -0.263079047f, -0.0534061901f, -0.0300165527f, -0.490757227f, + -0.444184959f, -0.271777302f, 0.0314969346f, -0.344541669f, -0.190558359f, -0.343727052f, -0.168702453f, 0.0742817745f, 0.0034009302f, 0.2651591f, + -0.00549737271f, 0.047501456f, -0.0756026059f, -0.132336915f, -0.308941603f, 0.132698029f, -0.244863763f, -0.152316704f, 0.11764963f, 0.0457874238f, + -0.110185832f, -0.439022481f, 0.119528674f, 0.0984431952f, -0.297237813f, -0.0504413508f, -0.138710871f, -0.234617084f, 0.0446182787f, -0.0804745778f, + -0.0186597817f, -0.300695688f, 0.342819512f, -0.211958081f, -0.348408878f, 0.169095665f, -0.0155810472f, 0.00323506957f, -0.0261075031f, 0.078106463f, + 0.136429086f, -0.127321601f, 0.154636174f, -0.0459230877f, -0.0454263911f, 0.0595952608f, -0.404079497f, -0.362658948f, 0.0368981138f, 0.286202967f, + -0.0902701244f, -0.265090585f, 0.446194708f, -0.984326065f, -0.190797389f, 0.0344950072f, -0.785891294f, -0.118167214f, -0.0671495944f, 0.00233914866f, + 0.0279990453f, -0.0886293277f, -0.107609093f, -0.135973513f, 0.0233715028f, 5.76883103e-05f, -0.807240605f, 0.30926919f, -0.188219354f, -0.216133654f, + 0.16235289f, -0.0975262821f, -0.155811459f, 0.0810327977f, 0.0974355265f, 0.0839609578f, 0.165887833f, 0.152746961f, -0.408948213f, 0.0169306453f, + -0.0492462814f, 0.0133063737f, -0.082682319f, -0.0971676111f, -0.191994846f, -0.0787149295f, 0.32837379f, 0.50485146f, 0.0522744656f, -0.00904801954f, + -0.108462684f, 0.0872501209f, 0.457067341f, 0.155725911f, 0.0397850797f, -0.101456687f, -0.121855102f, -0.139631763f, 0.0481188074f, -0.0477914512f, + 0.350521296f, -0.0191491619f, 0.0642604977f, 0.204274908f, -0.0669423863f, 0.348925859f, -0.155679166f, -0.208932444f, -0.109150581f, -0.023417715f, + -0.323940396f, 0.00329980184f, -0.39958787f, 0.289162278f, -0.0504307635f, 0.0934498757f, 0.0490983054f, 0.00874314085f, -0.464685768f, -0.460590005f, + -0.216913819f, -0.0669412389f, -0.606612921f, -0.520121932f, -0.100434825f, -0.25869298f, 0.563708663f, 0.685550094f, -0.0231895056f, 0.238361225f, + -0.0248538963f, -0.0207605418f, 0.0165900551f, -0.097674787f, 0.110928982f, 0.00941175222f, -0.0450086109f, 0.297514737f, -0.474539608f, -0.186334684f, + -0.217442587f, 0.529030025f, -0.37243709f, -0.39632988f, 0.275761992f, 0.0291089527f, -0.0114440992f, -0.176662579f, -0.157518908f, 0.256296962f, + 0.0168865286f, -0.289817721f, 0.190923184f, 0.135500267f, 0.256921589f, -0.0578199364f, 0.213797733f, -0.184915483f, 0.0202755965f, -0.109676376f, + 0.26533559f, 0.219839379f, -0.173163816f, -0.11101044f, -0.072197102f, 0.228155985f, 0.0827420875f, -0.345734566f, 0.0956542492f, 0.227069259f, + 0.0793390498f, -0.192140698f, -0.0266160239f, 0.370507389f, -0.382275164f, -0.263358653f, -0.167545512f, 0.28306964f, -0.0881048739f, 0.222874939f, + 0.160527825f, 0.240595415f, -0.00196697284f, 0.0530468263f, -0.334012568f, -0.190482184f, -0.0408429466f, -0.0154088279f, -0.0267183296f, -0.0735650435f, + 0.677615881f, 0.27659595f, -0.39775604f, 0.227559999f, 0.346823782f, 0.0682798997f, -0.0664288327f, -0.0584819652f, -0.915934801f, 0.257055283f, + 0.0359547473f, -0.373707741f, -0.0133694587f, -0.020848522f, 0.0374732316f, 0.0511495434f, -0.0765561834f, -0.0536312126f, -0.13430801f, 0.245448098f, + -0.658279777f, -0.0364106148f, 0.166686475f, 0.0390136316f, 0.114786834f, -0.047735583f, -0.508744538f, 0.0655316859f, -0.183292314f, 0.0469000302f, + -0.218012378f, 0.312913328f, 0.357922494f, -0.065188475f, 0.137738898f, -0.00486771483f, 0.116076797f, -0.091507569f, -0.242981523f, 0.102464855f, + -0.16872333f, -0.103672363f, -0.0494186766f, -0.00177382177f, 0.0677661747f, -0.0652248338f, 0.338376671f, -0.0801028833f, 0.262609243f, 0.00169717346f, + 0.00933678262f, -0.0123835662f, 0.00211638003f, -0.187837601f, -0.294081002f, -0.155105472f, -0.0591111705f, -0.0035843479f, 0.0722457916f, 0.193582118f, + 0.0941368341f, -0.020614678f, -0.371631622f, -0.000888354203f, 0.239180937f, 0.535330415f, 0.197563261f, -0.0952187926f, 0.0250757914f, 0.14736329f, + 0.0287371743f, -0.0194490142f, -0.431937009f, -0.504078627f, -0.0453983806f, 0.117302462f, 0.855374992f, 0.0646783561f, 0.892626703f, 1.18228507f, + -0.0606602542f, 0.742973506f, 0.551656783f, -0.212988064f, 0.0329209641f, -0.00070195616f, -0.00297855027f, -0.0185776614f, 0.00154749432f, -0.0543882065f, + 0.000530733087f, 0.0487250499f, 0.082624346f, -0.14047578f, 0.0204916745f, -0.325238615f, 0.0831610262f, 0.223416075f, 0.161652878f, 0.0739838332f, + 0.100064591f, -0.182887733f, -0.0869303942f, 0.143455058f, 0.303859681f, -0.0234533083f, 0.487969965f, -0.113467768f, 0.156184062f, 0.240437537f, + -0.0759639516f, -0.12122611f, -0.237878531f, 0.00932986196f, 0.199019536f, -0.0285488553f, -0.0543266162f, 0.00667788414f, 0.216036811f, -0.472389698f, + 0.0563929304f, -0.0221443567f, -0.358199596f, 0.491368622f, -0.342219681f, -0.256714672f, -0.285290807f, 0.256075144f, -0.211926907f, 0.150671631f, + 0.123872161f, 0.0190157704f, -0.364563882f, -0.208774865f, 0.322550207f, -0.316594541f, -0.211527765f, -0.0705750361f, 0.150519565f, 0.0146623813f, + 0.125864103f, 0.117193721f, -0.0180720109f, -0.0394352004f, -0.491217256f, 0.491590172f, 0.246169463f, -1.00475144f, 0.877820551f, 1.2220552f, + -0.268720925f, -0.0875447094f, 0.862180233f, -0.832334459f, -0.916531622f, -0.638044894f, 0.0288106259f, 0.0183063634f, -0.0772847682f, -0.0214981027f, + -0.0671613365f, 0.102768995f, -0.0168895498f, -0.274029851f, 0.167424083f, 0.304945171f, 0.189792439f, 0.178724989f, 0.0694057867f, 0.185127586f, + -0.253161639f, 0.156248108f, -0.0448272377f, 0.239925459f, 0.182366282f, -0.258032322f, 0.0866675153f, 0.356755346f, -0.324788421f, 0.0277492087f, + -0.251288265f, -0.694026113f, 0.470395923f, 0.228765309f, 0.241383016f, -0.0773602426f, 0.122657277f, 0.261969239f, -0.207085609f, 0.231330827f, + 0.337855667f, 0.08107467f, -0.000995132141f, 0.166259453f, 0.0157419443f, 0.469600439f, 0.0715823993f, -0.435181379f, 0.115352996f, 0.488546312f, + 0.193362877f, 0.219435185f, 0.0241404157f, -0.434927166f, -0.40048337f, -0.287105083f, -0.012672063f, 0.0710848644f, 0.145707622f, -0.0896566063f, + 0.220968172f, -0.0955985859f, -0.192817748f, -0.000788173929f, 0.0117613804f, -0.0251127519f, 0.308495522f, -0.292783171f, -1.34651303f, -0.351583868f, + 0.223624915f, -1.81127572f, -0.320200205f, -0.35107249f, -0.801280856f, -0.776457727f, -0.249039441f, -0.300582886f, 0.0654409155f, 0.0371786281f, + -0.0245480873f, 0.415881127f, 0.231153861f, -0.260837108f, 0.0380872972f, 0.31924817f, 0.569323421f, 0.0710578933f, -0.0153182829f, 0.384699762f, + -0.185544938f, -0.0987308249f, -0.240518287f, -0.0462403223f, 0.549551487f, -0.243354902f, -0.0245341808f, -0.246701792f, 0.24575609f, 0.097787872f, + -0.0746872127f, 0.117458448f, 0.217620417f, 0.0423328243f, 0.315523833f, 0.155714735f, -0.163596228f, -0.23109661f, -0.397474915f, 0.0617462099f, + -0.0433167443f, 0.570681334f, 0.36306718f, -0.0699967369f, -0.221772015f, 0.401808769f, -0.288340509f, -0.057114251f, 0.194534421f, -0.163764566f, + -0.0748466551f, 0.0515171811f, 0.323586762f, 0.0473966338f, 0.308541387f, 0.102785967f, -0.103936113f, 0.0912085027f, -0.284935445f, -0.263501555f, + -0.186476737f, -0.325457036f, -0.0965495855f, 0.20429787f, -0.0174423922f, -0.0476771854f, -0.0277372748f, 0.0672017559f, -0.329832047f, -0.538162053f, + -0.216201469f, -0.251757324f, -0.271745592f, -0.635576725f, -0.389014781f, 0.430850685f, -1.071123f, -0.0659291297f, -1.21257055f, -0.209767684f, + 0.0084555801f, 0.0170903411f, 0.0116934013f, -0.119627073f, -0.426090002f, 0.0726071075f, 0.442149132f, 0.0071642031f, 0.0483297072f, 0.0818785578f, + -0.24419795f, 0.00247444119f, -0.0845525265f, -0.203804702f, 0.188871726f, 0.126272485f, 0.079674907f, 0.188927531f, -0.134806454f, 0.161113098f, + -0.0141096544f, 0.35777998f, -0.00854808465f, 0.251267999f, 0.0765011087f, 0.148491934f, -0.525174081f, 0.053379558f, 0.0183548518f, -0.00319106807f, + 0.0872487351f, 0.213303119f, 0.863223433f, 0.167033538f, -0.0384497792f, 0.116188772f, -0.098335743f, -0.31945911f, 0.000689410721f, -0.204572588f, + -0.223210201f, -0.219819933f, -0.753384471f, -0.37818408f, 0.0970607027f, -0.183021277f, -0.10381531f, -0.136851132f, -0.437207669f, -0.0552054271f, + -0.234625071f, 0.2243101f, 0.180576056f, 0.0417517386f, 0.0416400507f, 0.0774980113f, -0.407232642f, -0.0488297828f, -0.106863111f, -0.00457485532f, + -0.124447778f, -0.0212140251f, 0.475198269f, 0.368676186f, 0.673797846f, -0.12588571f, 0.479600996f, -0.979948759f, -0.428744942f, -0.327228546f, + -0.129389241f, 0.447169155f, 0.0170960221f, 0.0587493479f, -0.0227914639f, 0.0765804723f, 0.0670175925f, 0.00575604523f, 0.0912425369f, -0.0617377125f, + -0.296780825f, 0.0575658716f, -0.0808038637f, -0.18434152f, -0.0743652359f, -0.180093482f, 0.170612141f, -0.0987498909f, 0.046698954f, -0.156154647f, + 0.194241136f, 0.18911083f, 0.332845628f, 0.00158734852f, -0.26507467f, -0.115789264f, -0.221080035f, 0.129929855f, 0.586402655f, -0.0333179533f, + -0.0620965064f, -0.00825600512f, -0.0795919895f, -0.0648192838f, -0.076117456f, 0.0206997413f, 0.00630325824f, -0.0482101552f, 0.0768938512f, 0.0581608489f, + 0.0770540312f, 0.0939431712f, 0.0101589207f, 0.203271449f, -0.288475931f, -0.461984724f, 0.202701226f, 0.206312656f, -0.0114159333f, -0.144247815f, + -0.0597989038f, -0.209983706f, -0.1519766f, -0.245742828f, -0.274189353f, -0.5196172f, 0.0600278862f, 0.385589242f, -0.29003036f, -0.0264699608f, + -0.0810084492f, 0.136118397f, 0.249403641f, -0.100483127f, -0.30636999f, -0.552264571f, 0.23042661f, 0.0549029931f, 0.690356195f, -0.674266398f, + -0.25836283f, -0.219172925f, 0.700225711f, 0.754231632f, -0.0230873339f, 0.118476503f, 0.107206643f, -0.131776497f, -0.347951889f, -0.439012498f, + 0.0802718326f, 0.135601148f, -0.463833153f, -0.128104851f, -0.22942546f, -0.169623986f, 0.151718006f, -0.110422634f, 0.243901789f, -0.0807118267f, + 0.0694751218f, 0.221752033f, -0.179525524f, 0.269996226f, -0.221448883f, 0.058084134f, -0.00813847315f, -0.0328493752f, -0.14205204f, 0.0596880019f, + -0.313470066f, 0.0257573612f, -0.0173248369f, 0.00111503026f, -0.122941025f, -0.0791793615f, 0.83296746f, 0.0968582183f, -0.0915723965f, 0.0673151314f, + 0.140836835f, 0.000563847658f, 0.040963117f, -0.160225451f, 0.0427955948f, 0.292159677f, 0.00791387726f, -0.292896926f, -0.0728510618f, 0.0256840978f, + 0.101006202f, 0.149693102f, -0.0475093275f, 0.00646829745f, 0.0972302705f, 0.0313147753f, 0.0204564016f, 0.0674838871f, 0.218945846f, -0.28016296f, + -0.0813762471f, 0.120221406f, 0.0954003334f, 0.0957333222f, -1.53362727f, -0.186303362f, -0.0307232775f, 0.511578679f, 1.00522327f, -0.178008184f, + 0.272665948f, 0.303577632f, 0.681704164f, 0.877419174f, -0.234017178f, 1.8512373f, 0.0977665633f, 0.086623162f, 0.104345866f, -0.00354507775f, + -0.139159068f, 0.0559733622f, 0.13935335f, 0.0647460669f, -0.137458488f, 0.312527984f, -0.0244517606f, 0.250826031f, 0.214475393f, -0.280313164f, + -0.296080142f, -0.289256901f, -0.0264055617f, -0.0976187214f, 0.00411937572f, -0.274148822f, 0.0240764972f, -0.0799137875f, -0.0157292783f, -0.0749033168f, + 0.152506679f, 0.00329097314f, -0.294757932f, 0.0675213486f, 0.0272387192f, 0.0724348202f, -0.150875553f, 0.0140162483f, 0.259694546f, -0.0828115791f, + 0.0396841243f, 0.0382898562f, 0.226521954f, 0.135014072f, -0.131727487f, -0.416658252f, 0.0296553057f, -0.168683708f, -0.201907158f, 0.155334637f, + -0.289465249f, 0.132328078f, 0.239778996f, -0.50539428f, -0.0677374378f, -0.370708704f, -0.154462993f, 0.0891699269f, -0.433418244f, 0.298638105f, + -0.178162932f, -0.394885838f, -0.142609149f, -0.0541007183f, 0.139482826f, -0.0804316849f, 0.351174265f, -1.17937374f, -0.020794088f, -0.764702499f, + 0.531815112f, 0.130673379f, -0.254254848f, 0.400573879f, -0.679449737f, -0.267281413f, 1.03662586f, -0.105699942f, 0.117630251f, 0.0819321796f, + 0.0659459159f, 0.237477571f, 0.0830164775f, -0.0913489163f, -0.0589358509f, -0.0178107675f, -0.0650069341f, -0.107363261f, -0.109671108f, -0.208883092f, + 0.0387524888f, 0.0704160929f, 0.0966857076f, -0.309043348f, 0.0550001189f, -0.107885562f, -0.196403071f, 0.0402524024f, 0.100972787f, 0.0140078459f, + 0.0313971192f, 0.0885106325f, 0.105221868f, -0.0429264605f, -0.345159173f, -0.145739362f, 0.0140408045f, -0.126359373f, 0.0295974966f, 0.0356954783f, + -0.0932768583f, 0.294238806f, -0.13073346f, 0.149529859f, -0.0637182593f, -0.110935442f, 0.0944140404f, -0.0822723955f, 0.137176692f, -0.165188f, + 0.0123224994f, -0.121211797f, -0.0336953178f, -0.0577581711f, -0.173220277f, 0.0911624879f, -0.21754016f, -0.146832287f, 0.131837055f, 0.163277209f, + 0.0383987427f, -0.0862317458f, 0.220193312f, -0.232064575f, -0.172231942f, -0.165473923f, 0.131046966f, 0.00980686862f, 0.148794279f, 0.0372303389f, + -0.246968344f, -0.0535709709f, -0.0552824065f, 0.427690446f, 0.279029369f, 0.152851254f, -0.0661079064f, -0.0373469479f, 0.0492651351f, 0.110842794f, + -0.171459705f, 0.131206661f, 0.00892266724f, 0.102644354f, 0.0320037827f, 0.0621830821f, 0.0251628682f, 0.131705955f, -0.361692399f, -0.071424529f, + 0.377325296f, -0.065346092f, 0.0695154667f, 0.271031678f, 0.0864033103f, 0.317965865f, -0.11573986f, -0.32164073f, -0.298760623f, -0.355377346f, + -0.0994481444f, -0.100475773f, -0.0188447703f, -0.264799386f, 0.302399516f, -0.0196609832f, 0.059759941f, 0.179792002f, 0.0480276942f, -0.0439457893f, + -0.0393867157f, 0.0370936655f, 0.00433101738f, 0.105597176f, 0.0213202573f, 0.0159960296f, 0.0619907454f, -0.173157394f, -0.0407185405f, 0.0159902889f, + 0.135770649f, -0.185107917f, 0.0324278586f, -0.0155561473f, -0.0578564331f, -0.483193427f, -0.156059623f, -0.487260073f, 0.121997103f, 0.27536276f, + 0.257466227f, -0.199314281f, 0.150954172f, -0.104526415f, -0.171335787f, -0.164695412f, -0.157087535f, -0.00184154988f, 0.096085526f, -0.339558095f, + -0.109617226f, 0.123117231f, 0.061074093f, 0.134945869f, -0.181167036f, 0.13377744f, 0.0299106613f, -0.0319762193f, -0.00142649445f, -0.739072919f, + 0.125070319f, 0.60753715f, 1.04854727f, 0.281889468f, 0.395148277f, -0.398102075f, -0.263917714f, 0.660986245f, 0.0929356292f, -0.0691016987f, + -0.71624893f, 0.112951502f, 0.0750945732f, 0.0701717585f, -0.0357603244f, 0.0883771554f, -0.0903375298f, -0.0351926498f, 0.241851792f, 0.0534297638f, + -0.0815814063f, -0.180102706f, -0.0999425948f, -0.0567828417f, 0.203779534f, 0.00645063724f, 0.277997404f, -0.0963692665f, -0.0613248385f, -0.0367237739f, + -0.0667100847f, -0.163703978f, -0.0137496674f, 0.0271597132f, -0.208471924f, -0.107932262f, -0.0862375721f, -0.198183954f, -0.0594921969f, -0.162577465f, + -0.00823701452f, -0.0121088764f, 0.162099883f, 0.0972050279f, 0.229265511f, -0.10469956f, 0.216809854f, -0.0870542228f, -0.00312647969f, 0.0556442365f, + 0.266792029f, 0.0730923936f, -0.139602557f, 0.099826619f, -0.109195165f, -0.18190372f, -0.0181384105f, -0.0469537713f, 0.0894618183f, -0.200750783f, + -0.106087163f, 0.14101702f, 0.114832483f, -0.0116928415f, -0.116993323f, 0.204964697f, 0.079141669f, 0.189386129f, 0.0819025412f, -0.0692694113f, + -0.0485704727f, 0.0587131567f, 0.224529058f, -0.102555618f, -0.0554298088f, -0.188542545f, 0.213919818f, 0.0896721706f, -0.398319393f, -0.103894316f, + -0.0565932617f, -0.279362172f, -0.0245546177f, -0.104394652f, -0.287633479f, -0.0070318575f, -0.199145153f, 0.00460830517f, 0.172748581f, -0.0682691038f, + 0.0491978079f, 0.121936336f, -0.186465189f, -0.213488221f, 0.339258403f, -0.276479781f, 0.0330258794f, -0.185619131f, -0.224100173f, -0.436641425f, + -0.211526126f, -0.0590243265f, -0.324868083f, -0.0628374293f, -0.0460484438f, 0.185864151f, -0.110167898f, 0.194983855f, 0.125400901f, -0.0674838573f, + -0.223007858f, 0.202364907f, -0.204021573f, -0.0640251264f, 0.00478914939f, 0.165085629f, -0.088835232f, -0.0170859378f, -0.0487111807f, 0.0330204852f, + 0.179315984f, -0.332448363f, 0.172380447f, -0.468003839f, -0.0479620397f, -0.145519137f, 0.199446991f, -0.154280171f, -0.283416688f, -0.347385198f, + -0.16828303f, -0.130206078f, -0.150963873f, 0.0506250933f, 0.170040786f, 0.0403566174f, -0.217061117f, -0.255255252f, -0.15115954f, 0.104055673f, + -0.109524094f, -0.224379867f, -0.112249687f, -0.34579435f, -0.295579135f, 0.00198035594f, -0.140976965f, -0.141014978f, -0.0165857971f, 0.00521265063f, + 0.0187760666f, -0.045281142f, -0.427766651f, -0.362767637f, -0.201276854f, 0.354522109f, 0.0625692755f, -0.666527748f, -0.15156047f, 0.434857696f, + 1.11530721f, -0.588538647f, 0.100584812f, -0.207470819f, 0.110181972f, 0.0768359452f, 0.0699680746f, 0.413283676f, 0.370083749f, 0.424682021f, + -0.08164455f, -0.308995903f, -0.152983725f, 0.588608444f, 0.772259653f, 0.904112101f, 0.298444301f, -0.357256293f, 0.174753338f, -0.210215747f, + -0.333873272f, 0.131238595f, 0.0823794827f, -0.244102955f, 0.391887218f, -0.200893372f, -0.198503822f, 0.216243953f, 0.0859928057f, -0.064906925f, + -0.0373795778f, 0.167975679f, 0.111660607f, 0.0177226905f, -0.391700506f, -0.349966168f, 0.0766395405f, -0.118354723f, 0.144502133f, 0.282144576f, + -0.0760368481f, 0.0906918049f, 0.507333577f, 0.245970249f, 0.436351359f, 0.161070108f, -0.0666386858f, -0.142044052f, -0.417888135f, 0.137446314f, + 0.439086854f, 0.0539826714f, -0.347063631f, 0.106539041f, -0.406685263f, 0.270749092f, 0.014434821f, -0.0455865748f, -0.0913750157f, -0.121487357f, + 0.471953452f, 0.223174259f, 0.0531440936f, 0.102728449f, -1.06495202f, 0.243224666f, 0.765315056f, 0.518074036f, -0.189798474f, 1.01733947f, + -0.54617399f, -0.827518404f, 0.278523266f, -0.777626157f, -1.2590344f, 0.476880848f, 0.104188479f, 0.0400933586f, -0.0791816935f, 0.165687427f, + 0.164410874f, -0.105252199f, 0.0908510908f, -0.172085881f, 0.427652806f, 0.165576652f, 0.239871725f, -0.309399784f, 0.18420963f, 0.407754272f, + 0.145768389f, 0.0789611563f, -0.0710080937f, -0.00715834554f, -0.0941102877f, -0.107677318f, -0.322791576f, 0.0556871966f, 0.53715533f, -0.05981455f, + 0.0406633578f, 0.0113947885f, 0.530252993f, 0.0837855339f, 0.452353418f, -0.374604672f, -0.100750826f, 0.819397986f, -0.28082186f, -0.0847766772f, + -0.259000003f, 0.08231958f, 0.445137024f, 0.177261144f, -0.346786827f, -0.490525693f, 0.0499240123f, 0.227560341f, 0.142333567f, 0.00954777561f, + 0.0962421447f, 0.122871995f, -0.113015279f, 0.275964409f, -0.483473599f, -0.440134466f, -0.161017373f, -0.632085919f, 0.0878804773f, 0.159301817f, + 0.558356941f, 0.131868586f, 0.870577037f, 0.12448848f, 0.122658394f, 0.0478865765f, 0.33526668f, -0.898157656f, 0.877696514f, -0.121537939f, + 0.565701783f, -0.932897031f, 0.426450998f, -0.256588221f, 0.515072584f, -0.770253658f, -0.0395745933f, 0.0782283098f, 0.0730038732f, -0.0202466343f, + -0.114251748f, 0.136814833f, -0.138700098f, 0.282687157f, 0.0635512471f, -0.105147853f, 0.614823997f, 0.11135067f, 0.159493804f, 0.610640287f, + 0.174026459f, -0.0652268529f, -0.256204665f, 0.158415318f, -0.221527517f, -0.153679639f, -0.240041673f, 0.0889296904f, 0.0490203425f, -0.623391092f, + -0.0859216973f, -0.201288089f, 0.0375940353f, 0.0484127514f, -0.248130962f, -0.00920057483f, 0.0983282402f, -0.126584142f, 0.414687425f, 0.0537357889f, + -0.01439045f, 0.0621449687f, 0.0419877768f, 0.288985878f, 0.394884616f, 0.437330246f, -0.011538188f, 0.259054333f, -0.0184250418f, -0.489712894f, + -0.315024823f, -0.217457265f, 0.0181961134f, -0.234984636f, -0.374340564f, -0.0245089959f, 0.638851047f, -0.00569208479f, 0.371599436f, 0.206786692f, + 0.565811932f, -0.326791972f, 0.305235773f, -0.190125793f, 0.117290765f, -0.105706587f, -0.220041633f, 0.136369184f, -0.529020965f, 1.13972509f, + 0.0403035581f, -0.890435159f, 0.577159703f, -0.536148727f, -0.232627705f, 0.219920546f, 0.273978263f, -0.127611682f, -0.0235837251f, 0.0343661159f, + 0.106501959f, -0.0198914763f, -0.0660520718f, -0.0567573421f, -0.0108998138f, -0.0404516682f, -0.0731246695f, -0.203391612f, 0.477649391f, 0.171327159f, + 0.165399179f, 0.460638374f, 0.108466797f, 0.365879744f, -0.306230128f, -0.16521126f, -0.117786221f, -0.359881788f, -0.0474107303f, -0.370551884f, + -0.477203846f, -0.523116887f, -0.293875784f, -0.341360748f, -0.112898268f, -0.364778876f, -0.1611709f, 0.191520542f, 0.216256618f, 0.0370546952f, + -0.0134465136f, -0.17243357f, 0.358523309f, 0.4125534f, 0.0343281031f, -0.194680199f, 0.190874681f, 0.326337904f, -0.408481777f, 0.023650432f, + 0.264358163f, 0.102605067f, 0.083563894f, 0.185519561f, 0.511408627f, -0.00425073039f, -0.0364449956f, 0.0956394747f, -0.0665204227f, 0.0940864384f, + -0.788454115f, 0.0926355943f, 0.191808939f, -0.0143237477f, 0.159178108f, 0.334516615f, -0.210794985f, 0.1271514f, -0.116600536f, 0.129919961f, + -0.833716273f, -0.491950065f, -0.259316981f, -0.605086684f, -0.0745243579f, -0.362372369f, -0.800359964f, -0.785486639f, 0.772647798f, 0.160622284f, + -0.0236800723f, 0.11360193f, -0.000994234928f, -0.0792641118f, 0.00767314527f, 0.0155587792f, -0.0421582498f, 0.107196316f, -0.0297019444f, -0.289220095f, + -0.298659354f, 0.333211958f, 0.311129898f, 0.0081768427f, -0.158257127f, -0.170108348f, -0.33634454f, -0.0132950405f, -0.096478425f, 0.166795388f, + 0.159231827f, 0.203336492f, 0.354465634f, 0.63214916f, 0.235243127f, -0.169785738f, -0.0389261916f, 0.0370655917f, 0.450367361f, 0.157209009f, + 0.242358923f, 0.10185504f, 0.182687312f, 0.241347104f, -0.0996524021f, 0.246183842f, 0.247258797f, 0.0171009675f, 0.287750721f, 0.472929209f, + 0.0834064856f, -0.0687300041f, 0.0206404887f, 0.0347239412f, -0.0962562039f, -0.124633864f, 0.00882993452f, -0.270120561f, -0.389553398f, -0.245953217f, + -0.0846167654f, -0.37950179f, -0.26411894f, 0.224497601f, 0.0971144959f, -0.247526035f, -0.0333143659f, -0.127209783f, 0.390705526f, -0.17552872f, + -0.0414970703f, 0.0979903862f, -0.117017031f, 0.0595430322f, 0.78285116f, -0.286667496f, 0.696584821f, -0.218139812f, 0.524651766f, -0.192394987f, + -0.00528492872f, 0.267883152f, -0.0269061476f, -0.368258178f, -0.0211206023f, 0.0352217034f, 0.0102346651f, 0.149097085f, 0.160881191f, 0.249318615f, + 0.247193113f, -0.232954428f, 0.288122118f, 0.276940316f, -0.0682634711f, 0.240998834f, 0.312025666f, -0.0244663395f, -0.239846602f, -0.0106779085f, + 0.744977534f, 0.16255489f, -0.181240141f, 0.0381530821f, -0.147275567f, 0.00439010933f, -0.0314614847f, -0.0625116751f, 0.0347904824f, 0.0652671233f, + 0.160579145f, 0.0356596299f, 0.0739542916f, -0.0311465748f, -0.0508100763f, -0.0866172388f, -0.487890393f, -0.0360243022f, 0.0404544398f, 0.0954675898f, + 0.010651025f, 0.155057117f, -0.445750833f, 0.0829955414f, 0.218594342f, -0.158319056f, 0.0176737439f, -0.0408586748f, 0.0186833628f, -0.23854509f, + -0.24106358f, 0.30161804f, 0.243713468f, -0.200695157f, -0.156180158f, 0.145630464f, -0.0611954443f, 0.0534827486f, -0.210341409f, -0.124976948f, + 0.0376024731f, -0.0703935474f, 0.000268083269f, 0.0385897458f, -0.304046094f, -1.70769227f, -0.515982747f, 0.19411543f, 0.190148219f, -0.61588347f, + 0.210131526f, 0.294053406f, -0.998728275f, -1.23476362f, 0.386759728f, -0.279310256f, 0.0107909655f, 0.0115279285f, -0.00664418098f, 0.223218799f, + 0.419897348f, -0.207308888f, -0.17031613f, -0.0242744498f, 0.119367614f, -0.176752746f, 0.310241371f, 0.184201419f, 0.21342057f, -0.118645594f, + 0.1375608f, 0.288616002f, -0.211897358f, 0.566988528f, -0.0227506012f, 0.145864114f, -0.0917523354f, 0.2160822f, 0.243199736f, -0.0322738029f, + -0.303198189f, -0.117357194f, -0.184124574f, -0.102499895f, -0.0735174343f, 0.0991401225f, 0.196479484f, -0.180965886f, 0.0142821819f, -0.0188364405f, + 0.305485964f, 0.762756884f, 0.123001546f, 0.492651969f, -0.106556728f, -0.146967486f, -0.0702059045f, -0.0605615489f, 0.0551293306f, 0.0875655934f, + 0.29468286f, 0.0621351823f, 0.0577881597f, 0.0410062708f, -0.0275039449f, 0.11876931f, -0.00437424239f, 0.00961470418f, 0.026983073f, 0.0380664021f, + -0.347236335f, -0.12417689f, -0.160840347f, -0.0631494895f, -0.0703094378f, 0.013703349f, 0.775448263f, -0.136947498f, 0.402539253f, 0.845378458f, + 0.1924676f, -0.226778314f, -0.169291228f, -0.590278685f, 0.176980317f, 0.65129143f, 0.328980774f, 0.445320189f, 0.0f, 0.0f, + 0.0f, 0.0374597758f, 0.22893253f, 0.00816218834f, 0.0733135417f, 0.0986459106f, 0.119771101f, -0.321177602f, 0.0361113362f, 0.0180106126f, + -0.240070134f, 0.0912688747f, 0.112684578f, -0.138208777f, -0.488096863f, -0.369724929f, -0.110115424f, 0.048613742f, -0.16086939f, -0.137464389f, + -0.0846471116f, -0.055013001f, 0.192156643f, 0.357360065f, 0.0386049077f, 0.18193838f, 0.112423658f, 0.191431686f, 0.137193292f, -0.219505981f, + -0.245162934f, -0.302261561f, 0.175365984f, 0.134799346f, -0.159733787f, 0.10756065f, 0.10518726f, 0.110826895f, 0.1147044f, 0.0858760551f, + -0.0594794303f, 0.0100343721f, 0.291962892f, 0.0134920245f, 0.0288935155f, 0.188338295f, -0.0473909974f, -0.18536976f, 0.0607016943f, -0.00883004256f, + 0.0199999996f}, + {0.292518049f, 0.73112011f, 0.173249841f, -0.290968627f, 0.225215673f, 0.113046132f, -0.115835786f, 0.154310301f, 0.104177386f, 0.085384354f, + 0.0184165873f, 0.136650056f, -0.162866756f, -0.0210976005f, -0.0954033285f, 0.156705409f, 0.0212813318f, -0.059971977f, -0.172606185f, -0.0432778671f, + 0.0199170802f, -0.0738108084f, 0.297775954f, 0.344444096f, -0.498383313f, -0.468125075f, 0.0502231047f, -0.107494637f, 0.0429170579f, 0.156358764f, + 0.63761133f, -0.285612613f, -0.000593790493f, 0.46932891f, 0.14557384f, 0.245666549f, -0.00856976863f, -0.417372108f, 0.113958642f, 0.0535282157f, + -0.291553229f, -0.20378834f, -0.0461087152f, -0.176867783f, 0.0748347193f, 0.0476337597f, 0.00327241514f, -0.164663225f, 0.108441211f, 0.253388941f, + 0.170932174f, -0.166645855f, 0.171900779f, -0.154103801f, 0.184426486f, -0.208299845f, 0.306282163f, -0.0277089868f, 0.142704546f, -0.0623336807f, + 0.00812248792f, -0.530812323f, -0.0604569428f, 0.0592397153f, 0.221418411f, -0.317254484f, -0.623883426f, 0.305107355f, -0.359563887f, 0.137222007f, + 0.372233152f, -1.05179238f, -0.035407681f, 0.043784108f, 0.0764201656f, 0.0122594852f, 0.295270473f, -0.0429561138f, -0.157978848f, 0.168719649f, + 0.0756873712f, 0.142519996f, -0.113329075f, -0.332749009f, -0.00641697133f, -0.149503157f, 0.161292255f, -0.0167296343f, -0.373678952f, -0.335231692f, + 0.160889223f, 0.143092781f, -0.141012847f, 0.00800906029f, 0.0427539907f, 0.100589342f, 0.145468563f, -0.0475567542f, -0.113596939f, -0.0926979706f, + 0.138128176f, -0.591710687f, -0.134259328f, -0.158661261f, -0.460926682f, -0.0289974306f, -0.265246749f, 0.108475387f, -0.134765118f, 0.0515354238f, + 0.14711757f, 0.179133773f, -0.151609689f, -0.316282511f, 0.535890996f, 0.100551501f, 0.0181414224f, 0.0842434615f, -0.0325195603f, 0.221532136f, + 0.0906174183f, 0.085931018f, -0.0409021713f, 0.114300191f, -0.20712176f, 0.0863115937f, 0.313334048f, -0.381868929f, -0.599299192f, -0.00251577841f, + -0.0879075155f, -0.0277722236f, 0.284038275f, 1.15511239f, -0.361299932f, -0.619772732f, 0.305273265f, -0.376332939f, -0.232791364f, -0.153116733f, + 0.305922389f, -0.318899333f, 0.0907810554f, -0.112818651f, -0.0235925242f, 0.024594197f, 0.0703446567f, -0.269858509f, -0.00077414664f, -0.114579678f, + -0.0965084508f, -0.313107401f, -0.237923548f, 0.198363259f, 0.0612649098f, 0.0351119451f, -0.0746902451f, -0.153690696f, 0.0940582529f, 0.273532301f, + 0.338252664f, -0.0900570974f, 0.283713698f, -0.223146319f, -0.307773411f, -0.195899829f, -0.153629407f, 0.317767233f, -0.272326291f, 0.230650321f, + -0.319896549f, 0.0486592278f, 0.188330606f, -0.0416946746f, -0.17065686f, 0.191828698f, 0.167350665f, 0.14929162f, 0.378564358f, -0.00474163657f, + 0.0279102046f, 0.225318387f, 0.11509373f, 0.00352921733f, -0.0375073068f, -0.00117469381f, -0.441531569f, 0.140913412f, -0.205466807f, -0.316361845f, + 0.0933156759f, 0.230784535f, 0.0244342126f, -0.0603574887f, -0.338008821f, 0.579469025f, 0.123085439f, -0.349771708f, -0.267186433f, -0.0682059228f, + -0.463518351f, -0.00861792546f, 0.0311530083f, -0.0832851455f, 0.222104311f, -0.238221005f, 0.509405792f, 0.681181908f, -1.60170317f, 0.0426187143f, + -0.924781442f, 0.572856724f, 0.102325954f, 0.38210687f, -0.427077115f, 0.999234676f, -0.0633541495f, 0.0158330631f, 0.0709191635f, 0.420924902f, + -0.242724225f, 0.0774375647f, -0.148981884f, -0.0284525305f, -0.311422199f, 0.338593364f, -0.232101724f, -0.0775928125f, 0.150298566f, -0.153188989f, + -0.135863081f, -0.194069445f, -0.0708414167f, -0.308897793f, -0.117480151f, -0.0771652162f, -0.130936265f, 0.071019724f, -0.0141299097f, 0.231877699f, + -0.0288134646f, 0.0130751394f, -0.105380833f, -0.120199174f, -0.277718872f, 0.14969781f, -0.24051106f, -0.150597796f, 0.122345306f, 0.0622134805f, + -0.119831972f, -0.471720278f, 0.109377652f, 0.0748317391f, -0.311467379f, 0.243317008f, -0.087364912f, -0.180364937f, 0.081035696f, -0.0105111971f, + 0.0823311135f, -0.399039298f, 0.440757245f, -0.111347802f, -0.345883667f, 0.144558176f, -0.0813733861f, 0.0507233813f, -0.118794538f, -0.0352457836f, + 0.0455284305f, -0.174430683f, 0.161990896f, -0.00549666677f, -0.032646101f, -0.0414185412f, -0.258946568f, -0.383445233f, 0.0522429757f, 0.0863494352f, + -0.105951913f, -0.474177122f, 0.307969898f, -0.987153888f, -0.534496188f, 0.0609814152f, -0.787956774f, -0.0332912542f, -0.0649967641f, 0.00445601856f, + 0.0473969169f, -0.097580187f, 0.0720928535f, -0.0586392581f, 0.0341303535f, -0.0608021542f, -0.68721813f, 0.423440248f, -0.058159098f, 0.0829301551f, + 0.362242311f, 0.0013846868f, -0.326818943f, 0.175141931f, 0.144392624f, -0.0243401062f, 0.00733701466f, 0.0901825428f, -0.341972858f, 0.055912897f, + -0.10185422f, -0.179941297f, -0.149944469f, -0.173922732f, -0.209090218f, 0.254220217f, 0.105088457f, 0.25612396f, 0.133102506f, 0.096300751f, + 0.0127357142f, 0.154114351f, 0.381963491f, 0.0103987996f, -0.0835813954f, -0.0320662707f, -0.00269967085f, -0.169076949f, 0.0319920145f, -0.067239441f, + 0.325169921f, -0.0344524533f, 0.0525157601f, 0.210657954f, -0.0747738853f, 0.333791703f, -0.171019033f, -0.221659407f, -0.117111132f, -0.0328399949f, + -0.334705085f, -0.0143073127f, -0.411255807f, 0.287512928f, -0.0546326227f, 0.069795683f, 0.0472999997f, 0.0162590407f, -0.282023549f, -0.37446171f, + -0.22708194f, -0.000629780581f, -0.504412651f, -0.535597622f, -0.120772526f, -0.324280322f, 0.580225527f, 0.633195877f, 0.0167397577f, 0.248020306f, + -0.0345985182f, -0.0156372096f, 0.0476052128f, -0.176353395f, 0.0577151217f, -0.029164331f, 0.101866402f, 0.378861099f, -0.575575352f, 0.206763312f, + -0.268413275f, 0.194716245f, -0.185838759f, 0.0433828421f, -0.0229044762f, 0.0404804163f, -0.00620329939f, -0.206638113f, -0.160835296f, 0.209359244f, + -0.0239869617f, -0.280189067f, 0.0720730722f, 0.0537220947f, 0.206067875f, -0.164240003f, 0.120068699f, -0.140204221f, 0.057288561f, 0.0482599922f, + 0.330260754f, 0.118276462f, -0.248106539f, -0.0564197078f, -0.011595415f, 0.275341839f, 0.181128338f, -0.250487328f, 0.139841512f, 0.235287651f, + 0.50109899f, -0.344188094f, -0.0499718413f, 0.353149533f, -0.271976829f, -0.243170634f, 0.0716535747f, 0.215260476f, -0.111584865f, 0.0981253982f, + 0.0497239456f, 0.293464452f, -0.0589020252f, 0.16717203f, -0.28350234f, -0.113832794f, -0.095007427f, -0.0190939419f, 0.00622080639f, -0.0412732698f, + 0.632368863f, 0.330394894f, -0.333903432f, 0.149854586f, 0.261871457f, -0.121658079f, -0.0888953432f, -0.0338858888f, -0.94470036f, 0.243708193f, + 0.0264164116f, -0.429746985f, -0.0339541733f, -0.0165290479f, 0.0543907396f, 0.112780973f, -0.2105252f, -0.0905671716f, -0.0750652924f, 0.279828489f, + -0.566220224f, -0.0110201761f, 0.13819173f, 0.119915143f, 0.0468317494f, -0.133673772f, -0.560809433f, 0.1384646f, -0.249461174f, 0.0265863314f, + -0.221548334f, 0.287090391f, 0.295559913f, -0.0654191896f, 0.163774982f, 0.0605344623f, 0.0925056189f, -0.0648531243f, -0.195440665f, 0.0618568696f, + -0.0843085274f, -0.104618579f, 0.0861379802f, 0.0484943688f, 0.0251727048f, -0.00333628897f, 0.342687398f, -0.0295026116f, 0.247835606f, -0.0180306043f, + 0.043636471f, -0.109482341f, 0.0801418126f, 0.0482179895f, -0.262025356f, -0.128806144f, -0.07516177f, -0.147840157f, 0.209426045f, 0.327298671f, + 0.118608028f, 0.23360163f, -0.08794716f, -0.0215738788f, 0.150527582f, 0.433357537f, 0.155466095f, -0.169518888f, -0.0746061653f, 0.076847285f, + 0.0241782703f, -0.0538820066f, -0.558542013f, -0.684288204f, -0.0846586153f, 0.245347649f, 0.919344425f, -0.0992695838f, 0.871340811f, 1.09713745f, + 0.00949203316f, 0.875102699f, 0.528605521f, -0.12935479f, -0.0268472563f, -0.00297430484f, 0.0414729044f, 0.0455568656f, 0.00946147367f, -0.0284606293f, + -0.0266371332f, 0.0167548191f, 0.206046775f, -0.168538645f, 0.120706037f, -0.147641093f, 0.159792811f, 0.0907656774f, 0.0440446958f, 0.0607062913f, + 0.238653988f, 0.0132301794f, -0.0206111055f, 0.0133209582f, 0.213632748f, 0.0560295396f, 0.565453887f, -0.0565848686f, 0.199635759f, 0.262685567f, + -0.0663529187f, -0.233934298f, -0.315814942f, 0.00828946009f, 0.235354185f, 0.0331112333f, 0.00171865989f, -0.138418823f, 0.088841185f, -0.537061989f, + 0.0246519931f, -0.0290850345f, -0.36727801f, 0.479034454f, -0.355576724f, -0.297180772f, -0.34972176f, 0.196317792f, -0.320006579f, 0.171848714f, + 0.128709361f, -0.0108907092f, -0.395960659f, -0.169496387f, 0.404418975f, -0.25268957f, -0.180651262f, -0.0804636404f, 0.15326941f, 0.090358302f, + 0.227741912f, -0.0136356503f, -0.0308971759f, 0.0187467895f, -0.494409353f, 0.458500445f, 0.197876588f, -0.959123194f, 0.873052716f, 1.15706074f, + -0.271870643f, 0.0378681906f, 1.12027979f, -0.782562494f, -1.13050532f, -0.498768806f, 0.0089910822f, 0.00470550172f, 0.0636855587f, -0.280036747f, + -0.16234307f, 0.321483701f, -0.0335878655f, -0.237929448f, 0.184509799f, 0.190733656f, 0.0547859371f, 0.138444975f, 0.0818301961f, 0.347486079f, + -0.451899856f, 0.0641769916f, -0.0980763286f, 0.155147329f, 0.0545337312f, -0.2621243f, 0.00672620349f, 0.130092829f, -0.338672101f, 0.000818460598f, + -0.265355051f, -0.236411735f, 0.213387653f, 0.137554511f, 0.0552042127f, -0.0718707517f, -0.205228493f, 0.30529505f, -0.372526616f, 0.117721409f, + 0.204298362f, 0.0990360454f, -0.230261222f, 0.023189215f, -0.11705222f, 0.444628865f, 0.066754818f, -0.415638328f, 0.118874833f, 0.47077629f, + 0.192518935f, 0.21662955f, 0.0201587137f, -0.452299803f, -0.400932372f, -0.275764704f, -0.0146813411f, 0.0392123535f, 0.130755246f, -0.115478456f, + 0.194310173f, -0.0967822671f, -0.197548002f, -0.0642617568f, -0.0989209563f, -0.033349514f, 0.450203001f, -0.439221442f, -1.33144367f, -0.521109581f, + 0.11104618f, -1.7567687f, -0.460480571f, -0.201988965f, -0.746907175f, -0.818768978f, -0.0871801674f, -0.28773734f, 0.0205638073f, 0.0708851144f, + 0.0598764606f, 0.373146147f, 0.105155028f, -0.333463162f, -0.167628363f, 0.208317518f, 0.501408517f, 0.0877607167f, 0.0257651024f, 0.397555947f, + -0.0240305699f, -0.0797993988f, -0.326558292f, -0.0903397501f, 0.517383456f, -0.328223854f, 0.0170015637f, -0.302618414f, 0.051521305f, 0.161172077f, + -0.0512386747f, 0.143955573f, 0.153638512f, 0.14335461f, 0.414151013f, 0.144293889f, -0.123246871f, -0.221087977f, -0.265317917f, 0.0877945945f, + -0.116609968f, 0.634139001f, 0.41332832f, -0.0603508614f, -0.0840128511f, 0.42588836f, -0.405345678f, -0.0413226336f, 0.271736771f, -0.16827023f, + -0.065139994f, -0.032713946f, 0.212247506f, -0.016465649f, 0.0360722803f, 0.0803415999f, -0.0431952551f, 0.203360155f, -0.21732302f, -0.278901875f, + -0.352200091f, -0.329887986f, -0.105281927f, 0.216094121f, 0.0135082463f, 0.0144874724f, -0.0351860747f, -0.0573740825f, -0.298948675f, -0.531878889f, + -0.286480308f, -0.225986823f, -0.395115912f, -0.768381476f, -0.259034693f, 0.549589396f, -1.18268716f, -0.0896312147f, -1.22392702f, 0.131788507f, + 0.025803484f, 0.0689896792f, 0.031587746f, -0.107754372f, -0.425253808f, 0.0637277961f, 0.420103341f, 0.0284937415f, 0.247984692f, -0.0562701747f, + -0.540333986f, 0.0659539849f, -0.175058961f, -0.383016378f, 0.126040235f, 0.0321661122f, -0.166505098f, 0.187219501f, -0.246085793f, 0.108986281f, + -0.224448711f, 0.153930664f, -0.229892418f, 0.371090055f, 0.0439963304f, 0.326368451f, -0.218145862f, -0.0965098888f, 0.209287167f, -0.646084011f, + -0.243510768f, 0.246512502f, 0.103443667f, 0.248458594f, -0.0669095367f, 0.123866878f, -0.139692858f, -0.287110656f, -0.371551871f, -0.104337171f, + -0.102298751f, -0.110954523f, -0.698049963f, -0.508980274f, -0.23420164f, 0.00841938052f, -0.128998175f, -0.09468171f, -0.192202896f, 0.629417539f, + -0.386972576f, 0.26336354f, 0.290539593f, 0.168947041f, 0.195187703f, 0.16629155f, -0.531744003f, -0.0527824238f, -0.0299397279f, -0.0285814386f, + 0.0587482303f, -0.0331460685f, 0.38305819f, 0.511526883f, 0.976665735f, -0.198032096f, 0.572697341f, -0.413016915f, -0.420027971f, -0.32663691f, + -0.58996588f, 0.385610878f, 0.0137390392f, 0.0806152523f, 0.0394649357f, 0.195466951f, 0.274437934f, 0.0460882559f, 0.132826343f, -0.0625102445f, + -0.191460386f, 0.0604663379f, 0.00614928268f, -0.30399701f, 0.0901714861f, -0.394575924f, -0.000592255325f, -0.183821291f, -0.132411063f, -0.28989616f, + 0.158479542f, 0.0585374795f, 0.202094421f, 0.0803281814f, -0.258101225f, -0.0410893559f, -0.236708686f, 0.134510875f, 0.274667412f, 0.0895578191f, + -0.115614884f, -0.0500314757f, 0.0847731456f, -0.309234023f, 0.0556983575f, -0.0101289125f, -0.180609465f, -0.154269323f, -0.00604214985f, -0.224790215f, + -0.246272251f, 0.233433828f, 0.104932584f, 0.403379023f, -0.238110214f, -0.433201462f, 0.216448829f, 0.259196639f, -0.130381733f, -0.311198086f, + 0.0135480296f, -0.393155873f, -0.0705845058f, -0.511482f, -0.101406284f, -0.514588118f, -0.0564976111f, 0.359869957f, -0.0687341467f, -0.070044376f, + -0.0351090319f, 0.0249400884f, 0.397221208f, -0.379579008f, -0.428128392f, -0.840583384f, 0.551595926f, -0.0231634881f, 0.844541907f, -0.677783549f, + -0.185332164f, 0.0266798642f, 0.772416353f, 1.00728822f, 0.0390365161f, 0.0563289411f, 0.0373030938f, -0.124486461f, -0.235994726f, -0.401868343f, + 0.188380063f, -0.0173787996f, -0.210110381f, 0.0954874381f, -0.192364067f, -0.277290165f, 0.0740700439f, -0.0702358931f, 0.458442211f, -0.204799607f, + 0.111240797f, 0.344073385f, -0.229823187f, 0.0819170177f, -0.0692415982f, 0.0320760161f, 0.0242207237f, 0.0548502095f, -0.231370643f, 0.0526521057f, + 0.00224892981f, -0.0270713903f, 0.20471026f, 0.180415317f, -0.121819466f, -0.00572441472f, 0.739286542f, 0.100714915f, -0.108795851f, -0.0200349707f, + 0.153724223f, 0.087858662f, 0.179606676f, -0.196885109f, 0.0944223925f, 0.232013315f, 0.150252655f, -0.24078542f, -0.0823509619f, 0.0367690995f, + 0.116759695f, 0.120481886f, -0.145260483f, 0.20641838f, 0.0168019459f, 0.124359645f, 0.0687215626f, 0.136362702f, 0.178361386f, -0.372272253f, + 0.0837767646f, 0.0425290428f, 0.0263837054f, 0.0347947814f, -1.37156415f, -0.519310296f, 0.120121226f, 0.467960119f, 1.07899988f, -0.265197098f, + 0.239037454f, 0.174888089f, 0.593141973f, 0.852331281f, -0.0662628859f, 1.94699848f, 0.0397610813f, 0.0402456038f, 0.0583121963f, 0.0363488384f, + -0.116971947f, 0.0984148234f, 0.129591241f, 0.0823681355f, -0.116270967f, 0.285993487f, -0.0331077799f, 0.277025521f, 0.266185373f, -0.360245675f, + -0.25976491f, -0.296795428f, 0.000774615328f, -0.0483586863f, 0.019054018f, -0.245117113f, 0.0460964441f, -0.0952533185f, -0.148025304f, -0.0717458278f, + 0.0785460621f, -0.146472722f, 0.263894856f, 0.151295334f, 0.162408233f, 0.117280841f, -0.166863427f, 0.17840378f, 0.342810124f, -0.052801203f, + -0.0497750081f, -0.0592781715f, 0.259560406f, 0.0933736041f, -0.0338125117f, -0.459937572f, 0.141823038f, -0.222580343f, -0.221685186f, 0.146064848f, + -0.258092314f, 0.14650248f, 0.223903403f, -0.480238497f, -0.0840690956f, -0.427378565f, -0.0786953941f, 0.157953814f, -0.380613089f, 0.359755218f, + -0.131189123f, -0.332990795f, -0.0820106491f, -0.0379733294f, 0.0455513671f, -0.0480523258f, 0.371606499f, -0.98247081f, -0.0548172407f, -0.780452549f, + 0.676401496f, 0.11080157f, -0.210712567f, 0.535028458f, -0.712442636f, -0.273335129f, 0.965053856f, -0.0893517286f, 0.0365471765f, 0.0306979399f, + 0.0623790137f, 0.232134983f, 0.0945121124f, -0.0739344805f, -0.0628598183f, -0.0230981857f, -0.0573117808f, -0.123719066f, -0.18043606f, -0.299697429f, + 0.0179808643f, 0.0700035989f, 0.0909450203f, -0.309864283f, 0.0967407003f, 0.0160465632f, -0.224926725f, 0.0277307071f, 0.121134929f, 0.0456956401f, + 0.0665075779f, 0.116802305f, 0.102488719f, -0.0741928369f, -0.388691038f, -0.141014591f, 0.0361065045f, -0.102647357f, 0.0592817031f, 0.0917218775f, + 0.00938217156f, 0.253354043f, -0.166727483f, 0.116153635f, -0.0967153385f, -0.142766535f, 0.0662314892f, -0.113440514f, 0.100391507f, -0.202287555f, + -0.0134231001f, -0.144958511f, -0.0615393892f, -0.0885686576f, -0.200347051f, 0.0730549023f, -0.276884049f, -0.162934542f, 0.163980097f, 0.184639007f, + 0.0902375206f, -0.135661602f, -0.0048017106f, -0.581012487f, -0.403874993f, -0.37250036f, 0.0237291306f, 0.161605537f, 0.41129905f, 0.329584241f, + -0.0475406088f, -0.162283003f, -0.138859704f, 0.370876938f, 0.188947618f, 0.0973890647f, -0.143621504f, -0.197092563f, -0.247715726f, -0.184041947f, + -0.461657226f, -0.0452532098f, 0.0520617478f, 0.24672839f, 0.197259203f, 0.162817001f, 0.039708171f, 0.186688438f, -0.300383955f, -0.08388675f, + 0.329988211f, -0.138267711f, -0.0159106012f, 0.117571391f, -0.11376939f, 0.116740629f, -0.19638145f, -0.216205403f, -0.092564933f, -0.149915338f, + 0.0605836138f, -0.0538277738f, 0.117993802f, -0.111909017f, 0.338687599f, -0.077873528f, 0.0429265685f, 0.202659175f, 0.0544726811f, -0.00703652669f, + 0.083320044f, 0.15810895f, 0.0183110889f, 0.0615774766f, -0.0836325958f, -0.0802493319f, 0.275138319f, 0.0234819911f, 0.0976665989f, 0.0496259518f, + 0.148039773f, -0.131814197f, 0.079218246f, 0.0434581675f, 0.0552949794f, -0.271227777f, 0.0321100093f, -0.492641121f, -0.036846865f, 0.0633619204f, + 0.107350938f, -0.246082917f, 0.115494311f, -0.16167964f, -0.248535529f, -0.214868903f, -0.128388822f, 0.0554902405f, 0.110607199f, -0.334775209f, + -0.0908013955f, 0.120262004f, -0.020024145f, 0.0432773381f, -0.218264893f, 0.11756625f, -0.008830823f, -0.0202706307f, -0.0165663995f, -0.837612689f, + 0.137044802f, 0.67918247f, 1.13894367f, 0.107092895f, 0.527663887f, -0.377648145f, -0.0604627244f, 0.720206082f, 0.258997113f, -0.23087655f, + -0.710693836f, 0.0350698568f, 0.0324941166f, 0.067963317f, -0.089000538f, 0.072274588f, -0.120977007f, -0.0785558522f, 0.163513169f, -0.0691031069f, + -0.144911692f, -0.219188407f, -0.176773801f, -0.107762851f, 0.153106391f, -0.0709265321f, 0.22766073f, -0.116009012f, -0.0252839122f, 0.0217540618f, + -0.0760426074f, -0.147837937f, -0.0297689009f, 0.0241849013f, -0.319871694f, -0.117099755f, -0.0850052685f, -0.154675558f, 0.0263501648f, -0.133448467f, + -0.0686489269f, -0.0184914805f, 0.111059465f, -0.0309827831f, 0.228604883f, -0.109768145f, 0.22729218f, -0.0829191133f, 0.0118307322f, 0.0695159212f, + 0.300014168f, 0.12209136f, -0.0806857646f, 0.165738419f, -0.050874386f, -0.137546882f, 0.0378934555f, -0.00840246119f, 0.129641786f, -0.00317467377f, + -0.028832471f, 0.0429670513f, -0.171275526f, -0.156860664f, -0.141195312f, -0.12884298f, -0.08033894f, 0.202866375f, -0.221181199f, -0.198837683f, + -0.25744468f, -0.0660415068f, 0.352562696f, 0.00669525145f, 0.232337534f, 0.00452690152f, 0.196157798f, -0.142156243f, -0.332957655f, 0.046466928f, + -0.242954567f, -0.235939175f, 0.28305164f, -0.0303532965f, -0.00491987774f, -0.0596838407f, -0.0618268587f, 0.221026734f, 0.214784086f, -0.0493646637f, + 0.001683968f, 0.112317771f, -0.225881666f, -0.223784298f, 0.363288701f, -0.284867615f, 0.0861335844f, 0.021254221f, -0.125027239f, -0.3115412f, + -0.119218349f, 0.0739088729f, -0.175723329f, 0.0411070175f, -0.0166702904f, 0.271173328f, -0.0685255155f, 0.16421175f, 0.113923527f, -0.119270869f, + -0.310032576f, 0.211331144f, -0.107522674f, -0.191817313f, 0.0933226869f, 0.0443977192f, -0.134888366f, -0.0430689901f, -0.0759667009f, 0.121921889f, + 0.334256202f, -0.295101047f, 0.107487194f, -0.443498999f, -0.0673378557f, -0.221572161f, 0.247624561f, 0.0345870368f, -0.206093758f, -0.130638525f, + -0.186998531f, -0.0133268377f, -0.0877164975f, 0.0276074205f, 0.202091768f, 0.0915239528f, -0.174025849f, -0.216375425f, -0.0797512978f, 0.150278628f, + -0.0382901169f, -0.117021039f, 0.0257964041f, -0.241629392f, -0.201389298f, 0.0294099003f, -0.07945472f, -0.103077546f, 0.0155197941f, 0.000386403466f, + -0.0120177893f, -0.0309223756f, -0.435850322f, -0.479679585f, -0.195725143f, 0.352900296f, 0.0475524254f, -0.684029818f, -0.158875674f, 0.36391905f, + 1.04210901f, -0.573415697f, 0.207612455f, -0.12124557f, 0.0429585986f, 0.0354783721f, 0.0413755663f, 0.183496922f, 0.100869611f, 0.664137185f, + 0.0272376966f, -0.43609491f, -0.162633926f, 0.125988841f, 0.105719618f, 0.844600439f, 0.3418625f, -0.470723569f, 0.0702487826f, -0.220492095f, + -0.326455504f, 0.270602256f, 0.118571728f, -0.24831444f, 0.46972546f, -0.215299234f, -0.301282793f, 0.273136586f, 0.0985317528f, -0.0481849238f, + -0.0107497061f, 0.084975794f, -0.0531376898f, 0.0509784035f, -0.395825952f, -0.300776362f, 0.159239888f, -0.121995807f, 0.143814653f, 0.320103824f, + -0.0677555427f, 0.0898678899f, 0.524928629f, 0.108696088f, 0.456075758f, 0.217337415f, 0.0397760943f, -0.182556883f, -0.411893517f, -0.306920946f, + 0.151951209f, 7.20876851e-05f, -0.185906261f, 0.0226134304f, -0.366425931f, 0.279098153f, 0.0456141494f, -0.00593193341f, -0.00969744846f, -0.04870262f, + 0.547462404f, 0.11158897f, 0.0506961904f, 0.0194843225f, -0.833841383f, 0.0720526576f, 0.886298239f, 0.433006108f, -0.14275001f, 1.0029943f, + -0.706935823f, -0.763082683f, 0.294251204f, -0.750709593f, -1.42879653f, 0.488877058f, 0.0316441059f, 0.0184177142f, -0.0479985997f, 0.169607893f, + 0.157248005f, -0.119924016f, 0.034606304f, -0.227970317f, 0.398869812f, 0.154944047f, 0.167635784f, -0.444818914f, 0.169522241f, 0.367200375f, + 0.153273791f, 0.14854835f, -0.0163289402f, -0.035525471f, 0.158537164f, 0.118896127f, -0.188861236f, -0.124414764f, 0.345367163f, -0.328901023f, + -0.0588756651f, -0.196402952f, 0.183196828f, 0.26853916f, 0.224558264f, 0.123130471f, -0.405243844f, 0.426809877f, 0.0497182272f, -0.052865047f, + -0.0206292793f, -0.0897673145f, 0.099691093f, 0.0471643992f, -0.0955119655f, -0.459057391f, 0.00861569308f, 0.226051584f, 0.2128869f, 0.0401770212f, + 0.135752335f, 0.0520840511f, -0.0802197084f, 0.215934321f, -0.53115952f, -0.518941998f, -0.00323828566f, -0.358840734f, 0.117198296f, 0.411009133f, + 0.131977528f, 0.0965787619f, 1.1413033f, 0.0563575774f, -0.0647216067f, 0.0300396122f, 0.309174538f, -0.319292247f, 0.404829383f, -0.0350391082f, + 0.412123144f, -0.829169631f, 0.347289264f, -0.25993067f, 0.52093178f, -0.683040738f, -0.162362844f, 0.0202471111f, 0.0336078107f, 0.0331952311f, + -0.138068944f, 0.154360384f, -0.227876201f, 0.332208723f, 0.0375208519f, -0.11120005f, 0.464636803f, 0.0897440836f, 0.0730795413f, 0.440704286f, + 0.351095319f, 0.00751229422f, -0.443429083f, 0.201303944f, -0.118636563f, -0.198125362f, -0.127620041f, 0.134072974f, 0.18192631f, -0.725651622f, + 0.0381940417f, -0.148810431f, 0.107320353f, 0.0996867493f, -0.0707713142f, -0.177666932f, -0.241980493f, -0.413015127f, 0.202417135f, -0.099090144f, + -0.214087009f, 0.0254609231f, -0.173997179f, 0.193840057f, 0.336171716f, 0.429330528f, -0.267033994f, 0.192674994f, -0.216064408f, -0.491115808f, + -0.293334931f, -0.296125233f, -0.0970490649f, -0.173833624f, -0.302315384f, -0.00797772501f, 0.426817626f, -0.166809589f, 0.212576166f, 0.109238192f, + 0.712966979f, -0.365218133f, 0.287017912f, -0.233798146f, 0.0143779293f, -0.0371073149f, -0.0809504092f, -0.0221694019f, 0.0411381274f, 1.48997724f, + -0.386443704f, -0.992263615f, 0.683153391f, -0.487695187f, -0.209849909f, 0.0772429481f, 0.133012071f, -0.0510355942f, 0.0646380335f, 0.195511177f, + 0.0420436673f, 0.0159953516f, -0.0898036733f, 0.151101947f, 0.0125186406f, -0.0478293374f, -0.18304351f, -0.00294406805f, 0.383833557f, 0.0477201119f, + 0.0923346579f, 0.269892633f, 0.211766303f, 0.371894985f, -0.573717892f, -0.164141059f, -0.153391913f, -0.336994708f, 0.105641276f, -0.364057183f, + -0.391364574f, -0.545094609f, -0.222161487f, -0.243477136f, -0.176720932f, -0.43629396f, -0.0268148426f, 0.216749102f, 0.107685685f, -0.0827160552f, + -0.0746958703f, -0.175383702f, 0.242751762f, 0.324123651f, -0.0721394494f, -0.294455588f, 0.169387564f, 0.298521578f, -0.529771209f, 0.00369853666f, + 0.375802249f, 0.1506311f, 0.00590370083f, 0.155055732f, 0.151486456f, -0.0126873245f, -0.0475360677f, 0.055044584f, -0.0898012146f, 0.027878603f, + -0.102169812f, 0.053728316f, 0.122385934f, -0.0781828016f, 0.110084713f, 0.379961103f, -0.0229181573f, 0.0554759204f, -0.0471065566f, -0.00448191492f, + -0.299413651f, -0.556947291f, -0.220020622f, -0.558503807f, -0.0287315976f, -0.308138341f, -0.806987345f, -0.85225445f, 0.608342469f, -0.0949634984f, + -0.104176991f, -0.0688760951f, 0.0190602317f, -0.0332671143f, -0.0562436171f, -0.0428743474f, 0.129982173f, 0.129499167f, -0.0620822161f, -0.164324835f, + -0.208085462f, -0.217797443f, 0.287445873f, -0.13682656f, -0.334911525f, -0.0911272019f, -0.178696081f, 0.181210086f, -0.11794851f, 0.241897061f, + 0.230578184f, 0.474731594f, 0.465830594f, 0.622141004f, 0.261998355f, -0.242484972f, -0.0864606127f, 0.0368301421f, 0.434261233f, 0.141610146f, + 0.25331521f, 0.0125997951f, 0.14599444f, 0.143122017f, -0.155232057f, 0.235455588f, 0.29072234f, -0.00263161189f, 0.251648426f, 0.421231151f, + 0.0474896543f, 0.0353574343f, -0.0973450094f, -0.000301002641f, -0.107139155f, 0.07521981f, 0.0728331283f, -0.213180274f, -0.264824927f, -0.106911615f, + -0.0433838516f, -0.231605664f, -0.0704703331f, 0.288181037f, 0.231855959f, -0.17267926f, 0.0149111338f, -0.108129777f, 0.418981582f, -0.0657367408f, + -0.051758863f, -0.00325464015f, -0.318429679f, -0.0233584233f, 0.830916464f, -0.482721627f, 0.722838223f, -0.32316196f, 0.216497689f, -0.111535795f, + 0.323644817f, 0.0915159509f, 0.00796524994f, -0.134786084f, 0.0345063247f, -0.221980661f, -0.0116723431f, -0.0532953329f, 0.0307278782f, 0.0147800241f, + 0.0837722793f, -0.14202702f, 0.64136821f, 0.036574766f, -0.117970921f, 0.0775357634f, 0.0475843213f, 0.0599373579f, -0.671457887f, -0.110289223f, + 0.461263269f, -0.0239972379f, -0.273848712f, -0.00408939924f, -0.529689312f, -0.018837953f, -0.0256888848f, -0.0210542269f, 0.0404606499f, 0.116371125f, + -0.172098666f, 0.0287395194f, 0.0246033072f, 0.00624043075f, 0.0172134507f, -0.0914190859f, -0.424561113f, -0.0187496077f, 0.0118457386f, 0.0102039268f, + -0.0799398422f, 0.181759998f, -0.575882971f, -0.0496134497f, 0.202701569f, -0.298992306f, -0.00804474019f, -0.0756809339f, -0.0538814664f, -0.161376894f, + -0.212158844f, 0.477746069f, 0.339287519f, -0.0960593522f, 0.104237556f, 0.254599661f, 0.0434258431f, 0.216066375f, -0.0257774238f, -0.0191849843f, + 0.134552598f, 0.034758538f, 0.124273278f, -0.0682435334f, -0.117607355f, -0.99569732f, 0.0504561253f, 0.106355026f, 0.156917647f, -0.525193334f, + 0.364482284f, 0.14899224f, -0.998404682f, -0.951191306f, 0.4284679f, -0.462533653f, 0.0293029305f, -0.0576484948f, 0.0371853448f, 0.143127903f, + 0.409072638f, -0.209444806f, -0.190269902f, -0.0259993784f, 0.0938965157f, -0.188483953f, 0.304909855f, 0.18390505f, 0.23676081f, -0.0912920907f, + 0.140244842f, 0.320245951f, -0.166675404f, 0.575362861f, 0.0151233412f, 0.192994758f, -0.0878670439f, 0.169445515f, 0.317277044f, -0.104794703f, + -0.327183813f, -0.160263225f, -0.301192582f, -0.201202452f, 0.103482351f, 0.0795877501f, 0.303185701f, -0.272718728f, 0.061443653f, -0.156132177f, + 0.33042112f, 0.607005417f, 0.0393402949f, 0.413213283f, -0.216914549f, -0.131822273f, -0.154444903f, -0.144087061f, -0.193493918f, -0.115900263f, + 0.193399116f, 0.0458172783f, 0.0161531158f, -0.0392448604f, 0.113807559f, 0.0939235017f, 0.116852157f, -0.0100247301f, 0.0100877499f, -0.0233913641f, + -0.213070244f, -0.190195486f, 0.0397416577f, -0.0924764201f, -0.0177386273f, -0.0469460823f, 0.768924475f, -0.209402591f, 0.345530301f, 0.845378458f, + 0.1924676f, -0.226778314f, -0.169291228f, -0.590278685f, 0.176980317f, 0.65129143f, 0.328980774f, 0.445320189f, 0.0f, 0.0f, + 0.0f, 0.0554855019f, 0.231676772f, -0.0792058557f, 0.0704088435f, 0.0745566487f, 0.145218417f, -0.319762826f, 0.0460477807f, -0.0197073054f, + -0.224957511f, 0.222134456f, 0.15808095f, -0.0884941295f, -0.370438337f, -0.286724806f, -0.132549196f, 0.102616064f, -0.146992549f, -0.236554042f, + -0.12135496f, -0.0518724844f, 0.261937261f, 0.413920313f, 0.0708470568f, 0.196522713f, 0.1279957f, 0.214635536f, 0.0443284623f, -0.216243461f, + -0.106019944f, -0.249030679f, 0.101534098f, 0.139532179f, -0.215464413f, 0.0335864723f, 0.0369455479f, 0.157839999f, 0.181515157f, 0.118768133f, + -0.0950295404f, -0.0333429426f, 0.238060921f, -0.0112305852f, 0.0390542895f, 0.215479255f, -0.000749078987f, -0.211998075f, -0.0397130549f, -0.00809921883f, + 0.0199999996f}, + {0.234248534f, 0.911192834f, 0.484700352f, -0.303133696f, 0.216242179f, 0.116227165f, -0.114525281f, 0.150566876f, 0.107539557f, 0.0724476501f, + 0.00881489646f, 0.140795887f, -0.161740392f, -0.0252102632f, -0.0900982022f, 0.14139688f, 0.00839680899f, -0.0577645414f, -0.173532352f, -0.0482708439f, + 0.0274418015f, -0.0153406477f, 0.330574363f, 0.270194352f, -0.595967114f, -0.429575443f, -0.0406793542f, -0.0313477665f, 0.0918976441f, 0.102401316f, + 0.562692881f, -0.231290057f, -0.0843613669f, 0.554221153f, 0.196435541f, 0.210200623f, -0.0543350466f, -0.356619537f, 0.0422448739f, 0.0754822716f, + -0.10474769f, 0.00646011159f, 0.0178075209f, -0.288522691f, -0.256759763f, 0.0573844165f, 0.200930163f, 0.0626293421f, 0.180677295f, 0.139558613f, + -0.171312958f, -0.154855609f, 0.376414597f, 0.0758602545f, 0.254346341f, -0.322056681f, -0.0372654274f, -0.0293919295f, -0.00902204588f, 0.00244404632f, + 0.0120467963f, -0.617827177f, -0.399411649f, 0.000572948076f, 0.241467088f, -0.870505333f, -0.611543417f, 0.0731101781f, -0.150051355f, 0.151196465f, + 0.372481912f, -0.994136155f, 0.00416451041f, -0.0017122915f, 0.0097618252f, 0.00722131459f, 0.34020865f, -0.0251663104f, -0.163272321f, 0.228829041f, + 0.11334189f, 0.115332596f, -0.0763057694f, -0.326198131f, -0.00261003803f, -0.0622695275f, 0.232364565f, -0.0426481627f, -0.356959581f, -0.255082339f, + 0.227466568f, 0.205862656f, -0.0907954201f, -0.0999928787f, -0.150075436f, -0.0369740725f, -0.000310577569f, -0.241773263f, 0.208077177f, -0.193277016f, + -0.00613982277f, -0.679156482f, -0.243079662f, -0.185145408f, -0.150769591f, 0.0918687508f, -0.290229291f, 0.172005191f, -0.132037967f, -0.0557512976f, + 0.579873562f, 0.169645116f, 0.0625570267f, -0.193269044f, 0.570624769f, 0.29081881f, -0.398116261f, 0.116801098f, 0.189547032f, 0.334734827f, + 0.140400097f, 0.178758547f, -0.379550189f, 0.105371587f, -0.0633445606f, 0.229572266f, 0.447366834f, -0.086629726f, -0.837217271f, -0.0496092401f, + 0.0205746274f, 0.0238549169f, 0.348123908f, 1.39489329f, -0.639825463f, -0.589336395f, 0.541609704f, -0.90794462f, -0.375687629f, -0.128164381f, + 0.277554095f, -0.343826354f, 0.160364345f, 0.0264071599f, 0.0239268374f, 0.0150044374f, 0.0163990371f, -0.0982762426f, 0.0942257866f, 0.0258919764f, + -0.0476187952f, -0.0316787176f, -0.590516508f, 0.245271981f, -0.0478141941f, -0.0166819151f, 0.110114329f, -0.058921814f, -0.0500765592f, 0.089052096f, + 0.141706556f, -0.113826849f, 0.144918621f, 0.0274037626f, -0.418245792f, -0.0395324565f, 0.0104430439f, 0.214966133f, 0.0620273985f, 0.266770095f, + -0.908649743f, 0.191665709f, 0.288003474f, -0.0396452732f, -0.163645595f, 0.00832375698f, 0.0322760195f, 0.270889878f, 0.473884404f, -0.0419730805f, + -0.0971929654f, -0.0271132328f, -0.291879803f, -0.054562144f, -0.0756360218f, -0.0296818707f, -0.417705864f, 0.164431095f, -0.136544302f, -0.313692302f, + 0.0916964412f, 0.23986575f, 0.0513176806f, -0.00945556909f, -0.24384667f, 0.575651884f, 0.107309796f, -0.369707853f, -0.265816212f, -0.0612240583f, + -0.428299278f, -0.0149884745f, 0.0189408641f, -0.0876119733f, 0.00656539854f, -0.374325395f, 0.588088751f, 0.903503597f, -1.80110931f, 0.0714995563f, + -0.514030635f, 0.395535886f, 0.076130271f, 0.349331766f, -0.399444312f, 1.00570238f, 0.0274971593f, 0.0225499552f, 0.0165638234f, 0.293348491f, + -0.111067981f, 0.0395369232f, -0.0576325394f, -0.0286192093f, -0.480625391f, 0.434461206f, -0.105936088f, -0.0177006349f, 0.122886136f, -0.192999139f, + -0.123624168f, -0.244944304f, 0.120167688f, -0.249497339f, 0.0310679227f, -0.135049373f, -0.218129694f, 0.06278947f, -0.0530145802f, 0.167283982f, + -0.00593786454f, 0.0613985918f, -0.091788277f, -0.0254422836f, -0.275096864f, 0.161683068f, -0.203991294f, -0.0675505698f, 0.17744714f, 0.127693057f, + -0.102839753f, -0.517478108f, 0.160518855f, 0.144654542f, -0.302553624f, 0.0348640643f, -0.0226230193f, -0.0473109111f, 0.00878391415f, 0.0894987434f, + -0.499780446f, 0.0249180607f, 0.531222045f, 0.010935029f, -0.26001671f, 0.247815251f, 0.0564923808f, 0.239668876f, 0.0750487149f, 0.157675683f, + 0.0674181804f, -0.167126641f, -0.156669378f, -0.00859133899f, -0.0608078204f, 0.00726591097f, -0.29807961f, -0.406855464f, -0.0354975015f, 0.248507589f, + -0.0759748593f, -0.491163522f, 0.271170944f, -0.887160361f, -0.232986212f, 0.0545336641f, -0.839826703f, 0.0792048052f, 0.0203500725f, 0.0229370687f, + -0.0136477686f, -0.02523252f, 0.0447694473f, -0.0203361195f, -0.00483712088f, 0.0751231536f, -1.23805702f, 0.250821054f, -0.0364581421f, 0.0473344028f, + 0.284451663f, 0.295893252f, 0.057347279f, 0.0349743143f, 0.199844301f, 0.0765479729f, 0.1149197f, 0.337564528f, -0.440763026f, -0.00247218646f, + -0.118016176f, 0.0184101537f, -0.0511948206f, -0.0468886197f, -0.552866101f, -0.0122854346f, 0.0728469715f, 0.227191404f, 0.110858023f, 0.29415223f, + 0.130862862f, 0.0758329704f, 0.366090447f, 0.00626980839f, 0.00684820162f, 0.177697256f, -0.19460018f, -0.117025822f, -0.0325395539f, -0.0100846086f, + 0.235507518f, -0.139410138f, 0.197113693f, 0.0771016181f, -0.106651716f, 0.321187794f, -0.192748129f, -0.420318097f, -0.0685854182f, -0.0158278421f, + -0.336946219f, 0.0748925433f, -0.455698043f, 0.15867193f, 0.0361889862f, 0.0665487126f, 0.00935475156f, 0.023650296f, -0.260346889f, -0.317981035f, + -0.213962048f, -0.294776559f, -0.551484704f, -0.519810557f, -0.122100227f, -0.352140218f, 0.423223108f, 0.840355396f, 0.111424871f, -0.104119152f, + 0.0322421752f, 0.0349122323f, 0.0052936906f, -0.101415448f, 0.0620792992f, -0.108037144f, 0.150780678f, 0.33025533f, -0.763413191f, 0.251641929f, + -0.276976049f, -0.162447155f, -0.2018269f, -0.0381939337f, -0.161729783f, -0.0716636479f, 0.0232036412f, -0.227937222f, -0.158419132f, 0.107579097f, + 0.11411202f, -0.0403596647f, 0.137336001f, 0.210809901f, 0.0612752363f, -0.216680288f, 0.453673661f, -0.0119987987f, -0.0590414889f, -0.180810034f, + 0.178515747f, 0.296247631f, -0.128846854f, -0.144930497f, -0.0645969212f, 0.0888759196f, 0.221951261f, -0.147020757f, -0.0589977093f, 0.252058595f, + 0.334626019f, -0.213055566f, -0.0850356743f, 0.303502411f, -0.22857748f, -0.331690848f, 0.049280595f, 0.173405722f, -0.23257634f, 0.222769499f, + 0.149426535f, 0.138534203f, -0.0783393905f, -0.10728287f, -0.451772004f, -0.123503849f, -0.211425915f, -0.0942426249f, 0.125012159f, -0.0909431204f, + 0.375164151f, 0.200983688f, -0.224226162f, 0.497262031f, 0.258563221f, -0.243331656f, -0.00665515475f, 0.016198745f, -0.920848787f, -0.573228836f, + 0.0457560606f, -0.331664681f, 0.0286646299f, 0.0171101224f, -0.0176839363f, -0.0296598151f, -0.10585396f, -0.0515625253f, -0.0584744811f, 0.21691522f, + -0.834611595f, 0.0259070247f, 0.139066383f, -0.0409164615f, 0.131222963f, -0.35264796f, -0.387285113f, 0.0286251176f, -0.142287105f, -0.0689403117f, + -0.0307873525f, 0.288220882f, 0.317812383f, -0.0464223549f, 0.0893744901f, 0.0119102653f, 0.0809468701f, 0.0425633825f, 0.0634756088f, 0.0918523595f, + -0.151476711f, 0.0450429209f, -0.0606210157f, 0.0551497787f, 0.176600009f, -0.0829764307f, 0.102014452f, 0.025255641f, 0.0823794007f, 0.0533127859f, + -0.0209988505f, 0.0135694612f, -0.00258547207f, 0.21288164f, -0.0722369924f, 0.0563327335f, 0.588665366f, -0.130699605f, 0.180488333f, 0.377257109f, + 0.286598265f, 0.117374815f, -0.094039686f, -0.0759303868f, -0.0341220759f, 0.40020147f, -0.0810037106f, -0.0855940059f, -0.345117331f, 0.104429141f, + 0.0662414506f, 4.99042253e-05f, -0.108342864f, -0.232510343f, -0.117960244f, 0.243580207f, 0.743101537f, -0.145031542f, 0.710404992f, 1.07451129f, + -0.0155239264f, 0.882029116f, 0.698908031f, -0.241187081f, 0.0553031638f, 0.0244525447f, -0.0313150212f, 0.119314574f, 0.0764498338f, 0.0511030555f, + 0.0938267931f, 0.0903572813f, 0.0535790361f, -0.117435828f, 0.116246544f, -0.246994779f, 0.170217857f, 0.301320493f, 0.238465443f, 0.0758472607f, + 0.161510542f, -0.149908006f, -0.0698189214f, 0.179179475f, 0.360545635f, 0.0134403231f, 0.363357216f, -0.222693399f, 0.183072373f, 0.327414066f, + 0.16951105f, -0.179270938f, -0.228271827f, 0.0813614428f, 0.274965227f, 0.0552713983f, -0.0731647238f, -0.05913179f, 0.333298832f, -0.303908467f, + 0.166421622f, 0.0298643224f, -0.54604125f, 0.0209701601f, -0.401906759f, -0.0948508158f, -0.165134981f, 0.170375213f, -0.535556674f, 0.162088871f, + 0.0646929741f, -0.0526782013f, -0.407778621f, -0.219875962f, 0.336833417f, -0.041937761f, -0.122716375f, -0.0929660797f, 0.149067f, 0.117179558f, + 0.345229626f, 0.0881345123f, 0.135232866f, -0.137693375f, -0.640026987f, 0.387655675f, -0.0827051401f, -0.959381163f, 0.901922226f, 1.3388983f, + -0.537547231f, -0.0977329686f, 0.172074169f, -0.809822738f, -1.06196511f, -0.559436977f, -0.108005077f, 0.0542914756f, 0.0600032955f, -0.0878070518f, + -0.0565486103f, 0.199540973f, 0.0433826633f, -0.297257602f, 0.159224376f, 0.286063492f, 0.107225083f, 0.0698168501f, -0.0326075256f, 0.205342606f, + -0.260452181f, 0.107511356f, -0.125235692f, 0.239547715f, 0.206498638f, -0.192209229f, 0.0214219913f, 0.392150253f, -0.151580602f, 0.02606727f, + -0.171011746f, -0.379639447f, 0.684929252f, 0.382674187f, 0.199800521f, -0.0498873815f, 0.0337908305f, 0.192166016f, -0.258854747f, 0.0677534118f, + -0.0544323139f, -0.113020465f, -0.182251036f, 0.197218776f, -0.351110578f, 0.453808784f, 0.0852692351f, -0.351993293f, 0.109303772f, 0.458808601f, + 0.18069534f, 0.224032506f, 0.0591560043f, -0.361170918f, -0.333882958f, -0.219265789f, 0.0533674993f, 0.0939205959f, 0.244918555f, -0.053720355f, + 0.307331562f, 0.0158581883f, -0.104372881f, 0.0865093693f, 0.22002621f, -0.0351949818f, 0.395379215f, -0.352949411f, -1.243469f, -0.571585178f, + 0.0925301015f, -1.56386507f, -0.211178333f, -0.164421439f, -0.840084851f, -0.703093112f, -0.409805596f, -0.408213317f, -0.0486335047f, -0.0630115047f, + -0.00110500632f, 0.274822325f, 0.00925006904f, -0.335870326f, -0.0496715084f, 0.267429978f, 0.401216894f, -0.180003345f, 0.00654999772f, 0.645219684f, + 0.175191224f, 0.161678836f, 0.325873166f, -0.0912009776f, 0.514438868f, -0.310146958f, -0.110129267f, -0.502697587f, 0.00821399782f, 0.213003993f, + -0.050649073f, 0.123001091f, 0.149828389f, 0.0749129206f, 0.311535209f, 0.13371864f, -0.0622452237f, -0.1066387f, -0.24132219f, 0.0410033986f, + -0.0941602588f, 0.679213107f, 0.555810392f, 0.210371047f, -0.00239648623f, 0.524114788f, -0.163718134f, -0.100526728f, 0.105644196f, -0.216233119f, + -0.121279776f, -0.0482071862f, 0.214591101f, -0.00318382611f, 0.188779593f, 0.25173223f, 0.0830043256f, 0.277126163f, 0.0780391544f, -0.173736468f, + -0.0962984338f, -0.208667934f, -0.106646203f, 0.0961240903f, 0.0703125522f, 0.0246670321f, -0.0536845252f, 0.0449304879f, -0.0159012955f, -0.61253196f, + -0.213954777f, -0.338569283f, -0.440970242f, -0.547917485f, -0.365541905f, 0.5905599f, -0.991461456f, -0.0179841369f, -1.11582506f, 0.0329620242f, + -0.0448983759f, -0.120625898f, 0.0307154059f, -0.0729750469f, -0.362219602f, 0.0122751612f, 0.332294762f, 0.0332933664f, 0.203911364f, -0.0499791503f, + -0.401058257f, 0.125931367f, -0.0907004774f, -0.366560936f, 0.0460869707f, -0.0899252146f, -0.162411764f, 0.0779852271f, -0.186803535f, 0.244092435f, + -0.213311166f, 0.144255444f, -0.172218114f, 0.192080125f, -0.0646197125f, 0.121464618f, 0.333368182f, -0.0502492525f, 0.261298716f, -0.35185644f, + -0.07985726f, 0.170838997f, -0.338270247f, 0.0628645122f, -0.103816837f, 0.23453106f, -0.0170160756f, 0.117811926f, -0.906675577f, -0.139342993f, + -0.131407142f, -0.0670036152f, -0.691845238f, -0.406226307f, 0.00308602839f, 0.047422599f, -0.192957059f, -0.128783107f, -0.483984619f, 0.445206344f, + -0.112376064f, 0.342925489f, 0.342030019f, 0.0723571479f, -0.184265763f, -0.119693995f, -0.297680676f, 0.0183503367f, 0.0372279398f, 0.147225961f, + 0.190253034f, -0.00990058854f, 0.312348127f, 0.497369319f, 0.903701484f, -0.208657205f, 0.425181508f, -0.290227145f, -0.494329065f, -0.20858939f, + -0.437894911f, 0.266690701f, 0.171185568f, -0.0999460444f, 0.0290481225f, -0.000981876161f, 0.0348442979f, -0.0180426855f, 0.154975072f, 0.0571981221f, + -0.486619681f, -0.0295778215f, -0.151391566f, -0.131527305f, 0.072880581f, -0.245830074f, 0.189054117f, -0.0992508009f, 0.0318401419f, -0.173087835f, + 0.0494507439f, -0.00304481038f, 0.475952327f, -0.018252803f, -0.181505606f, -0.12660706f, -0.0575667582f, 0.0924373716f, 0.547552824f, 0.00629627332f, + -0.100971632f, -0.108721524f, -0.00592142902f, -0.223366052f, -0.154891223f, 0.0377459899f, -0.18864426f, -0.0385728478f, -0.144151002f, -0.173547328f, + -0.504365325f, -0.00906601828f, -0.0153613593f, 0.133737355f, -0.0626351461f, -0.292748213f, 0.301190376f, 0.165519893f, -0.256770432f, -0.35562849f, + -0.127436787f, -0.33309117f, -0.0685744807f, -0.350136369f, 0.0145682637f, -0.173716679f, -0.133725211f, 0.233874395f, -0.161272183f, 0.143976584f, + 0.0425661802f, 0.0738358945f, 0.261200935f, -0.00944945216f, -0.247758344f, -0.757126272f, 0.677890837f, 0.00470946636f, 0.894137621f, -0.624402046f, + -0.101441532f, 0.0772534981f, 0.739853919f, 0.725890815f, 0.146591201f, 0.0657138228f, 0.121147439f, -0.0169928335f, -0.294746935f, -0.542156339f, + 0.0387291871f, 0.183077261f, -0.237418249f, -0.165314645f, -0.52492696f, -0.345059454f, 0.0655953363f, -0.115109235f, -0.0839451775f, -0.177596912f, + 0.154053122f, 0.311217546f, -0.147850052f, 0.135917127f, -0.108866692f, -0.017196212f, 0.0516736954f, 0.154342607f, -0.209934995f, -0.185960695f, + -0.0537674353f, -0.016604865f, -0.00364654674f, 0.180115834f, -0.11671304f, -0.109155655f, 0.184480399f, -0.0265337788f, -0.0501641594f, 0.0716465935f, + 0.0178580135f, 0.109593861f, -0.145329833f, -0.205042511f, -0.00384459225f, 0.24147819f, -0.108440146f, -0.238169402f, 0.102527089f, -0.151083395f, + 0.103843905f, 0.139141485f, -0.102449164f, -0.142784253f, -0.120403469f, 0.213350818f, 0.107965834f, 0.207585752f, 0.230819985f, -0.162766457f, + -0.0532284304f, 0.11317271f, -0.0221948158f, 0.112153545f, -0.516326368f, -0.177253678f, 0.656238079f, 0.419154972f, 0.74641186f, -0.0817491263f, + 0.330461591f, -0.0649378076f, 0.641035676f, 0.729502618f, -0.273951918f, 1.94586372f, 0.127438292f, 0.0928479359f, 0.112503499f, -0.0201878268f, + -0.124626257f, 0.0148540484f, 0.171989515f, 0.0978345424f, -0.311718971f, 0.302445471f, -0.0462580435f, 0.326398343f, 0.198801726f, -0.136790946f, + -0.236505702f, -0.271869093f, -0.0110064615f, -0.113473214f, 0.0979395583f, -0.193610579f, 0.0388378389f, 0.238674477f, 0.0764485523f, 0.189368397f, + -0.092203863f, -0.0332577303f, 0.0921324864f, 0.20475243f, -0.0167361666f, 0.151811555f, -0.124956958f, 0.092775315f, -0.0992988199f, -0.109477587f, + -0.093559362f, -0.0774927214f, 0.281453788f, -0.0030409731f, -0.155385435f, -0.367227793f, 0.0514618345f, -0.0908149108f, -0.277343065f, 0.00822825264f, + -0.222699419f, 0.0172384959f, 0.322293013f, -0.531459272f, -0.0903167203f, -0.484973848f, -0.170585126f, 0.0679721758f, -0.397447616f, 0.268012017f, + -0.203212604f, -0.413593143f, -0.133335531f, -0.0755623356f, 0.0235559233f, -0.080600135f, 0.168413877f, -0.381692559f, 0.0611598082f, -0.710753918f, + 0.409562677f, 0.0887147337f, -0.209577322f, 0.496216476f, -0.66073519f, -0.349438608f, 1.05090928f, -0.104766689f, 0.130507648f, 0.139093906f, + 0.0857878476f, 0.11996904f, -0.0477305651f, -0.161402702f, -0.092077665f, -0.0524717532f, -0.109083623f, -0.1534563f, -0.157771811f, -0.264128923f, + -0.0298960544f, -0.000280179142f, 0.0485408083f, -0.350799769f, 0.0298420824f, -0.0930748358f, -0.232730061f, -0.00804003794f, 0.0904112235f, 0.0462866873f, + 0.0820878968f, 0.109512053f, 0.0988271534f, -0.0313715786f, -0.333833009f, -0.135124117f, 0.0287826136f, -0.10183832f, 0.0718695819f, 0.0878495499f, + -0.0246699546f, 0.268827707f, -0.158348441f, 0.127388045f, -0.0810353979f, -0.125489205f, 0.0820922852f, -0.0956434458f, 0.124607176f, -0.176931381f, + 0.00231827423f, -0.131877258f, -0.0421030223f, -0.0625379682f, -0.175468996f, 0.0920634791f, -0.383038789f, -0.452488184f, -0.179345354f, -0.188424736f, + -0.296635121f, -0.159249753f, 0.229970425f, -0.460108638f, -0.302694678f, -0.324994802f, -0.127644628f, -0.290798157f, -0.0999008045f, 0.0794139579f, + -0.057588134f, 0.0193237327f, 0.0468107983f, 0.521348178f, 0.34984228f, 0.318660766f, 0.0490604118f, 0.0341029763f, 0.175058737f, 0.151392177f, + -0.185181409f, 0.158940941f, 0.0957559049f, 0.127064317f, -0.035743624f, 0.0208975561f, 0.0319743007f, 0.0974104702f, -0.399452984f, -0.179544151f, + 0.220199555f, -0.144694835f, 0.0316217579f, 0.102989919f, -0.141968995f, 0.034640152f, -0.389372706f, -0.491541475f, -0.335028142f, -0.302863002f, + -0.040221706f, -0.0544692725f, 0.0517141335f, -0.147534087f, 0.385123461f, -0.00945261773f, -0.00816831738f, 0.0615248047f, -0.0410457104f, -0.0953706577f, + 0.0101982206f, 0.131322771f, 0.0866089687f, 0.115487225f, -0.117746532f, -0.142787442f, 0.268701315f, -0.0756369457f, 0.0313649997f, 0.0816943273f, + 0.196301654f, -0.19891943f, -0.0579624437f, -0.0653084517f, -0.0640046895f, -0.385578305f, -0.0364301354f, -0.441193312f, 0.0661543012f, 0.102402993f, + 0.093433708f, -0.179350778f, 0.150381595f, -0.120859392f, -0.179742247f, -0.143724039f, -0.135776654f, 0.0085077174f, 0.104594395f, -0.330915958f, + -0.0947989523f, 0.128670782f, 0.0153397415f, 0.0443683192f, -0.281367958f, 0.0749852359f, -0.0229035839f, -0.0241289586f, -0.0524025634f, -0.791772306f, + 0.0169556234f, 0.626660645f, 1.08423758f, 0.331824601f, 0.492676228f, -0.411050886f, -0.455170542f, 0.724133551f, -0.052645646f, 0.0554708503f, + -0.749974728f, 0.118068554f, 0.120772108f, 0.0734371692f, 0.109967552f, 0.155851424f, -0.00892779231f, 0.100249998f, 0.274246365f, 0.0889373422f, + 0.0620183051f, 0.085378848f, 0.106490083f, 0.159949154f, 0.238446295f, 0.0300611202f, 0.197615996f, -0.0715096295f, -0.396444112f, 0.0992024764f, + -0.0191558693f, -0.102864966f, -0.0934342816f, 0.120706938f, -0.147792757f, 0.0329418294f, -0.0611278303f, -0.0823768601f, 0.0844594911f, 0.0614422597f, + -0.0388904549f, 0.0949542448f, -0.0234459992f, 0.126435935f, 0.257986426f, -0.0840976536f, 0.191898912f, -0.10286697f, -0.0244365148f, 0.0256584957f, + 0.236993f, 0.0594559535f, -0.139684752f, 0.0856477693f, -0.136823341f, -0.202119604f, -0.0530506298f, -0.0730321705f, 0.0813591555f, 0.0390553437f, + 0.141109914f, 0.141381115f, 0.0543014444f, -0.00365269114f, -0.0969572887f, 0.131810203f, 0.0394029915f, 0.117381029f, -0.00576428184f, 0.0259765275f, + -0.0825189203f, 0.0410789624f, 0.173967704f, 0.0261660013f, 0.0324276425f, -0.00348798046f, 0.140181199f, -0.102009773f, -0.310588747f, -0.00444843993f, + -0.0673568025f, -0.209989965f, 0.011145629f, -0.0684110075f, 0.0526152998f, -0.188878313f, -0.0336487517f, -0.11424759f, 0.06471093f, -0.0836527795f, + 0.0187304411f, 0.0914230868f, -0.207184985f, -0.176772445f, 0.389046133f, -0.19844535f, 0.148103386f, -0.0365237445f, -0.0614530966f, -0.281474233f, + -0.117255665f, 0.0558809973f, -0.285170168f, -0.0261599515f, -0.0140179023f, 0.245543599f, -0.117880888f, 0.176547289f, 0.0925693437f, -0.0204213131f, + -0.314656228f, 0.270345896f, -0.174539611f, -0.031684421f, 0.143665731f, 0.219622791f, -0.130005255f, 0.193515942f, -0.040058922f, 0.103535652f, + 0.306200087f, -0.292457998f, 0.100901604f, -0.421919733f, -0.0722553208f, -0.0874592513f, 0.204824388f, -0.052608639f, -0.177313656f, -0.0780396909f, + -0.152859658f, 0.0182742905f, -0.174690202f, 0.101687744f, 0.167109877f, 0.0544641167f, -0.218625143f, -0.245750636f, -0.096823141f, 0.143680677f, + -0.0112884203f, -0.0730397329f, 0.054447744f, -0.216159418f, -0.17598705f, 0.0511262491f, -0.111250401f, -0.126975223f, -0.0195037853f, 0.0374883004f, + 0.020524621f, -0.0351442285f, -0.711327851f, -0.20534496f, -0.180686072f, 0.352186084f, -0.00113470014f, -0.637716949f, 0.00620863866f, 0.312839806f, + 1.06007004f, -0.566058278f, 0.16969046f, -0.170213878f, 0.123271994f, 0.113078594f, 0.0748731643f, -0.032725025f, -0.126711279f, 0.432528079f, + 0.0592544749f, -0.15713951f, -0.207090586f, 0.6165241f, 0.466933906f, 0.490922272f, 0.513312876f, -0.184050933f, 0.206396133f, -0.243611664f, + -0.40441978f, 0.202849641f, 0.17846325f, -0.180181295f, 0.398895115f, -0.111867942f, -0.215983152f, 0.154507801f, 0.0564330034f, 0.200697258f, + 0.156725332f, 0.0953524858f, -0.0408544466f, -0.0230308026f, -0.411451399f, -0.605124652f, -0.15433073f, -0.0222569741f, 0.126182273f, 0.24933359f, + -0.0291378014f, 0.213176459f, 0.586679995f, -0.109723262f, 0.217794701f, 0.304381698f, 0.0958753005f, -0.236995161f, -0.234723255f, -0.102284871f, + 0.101105765f, -0.224439874f, -0.296219945f, 0.162378356f, -0.426262558f, 0.142481908f, -0.0783737004f, -0.0514954664f, -0.0413723476f, -0.137810528f, + 0.490999639f, 0.236733884f, 0.172409341f, 0.0497162044f, -0.707873762f, 0.308490485f, 0.54986918f, 0.375657767f, -0.154533774f, 0.898869991f, + -0.572665393f, -0.80987072f, 0.252574801f, -0.453189462f, -1.47676671f, 0.386817187f, 0.177526936f, 0.114778973f, -0.182977214f, 0.246477529f, + 0.201698408f, -0.0927212909f, 0.0617362037f, -0.226651192f, 0.377342433f, 0.036778152f, 0.195606157f, -0.389243454f, 0.0737171546f, 0.377108097f, + 0.0706928074f, -0.0357098728f, -0.171858519f, 0.0865065679f, -0.065893434f, 0.209565416f, -0.183429584f, -0.0974699408f, 0.366063744f, -0.304482996f, + -0.0436139256f, -0.183300719f, 0.194351748f, 0.25375846f, 0.294353932f, 0.226650998f, -0.203737244f, 0.542250872f, 0.198559001f, -0.141109228f, + -0.0721873939f, -0.0891127661f, 0.12840502f, 0.103592038f, -0.0029487086f, -0.395906031f, 0.159296811f, 0.229139537f, 0.20763211f, 0.148669586f, + 0.358356297f, 0.26118961f, -0.0478501618f, 0.310700834f, -0.303476095f, -0.358811796f, -0.300307751f, -0.357105076f, -0.0475402847f, 0.17251043f, + 0.343266577f, 0.0647772104f, 0.47833553f, 0.251400143f, -0.121866576f, 0.109659828f, 0.167119563f, -0.0722069293f, 0.341457397f, -0.359260917f, + 0.412575573f, -0.51758045f, 0.465750813f, -0.246308178f, 0.454019487f, -0.766867459f, -0.231384024f, -0.217317328f, 0.00326577108f, 0.0655076131f, + -0.289815724f, 0.190468013f, -0.267111808f, 0.35739404f, 0.0586594604f, -0.149312675f, 0.167275652f, 0.0227929186f, 0.27405113f, 0.508001983f, + 0.141128957f, -0.173520446f, -0.0935415626f, 0.101709351f, 0.0485275276f, -0.161779612f, -0.095738396f, 0.195691198f, 0.549308896f, -0.332540542f, + -0.0717763007f, -0.341071814f, 0.00503970264f, -0.198596001f, -0.0712912753f, -0.230482787f, -0.330287486f, -0.494768083f, -0.0498025008f, -0.240162179f, + -0.629106402f, 0.0476796143f, 0.0514516011f, 0.204898432f, 0.0189899486f, -0.0121757295f, -0.678012013f, 0.226606205f, -0.218768761f, -0.549034834f, + -0.341888815f, -0.284144282f, 0.0462290309f, -0.156008884f, -0.330352277f, 0.0156802181f, 0.478996038f, -0.0548202246f, 0.185756758f, 0.246514618f, + 0.741518617f, -0.225156501f, 0.366084993f, -0.132953048f, -0.00216025347f, 0.129029691f, 0.171052575f, -0.0451996438f, -0.672472894f, 1.35901713f, + -0.352148175f, -1.03246725f, 0.633149266f, -0.408994406f, -0.0755352601f, 0.092138499f, 0.0262702666f, -0.173333526f, 0.264824808f, 0.330361784f, + -0.0334757492f, 0.0643724054f, -0.2305931f, 0.133965701f, 0.0898760632f, -0.00796265341f, -0.208580837f, -0.1643617f, -0.265696764f, 0.259107888f, + 0.101855524f, 0.383070886f, 0.0283283275f, 0.143831953f, -0.166240945f, -0.250365883f, -0.199262634f, -0.358998984f, -0.0094084898f, -0.30807361f, + -0.227132723f, -0.501592696f, -0.263729841f, -0.296243191f, -0.0704164878f, -0.316405803f, -0.141764209f, 0.209710702f, 0.160190746f, -0.0602356493f, + -0.0113438834f, -0.186177701f, 0.364985228f, 0.364256769f, -0.0503607653f, -0.262165874f, 0.117755413f, 0.233764455f, -0.546935201f, -0.114999264f, + 0.176906601f, 0.0511806384f, 0.0557424575f, 0.13560228f, 0.441732615f, -0.172432542f, -0.0635215342f, 0.0516430624f, -0.144591898f, -0.0917834789f, + -0.747743666f, 0.0682083815f, 0.273712963f, 0.00909671187f, 0.218724892f, 0.27393952f, -0.212116286f, 0.257085472f, -0.0422064178f, 0.0616372563f, + -1.00574684f, -0.402993709f, -0.385105878f, -0.512408197f, -0.251141578f, -0.403146178f, -0.76530844f, -0.961333811f, 0.614862919f, 0.169522449f, + 0.0182289854f, 0.130650446f, -0.00538986083f, -0.194933295f, -0.0221928302f, -0.00171492365f, -0.0558825471f, 0.152140692f, -0.237195745f, -0.299977183f, + -0.306492388f, -0.0399423428f, 0.226973891f, -0.0744509399f, -0.286910474f, -0.160723567f, -0.19085066f, 0.122653008f, -0.12037386f, 0.151346982f, + 0.127063975f, 0.252424389f, 0.220249772f, 0.492052644f, 0.15297766f, -0.245509937f, -0.0512895361f, -0.0335331857f, 0.177554145f, 0.0778531879f, + 0.208040521f, -0.0294078272f, 0.197537914f, 0.230898708f, -0.0757832751f, 0.405196488f, 0.333760381f, 0.0790872499f, 0.348074496f, 0.574020743f, + 0.197266325f, -0.0116660222f, 0.00973233487f, -0.111761197f, 0.136024117f, -0.00737755327f, 0.0426210091f, -0.270049781f, -0.367529392f, -0.278250396f, + -0.0559668541f, -0.279034138f, -0.131831199f, 0.199861556f, 0.17064932f, -0.21532014f, -0.0160151143f, -0.185206965f, 0.356312156f, -0.0820886195f, + -0.113621488f, 0.168191493f, -0.662819684f, 0.0830749795f, 0.902415395f, -0.418562233f, 0.640123725f, -0.399000645f, 0.316655129f, -0.0980897993f, + -0.166447088f, 0.0217426009f, 0.0648108944f, -0.386173874f, 0.0104654599f, -0.0370211937f, -0.0598594211f, -0.0137214167f, 0.0165634882f, 0.140415892f, + 0.0240672044f, -0.11117851f, 0.400968432f, 0.0764445588f, -0.153121322f, -0.153123394f, 0.069066532f, 0.311856002f, -0.121855557f, -0.0266337637f, + 0.281654298f, -0.0719599426f, -0.143221721f, 0.0491686054f, -0.563222587f, 0.110234983f, -0.0694721565f, -0.341529697f, -0.0523422062f, 0.267559379f, + -0.102277309f, 0.181227311f, 0.199730664f, -0.134665042f, -0.336006612f, -0.133771732f, 0.193734407f, 0.0818445161f, 0.0934381261f, 0.0627355501f, + 0.3182697f, 0.26390174f, -0.19556582f, 0.0999682546f, 0.149131745f, -0.124562085f, -0.178363055f, -0.130591601f, 0.0823904574f, -0.259668589f, + -0.281433403f, 0.338986605f, 0.123179764f, -0.32319513f, 0.0286879223f, 0.0715496019f, -0.240392387f, 0.0559545755f, -0.126205251f, -0.1008614f, + 0.0561082847f, 0.0988785103f, -0.1853939f, 0.102075808f, 0.448273301f, -0.543776572f, -0.0817770287f, 0.0272221807f, 0.270996124f, -0.534372687f, + 0.216983721f, 0.152733475f, -1.08607447f, -0.966860533f, 0.220692188f, -0.423710227f, 0.0011839564f, -0.0744801685f, 0.00515900319f, 0.245178536f, + 0.283094436f, -0.171795949f, -0.204194248f, 0.158964396f, 0.0675036088f, -0.176815972f, 0.348264039f, 0.209298283f, 0.140862703f, -0.0275755674f, + 0.199205875f, 0.320711017f, -0.113712274f, 0.569916725f, -0.0127548976f, 0.192367628f, 0.00481467228f, 0.210641772f, 0.294443071f, -0.0950466096f, + -0.341700554f, -0.0248816926f, -0.296370059f, -0.104637481f, -0.0073854751f, 0.0923790336f, 0.317710429f, -0.174750581f, 0.122283302f, -0.0457957909f, + 0.334652454f, 0.65205729f, 0.186546862f, 0.37669307f, -0.110605709f, -0.117381439f, -0.11685577f, -0.116907783f, -0.210647702f, -0.0829195753f, + 0.575251997f, 0.0973852649f, 0.0597374365f, 0.0701462328f, -0.0459553227f, 0.171208277f, 0.136145771f, -0.049736049f, -0.0137568489f, -0.0284880623f, + -0.192027286f, -0.0860930234f, -0.146909267f, -0.151160046f, -0.0529989414f, -0.0219770484f, 0.725235701f, -0.0177678373f, 0.540882528f, 0.845378458f, + 0.1924676f, -0.226778314f, -0.169291228f, -0.590278685f, 0.176980317f, 0.65129143f, 0.328980774f, 0.445320189f, 0.0f, 0.0f, + 0.0f, -0.0160176829f, 0.154332235f, -0.10039971f, 0.0339571312f, 0.0480068028f, 0.125608578f, -0.268998742f, -0.0183741823f, -0.0664657205f, + -0.256169379f, 0.0469518006f, 0.0264029503f, -0.090033181f, -0.357052982f, -0.350407422f, -0.160541415f, 0.0162928011f, -0.0176916011f, -0.13104935f, + -0.193234906f, -0.137380049f, 0.0638293251f, 0.0880937576f, -0.180213749f, 0.0260707755f, 0.385296762f, 0.579923689f, 0.165090069f, -0.167601824f, + -0.0955990851f, -0.185705036f, 0.0669812411f, 0.144609809f, -0.129408881f, 0.0152920866f, -0.00838001259f, 0.144106075f, 0.0638380796f, -0.0678833574f, + -0.0759177357f, -0.0530318022f, 0.388186932f, 0.104784705f, -0.0389357433f, 0.252484649f, 0.131643593f, -0.00679071154f, 0.0129467603f, -0.0519438423f, + 0.0199999996f}, + {0.368327379f, 0.9880867f, 0.178414613f, -0.236041665f, 0.262483716f, 0.134494185f, -0.0942873955f, 0.197254568f, 0.177540511f, 0.14416264f, + 0.0592783913f, 0.161467046f, -0.137763411f, 0.0261055026f, -0.017240582f, 0.206610247f, 0.0567502193f, -0.0379817747f, -0.151353806f, -0.00542165199f, + 0.0812917426f, 0.235411108f, 0.529346585f, 0.34905991f, -0.621400893f, -0.501136541f, -0.134034082f, 0.207244232f, 0.279728919f, 0.166206807f, + 0.517862439f, -0.318857193f, -0.184085891f, 0.73285675f, 0.336889327f, 0.244351968f, -0.11445085f, -0.445268482f, -0.048268564f, 0.0447905622f, + -0.280374527f, -0.158823773f, -0.0097874701f, -0.200144231f, 0.0224835053f, 0.0398679636f, 0.0154065909f, -0.119191878f, 0.145202324f, 0.230931714f, + 0.120065145f, -0.16352658f, 0.193410471f, -0.103158511f, 0.225960031f, -0.222147137f, 0.264043629f, -0.0462143905f, 0.0564969033f, -0.0415055975f, + 0.0822728425f, -0.713620543f, -0.11034894f, -0.0395194069f, -0.0437473394f, -0.519254565f, -0.529355109f, -0.185862869f, -0.487174481f, 0.112900957f, + 0.731399119f, -0.838349283f, 0.0039163949f, -0.00825746078f, 0.0130010778f, 0.0593062676f, 0.271447182f, -0.0799869299f, -0.201133788f, 0.170103371f, + 0.101758778f, 0.243943527f, -0.0668112263f, -0.317523748f, 0.0103858206f, -0.100590385f, 0.215265557f, 0.0987065956f, -0.334003806f, -0.267769396f, + 0.190149382f, 0.268586814f, 0.0365919247f, -0.125651166f, 0.0218418706f, 0.00462626899f, 0.0746877789f, -0.0399234742f, -0.126889393f, -0.10838753f, + 0.236197829f, -0.592860699f, -0.129201576f, -0.00602871459f, -0.318414092f, -0.0221237149f, -0.203867495f, 0.237150237f, 0.0260150041f, 0.0819924697f, + 0.10820502f, 0.162934661f, -0.123017833f, -0.26607725f, 0.511946559f, 0.0842031315f, -0.0448775962f, 0.0809403956f, 0.00680972449f, 0.25580439f, + 0.0690716058f, 0.0739150196f, -0.0915001035f, 0.0786973462f, -0.269717544f, 0.14188692f, 0.346150368f, -0.384567499f, -0.604123652f, -0.0576423295f, + 0.00698767276f, -0.043368835f, 0.375216126f, 1.22426057f, -0.428382128f, -0.667636096f, 0.281174719f, -0.421410352f, -0.498078406f, 0.0872464478f, + 0.314042389f, -0.0900528133f, -0.152169719f, -0.0737860501f, 0.0257787444f, 0.00357445469f, 0.00127552345f, -0.257084697f, -0.112131558f, -0.239610493f, + -0.00682822522f, -0.237947747f, -0.229902148f, 0.339271754f, -0.0199089032f, -0.0267123058f, 0.121429794f, -0.0570521019f, -0.0101464f, 0.0954722092f, + 0.0554833487f, -0.199225992f, 0.261060357f, -0.0769869387f, -0.104982346f, -0.218351915f, -0.0950553417f, 0.400564522f, -0.236970007f, 0.0826931894f, + -0.516644776f, 0.0132359881f, 0.242724508f, 0.00743439374f, -0.0812280923f, 0.096281819f, 0.126271486f, 0.0325334519f, 0.400548846f, 0.000770595274f, + -0.176333338f, -0.00528678484f, 0.0877635702f, 0.0971752852f, -0.0381816402f, 0.00136859051f, -0.396859586f, 0.142441913f, -0.121855147f, -0.13466835f, + 0.14262253f, 0.218349069f, 0.0250174291f, -0.0785623267f, -0.293450117f, 0.307400703f, 0.1410705f, -0.218931273f, -0.13864404f, -0.0640452281f, + -0.341417462f, -0.0520877615f, -0.0280411579f, 0.0234156325f, 0.0641203001f, -0.230791062f, 0.571573734f, 0.693894923f, -1.3250277f, 0.0542852841f, + -0.799231946f, 0.735099912f, 0.0237011556f, 0.296848923f, -0.625563681f, 0.7139768f, 0.0152378324f, 0.016163202f, 0.0285971723f, 0.374637932f, + -0.202535436f, 0.087864399f, -0.189918801f, -0.085045889f, -0.339421242f, 0.0994603857f, -0.159277201f, -0.0994504467f, 0.0684186742f, -0.233098507f, + -0.0331806578f, -0.195637599f, -0.12984547f, -0.316313803f, -0.220261693f, 0.0204859562f, -0.126949698f, 0.109745331f, -0.0536017269f, 0.144602388f, + -0.0999201983f, -0.0449250937f, -0.126496285f, 0.341508001f, -0.0567232445f, 0.20272015f, -0.174061686f, -0.0941411257f, 0.171414196f, 0.0346972831f, + -0.0902840495f, -0.438485056f, 0.0542324521f, -0.0522369631f, -0.321899861f, 0.206961513f, -0.232207596f, -0.264306247f, 0.0812412947f, -0.113322802f, + 0.19634594f, -0.371796161f, 0.353351355f, -0.159447089f, -0.353456199f, -0.120605409f, 0.253800273f, -0.0691738874f, -0.113242418f, 0.0221645217f, + -0.0241809636f, -0.197164804f, 0.0575766452f, -0.0295673031f, -0.0903545395f, -0.0538804717f, -0.218836486f, -0.348790258f, 0.228383377f, 0.170849204f, + -0.0773607716f, -0.351616859f, 0.177213058f, -1.00219226f, -0.509464443f, 0.130462959f, -0.61488378f, -0.118480481f, 0.00492462609f, -0.00882314611f, + -0.0162314437f, -0.214703545f, 0.167078093f, -0.159272298f, -0.133379713f, -0.0695591271f, -0.664946258f, 0.384394675f, -0.0831031501f, 0.125593677f, + 0.30098787f, -0.022835698f, -0.566697121f, -0.0511274822f, -0.038418781f, 0.0523652397f, -0.168318182f, 0.0491415039f, -0.310497642f, 0.00578078255f, + 0.0325112902f, -0.116297312f, -0.228138298f, -0.0435350351f, -0.0850034058f, -0.00844380818f, -0.0279694088f, 0.148757473f, 0.100610144f, 0.119190089f, + -0.207320541f, 0.0112804249f, 0.128138721f, 0.0579948947f, -0.166047364f, -0.0934813321f, -0.00675002858f, -0.181601912f, 0.0674061775f, -0.117936626f, + 0.288527578f, 0.0391384065f, 0.104907922f, 0.127431318f, -0.0454369597f, 0.119344622f, -0.228044257f, -0.274749041f, -0.139711633f, -0.117145881f, + -0.255805016f, -0.00216637016f, -0.378988296f, 0.234999076f, -0.0256404951f, -0.109074257f, -0.00508923223f, -0.0150742019f, -0.406093717f, -0.478587061f, + -0.208704561f, 0.0112130204f, -0.360920638f, -0.30854398f, 0.0817961618f, -0.240614563f, 0.483964831f, 0.641534448f, 0.0587371103f, 0.273584157f, + -0.0115261516f, -0.00342502748f, -0.0225086585f, -0.229511976f, 0.0934993997f, -0.173467651f, -0.0612903237f, 0.175217643f, -0.623676598f, 0.062138848f, + -0.232221171f, -0.200221345f, -0.608302534f, -0.354061216f, -0.0332605802f, 0.0409762263f, 0.0267216936f, -0.119709812f, -0.159387603f, 0.197666734f, + -0.0806412399f, -0.317427307f, 0.109557681f, 0.0462670512f, 0.142292559f, -0.0834772214f, 0.115370899f, -0.0936913639f, 0.0338081941f, -0.13587597f, + 0.114982888f, 0.263234913f, -0.276588172f, -0.168476f, -0.0120969005f, 0.119028732f, 0.118960157f, -0.328524739f, 0.0055616023f, 0.154860243f, + 0.241500601f, -0.154403076f, -0.081851162f, 0.225199685f, -0.327937156f, -0.112568915f, -0.159702852f, 0.068472594f, 0.00395634724f, 0.178630888f, + -0.0860753283f, 0.0161398631f, 0.038435448f, -0.0232885014f, 0.0236883275f, 0.259498298f, 0.276770443f, 0.124227755f, -0.111727394f, 0.0401482359f, + 0.305809587f, 0.132076114f, -0.583723426f, 0.361437291f, 0.282878876f, -0.105208561f, -0.202136576f, -0.0179360453f, -0.587365091f, 0.0098189814f, + 0.171896189f, -0.288112551f, 0.00962291099f, 0.0363961384f, -0.00762797892f, 0.0276595093f, -0.250354648f, -0.0752898008f, -0.117585972f, 0.34869945f, + -0.586968422f, -0.0464493893f, 0.108164199f, 0.0323728621f, 0.111516573f, -0.18098779f, -0.675796449f, 0.00621614279f, -0.0462031402f, 0.0322131887f, + -0.0118667213f, 0.0234912094f, 0.0234976299f, -0.222129434f, 0.141955271f, -0.00575686526f, -0.105435133f, 0.0220726822f, -0.0755469874f, 0.107524402f, + -0.10772644f, -0.0772242919f, 0.131132185f, -0.104744136f, 0.174787447f, -0.0324674062f, 0.168755636f, -0.0305394717f, 0.18196784f, 0.00755271409f, + -0.0528805368f, -0.068909727f, 0.100656688f, -0.0511358641f, -0.24774456f, -0.427153319f, -0.0934697688f, 0.0282960571f, 0.013321613f, 0.147542f, + 0.0580355749f, -0.233510077f, 0.0344927572f, 0.0752840042f, 0.0799833834f, 0.393983424f, 0.239627272f, -0.181738585f, -0.0165971331f, -0.0600134656f, + -0.076856643f, 0.0580854751f, -0.440829724f, -0.319537848f, 0.0437156223f, 0.126419902f, 0.922879577f, 0.0645971224f, 0.79195267f, 0.860354185f, + -0.0674851388f, 1.09398437f, 0.631276369f, -0.0847932249f, 0.00500840321f, 0.0279910211f, 0.00699257664f, 0.0632600859f, 0.0178144779f, -0.0455452204f, + -0.0279244352f, 0.0741686076f, 0.152592376f, -0.267406046f, 0.0420740098f, -0.290391922f, 0.13272725f, 0.249776363f, 0.189100012f, 0.0675023869f, + 0.13320531f, -0.173412338f, -0.0820484459f, 0.0627329275f, 0.130141333f, -0.035155192f, 0.489475369f, -0.110671543f, 0.160042882f, 0.224684328f, + -0.0976482704f, -0.240268722f, -0.294906169f, 0.0731263533f, 0.345761806f, 0.165001139f, 0.115946151f, 0.164999798f, 0.253414631f, -0.485145003f, + 0.041390758f, 0.0796967372f, -0.036708124f, 0.502090037f, -0.327352643f, -0.231271312f, -0.266467839f, 0.264497161f, -0.190110922f, 0.137642458f, + 0.147944808f, 0.116217412f, -0.269112676f, -0.159386203f, 0.380643189f, -0.19649522f, -0.175136432f, -0.112324424f, 0.0556542352f, -0.0670400262f, + 0.118939295f, 0.00496431161f, 0.0689715743f, -0.019248629f, -0.655997396f, 0.420565188f, 0.301573247f, -1.28415251f, 0.746755183f, 1.16820681f, + -0.272755384f, 0.285753906f, 0.76103878f, -0.409723997f, -1.21750808f, -0.680295944f, -0.00302582444f, 0.0697986707f, 0.060195718f, -0.0453249775f, + -0.0648096353f, 0.233288035f, 0.170168355f, -0.195928514f, 0.250630558f, 0.413617134f, 0.26703313f, 0.255688131f, 0.0804956034f, 0.310910404f, + -0.123944059f, 0.124959052f, -0.0840137154f, 0.204207957f, 0.0466481782f, -0.278703958f, 0.0650766641f, 0.348603249f, -0.246978953f, -0.191225797f, + -0.233698621f, -0.365525842f, 0.235661864f, 0.397014469f, 0.214375496f, -0.00401900243f, -0.0434863791f, 0.0715015978f, -0.110430531f, 0.0264151227f, + 0.163478807f, 0.262457103f, -0.12412864f, -0.0735682324f, -0.129781067f, 0.497384042f, 0.182120591f, -0.186185867f, 0.288754135f, 0.397442132f, + -0.0465112142f, 0.33370176f, 0.262588948f, -0.0601687171f, -0.114745349f, -0.318699181f, -0.29418388f, 0.0488052294f, 0.028821338f, -0.29090786f, + 0.0947641581f, 0.136757553f, 0.175486252f, 0.0359192975f, 0.271541387f, -0.0342398472f, 0.700285494f, -0.766309679f, -1.43097341f, -0.731664181f, + 0.549189329f, -1.46045077f, -0.310350418f, -0.0183204338f, -0.972970188f, -0.605997324f, 0.0434501208f, -0.208515629f, 0.117069222f, 0.0359151177f, + 0.0265239365f, 0.298138916f, 0.0645491183f, -0.407573998f, -0.228626043f, 0.233375534f, 0.5891487f, -0.0408318825f, -0.0532918647f, 0.268571556f, + -0.174251646f, -0.0263587423f, -0.182525739f, 0.0651911497f, 0.611758709f, -0.236488029f, 0.0817986429f, -0.312723786f, 0.0757885948f, -0.099232167f, + 0.00953313522f, -0.0408178866f, -0.090539664f, -0.0148965707f, 0.183034167f, -0.00391864963f, -0.0365107208f, -0.268384755f, -0.348035276f, 0.0097886892f, + -0.302646339f, 0.489450991f, 0.107426845f, -0.0897822082f, -0.0684847981f, 0.239299774f, -0.232886225f, -0.0156022403f, 0.0963971391f, -0.0513590649f, + -0.0234010331f, -0.023404317f, -0.295417577f, 0.138074309f, -0.00111536169f, 0.296354383f, 0.120003954f, 0.290555924f, -0.734434426f, -0.247047365f, + -0.405449718f, -0.357691675f, -0.100737296f, 0.221591234f, 0.558989167f, 0.0187684037f, -0.0867070779f, 0.0247441046f, -0.251730472f, -0.736120045f, + -0.511864126f, 0.0233254042f, -0.200523645f, -1.0128659f, -0.215160921f, 0.557511687f, -1.7380693f, -0.375834733f, -0.970106423f, 0.3621324f, + 0.182680815f, -0.0385514461f, 0.0796483308f, -0.244589478f, -0.140679345f, -0.0719916299f, 0.292012095f, 0.0477236062f, 0.899561107f, 0.153153583f, + 0.0729769617f, 0.175146088f, -0.120216817f, 0.0305076689f, 1.32659543f, 0.0501577966f, -0.0211603213f, 0.338394254f, -0.104367651f, 0.183698356f, + -0.373057723f, 0.0359494016f, -0.258584559f, 0.365091681f, 0.0498603657f, 0.19815743f, 0.00471375091f, 0.0337727703f, 0.361868352f, -0.361427337f, + -0.117502607f, 0.130248278f, 0.314633042f, 0.214186206f, 0.0550500788f, 0.132221401f, -0.163593307f, -0.185722888f, -0.291179419f, -0.136404067f, + -0.113145955f, -0.00526593113f, -0.522189558f, -0.223313183f, 0.18189472f, 0.234915137f, 0.0268280152f, -0.0177754387f, -0.165558264f, 0.712506354f, + -0.0575711019f, 0.577933908f, 0.505037069f, 0.263804376f, -0.101470098f, 0.0993113518f, -0.116468124f, 0.148941353f, -0.0186333545f, -0.146711111f, + -0.220339283f, -0.256765634f, 0.606834173f, 0.830024958f, 0.821709394f, -0.135789871f, 1.12143993f, -0.343761295f, -0.373671889f, -0.845478654f, + -0.318390191f, 0.476092249f, 0.214904875f, -0.0685628429f, 0.246960819f, 0.115913309f, 0.19136177f, 0.00603227271f, 0.00358032994f, -0.0512298197f, + -0.332796246f, -0.259329259f, -0.281533152f, -0.342145681f, -0.00322403363f, -0.0716783106f, -0.312527508f, -0.126863882f, -0.0229288004f, -0.269954383f, + 0.258608907f, 0.117488228f, 0.458975822f, -0.00637759361f, -0.0936106741f, -0.0839561075f, -0.0987741053f, -0.0419358909f, 0.518862963f, 0.00869084522f, + 0.0549978912f, 0.0577327795f, 0.110182539f, 0.0477007888f, 0.856119514f, 0.0341379605f, -0.0391174927f, 0.00226954347f, 0.0722591281f, 0.0267129522f, + -0.298897237f, -0.0859658793f, -0.0258036815f, 0.36124751f, -0.178638071f, -0.333731085f, 0.153151974f, 0.0523342639f, -0.0397466011f, -0.206972137f, + 0.0597833991f, -0.0996391997f, -0.0601140931f, -0.345348835f, -0.0560344011f, -0.495880783f, -0.218764648f, 0.0724368989f, -0.170261532f, 0.0729736984f, + -0.12408074f, -0.126873866f, 0.546161354f, -0.183677778f, -0.00951282866f, -0.92414695f, 0.265735626f, 0.193581268f, 0.774882734f, -0.969864547f, + 0.0958072171f, 0.452510238f, 0.909753144f, 0.723948359f, 0.242507786f, -0.0386512652f, -0.00860536098f, -0.224263713f, -0.196811944f, -0.178290993f, + 0.0358549394f, -0.104410924f, -0.253592104f, 0.052943401f, -0.46109587f, -0.311446577f, 0.360949308f, 0.143117771f, 0.108281165f, -0.283461064f, + 0.0540457927f, 0.282515854f, -0.26383695f, -0.0596289448f, -0.199350268f, 0.0126620196f, -0.0486114286f, -0.0152106984f, -0.0717472807f, -0.0398125574f, + -0.392868489f, -0.0416381918f, 0.0490404889f, 0.11051739f, -0.0565170869f, -0.0426275171f, 0.10335625f, -0.0481836982f, -0.0555603728f, 0.164189667f, + 0.0499826111f, -0.015493568f, 0.118030444f, -0.00028052475f, 0.0409838296f, 0.056233529f, 0.0153067289f, -0.326039851f, 0.207168281f, -0.0960620791f, + 0.0233176891f, 0.0589421093f, -0.0571819246f, 0.283213109f, -0.19165206f, -0.00857602619f, -0.0608899184f, 0.0271514691f, -0.0549036153f, -0.263619304f, + -0.0776564628f, -0.155516371f, -0.0312586725f, -0.0805953145f, -0.875467181f, -0.0723574236f, 0.466272861f, 0.376644731f, 0.611266673f, -0.197038591f, + 0.0888675824f, -0.0825837255f, 0.810467243f, 0.767527938f, -0.235811755f, 1.65028942f, 0.121305913f, -0.0625406876f, 0.0259963907f, -0.0866210833f, + -0.143929884f, 0.0439771004f, 0.0261681098f, 0.0469171666f, -0.233501181f, 0.357121944f, 0.0151759479f, 0.260062665f, 0.37199828f, -0.222932085f, + -0.050325036f, -0.234706596f, -0.0319241919f, -0.069085978f, 0.134300843f, -0.218854561f, 0.0131007927f, -0.0125704613f, -0.255198061f, -0.168568999f, + -0.118578464f, -0.199287504f, -0.192874476f, 0.477147311f, 0.203318179f, 0.116629824f, -0.160125643f, 0.407229036f, 0.0380503908f, -0.185820341f, + -0.11448139f, -0.168200999f, 0.371599644f, -0.0313371867f, -0.0587074123f, -0.326079696f, 0.0182584133f, -0.14921692f, -0.279151529f, -0.0608872212f, + -0.360643625f, 0.189949393f, 0.356133789f, -0.229139835f, -0.0435057841f, -0.0979659334f, -0.0420698002f, 0.127507463f, -0.353449553f, 0.263609678f, + -0.123893872f, -0.229395583f, -0.101674967f, -0.11483337f, -0.144796461f, -0.23287119f, 0.279174179f, -0.567837179f, 0.11613892f, -0.690490365f, + 0.461242288f, 0.0445568711f, -0.158701301f, 0.453873515f, -0.557536423f, -0.209114522f, 1.11171305f, -0.0652313158f, 0.0219244454f, 0.00733288238f, + 0.00569032924f, 0.130871311f, -0.0217153095f, -0.124250449f, -0.0395233668f, -0.00302719465f, -0.073276341f, -0.0905757621f, -0.0162838604f, -0.0441848375f, + 0.134880677f, 0.115268365f, 0.313582897f, 0.076553449f, 0.517510235f, 0.294451475f, -0.0267599504f, 0.0685875416f, 0.101551168f, -0.021943314f, + -0.0171912145f, 0.0665769726f, 0.115672454f, 0.12398874f, -0.0976139158f, 0.0936523303f, 0.347418517f, 0.447357684f, 0.81218183f, 0.790447116f, + 0.457220614f, 0.164378509f, -0.206260055f, 0.129521891f, -0.0378106274f, -0.0503245741f, 0.158168361f, -0.083261691f, 0.129890889f, -0.133925766f, + 0.132664606f, -0.137155443f, -0.184427083f, -0.315169781f, -0.509694099f, -0.254677594f, -0.178125024f, -0.187861934f, 0.0358272269f, 0.0497061238f, + -0.00875596888f, -0.00587767363f, 0.31893456f, -0.164246991f, 0.0369106159f, 0.0457914956f, 0.306562841f, 0.16068399f, 0.193077981f, 0.147126988f, + -0.0422217287f, -0.174581662f, -0.222615376f, 0.256705403f, 0.0587155446f, 0.0422115326f, -0.062455833f, -0.00273481081f, -0.00254951976f, 0.0348951109f, + -0.252939641f, 0.113421574f, 0.029808417f, 0.118065603f, 0.0921614021f, 0.169647843f, -0.236671284f, 0.0301472507f, -0.462488085f, -0.211474523f, + 0.225979015f, -0.267773718f, -0.0656009316f, 0.127998069f, -0.181387812f, 0.0815940499f, -0.354960322f, -0.394766331f, -0.286868155f, -0.346229285f, + -0.222484618f, -0.0275041554f, 0.0671753138f, -0.143375158f, 0.393436939f, -0.0135004502f, 0.0233038086f, 0.131400764f, 0.0264709685f, -0.121538579f, + -0.151125923f, -0.0041160211f, 0.248137221f, 0.531802058f, 0.163267106f, -0.226114824f, 0.19664605f, -0.167177692f, -0.0769943297f, -0.0536059849f, + 0.0776468441f, -0.311571628f, -0.14874801f, -0.134065405f, -0.150638714f, -0.465674877f, 0.016558297f, -0.194066852f, 0.385882348f, 0.291211873f, + 0.0558825582f, -0.181199983f, 0.188641489f, -0.0183022171f, -0.0372124948f, -0.0064640115f, -0.0844450369f, 0.00125914032f, 0.148340896f, -0.178760558f, + 0.106308468f, 0.228459015f, -0.0595249832f, -0.0248371009f, -0.2087598f, 0.30158022f, -0.0292477384f, -0.0478062257f, 0.194229037f, -0.781089962f, + -0.636488199f, 0.0374273956f, 1.68813694f, 0.396566719f, 0.531710684f, 0.20946236f, -0.287857264f, 0.742483139f, 0.0659536198f, -0.149415165f, + -0.843087196f, -0.0052967025f, 0.201631412f, -0.0230165496f, 0.120300479f, 0.16671434f, -0.00179948995f, -0.00620021764f, 0.194000095f, 0.0105732763f, + -0.0295786876f, -0.190057948f, -0.0510211512f, -0.0723214f, 0.0996998101f, -0.10786961f, 0.119797431f, -0.034815751f, 0.00268549589f, 0.127320305f, + -0.00714713708f, -0.0832434669f, -0.0492389835f, -0.111412041f, -0.442637712f, -0.165972307f, -0.0876027793f, -0.0784224719f, 0.152917072f, -0.142466486f, + -0.114580795f, -0.00230062893f, 0.0330201909f, -0.0983080417f, 0.125890926f, -0.190271616f, 0.0872597173f, -0.177759752f, -0.00283640483f, 0.0797925219f, + 0.313194722f, 0.156168818f, -0.0493105389f, 0.200529709f, 0.011899611f, -0.0484922715f, 0.112990759f, 0.0562183484f, 0.183592632f, 0.104906224f, + 0.136213973f, 0.191597417f, 0.0874277055f, 0.0627378598f, -0.0174641721f, 0.156907618f, -0.0945919156f, 0.0328459367f, -0.208437935f, -0.176131546f, + -0.220587924f, -0.115270153f, 0.0271447655f, 0.0392758101f, 0.067621246f, 0.0202301778f, 0.164220572f, 0.0441027991f, -0.0256725699f, 0.204767182f, + 0.06230646f, 0.0292298011f, 0.174481675f, 0.294518173f, 0.258752346f, -0.105325192f, 0.216631547f, 0.086571835f, 0.201671079f, -0.334212601f, + -0.151639968f, -0.0667664707f, -0.238909543f, -0.248262361f, 0.221106142f, -0.189367548f, 0.162087172f, -0.00773638999f, 0.101843625f, -0.088303782f, + 0.0268691722f, 0.204393044f, -0.124892831f, 0.0598089881f, 0.0146069964f, 0.0149204871f, -0.0158311501f, 0.0030879702f, 0.109539337f, 0.101380691f, + -0.11232233f, -0.0136279408f, -0.0263411812f, 0.0854537189f, -0.000676175288f, 0.0821558982f, 0.0176799633f, -0.142150864f, -0.411974847f, -0.0489270315f, + 0.0392945819f, -0.211978227f, 0.101287462f, -0.0669199899f, 0.195273101f, 0.140846431f, 0.309790552f, 0.144505575f, 0.066638723f, 0.119366266f, + 0.018308064f, 0.00913781021f, 0.219609201f, -0.0397473425f, 0.0696232989f, 0.132075429f, -0.148267671f, -0.0632030368f, -0.0296609607f, 0.00117317645f, + -0.102980584f, -0.0780204982f, -0.0992893353f, -0.189615324f, -0.0878756642f, 0.0135804452f, -0.00690099876f, -0.00377333513f, 0.0976145118f, -0.175252244f, + 0.351152182f, 0.169557616f, 0.0181343481f, -0.281986028f, -0.356314957f, -0.00428265333f, -0.0442856923f, -0.668457806f, -0.330625981f, 0.190708399f, + 0.486206383f, -0.753990531f, 0.203869313f, -0.0848159641f, 0.0473243669f, 0.0313923806f, 0.101788752f, 0.436086804f, 0.427127987f, 0.634017408f, + 0.287697762f, -0.136266187f, -0.247837305f, -0.0263506006f, -0.0333421938f, 0.466805518f, 0.319073319f, -0.355528235f, -0.0434040576f, -0.206104159f, + -0.365978986f, 0.0549260788f, -0.00124498724f, -0.273087591f, 0.465883076f, -0.458815306f, -0.174581289f, 0.371291459f, 0.298179835f, 0.144446388f, + 0.0609106794f, -0.0704424158f, -0.175629526f, -0.0725880414f, -0.313399225f, -0.141393676f, 0.200009301f, -0.218361199f, 0.0927748308f, 0.191879407f, + -0.252846479f, -0.0989015028f, 0.382335663f, 0.243978739f, 0.510491133f, 0.388793856f, 0.115239933f, -0.200277567f, -0.365846068f, -0.0314801298f, + 0.319476426f, 0.250864953f, 0.00800600369f, 0.181021169f, -0.249336094f, 0.352413774f, 0.020985458f, -0.0678483099f, -0.0520504266f, -0.0414183736f, + 0.610688746f, -0.118238896f, -0.211845011f, 0.14655824f, -1.18035984f, 0.266941845f, 0.878561258f, 0.667692423f, 0.0120365052f, 1.33030486f, + -0.710911214f, -0.656958282f, 0.206502736f, -0.918558419f, -1.41331673f, 0.276508212f, 0.151175395f, 0.00267039193f, 0.0637201518f, 0.0620548241f, + 0.0552138835f, -0.155369446f, 0.0837620422f, -0.0552626923f, 0.60529393f, 0.138885155f, 0.173313007f, -0.430311233f, 0.112130649f, 0.178237513f, + -0.274313539f, 0.222453967f, 0.0571191609f, -0.0104129994f, 0.192496702f, 0.0867958814f, 0.0075284862f, -0.0654804111f, 0.321012616f, -0.298366725f, + -0.0182039477f, -0.0245172568f, 0.343509972f, 0.22396715f, 0.310706079f, 0.253964096f, -0.173591897f, 0.528144062f, 0.0927110687f, -0.122106016f, + -0.0326196328f, -0.0995992646f, 0.0887224823f, 0.0477890298f, -0.246219531f, -0.238179594f, 0.0380758867f, 0.0768506005f, -0.0267783813f, -0.0852332637f, + 0.344089717f, 0.104966491f, -0.0830771476f, 0.0911617875f, -0.496296048f, -0.457219839f, -0.457731277f, -0.410816759f, -0.131835163f, 0.28001672f, + 0.548774719f, -0.0720639229f, 0.289120823f, -0.0674598515f, -0.341878057f, -0.186997443f, 0.459172517f, -0.350608706f, 0.251648098f, -0.191382051f, + 0.0228391439f, -0.89399004f, 0.404006749f, -0.360789269f, 0.274683475f, -0.954035044f, -0.0682818443f, 0.199836165f, 0.315016598f, 0.158338264f, + 0.137694255f, 0.159561083f, -0.216312766f, 0.285540849f, 0.0736897886f, -0.0630915314f, 0.363597125f, 0.107728295f, 0.291849703f, 0.579296708f, + 0.249604002f, -0.0779494867f, -0.0506449006f, 0.162844583f, -0.00143999059f, 0.00353213307f, -0.0575588085f, 0.148261502f, 0.541810811f, -0.431815356f, + -0.0263044145f, -0.0810825378f, 0.163998395f, 0.111833706f, 0.250615001f, -0.283921003f, -0.192224711f, -0.300815552f, 0.132223323f, -0.109815992f, + -0.340802342f, -0.24551259f, -0.0598495454f, -0.00770300347f, 0.159064621f, 0.223931298f, -0.757913589f, 0.189121708f, -0.0902571529f, -0.279147208f, + -0.0594196916f, -0.108534142f, -0.0743903518f, -0.235114425f, -0.406153321f, -0.172781527f, 0.300346822f, -0.31740436f, -0.0700557753f, 0.29104653f, + 0.76287812f, -0.352979451f, 0.319397569f, -0.138001025f, 0.0930234343f, 0.146106943f, -0.271738917f, -0.191447526f, 0.232709423f, 1.15183282f, + -0.246489391f, -0.957793415f, 0.58745116f, -0.357166529f, 0.16834496f, -0.260615557f, -0.199724019f, -0.395956486f, 0.371227682f, 0.206258342f, + 0.110524759f, -0.0531278849f, -0.156722292f, -0.0122004347f, -0.0384959914f, -0.0899775699f, -0.100294694f, -0.128005698f, 0.438655734f, 0.342898309f, + 0.213263616f, 0.275214434f, -0.0824651122f, 0.146292493f, -0.251713544f, -0.217767403f, -0.155428901f, -0.315238297f, -0.0728120506f, -0.162930936f, + -0.0169189442f, -0.41742757f, -0.282421798f, -0.150936171f, -0.122574441f, -0.431016803f, -0.179539427f, 0.16472353f, 0.0795657411f, -0.259798378f, + -0.271263957f, -0.418616533f, -0.0386454314f, 0.320778131f, -0.109781303f, -0.299663067f, 0.12069957f, 0.28102994f, -0.372825176f, 0.17490603f, + 0.3050704f, 0.22129418f, 0.211351186f, 0.13252978f, 0.0507364869f, -0.132750228f, 0.18666622f, 0.37375772f, 0.114546515f, 0.2388511f, + -0.0716949105f, 0.0367986299f, 0.157256216f, -0.0958242565f, -0.0802932456f, 0.186010256f, -0.308100224f, 0.093114458f, -0.0241881162f, 0.165707231f, + -0.00172724412f, -0.390628874f, -0.827830434f, -0.665796697f, -0.152253732f, -0.189972565f, -0.900128007f, -0.973143578f, 0.404395312f, -0.33414185f, + -0.0794574991f, -0.0755254701f, -0.0376647972f, -0.0563134626f, -0.0955413803f, -0.215304077f, 0.0796341971f, -0.114806406f, -0.35725531f, -0.306609333f, + -0.0580836684f, -0.17740804f, 0.264658272f, -0.202360779f, -0.444706857f, -0.363530934f, -0.375513166f, -0.0289734136f, -0.331221521f, 0.0700778291f, + 0.102219738f, 0.259417206f, 0.160694629f, 0.534891307f, 0.300858706f, -0.158628449f, -0.0266615339f, 0.00342709851f, 0.257915229f, 0.0332291983f, + 0.155834675f, -0.114227742f, 0.0765147507f, 0.12016207f, -0.104107693f, 0.345174253f, 0.375378728f, 0.059708111f, 0.36307025f, 0.537306845f, + 0.234626189f, 0.00609729718f, -0.106556185f, -0.133535594f, 0.101593405f, -0.0781360269f, -0.055609528f, -0.248985454f, -0.36395213f, -0.220662951f, + 0.13903144f, -0.19128041f, -0.155968562f, 0.36951679f, 0.277506232f, -0.0873048306f, 0.159178615f, -0.157511711f, 0.354754567f, 0.120551981f, + -0.0670322254f, -0.00585158914f, -0.513801336f, 0.00347290328f, 0.736419082f, -0.674239695f, 0.655664265f, -0.49940303f, 0.109152257f, -0.160232425f, + -0.0637531877f, 0.0902466848f, -0.0941672027f, -0.621255636f, 0.0146690048f, 0.136127397f, -0.140431181f, 0.126908705f, 0.201502234f, 0.165417567f, + -0.2086422f, -0.392252803f, 0.9839378f, 0.157926649f, 0.0661353469f, 0.11529123f, 0.0236536823f, -0.329108119f, -0.605028391f, -0.00505242962f, + 0.164701551f, 0.0754689947f, -0.141552806f, 0.121768735f, -0.571389973f, -0.0806358084f, -0.0899260268f, -0.392969638f, 0.108102955f, 0.246364683f, + -0.237752497f, -0.106994271f, 0.133791044f, -0.431653708f, -0.22971271f, -0.101943322f, -0.021408543f, 0.101026565f, 0.115069702f, 0.0515818521f, + 0.210237175f, 0.227633968f, 0.00375050213f, 0.0392146669f, -0.166435152f, -0.40443188f, 0.106956102f, 0.0304393303f, -0.0674872622f, -0.143281415f, + -0.182484865f, 0.343691885f, -0.0514854379f, -0.252838552f, 0.0274863951f, -0.0749772191f, 0.0455047749f, -0.0786254033f, -0.0171200819f, -0.0366014764f, + -0.036878638f, 0.129225627f, -0.0734592378f, -0.0225262735f, 0.070658356f, -1.43138659f, 0.00879648793f, 0.00640334561f, 0.278290272f, -0.690539956f, + -0.223737404f, 0.120553896f, -1.29964304f, -0.968788028f, 0.294547707f, -0.156623274f, -0.0974406153f, 0.0304283742f, -0.154148683f, 0.153602481f, + 0.353361279f, -0.0837050676f, -0.103908516f, -0.00713188434f, 0.0955676213f, -0.305374712f, 0.210261896f, 0.165399835f, -0.0038093226f, -0.102703474f, + 0.0506220832f, 0.354049534f, -0.0745977014f, 0.620569825f, 0.0681680217f, 0.232349798f, 0.0580504537f, 0.0615104139f, 0.308384955f, -0.0671902969f, + -0.391061574f, 0.0412302911f, -0.265070349f, -0.15822044f, 0.0125618391f, 0.00532947015f, 0.265744179f, -0.27169314f, 0.0353224948f, 0.0610866249f, + 0.402550548f, 0.68809396f, 0.29403311f, 0.299417883f, -0.0458146594f, -0.145336226f, -0.139075652f, -0.0906241164f, -0.403998762f, -0.263589591f, + 0.349196672f, 0.0614623725f, 0.0660992265f, 0.0153434426f, 0.168016955f, 0.0677933767f, 0.487051517f, -0.0919594616f, -0.0955494493f, -0.0348829553f, + -0.23241657f, -0.189550951f, -0.0904179364f, -0.104091115f, -0.0594541356f, 0.103100732f, 0.948731959f, -0.327689409f, -0.0958179384f, 0.845378458f, + 0.1924676f, -0.226778314f, -0.169291228f, -0.590278685f, 0.176980317f, 0.65129143f, 0.328980774f, 0.445320189f, 0.0f, 0.0f, + 0.0f, -0.0924276337f, 0.150899127f, -0.124345265f, -0.0182682872f, 0.00879414752f, 0.135531142f, -0.292124867f, 0.0411674157f, 0.0092402054f, + -0.173635885f, 0.122928835f, 0.0970591456f, -0.119790137f, -0.473439366f, -0.363711238f, -0.0875765905f, 0.170427829f, -0.0162609033f, -0.0356650501f, + -0.0247421898f, -0.0652708411f, 0.208866611f, 0.39189899f, -0.0156926624f, 0.122952774f, 0.154176146f, 0.245059669f, 0.162321284f, -0.133669719f, + -0.0583983436f, -0.0255192667f, 0.478531301f, 0.214664176f, -0.190519243f, 0.0616070554f, 0.0599223375f, 0.157739639f, 0.167653933f, 0.111179434f, + -0.0757338032f, -0.0172818657f, 0.203279018f, -0.0664374456f, -0.0177854188f, 0.177363023f, -0.0478785634f, -0.228205517f, -0.0173032675f, 0.125626057f, + 0.0199999996f}, + {0.26579529f, 0.865616262f, 0.478914112f, -0.106267557f, 0.368675053f, 0.18808648f, -0.191789925f, 0.00314706471f, 0.0320013352f, 0.272390932f, + 0.166063249f, 0.215591222f, -0.234997049f, -0.165516138f, -0.157529607f, 0.354174167f, 0.176117048f, 0.0219098087f, -0.246756434f, -0.192151532f, + -0.0445315689f, -0.0148327341f, 0.357131302f, 0.296025425f, -0.578776717f, -0.399047494f, 0.0213306267f, -0.060820628f, 0.0916926861f, 0.0991782323f, + 0.548800945f, -0.226142436f, -0.0361128673f, 0.531007707f, 0.203084081f, 0.212365627f, -0.0645497814f, -0.347183436f, 0.0964040831f, 0.0603978112f, + -0.256317109f, -0.14004232f, -0.0163379833f, -0.229716837f, -0.0264815204f, 0.0554128923f, 0.0398268104f, -0.0995931849f, 0.139561653f, 0.202683941f, + 0.0727898926f, -0.155503333f, 0.208416358f, -0.0955859572f, 0.207165062f, -0.260325998f, 0.213532627f, 0.0508164279f, -0.0671972781f, -0.102062054f, + -0.0582314841f, -0.570733011f, -0.160044968f, -0.786662042f, -0.0240865108f, -0.563726544f, -0.531763613f, 0.0977816582f, -0.163663983f, -0.121561795f, + 0.349605203f, -0.756136656f, 0.12329495f, 0.0270171259f, 0.0309699364f, 0.068856433f, 0.280064106f, -0.131376609f, -0.270567447f, 0.151363283f, + 0.0505998917f, 0.260451585f, -0.0508622117f, -0.380197763f, -0.0750746503f, -0.123091981f, 0.180019408f, 0.113436595f, -0.341768324f, -0.305727214f, + 0.163513348f, 0.141790733f, -0.14610073f, -0.0145902364f, -0.311349928f, -0.207563534f, -0.00977893174f, -0.216794938f, 0.407184571f, -0.131931752f, + -0.162902176f, -0.811397195f, -0.305004537f, -0.191464052f, 0.0425464287f, 0.0181629881f, -0.559207082f, -0.0981654152f, -0.338806957f, -0.0579097532f, + 0.492296517f, 0.231689453f, 0.263527304f, -0.0266153216f, 0.582741261f, 0.260748327f, -0.419084847f, 0.136595413f, 0.3485322f, 0.434821159f, + 0.176152274f, 0.167290702f, -0.431995541f, 0.290227115f, 0.199378744f, 0.451708883f, 0.633755922f, -0.113681115f, -0.66120106f, -0.0570343882f, + 0.0988790691f, 0.11846479f, 0.305285513f, 1.45258796f, -0.631727219f, -0.568677425f, 0.577965856f, -1.08749998f, -0.0532283187f, -0.0688028336f, + 0.0649626777f, -0.459879994f, 0.3728984f, -0.409506887f, 0.0341693498f, 0.0587154366f, 0.0352760442f, -0.115972325f, -0.120573394f, -0.014870056f, + 0.0195022281f, -0.295186222f, -0.00607062411f, 0.386234999f, 0.0355724469f, 0.0465353727f, 0.144048229f, -0.0369948111f, 0.102468058f, 0.258545101f, + -0.076913029f, -0.0500877239f, 0.232309416f, -0.0876469985f, 0.133214235f, 0.0248421617f, -0.00726857223f, 0.363509953f, 0.106783137f, 0.424123824f, + -1.20135295f, 0.0344022997f, 0.207351491f, -0.0717697516f, -0.122187413f, 0.0885134935f, 0.0047418084f, 0.147416875f, 0.375609547f, -0.0783741549f, + 0.118030079f, 0.0765534863f, -0.591346979f, -0.132927448f, 0.0616557449f, 0.135065109f, -0.1460246f, 0.385694861f, -0.0127267549f, -0.429432243f, + 0.0741847456f, 0.23213242f, 0.0870096236f, 0.0330516659f, -0.220849767f, 0.424055606f, 0.130760714f, -0.291996956f, -0.0450381637f, 0.00497677736f, + -0.417737871f, 0.0762126669f, -0.00262033939f, 0.0643552318f, 0.0675775409f, -0.263085723f, 0.575066864f, 0.421733201f, -2.11346507f, -0.0455407277f, + -1.06895399f, 0.233488277f, -0.0422704741f, -0.0087338537f, -0.394331872f, 0.85498476f, 0.0504335612f, 0.0711418986f, -0.00562099507f, -0.0358141996f, + -0.0799472854f, 0.0418046117f, -0.113481946f, -0.150165915f, -0.516587317f, 0.27591756f, -0.122619048f, 0.0584223345f, 0.0290329102f, -0.38566035f, + -0.390137643f, -0.00784267392f, 0.325766593f, 0.074563764f, 0.439836621f, 0.284296602f, 0.0109825376f, -0.0188378524f, -0.00407920731f, 0.128692642f, + -0.0252608433f, 0.09395051f, -1.04954815f, 0.0657648221f, -0.0824617594f, 0.392784536f, 0.0602624528f, 0.236447915f, 0.0391133241f, 0.169105202f, + 0.161207378f, -0.112205997f, 0.322664052f, 0.361137301f, -0.40045023f, 0.123977654f, 0.0713931248f, 0.0174260046f, -0.0913700461f, 0.0836877003f, + 0.307041347f, -0.266047031f, 0.267931789f, -0.230077282f, -0.299003899f, 0.236121178f, 0.140198112f, 0.0522395894f, -0.1753546f, -0.104980513f, + -0.0232879017f, -0.216991201f, 0.22190176f, -0.17503123f, 0.033382386f, -0.0306868013f, -0.339618027f, -0.132113039f, 0.122207113f, 0.356803298f, + -0.632796407f, -0.318935812f, 0.482130438f, -1.18033612f, -0.351782113f, 0.176623955f, -0.718633771f, 0.0614353567f, 0.0533166379f, 0.0279543381f, + -0.00325565855f, 0.0848382562f, 0.125801429f, 0.0599196963f, 0.0500202067f, 0.0209579114f, -1.4493041f, 0.187066942f, -0.0446617268f, 0.0444400422f, + 0.138482898f, -0.0506616496f, -0.470301539f, -0.321522266f, -0.186835065f, -0.178168565f, -0.247795582f, 0.109305911f, -0.218082249f, -0.0426610373f, + -0.0468187891f, -0.0247883536f, 0.118486688f, -0.00447007222f, -0.874403179f, 0.159772113f, 0.138179898f, 0.373307705f, 0.184671372f, 0.172229424f, + -0.379043907f, -0.126338065f, 0.0213562362f, -0.282547355f, -0.276749015f, -0.071423173f, -0.250026405f, -0.0175597798f, -0.000471222098f, -0.0721946955f, + 0.226038218f, -0.0388920195f, 0.17983456f, -0.0749884397f, -0.0798001662f, 0.0321936719f, -0.265981495f, -0.450312018f, -0.301652104f, -0.0125954719f, + -0.0572701171f, -0.0960287675f, -0.261534601f, 0.27784881f, -0.0436973795f, 0.0074438653f, 0.0313603356f, -0.00317894784f, 0.170338437f, 0.149395928f, + -0.172349349f, -0.319904715f, -0.483030409f, -0.111618631f, -0.414865285f, -0.499313414f, 0.542635024f, 0.6285007f, -0.0566006899f, 0.470818758f, + 0.070482038f, 0.00770367216f, -0.0395783111f, -0.16118145f, 0.0520598516f, -0.0250879396f, 0.108994387f, 0.135058463f, -0.976616681f, 0.0964239761f, + -0.0893700197f, -0.0211448446f, -0.183664784f, -0.119569629f, -0.161599919f, -0.29192552f, -0.162761301f, -0.294177711f, -0.160705581f, -0.059233062f, + -0.191926539f, 0.00233873539f, -0.00809086766f, 0.119208492f, 0.0133468583f, -0.0700460672f, 0.0829775259f, -0.00101913244f, 0.0326346494f, -0.118721917f, + 0.0750476122f, 0.323709279f, -0.0722680092f, -0.439539433f, -0.137637213f, 0.125164598f, 0.123287477f, -0.515675008f, 0.0756309852f, 0.156800672f, + 0.014499641f, -0.165790439f, -0.039806962f, 0.0213508978f, -0.52365464f, -0.126591265f, -0.039945513f, 0.112357453f, 0.00284326868f, -0.0120450752f, + -0.121189535f, 0.065824613f, -0.0787981078f, -0.234877586f, -0.368253142f, -0.206581503f, 0.111175023f, 0.0584695376f, 0.00428766198f, 0.0723178759f, + 0.279032975f, 0.35607785f, 0.0884274542f, -0.0902937129f, 0.0733311325f, -0.246157989f, -0.497859329f, -0.172433868f, -0.633626103f, 0.349614024f, + 0.0862277746f, -0.277948529f, 0.107547045f, 0.00314255548f, -0.022105718f, -0.0426589325f, -0.0926254913f, -0.0757442117f, -0.050936155f, 0.113547251f, + -0.389466524f, -0.000668726861f, 0.0409661271f, 0.0198011156f, 0.030405527f, -0.0837379843f, -0.650759935f, -0.0902011469f, -0.0769778565f, -0.143034548f, + -0.0401457138f, -0.0315288603f, 0.141313314f, -0.00211268896f, 0.0154681234f, -0.00408452936f, -0.0503886081f, -9.17610596e-05f, 0.158912674f, 0.0264798142f, + 0.0109266322f, 0.0199884009f, 0.0570696555f, 0.00492684264f, 0.154284239f, 0.117134362f, 0.111857183f, 0.0940841138f, 0.0982547179f, 0.0285130851f, + -0.361654788f, 0.0531426817f, -0.0447270758f, -0.0234832298f, -0.0712030828f, -0.268173903f, -0.683621645f, -0.0224655531f, 0.0376596376f, 0.0441587567f, + 0.0425877236f, 0.161427975f, -0.628114641f, -0.0500267409f, -0.0553761721f, 0.105974309f, -0.037586987f, -0.123508126f, 0.666909516f, -0.11359591f, + 0.0398313366f, -0.0440389514f, -0.11968644f, -0.145459592f, 0.0713685751f, 0.498814851f, 0.693195641f, 0.174920723f, 0.837032795f, 0.767957926f, + 0.187996954f, 0.245343044f, 0.786933064f, -0.308404028f, 0.108993649f, -0.0129852891f, -0.0369512811f, 0.102127798f, -0.0373311006f, 0.123804905f, + 0.156070814f, 0.105468936f, 0.193674222f, -0.0765696988f, -0.0410662405f, -0.0303575415f, 0.23436214f, 0.12880525f, 0.078473635f, 0.0716830269f, + 0.204748943f, -0.193842277f, -0.100633487f, 0.0188876912f, 0.466309339f, -0.131141752f, 0.4611561f, -0.1099336f, 0.223351747f, 0.279919386f, + -0.0628157556f, -0.079706043f, -0.113269851f, 0.207417011f, 0.443950921f, 0.187040329f, 0.0317940302f, 0.116351776f, 0.362216771f, -0.566323519f, + -0.206085339f, -0.200374052f, -0.186925277f, 0.278455228f, -0.377358764f, -0.200430557f, -0.0729862452f, 0.545458078f, -0.0651360527f, -0.0472199768f, + 0.0760199949f, 0.0824507549f, -0.0291845649f, 0.167963177f, 0.233033031f, -0.253001839f, -0.0285566952f, 0.0380236879f, 0.0476882048f, -0.166460618f, + -0.0152158095f, 0.00896230619f, 0.0473108292f, 0.0593039878f, -0.530300319f, 0.390776336f, 0.299020559f, -0.940861225f, 0.825051069f, 0.926626384f, + -0.13430883f, 0.144075274f, 0.754869163f, -1.08893108f, -1.22801304f, -0.522974908f, 0.185616672f, -0.0398112088f, 0.0626455694f, -0.105885379f, + -0.209946111f, 0.0481868908f, 0.0188308395f, -0.327458978f, 0.0434070453f, 0.490184277f, 0.0990238115f, 0.0886212587f, -0.045356717f, 0.164545283f, + -0.273994029f, 0.00509090722f, -0.0927160308f, 0.268063456f, 0.287557125f, -0.17813848f, 0.13668707f, 0.560180902f, -0.0404505916f, 0.194221631f, + -0.31918782f, -0.233427227f, 0.190742835f, 0.327534378f, 0.0398698077f, 0.324557543f, -0.107623674f, -0.045121029f, 0.229410753f, -0.355491847f, + 0.21591869f, 0.0299034696f, 0.276291281f, -0.0822856352f, 0.067710489f, 0.346595615f, 0.167308807f, -0.574242532f, 0.17272374f, 0.450098962f, + 0.275964648f, -0.128592744f, 0.111930877f, -0.767715573f, -0.0879727826f, -0.251477391f, -0.130046234f, 0.107336618f, 0.0521084033f, 0.175032407f, + 0.558022141f, 0.0936128721f, -0.0164007526f, 0.0409918576f, 0.418853194f, 0.07275296f, 0.361820936f, -0.381330222f, -1.03839779f, -0.512809873f, + 0.245610043f, -2.01194787f, 0.074416928f, -0.611302972f, -0.902980506f, -0.730209768f, -0.10894081f, -0.295530736f, 0.254628539f, -0.165510282f, + -0.0756166205f, 0.102972336f, 0.00841110665f, -0.11456085f, -0.05002198f, 0.922951162f, 0.53719008f, -0.178119242f, -0.190129742f, 0.499661297f, + -0.37498793f, -0.0131261256f, -0.187322646f, -0.325220704f, 0.343690485f, -0.213943794f, -0.924647868f, -0.0259619076f, 0.0475712456f, 0.122340336f, + 0.200802356f, 0.312598407f, 0.43281287f, 0.357478201f, 0.308970541f, -0.0895893723f, -0.0694525912f, -0.378667206f, -0.382454962f, 0.120463923f, + -0.162726685f, 0.385627806f, 0.24797219f, -0.121116206f, -0.0434733406f, 0.4655855f, 0.0619657263f, -0.0277642421f, 0.0580510423f, -0.116363816f, + 0.0461875461f, 0.34196189f, 0.139679089f, -0.00433746027f, -0.127039015f, 0.142031193f, -0.01103961f, 0.226518676f, -0.136219606f, -0.142615452f, + -0.09791971f, -0.0691759735f, -0.472453326f, 0.458628118f, 0.0756130442f, 0.464947134f, 0.232435629f, 0.0928653404f, -0.380967021f, -0.407199234f, + -0.222211346f, -0.287740201f, -0.176950514f, -0.634786248f, -0.68524456f, 0.247644588f, -1.22639036f, -0.602238774f, -1.29464364f, -0.262310177f, + 0.135295019f, -0.00547266612f, -0.101139776f, -0.0915719941f, -0.00826347061f, -0.00497855432f, 0.216185525f, 0.0949193016f, 0.165468931f, 0.0134510333f, + -0.345376253f, 0.179599911f, -0.080491364f, -0.219500348f, 0.333992451f, -0.00309563288f, -0.142698556f, -0.0428414345f, -0.391162038f, 0.0451394655f, + -0.0652612671f, 0.181408569f, 0.0398720019f, 0.243381798f, 0.0613265038f, 0.392467827f, -0.289527416f, -0.0921596289f, 0.114233471f, -0.358965665f, + -0.0893471092f, 0.142622054f, 0.0578800701f, -0.0353687964f, 0.00316683203f, 0.0906525776f, -0.00827231538f, -0.462786019f, -0.481706738f, -0.036606539f, + -0.232187808f, -0.075170204f, -0.236718625f, -0.613729596f, 0.371611804f, 0.00405814499f, -0.109085009f, -0.0604729056f, -0.168365404f, 0.321247011f, + -0.25883919f, 0.0243654475f, 0.0996393114f, 0.064113684f, 0.0257792324f, -0.184899732f, -0.867855132f, 0.10436511f, 0.0671279579f, -0.0367333032f, + 0.115962148f, -0.00482539367f, 0.431708932f, 0.437042177f, 0.912806392f, -0.217077747f, 0.125723451f, -0.0537380427f, -0.314128935f, -0.21762681f, + -0.129634649f, 0.576236904f, 0.283071399f, 0.0241160691f, -0.0981567204f, 0.0985091254f, 0.164645106f, 0.162251845f, 0.0193353817f, 0.0521233268f, + 0.184500247f, 0.0104678767f, -0.0331569165f, -0.0460948013f, 0.0428480506f, -0.192188025f, 0.310460597f, -0.169386297f, -0.134500057f, -0.312734485f, + -0.00996869523f, 0.0518846661f, 0.386212707f, 0.0147238718f, 0.0192864481f, 0.0394520983f, 0.0187454f, 0.206869662f, 0.228885353f, -0.0577751286f, + -0.0381222591f, -0.0377417095f, 0.0364332199f, -0.164610103f, -0.0187923964f, 0.0849610344f, -0.0656784698f, -0.134385109f, 0.0170865469f, -0.183967158f, + -0.431810498f, 0.0783165917f, 0.231892571f, 0.198971674f, -0.0551428571f, -0.265602559f, 0.298594743f, 0.116431758f, -0.00779022416f, -0.0179176889f, + -0.00391556975f, -0.146732971f, 0.000518856046f, -0.42991358f, -0.0440376513f, -0.284032583f, -0.0799166411f, 0.257400155f, -0.503441334f, -0.0610296354f, + 0.185888276f, 0.0465235598f, 0.363257647f, -0.281168491f, -0.229521602f, -0.636502922f, 0.613862157f, -0.0789989084f, 0.875027418f, -0.567650616f, + -0.173079386f, -0.0773149356f, 0.695560277f, 0.81027019f, 0.280704886f, 0.187237948f, 0.0954450592f, -0.115722463f, -0.378841281f, -0.460043639f, + 0.15074496f, 0.0634566024f, -0.191511542f, -0.00770626171f, -0.422176689f, -0.283810914f, 0.281503856f, 0.0524208136f, 0.0776792392f, -0.348690927f, + 0.0301843826f, 0.30118075f, -0.29357639f, -0.0983090252f, -0.147608161f, 0.0180636253f, -0.0197976604f, 0.0112408148f, 0.0256902874f, 0.034573663f, + 0.189842135f, 0.0088165151f, -0.00598334474f, -0.00859669223f, -0.0042630462f, -0.0260677487f, 0.813087046f, -0.0314835906f, 0.0427199155f, 0.0225413311f, + -0.0140677253f, 0.132648766f, 0.102063395f, -0.0502787009f, 0.0912026763f, 0.242552146f, -0.0379245058f, -0.0588618927f, 0.177509457f, -0.0293164458f, + -0.0455455892f, -0.033017341f, -0.0100915246f, 0.0305406209f, 0.0119410716f, 0.046262484f, 0.0800554529f, 0.165365547f, 0.283058494f, -0.170110166f, + -0.179730982f, -0.019472219f, -0.044315476f, 0.092096746f, -0.994232059f, -0.110341951f, 0.631436527f, 0.48322776f, 0.450323582f, -0.252580553f, + 0.314202785f, -0.640538633f, 0.511089981f, 0.690772235f, 0.0500026383f, 1.77326274f, 0.175413981f, 0.129719377f, 0.115499273f, 0.0487570539f, + -0.0236526728f, 0.096997723f, -0.0231899749f, 0.0626404732f, -0.323377341f, 0.0112486035f, -0.00363131613f, -0.0235723909f, -0.00718096457f, 0.015372741f, + -0.564430296f, -0.0581179522f, -0.0134811178f, -0.0641853362f, 0.0910763517f, -0.0854271874f, 0.147330344f, 0.0757017657f, 0.0455118045f, 0.0872601941f, + 0.0380323492f, 0.0774442106f, 0.0993278697f, 0.00449939491f, -0.024144331f, -0.00652589602f, -0.0340498835f, 0.0264910907f, 0.294389933f, -0.0473852195f, + 0.0372794569f, 0.000528099074f, 0.211889699f, 0.011315844f, -0.119912945f, -0.414485246f, 0.252464056f, -0.221121907f, -0.175326437f, 0.0549730137f, + -0.234133363f, -0.122408502f, 0.0207579043f, -0.0655173734f, -0.0451056547f, -0.162004575f, -0.0327976011f, 0.110429145f, -0.350063622f, 0.24743858f, + -0.262655795f, -0.48472029f, -0.0659960508f, -0.0300881993f, 0.139525801f, -0.0402207002f, 0.377922386f, -0.535824955f, 0.0784707367f, -0.514006972f, + 0.400271684f, 0.0611512177f, -0.289582431f, 0.33739543f, -0.570113957f, -0.505197048f, 0.989724159f, -0.132455438f, 0.164911717f, 0.104897417f, + 0.144503847f, 0.114736408f, -0.0416710675f, -0.155536234f, -0.0713011324f, -0.0389529578f, -0.0737376288f, -0.076906912f, -0.0704492331f, -0.184324533f, + 0.0350908898f, 0.0388398245f, 0.0561028197f, -0.345757514f, 0.0302117933f, -0.0964486301f, -0.262780815f, -0.0668902919f, 0.0998117104f, 0.036996942f, + 0.00210881419f, 0.0429498032f, 0.0750331134f, -0.0174903795f, -0.321297437f, -0.0528166592f, 0.0968603492f, -0.0465814918f, 0.0709976777f, 0.069602713f, + 0.000753079075f, 0.248862654f, -0.184067249f, 0.115859143f, -0.0850481763f, -0.130400941f, 0.0850814506f, -0.0865089968f, 0.137977183f, -0.170759767f, + 0.0162309669f, -0.125351936f, -0.0340997837f, -0.0471342728f, -0.161929205f, 0.106360577f, 0.0197148286f, -0.0158383697f, 0.207902819f, 0.170701846f, + -0.0508398674f, -0.00998047087f, 0.429881781f, -0.139631942f, -0.0193971843f, -0.109049998f, 0.131914467f, -0.0415863171f, -0.0516971648f, -0.143518969f, + -0.313341677f, 0.107187048f, 0.0258331057f, 0.600760996f, 0.410761833f, 0.149649501f, 0.0347509794f, 0.228005067f, -0.0417555608f, 0.107219577f, + -0.124900728f, 0.105940081f, 0.175860271f, 0.308733612f, 0.249585181f, 0.383521944f, 0.0528113954f, 0.120789647f, -0.387189001f, -0.142690778f, + 0.217243075f, -0.198511779f, 0.0181159079f, 0.122607477f, -0.0825547799f, 0.127934024f, -0.254536062f, -0.341221839f, -0.231343731f, -0.270407975f, + -0.0224351417f, -0.0641790405f, 0.0421754457f, -0.154466495f, 0.405170918f, 0.0304950774f, 0.1031304f, 0.107186347f, -0.204146206f, -0.201591641f, + -0.0112296259f, 0.151303917f, 0.118547589f, 0.147212058f, -0.0840214044f, -0.157515377f, 0.267138779f, 0.089358747f, 0.233689755f, 0.145310342f, + 0.229436129f, -0.0225429293f, 0.216277584f, -0.176417023f, 0.0408602692f, -0.102606617f, 0.124491334f, -0.356976956f, 0.14224264f, 0.155599833f, + 0.0714485496f, -0.238868237f, 0.129846409f, -0.140840143f, -0.224598944f, -0.218936667f, -0.176104546f, 0.0148817571f, 0.0476378538f, -0.355991542f, + -0.0982949138f, 0.104051381f, -0.00277921744f, 0.0461140946f, -0.290118963f, 0.0568146147f, -0.0765421316f, 0.104434893f, 0.135641724f, -0.737987816f, + 0.590592623f, 1.03328776f, 0.920656383f, 0.416708469f, 0.585961521f, -0.339867949f, -0.258008152f, 0.811445177f, -0.135523498f, 0.0013273682f, + -0.594302714f, 0.115853675f, 0.034211129f, 0.226815686f, 0.0730306655f, 0.200779736f, 0.0354680493f, 0.0799727663f, 0.328944385f, 0.192251816f, + 0.105401233f, 0.023813501f, 0.0162849426f, 0.0670188516f, 0.230579749f, -0.130890459f, 0.107793599f, -0.20582974f, -0.232782975f, -0.16915682f, + -0.0672046244f, -0.203465775f, -0.0179140903f, -0.123698838f, -0.10872791f, -0.217727274f, -0.214406788f, -0.126469165f, -0.107491143f, -0.0687729418f, + -0.0377271883f, 0.0591251068f, 0.0388353243f, -0.0156471003f, 0.278827846f, -0.0377950147f, 0.237933412f, -0.0488711596f, 0.0339324102f, 0.0864377618f, + 0.226938993f, 0.0988695771f, -0.0903691202f, 0.0889346525f, -0.0966230854f, -0.176641762f, -0.0381229036f, -0.0202313233f, 0.178630307f, -0.264923871f, + 0.36340636f, -0.0707991868f, 0.119857416f, -0.0876048133f, -0.0585004129f, 0.374116868f, 0.131042227f, 0.328476697f, 0.0477033965f, 0.177047521f, + -0.116084315f, 0.0651718453f, 0.0341925807f, -0.0958952382f, 0.459944129f, -0.155857518f, 0.195794597f, 0.0673998743f, 0.174395859f, 0.311852992f, + 0.403165698f, -0.03160901f, 0.0696694031f, 0.187078625f, 0.309799135f, 0.337043256f, 0.25348103f, 0.443448275f, 0.242029682f, -0.256796747f, + 0.0691596493f, -0.00334975566f, -0.279522896f, -0.111387603f, 0.27992329f, -0.252598286f, -0.0878121182f, -0.0754157305f, -0.0845282152f, -0.403495729f, + -0.0673419461f, 0.0395382755f, -0.251345634f, -0.0346062593f, -0.03236074f, 0.403354943f, -0.265851021f, 0.327138066f, -0.0476572812f, 0.0208941326f, + -0.246567383f, 0.194854975f, -0.105358727f, -0.0263010357f, 0.136492684f, 0.13427408f, 0.0140548479f, -0.112830043f, -0.0111005278f, 0.143361509f, + 0.077422604f, -0.170926869f, 0.0953296125f, -0.118206501f, 0.0884102583f, -0.0203215312f, 0.496904165f, 0.0872106031f, -0.110801436f, 0.0523779541f, + 0.030336583f, 0.121502653f, 0.134403557f, 0.0632332638f, 0.102284253f, 0.0566462353f, -0.248582602f, -0.257816851f, -0.126349524f, 0.106656365f, + -0.0681326538f, -0.224459827f, -0.0530370139f, -0.276587218f, -0.321860015f, 0.0111818751f, -0.146936342f, -0.110153005f, -0.0575194284f, -0.00219013612f, + -0.0324476436f, -0.0540041588f, -0.577929735f, -0.424422085f, -0.304043233f, 0.392552048f, -0.0840322375f, -0.683541f, -0.143847704f, 0.533747673f, + 1.08496416f, -0.560750067f, -0.0721708164f, -0.192363098f, 0.145770684f, 0.0384769551f, 0.16611962f, 0.0918755084f, 0.051530052f, 0.23056376f, + 0.0299603008f, -0.229903266f, -0.204632536f, 0.13449654f, -0.00411641505f, 0.195536509f, -0.0424904749f, -1.0076102f, -0.182893798f, -0.120322019f, + -0.37391448f, 0.13873674f, 0.309966207f, -0.123458751f, 0.505632401f, -0.12687856f, -0.112844244f, 0.163506448f, 0.000829645956f, -0.0833938345f, + 0.0501746945f, 0.27116251f, 0.093361713f, 0.00331761688f, -0.133612856f, -0.480106741f, -0.155622154f, 0.00958703924f, 0.116534203f, 0.122792944f, + -0.0598214529f, 0.0896737576f, 0.489048243f, 0.177507937f, 0.4027282f, 0.3893058f, 0.128409773f, -0.160470903f, -0.355286926f, -0.399864107f, + 0.0337182954f, 0.192735985f, 0.00973715354f, 0.0244330391f, -0.0576038286f, 0.192101985f, -0.0437346362f, 0.0348619744f, -0.0207339209f, -0.164216444f, + 0.307010084f, 0.152568325f, 0.203703418f, 0.167089835f, -0.995042741f, 0.148674101f, 1.02190399f, 0.64612627f, -0.253626674f, 0.830720603f, + -0.513407707f, -0.877997458f, 0.271783501f, -0.819350064f, -1.17454886f, 0.585202098f, 0.195181653f, 0.194063902f, -0.0798772797f, 0.228789657f, + 0.23815459f, -0.024612207f, 0.100276239f, -0.21751292f, 0.315932691f, 0.150816232f, 0.303107947f, -0.382537365f, 0.166769445f, 0.396797508f, + 0.124812201f, -0.0860078558f, -0.180949003f, -0.157954857f, -0.0679153726f, -0.0523592606f, -0.164307386f, 0.130872011f, 0.461765736f, -0.130107105f, + 0.115250766f, -0.262812853f, -0.136637762f, 0.0590657666f, 0.474076509f, -0.125461146f, -1.44242823f, -0.0561153665f, 0.0293942336f, 0.103204928f, + -0.176134214f, 0.0682726502f, -0.495406896f, 0.103436381f, 0.0629040748f, -0.396417022f, 0.212351575f, 0.282956928f, 0.230823904f, 0.0998745635f, + 0.287678331f, 0.400533497f, 0.143281445f, 0.379132688f, -0.631471157f, -0.214981571f, -0.220695987f, -0.227752119f, 0.0893863589f, 0.108212359f, + -0.0704766735f, 0.148135096f, 0.298667073f, 0.233996004f, 0.302257091f, -0.0412210338f, -0.207917228f, -0.45689863f, 0.870308816f, -0.348576218f, + 0.158495918f, -0.754631937f, 0.588230789f, -0.0167272519f, 0.356533557f, -0.696774721f, -0.288119435f, -0.098565191f, 0.101819322f, 0.242441118f, + -0.0543161295f, 0.181965634f, -0.143922657f, 0.254550517f, 0.0045293672f, -0.0312086735f, 0.44788909f, 0.195771664f, 0.373756558f, 0.518196106f, + 0.243224546f, 0.133594766f, -0.147071049f, 0.0305735432f, -0.154937908f, -0.18450816f, -0.166966617f, 0.0387105867f, 0.417630225f, -0.513288915f, + -0.0405243561f, -0.158956289f, 0.083955124f, -0.183702946f, -0.210805535f, -0.0999723971f, -0.183483437f, -0.506311834f, 0.27930522f, -0.200268894f, + -0.116295889f, 0.0929720178f, 0.146828607f, 0.17211695f, 0.356871277f, 0.58907795f, -0.0960001647f, 0.0106026018f, -0.0477455184f, -0.338782519f, + -0.132188722f, -0.333090007f, -0.369517326f, -0.305375963f, -0.309628487f, -0.192456275f, 0.255153984f, -0.265883118f, 0.0222247373f, -0.0202726126f, + 0.211962223f, -0.109672382f, 0.0929111764f, -0.664055943f, -0.129270673f, 0.177694678f, -0.0355530344f, -0.315971226f, -0.580522716f, 1.26805627f, + 0.502606928f, -1.13063061f, 0.676544249f, -0.274410516f, -0.0495743938f, 0.133038431f, -0.213863567f, -0.0800693259f, 0.016845569f, 0.677071869f, + -0.10387969f, 0.116950862f, -0.117793195f, 0.0203814376f, -0.0274360236f, -0.216175884f, 0.0104331626f, -0.221400216f, -0.00448231073f, 0.114480406f, + 0.114612021f, 0.241621196f, 0.0635632575f, 0.00264769979f, -0.0948280171f, -0.177776888f, -0.0836451724f, -0.260512948f, 0.0844447017f, -0.307194024f, + 0.183905125f, -0.164850622f, -0.148439392f, -0.203316078f, -0.138020635f, -0.151591942f, 0.121790782f, -0.00481842924f, 0.0930970386f, 0.116226576f, + 0.0218743552f, 0.137129486f, 0.803830028f, -0.033967305f, -0.0427006856f, -0.0935880095f, 0.0333493799f, 0.143827513f, -0.740584314f, 0.00367988367f, + 0.359907746f, 0.124462537f, 0.0998263434f, 0.174555838f, 0.109161638f, -0.208635956f, -0.160273358f, 0.0430734046f, -0.0616604686f, 0.160981074f, + -0.000241925154f, 0.277326405f, 0.354895711f, 0.198913231f, 0.244714409f, 0.46209684f, 0.0152162947f, 0.198030695f, -0.0469215326f, -0.124353841f, + -0.756472886f, -0.489281476f, 0.102078706f, -0.502158761f, -0.135078564f, -0.373461246f, -0.454011202f, -0.721678913f, 0.432290673f, -0.199621633f, + 0.0558039062f, 0.0694706589f, -0.00872199889f, -0.0576945283f, 0.0922795534f, -0.025582239f, 0.172482148f, 0.31275624f, -0.0543217473f, -0.106067583f, + -0.244007722f, -0.0889380202f, 0.158122182f, -0.0114007723f, -0.141156837f, -0.109820835f, -0.200878292f, 0.171129197f, -0.0948949307f, 0.15417327f, + 0.19228065f, 0.221416205f, 0.46979782f, 0.580094934f, 0.256961048f, -0.17814894f, -0.00649817474f, 0.0295493156f, 0.319039166f, -0.00251971232f, + -0.0641416162f, -0.177903578f, 0.221303165f, 0.467008799f, -0.0358484946f, 0.075381726f, 0.0717307478f, 0.034040872f, 0.487554669f, 0.756221354f, + -0.0301674884f, 0.0440894887f, 0.0338330567f, -0.0467986688f, 0.326251328f, 0.333540678f, 0.058390744f, -0.200796962f, -0.265400559f, -0.0929172933f, + -0.0504758209f, -0.13342464f, 0.209845722f, 0.358789116f, 0.324919164f, 0.101196468f, 0.0247550346f, -0.094414264f, 0.100352913f, 0.0242747348f, + -0.0746866316f, 0.202638835f, -0.376211524f, 0.283201367f, 1.65670669f, -0.437693954f, 0.675470293f, 0.0295848344f, 0.325478017f, -0.22280775f, + -0.454023778f, 0.000892148644f, 0.0315324441f, -0.224356353f, -0.0381220207f, 0.0979854763f, -0.0453924909f, 0.25726679f, 0.134442225f, 0.259405315f, + 0.387674838f, -0.101078436f, 0.412818521f, 0.232169762f, -0.0114019476f, 0.283835679f, 0.276212484f, 0.00318502658f, -0.0542123057f, -0.0267556515f, + 0.826535225f, 0.335728109f, -0.156119302f, -0.0303225424f, 0.0175905284f, 0.0102733094f, 0.0044653276f, -0.0162722711f, -0.00817314722f, 0.0755745098f, + -0.0340374187f, 0.00792582892f, 0.0260253306f, 0.0353904143f, -0.0278882477f, -0.0484363399f, 0.400835723f, -0.00912219007f, -0.0331406072f, -0.0589315854f, + 0.041141659f, 0.0959891751f, -0.686217666f, 0.0856424347f, 0.0350263044f, -0.148475945f, -0.219226196f, -0.219991863f, 0.123340115f, -0.143633395f, + -0.0203752574f, 0.12116348f, 0.106109165f, -0.118062489f, 0.192165419f, 0.15498051f, 0.0168678202f, -0.132389367f, -0.191884577f, -0.0178915747f, + -0.181250736f, -0.04241753f, 0.12500076f, 0.062404301f, -0.156579822f, -0.127347335f, 0.591336906f, 0.172824562f, 0.409934253f, -0.605356038f, + 0.113397606f, 0.278923005f, -1.10030544f, -1.20372045f, 0.210897148f, -0.407905132f, -0.000733361521f, 0.103168324f, -0.077611655f, 0.186787441f, + 0.322786033f, -0.106080726f, -0.249039277f, 0.178946167f, 0.146632209f, -0.200722069f, 0.256384313f, 0.195997119f, 0.181951195f, 0.0107355807f, + 0.173782244f, 0.305276453f, -0.155269116f, 0.571909487f, -0.0296512526f, 0.123393632f, 0.0435554571f, 0.171860352f, 0.392693907f, -0.0334263518f, + -0.104534939f, 0.0031639142f, -0.211147964f, -0.104199432f, 0.071289964f, 0.0257088318f, 0.539912701f, -0.146972448f, 0.222321168f, 0.0311198942f, + 0.406307548f, 0.682808042f, 0.261038959f, 0.527953565f, -0.148585677f, -0.0600920804f, -0.0578245781f, -0.0820423141f, -0.0676971599f, -0.160799265f, + 0.370563149f, 0.0228595361f, -0.0104287257f, 0.015063012f, 0.0365297794f, 0.0614012629f, 0.319141388f, -0.0918317884f, -0.0397308506f, -0.0838939026f, + -0.0903114974f, -0.115013979f, -0.219196141f, 0.00370736211f, -0.0970862061f, 0.0655997396f, 0.777882338f, 0.0918346718f, 1.06368291f, 0.845378458f, + 0.1924676f, -0.226778314f, -0.169291228f, -0.590278685f, 0.176980317f, 0.65129143f, 0.328980774f, 0.445320189f, 0.0f, 0.0f, + 0.0f, 0.0458548404f, 0.0897907913f, -0.141011849f, -0.023004625f, -0.0203349423f, 0.0552762859f, -0.302541435f, -0.0561768375f, -0.070935294f, + -0.105499968f, 0.105184808f, -0.0499012582f, -0.0947716385f, -0.194515601f, -0.0864544287f, -0.0554887913f, 0.136673555f, -0.00151657953f, -0.226624578f, + -0.169792637f, -0.0458926223f, 0.352193177f, 0.492016077f, -0.0845105946f, 0.146342695f, 0.202062368f, -0.0715256482f, -0.115633778f, -0.0797739625f, + -0.00386887277f, -0.244762108f, 0.0672551692f, 0.161093608f, -0.0962780043f, 0.0545201898f, 0.0137167741f, 0.185466811f, 0.16616036f, 0.141488761f, + -0.0743243769f, -0.00519971829f, 0.140967235f, -0.144209221f, -0.0406353474f, 0.191139787f, 0.086223416f, -0.0953981876f, 0.0416129157f, -0.0241755489f, + 0.0199999996f}, + {0.261185527f, 0.896236956f, 0.170338765f, -0.330902934f, 0.199542448f, 0.102508239f, -0.114888526f, 0.161871001f, 0.119715326f, 0.0442480855f, + -0.00798505824f, 0.125909612f, -0.161367163f, -0.0122157549f, -0.0781270638f, 0.122839183f, -0.000382336671f, -0.0691721514f, -0.172866315f, -0.0389033966f, + 0.0301657021f, -0.0753539875f, 0.316279441f, 0.241802141f, -0.643897712f, -0.471882671f, -0.108076274f, -0.114441842f, 0.0568250157f, 0.0514301062f, + 0.490549266f, -0.291802526f, -0.158185035f, 0.454361737f, 0.146199673f, 0.147537217f, -0.13584201f, -0.420746833f, -0.0263607055f, -0.0219764411f, + -0.322551876f, -0.175376475f, -0.00447956147f, -0.178390697f, 0.0492753871f, -0.0282022636f, -0.0273222048f, -0.135452256f, 0.151567683f, 0.254540831f, + 0.149522528f, -0.23140128f, 0.146863103f, -0.127063632f, 0.221992925f, -0.209719107f, 0.284079164f, -0.0244463459f, 0.099832274f, -0.1150916f, + 0.023876369f, -0.690474808f, -0.084991239f, 0.0274384934f, 0.157501683f, -0.603641033f, -0.570149839f, -0.00113502599f, -0.569260836f, 0.134541333f, + 0.558632076f, -0.975999475f, 0.0140848411f, -0.0101664653f, -0.0224573836f, 0.175046965f, 0.440782309f, 0.124595433f, -0.0896555781f, 0.152855441f, + 0.0403161682f, 0.317083269f, 0.0843774751f, -0.110267282f, 0.0681362748f, -0.268067509f, 0.0272889026f, 0.0688102171f, -0.443098724f, -0.467912734f, + 0.0815185681f, 0.439284652f, 0.168918863f, -0.331666768f, -0.178152904f, -0.110558853f, 0.106537707f, 0.106643759f, 0.0592486188f, -0.488608539f, + -0.125500873f, -0.806285977f, -0.109000005f, 0.167682737f, -0.122825146f, 0.135850698f, -0.03257332f, 0.328810066f, -0.0533195958f, -0.146613732f, + -0.10733179f, -0.060114231f, -0.297011375f, -0.409296274f, 0.38770768f, -0.00507438974f, -0.0821120292f, -0.0438192524f, -0.083350651f, 0.189579248f, + 0.0109111769f, 0.0337609723f, -0.102405794f, 0.223902836f, -0.174643219f, 0.201029241f, 0.405694067f, -0.33918339f, -0.600779831f, 0.0428304188f, + 0.0139941107f, -0.0732774362f, 0.187360048f, 1.41879725f, -0.432936102f, -0.702861488f, 0.927979708f, -0.240818441f, -0.12564306f, 0.395673484f, + 0.442311645f, -0.189715579f, 0.33460319f, 0.191584542f, 0.0178458132f, -0.00332962302f, -0.00350978714f, -0.143523201f, 0.0665746555f, 0.00435494352f, + -0.00236499193f, -0.0657988042f, -0.624322474f, 0.219336584f, 0.0137178488f, 0.0473014116f, 0.0886623859f, -0.0105016539f, -0.159752339f, 0.0130271791f, + 0.0296008475f, -0.131707296f, 0.234959826f, 0.0345524512f, -0.559862435f, -0.207883582f, -0.141111612f, 0.391533673f, -0.313200235f, -0.0566308387f, + -0.497264504f, 0.0494126938f, 0.212533548f, -0.0469509996f, -0.169011965f, 0.0225455724f, 0.154775098f, 0.0652958527f, 0.281113565f, -0.0958993062f, + -0.238974124f, -0.148654863f, -0.0702897087f, 0.044212196f, -0.188447699f, -0.0675809681f, -0.26381436f, 0.241053969f, -0.117423147f, -0.229337692f, + 0.131802559f, 0.27707088f, 0.120754018f, 0.00434506079f, -0.238942698f, 0.61961472f, 0.214402005f, -0.151216105f, 0.0941592231f, 0.0578566268f, + -0.630641639f, -0.0264866389f, -0.084773995f, -0.0801019818f, 0.0685022846f, -0.216792673f, 0.570531964f, 0.0488477349f, -1.56394064f, -0.137504146f, + -0.824264705f, 0.450850755f, 0.0905093402f, 0.471261591f, -0.563372731f, 0.870842159f, -0.00552377524f, 0.0370740257f, -0.00388307986f, 0.11300879f, + -0.01477955f, 0.0240729973f, -0.24773261f, -0.354918927f, -0.273137152f, -0.00570347533f, -0.282965153f, -0.209084809f, -0.0226430576f, -0.214997992f, + -0.039817214f, 0.0321194753f, 0.0558634326f, -0.27992481f, 0.0591310188f, 0.0223985761f, 0.0370752029f, 0.0511436872f, 0.0236392114f, -0.0231786408f, + 0.0746628866f, -0.0826963708f, -0.749490619f, -0.0517104827f, 0.00435318751f, 0.163653255f, 0.043380104f, 0.224053875f, -0.12905401f, 0.0793882981f, + 0.0826037601f, -0.126775697f, -0.154891506f, -0.243982375f, -0.137889653f, 0.143072411f, -0.161947772f, -0.0728921071f, -0.144827604f, -0.181048214f, + 0.460544169f, -0.381222725f, 0.246348158f, -0.0820818543f, -0.25638324f, 0.044204589f, 0.132468835f, -0.0735270903f, -0.184564024f, 0.154117137f, + 0.229873583f, 0.0713132247f, 0.0760232955f, -0.0586268529f, 0.120144971f, -0.00919226278f, -0.273349881f, -0.480227143f, 0.180627972f, 0.201901406f, + -0.21603927f, -0.539798796f, 0.235333964f, -1.04852235f, -0.338369817f, 0.236158803f, -0.785497725f, -0.0464777164f, 0.0103703951f, 0.0106996391f, + 0.0316747129f, -0.10776902f, 0.260860741f, -0.0752684548f, -0.271688193f, -0.204912707f, -0.976891398f, 0.099860087f, -0.134729251f, -0.0460652187f, + 0.415874332f, 0.458501399f, -0.718125939f, -0.0251469407f, 0.112594001f, 0.0700355917f, -0.0367189907f, 0.174319237f, -0.439237595f, -0.0210973378f, + -0.0472756959f, 0.0180361141f, -0.16060181f, -0.0900646448f, -0.785499334f, -0.0315420851f, -0.0377420709f, -0.0248522591f, 0.181107342f, 0.321680963f, + -0.634399414f, 0.0818780437f, 0.0643855333f, 0.107079595f, -0.212999508f, -0.338351578f, -0.488398314f, 0.0125352154f, 0.246245593f, -0.0636448935f, + 0.484909117f, -0.0596835539f, 0.180209458f, -0.0835012868f, 0.147226095f, 0.108583502f, -0.00921553187f, -0.270531029f, 0.0137474965f, -0.0360540822f, + -0.200607508f, -0.0234327074f, -0.252534747f, 0.353253841f, 0.120542496f, 0.0422595479f, -0.00350717362f, 0.00867851637f, -0.0566466488f, -0.35572052f, + -0.14041616f, -0.166073143f, -0.572652578f, -0.327378482f, 0.197061688f, -0.316584647f, 0.408613324f, 0.600702822f, 0.355141699f, 0.246526837f, + 0.0455884598f, -0.00648856536f, 0.0018915619f, -0.212421373f, -0.00589415804f, -0.241933405f, 0.088649191f, 0.589264274f, -0.720220923f, 0.0798267275f, + -0.0114054866f, 0.0928160176f, -0.245670572f, -0.103564709f, -0.170153052f, -0.161670253f, 0.0158154294f, -0.189556271f, -0.118009858f, 0.145786211f, + -0.189991593f, -0.243726149f, 0.160246462f, 0.00741628977f, 0.0479184948f, -0.104859933f, 0.281476527f, -0.110599548f, 0.139590979f, 0.030032767f, + 0.114664301f, 0.314406276f, -0.0443991981f, -0.202102765f, -0.152644679f, 0.00802704226f, 0.0778448731f, -0.285671026f, -0.109589659f, 0.0331086107f, + -0.0393290669f, -0.388642937f, -0.0779758245f, 0.0868967548f, -0.259929508f, -0.0147474138f, 0.0299106259f, 0.121317312f, -0.0451540053f, 0.00314560137f, + 0.0793214738f, 0.0618255995f, -0.0791575015f, -0.217493892f, -0.050560046f, 0.0186694041f, -0.191392675f, -0.01845273f, -0.0454145335f, 0.0334029496f, + 0.297378272f, 0.279974043f, -0.240992785f, 0.290005386f, 0.128083423f, 0.0487299226f, 0.00672829058f, -0.0928049758f, -0.371607333f, 0.10498327f, + 0.248657823f, -0.526602864f, 0.0560479164f, 0.00459098211f, -0.0007826371f, 0.0455649868f, -0.264622122f, -0.0215607267f, -0.0918087065f, 0.397833437f, + -0.256877661f, -0.0344146825f, 0.0903921872f, 0.0244074687f, 0.0607045293f, -0.138613015f, -0.443862379f, 0.019365197f, -0.0885707289f, -0.0578217022f, + -0.135146007f, 0.165455207f, 0.111198708f, -0.227545023f, 0.106510781f, 0.0560257211f, -0.0462862216f, -0.0143177668f, -0.0638412312f, 0.10480383f, + -0.00325207715f, 0.112517133f, 0.189498216f, -0.111475378f, 0.134973034f, 0.0735263675f, 0.258886665f, -0.182119772f, -0.0453580692f, -0.115459286f, + -0.0400189534f, -0.0731465593f, 0.00169785065f, -0.108622923f, -0.263742298f, -0.341181666f, -0.268216997f, 0.0330583863f, 0.0395105965f, 0.135103688f, + 0.166525781f, -0.0790969878f, -0.294942498f, 0.116312154f, 0.126776323f, 0.218765929f, 0.00356068602f, -0.281999737f, 0.407787085f, -0.108037315f, + -0.149893805f, 0.0923206136f, -0.120909616f, -0.34714666f, -0.414509684f, 0.142343596f, 1.04284883f, 0.0480163507f, 0.526505947f, 0.970466793f, + -0.0473623537f, 0.880560219f, 0.422143489f, -0.0971000716f, 0.0342291594f, 0.00291882758f, 0.0254644249f, 0.055938635f, 0.0351311378f, 0.0307228677f, + 0.0858471468f, 0.240028366f, 0.423501343f, -0.244574413f, 0.0162210967f, -0.274822026f, 0.172764435f, 0.321208477f, 0.342032373f, 0.0405641794f, + 0.13380301f, -0.152997956f, -0.0504622795f, 0.108097009f, 0.206285223f, -0.0860003531f, 0.460887998f, -0.0935140401f, 0.214240506f, 0.298024327f, + -0.147793859f, -0.148021221f, -0.178545907f, 0.154208899f, 0.332623333f, 0.0712074265f, -0.103742778f, 0.100652404f, 0.301757872f, -0.428463638f, + 0.00378911756f, -0.0567252561f, -0.175952494f, 0.441137433f, -0.357377857f, -0.258178204f, -0.295191884f, 0.228396207f, -0.262583286f, 0.171428129f, + 0.225313112f, 0.179430619f, -0.219141051f, -0.110391326f, 0.385351598f, -0.256900489f, -0.155697018f, -0.0496042818f, 0.105873927f, -0.0852345526f, + -0.00911038928f, 0.0260505434f, 0.035076309f, 0.00431934604f, -0.748278797f, 0.237625271f, 0.268473864f, -1.48628473f, 0.682120323f, 1.24880791f, + -0.263095915f, -0.0147471726f, 0.63414371f, -1.10403264f, -1.10782254f, -0.741034091f, 0.0315411687f, -0.00722226733f, 0.0629718006f, -0.154688925f, + -0.153307348f, 0.129599079f, 0.0536501668f, -0.331586838f, 0.107241929f, 0.343752682f, 0.180624798f, 0.139754191f, -0.0375091098f, 0.209178716f, + -0.279802322f, 0.0702509806f, -0.104463145f, 0.247357085f, 0.0925415978f, -0.297714025f, 0.107933037f, 0.175262287f, -0.406024069f, -0.19804129f, + -0.223293915f, -0.420134485f, 0.177295536f, 0.321961492f, 0.17618522f, 0.0443556234f, 0.052356001f, 0.120982729f, -0.0408258997f, 0.115022965f, + 0.226111382f, 0.283900559f, -0.243245482f, -0.118278868f, -0.209087431f, 0.493023247f, 0.227067485f, -0.164289296f, 0.19353953f, 0.396782726f, + 0.0871779546f, 0.325566769f, 0.251866907f, -0.0433513038f, -0.133801684f, -0.38812983f, -0.202820733f, 0.0395802818f, 0.113783568f, -0.11928843f, + 0.0517826118f, 0.0308256764f, 0.16308333f, -0.0331571698f, 0.0738897324f, -0.0308708716f, 0.34621647f, -0.606991887f, -1.22570717f, -0.497222394f, + 0.272338122f, -1.34711909f, -0.065292418f, -0.252698004f, -0.6552912f, -0.757568419f, -0.104061671f, -0.04527165f, 0.160085917f, -0.0274412539f, + 0.0674389973f, 0.208484739f, -0.0187354926f, -0.379184783f, -0.274079353f, 0.197949916f, 0.727449596f, 0.0149689894f, -0.0648000464f, 0.378086984f, + -0.0728200972f, 0.0321487263f, -0.0600346774f, -0.0476983637f, 0.605401337f, -0.261396617f, 0.0122365914f, -0.39341107f, -0.100089788f, -0.0687510669f, + 0.0311659947f, 0.0203078855f, 0.140630335f, 0.10887298f, 0.328427404f, -0.0280387942f, -0.172513455f, -0.222758621f, -0.179034278f, 0.0125983609f, + -0.278899193f, 0.245620981f, 0.0338288806f, 0.00551719777f, -0.185951859f, 0.120071411f, -0.325026006f, 0.00763959438f, 0.0715669766f, -0.0181578249f, + 0.0193239637f, -0.0490490533f, -0.0517327003f, 0.165787145f, 0.196242481f, 0.279876679f, 0.0807588026f, 0.207602486f, -0.496830463f, 0.0391024686f, + -0.0236364361f, -0.0634056106f, 0.067698434f, 0.236707285f, 0.79214716f, 0.0396427326f, 0.106119573f, 0.150553927f, -0.439454526f, -0.698253512f, + -0.412873387f, 0.010063176f, -0.305105656f, -1.00433457f, -0.197659984f, 0.805686891f, -1.35723293f, -0.345164239f, -0.834847391f, 0.559808671f, + 0.181590334f, -0.0614222735f, 0.0755641311f, -0.131911755f, -0.272917151f, -0.268127829f, 0.0536959097f, -0.144405231f, 0.800887108f, 0.202978f, + -0.166106462f, 0.0797505379f, -0.28713131f, -0.12872155f, 0.808802962f, 0.12280795f, -0.0985100344f, 0.116127789f, -0.308929712f, -0.0622650422f, + -0.656992614f, 0.128816575f, -0.162194639f, 0.404067218f, 0.0636960045f, 0.166952282f, -0.243888214f, -0.0890791193f, 0.197880521f, -0.473539203f, + -0.183703512f, 0.158343628f, -0.00672436273f, 0.105056442f, -0.0314422473f, -0.00981708895f, -0.204578146f, -0.213033795f, -0.351601303f, -0.219341427f, + -0.306847751f, 0.00966667943f, -0.395491391f, -0.499062628f, 0.500340939f, 0.256829202f, -0.11211814f, -0.238173828f, -0.305406034f, 0.23513265f, + 0.417110175f, 0.104772359f, 0.0295741782f, 0.0755354911f, -0.44068566f, 0.125852153f, -0.770450115f, -0.0302091688f, 0.057240326f, -0.13393788f, + -0.199168563f, -0.100776426f, 0.898360729f, 0.624099016f, 0.73072207f, -0.214713737f, 0.812274158f, -0.243554145f, -0.384876132f, -0.448866487f, + -0.355244368f, 0.510475039f, 0.153592333f, -0.0971018523f, 0.126586661f, 0.0812553912f, 0.182973504f, 0.0471726991f, -0.0523986667f, -0.162792563f, + -0.0629014f, 0.00294229435f, -0.0555977561f, -0.172569811f, 0.0902513862f, -0.343124926f, 0.0356321298f, -0.0466163903f, 0.00573288742f, -0.30368641f, + 0.158047587f, 0.0539830476f, 0.0548924804f, 0.116398424f, -0.0626142174f, -0.104147688f, -0.143030062f, 0.179653466f, 0.241342008f, -0.0485922769f, + -0.0319267623f, -0.00733043766f, 0.109633319f, -0.149078012f, -0.0488778502f, 0.117656514f, -0.0771025643f, -0.0426457003f, 0.0191918891f, -0.178920567f, + -0.0875288546f, 0.102587938f, 0.234850377f, 0.378978461f, -0.0522091426f, -0.361588478f, 0.152112857f, -0.0708849132f, -0.0935997367f, -0.354615718f, + -0.035755761f, -0.487995565f, -0.0768143758f, -0.289668053f, -0.0128632691f, -0.35176f, -0.15238151f, 0.274332583f, 0.00793904252f, 0.0147834895f, + 0.0405295081f, 0.046551846f, 0.468642503f, 0.0173071716f, -0.428806692f, -0.774888694f, 0.643130839f, 0.256259888f, 0.669935226f, -0.455318332f, + -0.0270849075f, 0.045303043f, 0.619042993f, 0.792803347f, 0.154276267f, -0.0541753545f, 0.0788252726f, -0.214515179f, -0.104989842f, -0.216178492f, + 0.0882944688f, -0.114915535f, -0.0242388602f, -0.0313234963f, -0.296944141f, -0.251841933f, 0.2691122f, 0.125576809f, 0.0119392406f, -0.157994255f, + 0.0431018434f, 0.277738422f, -0.166480944f, -0.0300732441f, -0.36916098f, -0.00149635226f, 0.0283021405f, -0.0184523501f, -0.0283691902f, 0.0220206417f, + -0.13895008f, 0.0173328668f, -0.0546804368f, -0.0463809632f, 0.045239117f, -0.0702845827f, 0.409830362f, -0.00242642825f, -0.0265169349f, 0.0659652576f, + 0.08854568f, 0.0834278464f, 0.221201435f, -0.018359432f, -0.0215335004f, 0.0293920971f, 0.0147089735f, -0.28265354f, 0.212274447f, -0.00511118257f, + 0.0131783038f, -0.0132546714f, -0.162930205f, 0.111015357f, 0.00982464571f, -0.0300267842f, -0.0476577543f, 0.153131545f, 0.15663825f, -0.378268898f, + -0.282983154f, -0.133299574f, 0.0401792638f, -0.11680112f, -0.820995867f, -0.353250325f, 0.498553753f, 0.0424014702f, 0.496413291f, -0.364988238f, + 0.0604630075f, -0.285732776f, 0.520472288f, 0.719358742f, -0.240321755f, 1.66272819f, 0.0958441496f, -0.0962347239f, 0.100093268f, -0.175574735f, + -0.134562656f, 0.121302634f, -0.0554759204f, -0.0442088358f, -0.115209259f, 0.196740329f, -0.0656225979f, -0.0210957453f, 0.0171511099f, -0.427629292f, + -0.0139925331f, -0.181985989f, 0.0681574866f, -0.104503572f, 0.000375562231f, -0.0701221377f, -0.0618544891f, 0.0368236527f, -0.271640718f, -0.0946147218f, + -0.0093268929f, -0.35796383f, -0.0759957284f, 0.346813291f, 0.143673927f, 0.380036771f, -0.273213089f, 0.471682817f, -0.00970017072f, -0.178792179f, + -0.0734313503f, -0.229520112f, 0.393782437f, -0.0878822654f, -0.129330054f, -0.245512873f, 0.102546565f, -0.193516791f, -0.251545608f, -0.014448097f, + -0.226480335f, 0.0890534148f, 0.423194885f, -0.213539213f, -0.0918143615f, -0.244643509f, 0.126828536f, 0.0611949265f, -0.48636505f, 0.314628065f, + -0.222034827f, -0.246842638f, -0.163790539f, -0.0503128357f, -0.0917721316f, -0.185129419f, 0.5650509f, -0.735080898f, 0.193814442f, -0.66699636f, + 0.594456017f, 0.0574356876f, -0.0685883686f, 0.496528894f, -0.551997364f, -0.137789771f, 0.907627225f, -0.0882594511f, 0.0226486772f, -0.0515324511f, + 0.068179056f, 0.282298267f, 0.106264599f, -0.0601794049f, -0.011867824f, 0.0173964221f, -0.0666826665f, -0.122256473f, -0.102566235f, -0.16066967f, + 0.0557763204f, 0.0358818509f, 0.0671432167f, -0.307293236f, 0.113098599f, -0.0292488225f, -0.178754106f, 0.0315251723f, 0.087109223f, 0.0138561316f, + 0.0275376774f, 0.0619708635f, 0.0568683036f, -0.0608201735f, -0.290911853f, -0.11686641f, -0.0379719846f, -0.196320236f, 0.00919874012f, 0.117136046f, + -0.00716516655f, 0.230361328f, -0.184774995f, 0.101695515f, -0.101679832f, -0.142543972f, 0.0792957619f, -0.093704313f, 0.147152781f, -0.135807276f, + 0.0561773293f, -0.0604898781f, 0.00584899448f, -0.0347878039f, -0.214949355f, -0.0290753078f, -0.0271701738f, -0.01563197f, 0.185976461f, 0.151457533f, + 0.00915175583f, -0.0788729489f, 0.256194741f, -0.140876502f, 0.0921951309f, 0.123320587f, 0.386896282f, 0.143745303f, 0.0899944603f, -0.0217246525f, + -0.186856404f, -0.0894812942f, -0.107078128f, 0.244900212f, 0.0392758474f, -0.171999678f, -0.341921449f, -0.329158455f, -0.227119237f, -0.0259333029f, + -0.210690707f, 0.133965045f, -0.165988058f, -0.241084844f, -0.234752938f, 0.0826799348f, -0.110588044f, 0.0413496755f, -0.385273397f, -0.101577789f, + 0.372469544f, -0.0282890219f, 0.0143749574f, 0.0787581578f, -0.204746947f, 0.114046484f, -0.122685306f, -0.200572342f, -0.0472829603f, -0.203703895f, + -0.183209524f, -0.144936129f, -0.0049776081f, -0.171371356f, 0.321736932f, -0.067040801f, -0.0353748798f, 0.0232453477f, -0.100440942f, -0.166329086f, + -0.0422085263f, 0.0996678695f, 0.185207918f, 0.394513994f, 0.268327802f, 0.231377929f, 0.13737759f, -0.156778321f, -0.00226093573f, 0.0207840409f, + 0.166936636f, -0.202871099f, -0.0974776149f, -0.0967016965f, -0.0036113488f, -0.222243622f, 0.161299691f, -0.124452375f, 0.51393193f, 0.624659538f, + 0.465430349f, -0.156094089f, 0.186500013f, -0.0891926065f, -0.154866457f, -0.0747344792f, -0.0572509244f, 0.0752951503f, 0.196438655f, -0.20863919f, + 0.00790116377f, 0.130220726f, -0.0304389205f, -0.0401399247f, -0.336381912f, 0.0554717705f, -0.179501444f, 0.0307538603f, 0.0506599545f, -0.596079528f, + 0.000845863891f, -0.127654657f, 0.857344985f, 0.31268996f, 0.538229585f, -0.287800968f, -0.373028755f, 0.565736532f, -0.102005661f, -0.0192061234f, + -1.13855481f, 0.086252518f, -0.0435393415f, 0.164799571f, -0.0251159873f, -0.0152954739f, -0.0908372104f, -0.178940162f, 0.000230070291f, -0.0706408545f, + 0.0256783795f, -0.123466842f, -0.0445464142f, 0.0156681892f, 0.11985825f, -0.0998636708f, 0.0657703727f, -0.128577232f, -0.143334061f, 0.0722451359f, + -0.02689882f, 0.0824172124f, 0.101467259f, 0.0900587589f, -0.0655491799f, 0.137704611f, 0.208368927f, -0.0355240181f, 0.0517312028f, -0.145583734f, + 0.0598792136f, -0.00934811123f, 0.126606449f, -0.214223102f, 0.229166478f, -0.0290193968f, 0.180197537f, -0.0675602555f, 0.0304522868f, 0.0150327552f, + 0.143877983f, 0.0776066929f, -0.0395734236f, 0.142123193f, -0.0481754653f, -0.14557068f, 0.0883044899f, -0.00924800057f, 0.383012712f, 0.0351959243f, + 0.133050978f, 0.147752762f, -0.0153647801f, -0.0457287021f, -0.108140297f, -0.0363371633f, -0.048047591f, 0.00275055831f, -0.0978542715f, -0.0304032974f, + -0.140735179f, 0.076320976f, 0.0386840031f, 0.0841514692f, -0.0137840603f, -0.0357961282f, 0.0644277111f, 0.0458673835f, -0.0801452696f, 0.0174855068f, + -0.00964540616f, 0.0261384193f, -0.132229775f, 0.0608623922f, 0.0192520004f, -0.106568672f, -0.0876312554f, -0.235796794f, -0.70197165f, -0.0069093206f, + 0.137956396f, 0.182768598f, 0.00160963729f, -0.11020726f, -0.0147029255f, -0.085057646f, 0.0172587447f, -0.0628964081f, 0.0644855276f, -0.099280268f, + 0.00406285748f, 0.103343248f, 0.13908416f, 0.18891795f, -0.136030316f, 0.0461179651f, -0.192365229f, 0.0843814239f, -0.0131205656f, -0.114341743f, + -0.32509765f, 0.00560654886f, -0.368766904f, -0.20465745f, -0.108947486f, -0.0307114497f, -0.285534799f, -0.248913065f, -0.28611204f, 0.0711003616f, + 0.323414087f, -0.0267341956f, 0.379969239f, -0.114549555f, 0.131349891f, -0.169380993f, 0.195448428f, -0.16587615f, -0.10237252f, -0.00809231494f, + -0.117032357f, -0.0986806899f, -0.189328432f, -0.163563341f, 0.0729920194f, 0.0237494241f, -0.25180462f, -0.304950505f, -0.024933422f, 0.143566832f, + 0.0313514136f, 0.0439313985f, 0.0780206472f, -0.229951978f, -0.0407980233f, 0.0897220597f, 0.00855677202f, 0.0527190752f, -0.00290674064f, -0.0139950961f, + 0.20812051f, -0.0971516669f, -0.140770793f, -0.67681396f, -0.575155914f, 0.06697914f, -0.0289284568f, -0.467576385f, -0.156838715f, 0.306171924f, + 0.979943752f, -0.725835681f, 0.274389178f, -0.220751837f, 0.0707841441f, -0.0352517627f, 0.175644934f, 0.435504764f, 0.289118588f, 0.425698429f, + 0.201830015f, -0.0150458561f, 0.0126208588f, 0.450626463f, 0.32401073f, 0.548214674f, 0.335053623f, -0.253366292f, 0.114199519f, -0.352420211f, + -0.538136959f, 0.0642294809f, 0.101515263f, -0.237412065f, 0.301437467f, -0.0289346725f, -0.0987999514f, 0.20138602f, 0.0347921066f, -0.0939375833f, + -0.0666765571f, 0.171050668f, 0.123459928f, -0.0496562198f, -0.500437498f, -0.377694309f, 0.0874409899f, -0.23344253f, 0.0234393384f, 0.284771115f, + 0.00998348277f, 0.227717787f, 0.494710952f, 0.229547843f, 0.353763044f, 0.260855198f, 0.116621293f, -0.0294636488f, -0.217731878f, -0.109377332f, + -0.0314268805f, -0.175810754f, -0.270490289f, 0.100223072f, -0.368914545f, 0.175762832f, -0.0104488246f, 0.156681433f, 0.099962227f, -0.144495189f, + 0.543401778f, -0.0363075472f, 0.0148617933f, 0.203363016f, -0.959693491f, -0.0526632667f, 0.698668957f, 0.447243154f, -0.081349276f, 0.801781118f, + -0.866630197f, -0.568688989f, 0.332183391f, -0.827428758f, -1.09676027f, 0.459131479f, 0.119865276f, -0.00768060051f, 0.0940355584f, 0.0605668873f, + 0.0575886257f, -0.186026156f, 0.0608951263f, -0.205507532f, 0.461323798f, 0.0425076298f, 0.149080485f, -0.504132092f, 0.159037516f, 0.282768995f, + 0.0658006594f, -0.023629142f, 0.0447105169f, -0.0896516666f, 0.323145241f, 0.376940876f, 0.174169794f, -0.119114339f, 0.386568666f, -0.309983045f, + 0.0134029444f, -0.109610513f, 0.231430665f, 0.29304412f, 0.105928361f, 0.154263481f, -0.246034727f, 0.352476269f, 0.0369536318f, -0.146229729f, + -0.0610069036f, -0.0604832694f, 0.133169949f, -0.0634374917f, -0.169021755f, -0.571579456f, -0.05821326f, 0.100026973f, 0.075198248f, -0.00682039652f, + 0.330740243f, 0.285376608f, 0.139300093f, 0.361328244f, -0.194624394f, 0.0873722807f, -0.412204176f, -0.5116027f, -0.127419114f, 0.205481097f, + 0.196692675f, -0.415005684f, -0.405596465f, 0.124970049f, -0.207206592f, -0.228518993f, 0.046886038f, -0.00752059836f, 0.281156331f, 0.0778796226f, + 0.625333965f, -0.771639585f, 0.29634732f, -0.414226115f, 0.729987085f, -0.635870814f, -0.0118029276f, 0.59068948f, 0.196338534f, 0.0551726706f, + -0.0613083914f, 0.124416314f, -0.283795506f, 0.315039098f, 0.0343042165f, -0.152786419f, 0.396263778f, 0.0322139449f, 0.176825896f, 0.373382419f, + 0.0523176268f, -0.136073083f, -0.174451157f, 0.177919105f, -0.00543772057f, -0.0951664075f, -0.0237642303f, 0.134214014f, 0.377221882f, -0.173601225f, + 0.103336178f, 0.00401021354f, 0.0872557461f, 0.104176767f, 0.0337390751f, -0.148493692f, -0.15114902f, -0.258394241f, -0.236797646f, -0.142174065f, + -0.80147624f, -0.163694859f, -0.012350481f, -0.0110763768f, 0.112499982f, 0.104156733f, -0.676324844f, 0.425136566f, -0.0891188085f, -0.325407982f, + -0.138893455f, -0.10636989f, -0.0193373971f, 0.171028197f, -0.174018487f, 0.153276518f, 0.190725148f, 0.125198588f, -0.143752009f, 0.147951767f, + 0.485654891f, -0.205902085f, 0.19451873f, -0.313722223f, -0.152186379f, 0.102090396f, 0.119703531f, 0.186912358f, 0.0198998377f, 1.24446905f, + -0.98595643f, -0.991975129f, 0.618011653f, 0.00502604339f, 0.101554342f, -0.0889555663f, 0.292044699f, -0.070850268f, 0.0372430906f, 0.048032295f, + 0.0904017091f, 0.114938825f, -0.110342719f, 0.0526529029f, -0.00911239069f, -0.0268706307f, -0.126174763f, -0.183599576f, 0.457185298f, 0.0979749113f, + 0.00241230056f, 0.184889629f, -0.0334757008f, -0.0215115789f, 0.0616665483f, -0.0417971648f, -0.00388842938f, -0.180009186f, -0.101601727f, -0.0452780053f, + -0.260946006f, -0.610628486f, -0.378932327f, -0.172217086f, -0.145609841f, -0.501830399f, -0.115533754f, 0.154708326f, 0.202736631f, -0.183018908f, + -0.0690261722f, -0.283487797f, 0.29741025f, 0.332894713f, 0.0347315371f, -0.135610282f, 0.296295166f, 0.415174961f, -0.431570798f, 0.208674937f, + 0.446940154f, 0.201720193f, 0.0763900355f, 0.0763155222f, 0.138383389f, 0.00157194084f, 0.147875488f, 0.117824808f, 0.0637821183f, 0.153707221f, + -0.719499469f, 0.0329043344f, 0.181867599f, -0.0437332615f, 0.157641947f, 0.265900612f, -0.194270328f, 0.411422312f, 0.128361732f, 0.144830316f, + -0.357994258f, -0.51232475f, -0.440753281f, -1.00182676f, -0.123285398f, 0.0425751656f, -0.443559229f, -0.886866271f, 0.603559971f, 0.199437201f, + 0.131643817f, -0.157521963f, 0.0233483594f, -0.129989982f, -0.0279935077f, 0.022281047f, 0.0460156277f, -0.0814636275f, -0.4034082f, -0.294438124f, + 0.00623764656f, -0.1143272f, 0.487341046f, -0.140773669f, -0.455420732f, -0.409143269f, -0.379860044f, 0.0206336584f, -0.0611772984f, 0.290609688f, + 0.508339942f, 0.38005656f, 0.222366527f, 0.2008439f, -0.0355829559f, -0.427789479f, -0.034017425f, 0.067815274f, 0.185312241f, 0.176281273f, + 0.0826884061f, -0.256043047f, -0.296122372f, -0.147079691f, -0.0905212909f, 0.344145685f, 0.337163895f, 0.151234984f, 0.168740258f, 0.260502279f, + 0.197672084f, 0.0750121176f, 0.10899844f, 0.195953131f, 0.281281352f, -0.0466922f, -0.0710619316f, -0.138331011f, -0.0801873803f, 0.0304917432f, + 0.395708472f, 0.0783783942f, -0.166093424f, 0.140060976f, -0.0005903907f, -0.0703246444f, -0.160712048f, -0.235454336f, 0.292686194f, 0.173383206f, + -0.171640962f, 0.221493289f, -0.0204905272f, -0.43652004f, 0.494191557f, -0.332610011f, 0.427477568f, -0.189693466f, 0.102042697f, -0.274582028f, + 0.609279633f, 0.0428031534f, 0.212277904f, -0.553916037f, 0.0726739988f, 0.184942514f, -0.107535824f, -0.0268543661f, 0.115160458f, 0.269437164f, + 0.0273179505f, -0.260253251f, 0.898743331f, 0.0896770805f, -0.0927004591f, 0.348708689f, 0.263304979f, -0.280758739f, -0.225737184f, -0.138686284f, + 0.112805344f, -0.094666943f, -0.178090215f, 0.0852945894f, -0.487968802f, -0.104722567f, -0.122023582f, -0.513671398f, 0.0144542856f, 0.278276831f, + -0.214290768f, 0.0278955996f, 0.0888625979f, -0.37808308f, -0.253313482f, -0.322202086f, -0.198934615f, 0.259812474f, -0.031065587f, 0.290909976f, + 0.297810853f, 0.0368144736f, -0.170884266f, 0.165565819f, -0.0032650854f, -0.348188013f, 0.00901716761f, 0.121860333f, 0.108194031f, -0.139635071f, + -0.0512389727f, 0.243301541f, 0.0910048708f, -0.155052751f, 0.0929851532f, 0.0259271674f, -0.0091913864f, 0.130788013f, -0.0487637036f, -0.134134844f, + -0.130342066f, 0.186239675f, -0.088472195f, 0.0614632815f, -0.146952853f, -1.14881146f, -0.0507233106f, -0.121522509f, 0.326650172f, 0.0321275219f, + -0.139410287f, 0.255765706f, -1.25248003f, -0.910977542f, 0.137958169f, -0.269724101f, -0.0591546968f, -0.0347430557f, -0.0826679245f, 0.0771473199f, + 0.223254114f, -0.103661135f, -0.198615268f, -0.131910294f, 0.110365182f, -0.298827082f, 0.387461573f, 0.0221485756f, 0.0928260013f, -0.0955397561f, + -0.0318998769f, 0.334575444f, -0.0609103367f, 0.424938858f, 0.0382942185f, 0.26358667f, 0.043462038f, 0.110744141f, 0.133486897f, -0.0589921735f, + -0.351243585f, -0.134067193f, -0.400999695f, -0.36101675f, 0.151270047f, -0.350251526f, 0.365078896f, -0.26050204f, -0.0489555337f, -0.0983098745f, + 0.394850671f, 0.433760315f, 0.117270023f, 0.406606615f, -0.115579247f, -0.00668902695f, 0.083862327f, -0.229043618f, -0.186382681f, -0.116972566f, + 0.232134879f, 0.0674479082f, -0.0211856682f, -0.0540340357f, 0.0218105726f, 0.00939837098f, 0.383585483f, -0.0112104099f, -0.0184504036f, 0.0225038752f, + -0.139394566f, -0.0720874071f, 0.0477029532f, -0.138865829f, -0.0819087625f, 0.0501355194f, 0.95574677f, -0.0223195199f, 0.216131136f, 0.845378458f, + 0.1924676f, -0.226778314f, -0.169291228f, -0.590278685f, 0.176980317f, 0.65129143f, 0.328980774f, 0.445320189f, 0.0f, 0.0f, + 0.0f, -0.0277302954f, 0.185998231f, -0.0509622693f, 0.0586704351f, 0.0850594565f, 0.139311597f, -0.265101612f, 0.0472348891f, -0.0119542833f, + -0.202859774f, 0.0485027693f, 0.0242230408f, -0.134916425f, -0.447514415f, -0.345167756f, -0.0811896101f, 0.0361979567f, -0.141079962f, -0.162895963f, + -0.133052468f, -0.137587145f, 0.087919496f, 0.237669453f, -0.121589869f, 0.0897248164f, 0.242270723f, 0.258620054f, 0.0308587458f, -0.199450672f, + -0.136823267f, -0.273936778f, 0.102793269f, 0.23199898f, -0.160756052f, 0.0540839359f, 0.044429265f, 0.129874378f, 0.147885829f, 0.118120909f, + -0.0404408984f, 0.0257051308f, 0.244449541f, -0.0404591262f, -0.0291091129f, 0.156805396f, -0.00201254431f, -0.106994435f, 0.0982012674f, 0.0909557864f, + 0.0199999996f}, + {0.277467698f, 0.927522838f, 0.614417255f, -0.223682925f, 0.230302691f, 0.0881967321f, -0.177242622f, 0.0887448713f, 0.0747867078f, 0.165127605f, + 0.0336403288f, 0.120872639f, -0.216517538f, -0.0794860572f, -0.116869658f, 0.244960651f, 0.0377552658f, -0.0790882483f, -0.232124656f, -0.105453014f, + -0.000445031415f, -0.0511510782f, 0.353138775f, 0.295149267f, -0.597802281f, -0.441955715f, -0.0512411632f, -0.0644821078f, 0.123008147f, 0.132903755f, + 0.561007977f, -0.24276346f, -0.0846924558f, 0.506446302f, 0.221849725f, 0.23842755f, -0.0595822074f, -0.374620974f, 0.0354122184f, 0.364289194f, + -0.165921867f, -0.196747378f, -0.177908048f, -0.363478869f, -0.094745934f, 0.376079232f, 0.134426549f, -0.158255652f, -0.029653037f, 0.0647999421f, + 0.00989249442f, 0.220085785f, 0.32752803f, -0.155635402f, 0.0179735217f, -0.41862309f, 0.13388744f, 0.0432803668f, -0.0179251432f, 0.0313675962f, + -0.0179301314f, -0.618942022f, -0.221412808f, 0.0224467777f, 0.368638694f, -0.55688864f, -0.586354196f, 0.0251917727f, -0.269223213f, -0.0701193139f, + 0.155965745f, -1.17638755f, 0.00623515202f, 0.0335726291f, 0.0582892075f, -0.111807182f, 0.194586337f, -0.0945792124f, -0.201008528f, 0.18870008f, + 0.182767361f, 0.0281333998f, -0.16203101f, -0.351854295f, -0.0065839109f, -0.0437650792f, 0.347486615f, -0.130901799f, -0.437653363f, -0.257256538f, + 0.230196983f, 0.20225516f, 0.0229154192f, -0.313657045f, -0.219758615f, -0.141973704f, 0.142972901f, 0.258844793f, 0.154250249f, -0.411399513f, + -0.14974457f, -0.844912112f, -0.0997457653f, 0.229258046f, -0.0847529098f, -0.34791854f, -0.600171208f, -0.144042969f, -0.116857879f, 0.461449534f, + 0.606743395f, 0.27571559f, 0.0868628845f, -0.124708071f, 0.42174089f, -0.132108033f, -0.116351649f, 0.219205156f, 0.246357128f, 0.440366447f, + 0.0312024616f, -0.157172516f, -0.223073855f, 0.315438181f, 0.114989981f, 0.409716755f, 0.288276136f, -0.647155344f, -0.626376033f, -0.0411840044f, + 0.0133952266f, 0.00813039392f, 0.391284943f, 1.42287683f, -0.516137779f, -0.672591031f, 0.837657392f, -0.754237592f, -0.429896832f, -0.0345218405f, + 0.201635718f, -0.471440136f, 0.436546773f, -0.326423615f, -0.00590329478f, 0.0299444534f, 0.0270558316f, -0.168192297f, 0.0653702617f, -0.0867449269f, + -0.169471174f, -0.129182205f, -0.329731584f, 0.12590389f, -0.112769604f, -0.0730714574f, 0.0213193391f, -0.137035251f, -0.0842132196f, 0.114775218f, + 0.252653658f, -0.0957776755f, 0.121907629f, 0.042723462f, -0.231950685f, -0.118234277f, 0.0174495f, 0.426349163f, 0.106439292f, 0.110265218f, + -0.872194767f, 0.00933201239f, 0.201365665f, -0.00940359198f, -0.0431319997f, 0.107050985f, 0.00833545905f, 0.187100172f, 0.467294753f, 0.0666513368f, + 0.118172668f, -0.0111550717f, -0.408213317f, -0.269446403f, -0.159864172f, -0.00937117077f, -0.510241747f, 0.151986092f, 0.0156862997f, -0.409680843f, + 0.0742185563f, 0.23729305f, 0.0527560636f, 0.0266925339f, -0.172528639f, 0.394523531f, 0.0433197692f, -0.367560625f, -0.331667751f, -0.0464268588f, + -0.267827898f, 0.0401774757f, 0.0440656319f, 0.000562727568f, 0.0187882539f, -0.32719174f, 0.671010971f, 0.4263587f, -1.78910029f, 0.0391575322f, + -0.908959568f, 0.270342201f, 0.0131932916f, 0.16246137f, -0.645572722f, 0.88338995f, 0.0442218259f, 0.00367578259f, 0.0100341439f, 0.395288795f, + -0.0832252204f, -0.0199039113f, -0.145086735f, -0.239737883f, -0.232806146f, 0.476626545f, -0.0349412896f, 0.0784740895f, 0.19530277f, -0.128257036f, + -0.10030251f, -0.0420065038f, 0.287122905f, -0.281793654f, -0.0524932183f, -0.389734775f, -0.0314620808f, -0.0264110509f, -0.00168969319f, 0.226426825f, + -0.019391261f, 0.0318648256f, -0.629397273f, -0.0573169626f, -0.245025709f, 0.213177443f, -0.0126230065f, 0.0950836539f, 0.111204393f, 0.0136307608f, + 0.0372544006f, -0.433197767f, 0.455846339f, 0.447908372f, -0.458795547f, 0.197226927f, -0.0333405845f, -0.0910158083f, -0.0547143146f, -0.10224922f, + -0.233747825f, -0.186182246f, 0.517326415f, -0.0400609858f, -0.270790398f, 0.186136827f, -0.143303856f, 0.0854253918f, -0.0332383253f, 0.0327277854f, + -0.017253289f, -0.237183705f, -0.0859387964f, -0.070379436f, 0.146088153f, -0.0159968063f, -0.30665341f, -0.24265936f, 0.0693498701f, 0.299626857f, + -0.428391099f, -0.265312999f, 0.197693661f, -1.22282803f, -0.397939861f, 0.0696616024f, -0.620552301f, -0.124278657f, 0.0487500764f, -0.00915102754f, + -0.00477696536f, -0.240956306f, 0.143344983f, -0.0414756201f, -0.180535123f, -0.0229063667f, -0.99772197f, 0.477008164f, -0.0556298234f, -0.0529876351f, + 0.286322236f, 0.145012408f, -0.413465172f, -0.130587891f, 0.0466349907f, 0.020193873f, -0.0948546603f, 0.098890841f, -0.47603029f, -0.140915915f, + -0.19889845f, -0.0269821957f, -0.0825424641f, -0.0154696247f, -0.631517529f, 0.153530359f, 0.052765023f, 0.173868328f, 0.147374228f, 0.168876946f, + -0.253395677f, -0.00436907681f, 0.0495376214f, -0.0613902621f, 0.0419855006f, -0.0679674298f, -0.450071067f, -0.139881477f, 0.066328153f, -0.15131098f, + 0.390781552f, 0.0419600159f, 0.255526245f, 0.099916853f, 0.0139625017f, 0.181754768f, -0.184558854f, -0.390899181f, -0.192931935f, 0.0476096421f, + -0.157389954f, -0.0877368152f, -0.305022359f, 0.148078844f, -0.0264765359f, -0.00517247897f, -0.0158687923f, 0.0710538998f, -0.0569178164f, -0.137717754f, + -0.273334831f, -0.259709299f, -0.577830613f, -0.443285733f, -0.040304061f, -0.252770662f, 0.675859869f, 0.750194192f, 0.0826221034f, 0.18946287f, + 0.0503353328f, -0.00184302125f, 0.00535605336f, -0.113295265f, 0.135171428f, -0.0202950146f, 0.161794439f, 0.201911181f, -0.502112329f, 0.229156524f, + -0.160011306f, 0.0158878788f, -0.298155099f, -0.103486866f, 0.316116124f, -0.0112902867f, -0.0135303373f, -0.204157203f, -0.106691107f, 0.292656332f, + -0.303863257f, -0.115029581f, 0.0317443907f, 0.0663066879f, 0.244847387f, -0.21926114f, 0.147192419f, -0.0283106305f, -0.0804759786f, -0.248997033f, + 0.512113333f, 0.218476221f, -0.22956866f, -0.38093695f, -0.138828292f, 0.0764495209f, 0.114944153f, -0.45261696f, 0.0306536891f, 0.273679018f, + 0.358914137f, -0.254783243f, -0.0310341343f, 0.306114912f, -0.16415824f, -0.180505157f, 0.0796665996f, 0.337777555f, -0.120270111f, 0.075403668f, + 0.132904172f, 0.172514886f, -0.0378723592f, 0.0401071236f, -0.326892674f, -0.109261192f, -0.291002035f, 0.149261892f, -0.156999201f, -0.100229606f, + 0.657348573f, 0.225903735f, -0.361570895f, 0.176726028f, 0.357242078f, -0.136984423f, -0.271252722f, -0.0772087574f, -0.791625023f, 0.171996802f, + 0.0524192154f, -0.517002642f, 0.084497273f, 0.0282852612f, 0.0066500539f, 0.0110421656f, -0.136571184f, -0.070491299f, -0.071934633f, 0.222221181f, + -0.568021059f, -0.00394849665f, 0.16754888f, 0.0732542723f, 0.0966644585f, -0.307893664f, -0.746647716f, 0.0235900376f, -0.0390693024f, -0.0464351773f, + -0.0745566115f, 0.0772220194f, 0.0775165856f, -0.116249904f, 0.165801615f, 0.0827273428f, -0.0648508072f, 0.136647403f, -0.0344803855f, 0.20520702f, + 0.0300265215f, -0.0403154269f, 0.142735735f, 0.0205753315f, 0.111721724f, -0.0758279487f, 0.169504374f, -0.198559612f, 0.159873992f, -0.0736306086f, + -0.131507114f, -0.00494558131f, -0.00116451399f, -0.13237384f, -0.165791273f, -0.11300952f, -0.212605014f, -0.113872685f, 0.0769968852f, 0.301453143f, + 0.205859065f, 0.0977465436f, -0.244097248f, -0.194055021f, 0.14091365f, 0.512628317f, 0.142166883f, -0.286117882f, 0.226933613f, -0.0724515766f, + -0.146951124f, 0.0109971352f, 0.0292007029f, -0.401224524f, -0.133883089f, -0.068660818f, 0.939153433f, -0.0486190282f, 0.833114386f, 0.924524605f, + 0.0580862351f, 0.918989122f, 0.512783706f, -0.091342628f, 0.0759145468f, 0.000856521016f, 0.0337805077f, 0.0596834794f, -0.196862862f, -0.243939981f, + -0.153084561f, 0.0912104324f, 0.287270725f, -0.10766834f, 0.100703165f, -0.263904572f, 0.0643579364f, 0.10463994f, 0.0780411735f, -0.0822105035f, + 0.198123634f, -0.0147005795f, 0.0768842399f, 0.205581158f, 0.328746974f, 0.0245571882f, 0.522743046f, -0.104997784f, 0.166857854f, 0.214868903f, + -0.135780364f, -0.171887353f, -0.262211442f, 0.0444118902f, 0.258561343f, 0.0549103357f, 0.0321852341f, -0.179075211f, 0.053108938f, -0.59274596f, + -0.0603536852f, -0.0961991549f, -0.392203927f, 0.371636987f, -0.357121587f, -0.20309034f, -0.259833068f, 0.17745468f, -0.338138312f, 0.123802565f, + 0.138396248f, 0.0364919156f, -0.38535291f, -0.247416034f, 0.267194211f, -0.102139473f, -0.0514815524f, 0.0279620867f, 0.240570739f, 0.163022205f, + 0.292840391f, 0.116197102f, -0.0741590932f, -0.248279601f, -0.309121966f, 0.428167731f, 0.111905448f, -1.05663574f, 0.833875299f, 1.30345333f, + -0.444214493f, 0.0401964746f, 0.343645811f, -0.683548093f, -1.1358732f, -0.851284027f, -0.0022804474f, 0.0365069136f, -0.093485117f, -0.162972227f, + -0.175574675f, 0.137773931f, -0.0691415966f, -0.710343242f, -0.216515377f, 0.282640249f, 0.2245235f, 0.164524332f, -0.287085891f, -0.1915351f, + -0.517245829f, 0.0394578986f, 0.217693225f, 0.335351288f, 0.409219116f, 0.404915482f, 0.00345455087f, 0.384838432f, -0.371143609f, -0.458401054f, + -0.26858896f, -0.138438553f, 0.0468764491f, 0.561228752f, 0.275192648f, -0.183400348f, -0.226623565f, 0.170086354f, 0.311703056f, 0.189860597f, + 0.374393404f, -0.143326595f, -0.807402551f, -0.321024507f, 0.310545832f, 0.469097704f, 0.122263983f, -0.337196469f, 0.170280695f, 0.497322679f, + 0.256698012f, 0.264822364f, 0.0781178176f, -0.360141635f, -0.321860164f, -0.206410423f, 0.0442267545f, 0.0801960602f, 0.17896682f, -0.0116992835f, + 0.289149612f, -0.0164731815f, -0.168256f, -0.118687764f, -0.0923533365f, -0.11218904f, 0.349516124f, -0.491183698f, -1.19515324f, -1.11203671f, + 0.117287643f, -1.63927364f, -0.259827346f, -0.131334558f, -0.702737153f, -0.991126657f, -0.00291188201f, -0.318732917f, 0.0564381927f, -0.0568627827f, + 0.133414015f, 0.172083333f, -0.169391274f, -0.298885763f, 0.0228193719f, 0.226922616f, 0.671852231f, 0.178524762f, 0.0181721263f, 0.289244831f, + 0.0714679807f, -0.132410035f, -0.202368557f, -0.207730338f, 0.122170806f, -0.102146283f, 0.389137059f, -0.385432512f, 0.00590417022f, -0.0981407836f, + 0.0615423955f, 0.245393574f, 0.0903864577f, 0.00534521183f, 0.199966162f, -0.0243757181f, -0.1524259f, -0.163021475f, -0.317936689f, -0.0812957138f, + -0.303465605f, 0.377854347f, 0.339092851f, 0.234137818f, 0.0686106607f, 0.18277505f, 0.0435651466f, 0.145102337f, 0.196042344f, 0.0814154223f, + 0.0497032255f, -0.159620479f, 0.469873279f, -0.0155129153f, -0.0543853305f, -0.0242527816f, -0.102014884f, 0.100242086f, -0.0552667081f, -0.088211745f, + -0.125561595f, 0.0296753105f, 0.0841094628f, 0.233635604f, 0.315855324f, 0.0652710274f, 0.143150046f, 0.0618322045f, -0.403148979f, -0.686787009f, + -0.197504863f, -0.302477032f, 0.356982768f, -0.597375453f, -0.0124968635f, 0.566670716f, -1.08749342f, 0.208825514f, -0.967092693f, -0.0635890365f, + -0.0509523638f, -0.0175678134f, 0.116101123f, 0.0542866997f, -0.289517581f, 0.0462481678f, 0.275909424f, 0.0402614065f, 0.113129206f, 0.17363064f, + -0.288429648f, 0.200469434f, -0.123067714f, -0.322508276f, -0.108965889f, 0.132509455f, -0.088400282f, 0.145990968f, -0.318619251f, 0.177827403f, + -0.0202042907f, 0.245370403f, -0.00694340421f, 0.422958583f, 0.20538047f, 0.414615959f, -0.116018102f, 0.0160147808f, 0.26264894f, -0.472914279f, + -0.173786804f, 0.201174781f, 0.0560399555f, 0.0284406282f, 0.0291500427f, 0.00880295318f, -0.0460181944f, -0.103339948f, -0.10530971f, -0.339287519f, + -0.216066092f, -0.164030269f, -0.543910146f, -0.440465987f, 0.103722967f, -0.0309839379f, -0.0923867449f, -0.166068688f, -0.245546415f, 0.326044202f, + 0.15491657f, 0.104947805f, 0.0138144419f, 0.0915891007f, 0.13581875f, -0.0218751859f, -0.65949142f, -0.289476693f, -0.167924136f, 0.058479622f, + -0.154918373f, -0.140610188f, 0.434321523f, 0.00279783318f, 0.790789843f, -0.125219315f, 0.353452891f, -0.244891927f, -0.472303092f, -0.157289416f, + -0.202561542f, 0.31892553f, 0.242536321f, -0.104607284f, -0.00574161764f, 0.045345813f, 0.0490607135f, 0.0893741027f, 0.0184817016f, -0.0440935791f, + -0.464468956f, 0.0589081235f, 0.0108993612f, -0.165554762f, 0.0721720383f, -0.259985119f, -0.122471325f, -0.147438735f, -0.0643362477f, -0.136126295f, + -0.0116985301f, 0.0827997103f, 0.441352844f, 0.0397288203f, -0.157735258f, -0.016939614f, -0.0349921659f, 0.304118931f, 0.365143538f, 0.0973850489f, + -0.0336492062f, -0.0145710483f, 0.136469841f, -0.107452638f, 0.198468044f, 0.066431962f, -0.119582646f, -0.140127108f, -0.0549095981f, -0.307091892f, + -0.314015865f, 0.000740691437f, 0.0792547464f, 0.212423623f, -0.0977405682f, -0.229399145f, 0.494410396f, -0.0743433312f, -0.199156076f, -0.396832108f, + 0.0128925033f, -0.349152088f, 0.159661561f, -0.0891899467f, 0.0385095775f, -0.28348434f, 0.0970428139f, 0.314343989f, -0.129772753f, -0.114860758f, + -0.0972071737f, 0.12339288f, 0.41195181f, -0.401277542f, -0.419852734f, -0.602637708f, 0.394363314f, -0.0011337687f, 0.93858695f, -0.705048084f, + -0.343070745f, -0.359548211f, 0.6857723f, 0.559280872f, 0.162841901f, -0.12369442f, 0.0429472364f, -0.0865175501f, -0.241056219f, -0.309992403f, + 0.174259022f, 0.161168665f, 0.0574117154f, -0.0972264558f, -0.421547771f, -0.401015371f, 0.245155931f, 0.148114532f, 0.138479263f, -0.0379350856f, + 0.119005695f, 0.294098884f, -0.213424996f, -0.123720519f, 0.00172543211f, -0.0247510914f, -0.0184055492f, 0.00163567916f, -0.0921295658f, 0.0139975986f, + 0.0983752683f, -0.0851598457f, 0.0194471832f, 0.0403845459f, -0.148863256f, -0.0883122236f, 0.445890963f, 0.101133287f, 0.0738478079f, 0.0243793819f, + 0.167960033f, -0.0143162273f, 0.386334509f, -0.041001901f, 0.215247482f, 0.283512712f, 0.069700025f, -0.128451243f, 0.24605684f, -0.0417329408f, + 0.0512930788f, 0.210191667f, -0.0944797248f, 0.2817716f, 0.17495352f, 0.0591870621f, -0.0632998496f, 0.0273464769f, 0.193303674f, -0.318269044f, + -0.212904304f, 0.0233078711f, 0.114741102f, -0.165780231f, -1.08439422f, -0.332648456f, 0.437941939f, 0.404223859f, 0.755206168f, -0.146085516f, + 0.323839337f, 0.0177687407f, 0.687054515f, 0.281724453f, 0.0487352498f, 1.94806075f, 0.117163144f, -0.0616696328f, 0.0581014901f, 0.0485964119f, + -0.106376745f, 0.0945957899f, -0.00670341682f, 0.157805607f, -0.112368613f, 0.226470158f, 0.0992699489f, 0.215980724f, 0.11550273f, -0.0918259546f, + -0.160881862f, -0.301226676f, 0.0119121643f, -0.0843693092f, 0.0488433354f, -0.217150673f, 0.086606741f, 0.252410203f, -0.143687174f, -0.0115424143f, + 0.0638900623f, -0.0277799182f, -0.0060229362f, 0.383791775f, 0.334277987f, 0.328779519f, -0.163926512f, 0.41264233f, 0.108409762f, -0.247905791f, + -0.170411691f, -0.167574733f, 0.2968463f, -0.0492121764f, -0.135644123f, -0.229349852f, 0.136675447f, -0.127474084f, -0.0580233485f, 0.0550346375f, + -0.162668675f, 0.329421669f, 0.441037357f, -0.376169533f, 0.161720812f, -0.318740487f, 0.145217165f, 0.0427741781f, -0.41359517f, 0.24522461f, + -0.206085712f, -0.384398401f, -0.125486985f, -0.0794075951f, -0.134823322f, -0.242951512f, 0.253589988f, -0.577269435f, -0.150246188f, -0.631118f, + 0.451975524f, 0.0833057836f, -0.176901251f, 0.440500587f, -0.53644526f, -0.299728215f, 1.13477015f, -0.22321634f, 0.0860719383f, -0.00864490774f, + -0.033085648f, 0.144043446f, -0.00298676454f, -0.11111854f, -0.0232725274f, 0.0520891063f, 0.00392932072f, -0.068006441f, -0.0505088568f, -0.113014869f, + 0.152243525f, 0.210292026f, 0.246680647f, -0.208996147f, 0.0860823095f, -0.086852394f, -0.237267092f, 0.0190535337f, 0.124950148f, 0.0540371425f, + 0.0236100461f, 0.00734423706f, 0.00567066949f, -0.0569116808f, -0.248058602f, -0.00150916644f, 0.128602788f, -0.0658912733f, 0.184860945f, 0.33943975f, + 0.198649168f, 0.249301851f, -0.164609373f, 0.123695955f, -0.0843616202f, -0.130464494f, 0.0780949518f, -0.0967378467f, 0.141616061f, -0.136871919f, + 0.049920328f, -0.086191006f, -0.00887280423f, -0.0284531135f, -0.145691231f, 0.0887040272f, -0.190501943f, -0.17026712f, 0.111032687f, 0.107881241f, + 0.0738912225f, 0.0580388755f, 0.350928336f, -0.173407078f, -0.0647844598f, -0.0539622381f, 0.236918211f, 0.122083053f, 0.233760923f, 0.197607264f, + -0.00247595902f, -0.0683534816f, -0.123339713f, 0.334507614f, 0.163646042f, 0.111869477f, -0.0480377041f, -0.0335904956f, 0.00789931789f, 0.112710789f, + -0.173902601f, 0.142803058f, 0.0616232641f, 0.151408866f, 0.154874161f, 0.233804822f, -0.115832284f, -0.0037722378f, -0.501554787f, -0.275970221f, + 0.156885087f, -0.271841258f, -0.159186915f, -0.00703217601f, -0.169049576f, 0.102285832f, -0.223938406f, -0.315005839f, -0.239777848f, -0.304178655f, + -0.10118822f, 0.000672983355f, 0.0154015189f, -0.303919733f, 0.137499526f, -0.105617814f, 0.0336633921f, 0.191299781f, 0.134096205f, -0.0131890504f, + 0.0356689766f, 0.128590003f, 0.0132047879f, 0.0384545997f, -0.0698242188f, -0.110136226f, 0.295672596f, -0.0483258516f, 0.0581170991f, 0.0671758428f, + 0.188696057f, -0.133781239f, 0.00849151332f, 0.00511312019f, 0.0640127063f, -0.270430326f, -0.0022415428f, -0.328275204f, 0.256909311f, 0.187816992f, + -0.0183999427f, -0.0747431144f, 0.195485249f, -0.13893126f, -0.209631115f, -0.0564197972f, 0.00911236368f, 0.140792221f, 0.255190969f, -0.230306908f, + -0.0725352839f, 0.11762365f, 0.069303222f, 0.164839879f, -0.157661214f, 0.0647500157f, -0.075390622f, -0.201652497f, -0.23699753f, -0.539162099f, + 0.143748969f, 0.377319217f, 1.02312863f, 0.302800924f, 0.483752787f, -0.317887783f, -0.21389842f, 0.45078975f, -0.0874325484f, 0.118787564f, + -0.430952936f, 0.089893505f, -0.0159686916f, -0.0970211625f, -0.0464262255f, 0.144842327f, 0.00379413948f, 0.122997031f, 0.157566234f, 0.176121891f, + 0.0298721921f, 0.0773827732f, 0.142486691f, 0.106580809f, 0.251055509f, 0.194119394f, 0.315801829f, 0.0518628247f, -0.188491851f, -0.0523687899f, + -0.0568789467f, -0.0973626673f, -0.0500313155f, 0.0851411447f, -0.110637143f, -0.109504901f, -0.0156227862f, 0.0398503356f, 0.0075118863f, 0.033682853f, + -0.0750219524f, 0.0145030804f, 0.0809951574f, -0.157899499f, 0.134762466f, -0.122230045f, 0.155932158f, -0.0776870176f, -0.0466872752f, 0.0442046374f, + 0.208856046f, 0.114606895f, -0.031488847f, 0.142421097f, -0.0409219526f, -0.0992704555f, 0.0471593365f, 0.0104902685f, 0.200313151f, -0.0906191841f, + 0.0111912619f, 0.103585266f, 0.00493074628f, 0.0689232647f, -0.0975863412f, 0.0705565512f, -0.0572717302f, 0.15947926f, 0.0419971161f, -0.0238895137f, + 0.0659225062f, 0.0523501821f, 0.0677933097f, -0.0929183587f, 0.127291113f, 0.0519443601f, 0.251333475f, 0.113555916f, -0.119178772f, -0.00170514418f, + 0.0171649531f, -0.250693977f, 0.132856354f, 0.220285431f, 0.264402479f, 0.0697812587f, 0.160155639f, -0.143676177f, -0.021362301f, -0.145393208f, + -0.0881901756f, 0.0983616561f, -0.25181669f, -0.244740263f, 0.237886876f, -0.286750376f, -0.0210676175f, -0.0720860511f, -0.0218627974f, -0.284064859f, + -0.108834818f, 0.115770929f, -0.317529172f, -0.00345864845f, 0.128632709f, 0.264340281f, 0.130885273f, 0.231670752f, 0.160467073f, 0.0621584877f, + 0.0304233003f, 0.16574879f, -0.0364468805f, 0.0671173111f, 0.0488469526f, -0.102830142f, -0.124160416f, -0.101074293f, -0.188118413f, 0.21405378f, + 0.313744903f, -0.0725570023f, 0.157267317f, -0.172962695f, 0.0449597649f, 0.0810536966f, 0.34842217f, 0.249501944f, 0.100386843f, 0.147487894f, + 0.0192574803f, 0.0382567458f, -0.0669459254f, -0.0768318847f, 0.105606228f, -0.0239676666f, -0.158403456f, -0.271072596f, -0.111925684f, 0.117756605f, + 0.0328129902f, -0.122137882f, 0.0184183381f, -0.187827751f, -0.190510586f, -0.0147947529f, -0.0853738561f, -0.0894404352f, 0.0166393183f, 0.0706731379f, + -0.0606708452f, -0.0303290263f, -0.478003144f, -0.413098454f, -0.34367308f, 0.331015646f, 0.0998993814f, -0.588421106f, 0.0927857906f, 0.330799043f, + 0.847426832f, -0.575366914f, 0.16082032f, 0.0128269605f, 0.0530175306f, -0.0052746702f, -0.0995033681f, 0.193519995f, 0.179418281f, 0.432001382f, + 0.186320662f, -0.204863533f, -0.289786845f, 0.249679312f, 0.140404627f, 0.225307047f, -0.0343253203f, -0.316201419f, 0.178037703f, -0.106441371f, + -0.217321768f, 0.220192164f, 0.130881116f, -0.261059493f, 0.321758479f, -0.0695778355f, -0.023649238f, 0.378145397f, 0.341159821f, 0.326983035f, + 0.244429931f, -0.0243531838f, -0.306188375f, -0.166243687f, -0.204724595f, 0.0928042009f, 0.388078302f, -0.214391753f, 0.0579735264f, 0.257450074f, + 0.0205322802f, 0.232772678f, 0.573641121f, 0.0220659953f, 0.29787612f, 0.256807595f, 0.299242049f, 0.126971647f, -0.319353312f, -0.208485752f, + -0.0854388326f, -0.092235595f, -0.181530312f, 0.136270672f, -0.0296339821f, 0.064536117f, -0.15785408f, -0.157985464f, -0.093108058f, -0.108346805f, + 0.451959372f, -0.440518469f, -0.156426221f, 0.223317608f, -0.641416848f, 0.563581228f, 0.53373456f, 0.207416445f, -0.0707245469f, 0.924178839f, + -0.652196407f, -0.672917247f, 0.288334519f, -0.354775935f, -1.658548f, 0.303783774f, 0.322130829f, 0.0535530075f, 0.0535031259f, 0.29180336f, + 0.161157995f, -0.121117644f, -0.0321019366f, -0.223925099f, 0.440660387f, 0.137816831f, 0.17772834f, -0.335468352f, 0.141813949f, 0.172515526f, + 0.0902596191f, 0.0054409923f, -0.0289572645f, -0.0267072991f, 0.0427095331f, 0.0865530968f, -0.152215689f, 0.146740526f, 0.502789736f, -0.29562971f, + -0.179921895f, -0.127485052f, 0.4443672f, -0.262699783f, -0.0464255027f, 0.258010268f, 0.190189809f, -0.381791055f, -0.0548949838f, -0.18331778f, + -0.147813737f, 0.0995309502f, 0.966033399f, -0.437220275f, 0.135250017f, -0.433649689f, 0.0393961556f, 0.173995271f, 0.201212823f, 0.160471901f, + 0.388483584f, 0.207075447f, -0.136088878f, 0.402706236f, -0.42906335f, -0.255677521f, -0.249065652f, -0.415307701f, -0.124408007f, 0.433338225f, + 0.213607848f, 0.211742237f, 0.0698127747f, 0.135880113f, 0.299614191f, -0.302542895f, 0.0987956971f, 0.0653359964f, -0.184583381f, -0.224296451f, + 0.132024527f, -0.77700299f, 0.470721126f, -0.48305732f, 0.409418792f, -0.987737954f, -0.10855002f, -0.140149951f, 0.38822493f, -0.060350582f, + 0.0846407413f, 0.295686722f, -0.137053639f, 0.365696073f, 0.217868268f, -0.112466358f, 0.321329355f, 0.117699593f, 0.113980673f, 0.412178636f, + 0.126271307f, -0.172631517f, -0.459109545f, -0.0499430262f, -0.0111093186f, -0.131580308f, -0.188834473f, 0.335550368f, 0.743537605f, -0.336420864f, + -0.162843809f, -0.111027971f, 0.0987212136f, 0.100473411f, 0.170955613f, -0.363280296f, -0.312082976f, -0.392545253f, -0.202453762f, -0.277293146f, + -0.261315644f, 0.0355851613f, -0.0480615422f, 0.0775201842f, 0.215976149f, 0.157541186f, -0.640751719f, 0.327961385f, -0.186328024f, -0.316303402f, + -0.1956359f, -0.182079136f, 0.155328974f, -0.112292081f, -0.408430368f, -0.0303186029f, 0.356629282f, -0.154018566f, 0.444047809f, 0.00121863896f, + 0.453550518f, -0.530225575f, 0.125946775f, -0.517413795f, -0.481258571f, 0.384072214f, 0.266777724f, 0.09779796f, -0.0925946459f, 1.2157836f, + -0.763454676f, -0.985040903f, 0.535525084f, -0.351059616f, -0.230641589f, -0.176600978f, 0.263139129f, -0.383236736f, 0.41634202f, 0.167553023f, + 0.182448193f, 0.003120885f, -0.134129703f, 0.0238568988f, 0.0562412888f, -0.0708081126f, -0.141120479f, -0.0706041679f, -0.0222896375f, 0.0838591903f, + 0.1625835f, 0.180177003f, -0.0112714982f, -0.00731980102f, -0.761635959f, -0.278902292f, -0.238981932f, -0.310968459f, 0.0179917887f, -0.224645704f, + 0.202039227f, -0.0403334387f, -0.0478617661f, -0.23129043f, 0.0117672924f, -0.287047118f, 0.00247578626f, 0.0420551375f, 0.0758238137f, 0.000440670032f, + -0.0889078155f, -0.197394475f, 0.323904067f, 0.291106075f, 0.0279629044f, -0.0768248886f, 0.182854757f, 0.297349572f, -0.454384953f, 0.120486178f, + 0.24219799f, 0.105178878f, 0.108864561f, 0.173979864f, 0.408688605f, -0.139055192f, -0.130234867f, 0.134036645f, -0.144928619f, 0.0284455866f, + -0.221262932f, 0.167558566f, 0.384082884f, 0.0243602581f, 0.201599643f, 0.281964242f, -0.460225582f, 0.27340737f, -0.315977186f, 0.145801187f, + -0.411468863f, -0.120196767f, -0.366867572f, -0.690623522f, -0.0567998439f, -0.422394514f, -0.843809903f, -0.78285408f, 0.680445313f, -0.0694641247f, + -0.0765206739f, 0.315118372f, 0.0367431901f, -0.17631571f, 0.000871494005f, 0.0613397546f, 0.116332717f, 0.189532876f, 0.0633820146f, -0.079442665f, + -0.357596099f, -0.0044811843f, 0.00165847025f, -0.0874392539f, -0.11354392f, -0.227286473f, -0.567620695f, -0.0298102964f, -0.317024291f, -0.096759364f, + -0.205914408f, -0.141844362f, 0.263436079f, 0.090466857f, 0.0769530311f, 0.0309630074f, -0.01268744f, -0.0173975918f, -0.243604392f, -0.0123098725f, + -0.00901651103f, 0.0407512859f, 0.2110679f, 0.201213956f, 0.112119399f, 0.0745828599f, 0.0604453832f, 0.0681941584f, 0.137119576f, 0.14975515f, + -0.0237598252f, 0.0848230496f, -0.00474787224f, -0.0330243148f, 0.00246166508f, 0.0696500391f, 0.149355471f, -0.0918588117f, -0.226155207f, -0.266309083f, + -0.148678362f, -0.2542409f, 0.0452752747f, 0.125719607f, -0.00214059348f, -0.365951896f, -0.15730387f, -0.285431653f, 0.184516683f, 0.206238464f, + 0.0057278187f, 0.0803279653f, 0.0501020886f, 0.0917493999f, 0.750175118f, -0.617480636f, 0.616806269f, -0.671807587f, 0.132289618f, 0.0836416483f, + -0.195019901f, 0.076224111f, 0.26716125f, -0.582946181f, 0.0683091283f, 0.225424007f, -0.200268477f, 0.0494274199f, 0.0432228148f, 0.0306643546f, + -0.0410277694f, 0.000584183435f, 0.0335596427f, -0.0487603396f, -0.0504492559f, -0.0325846635f, 0.126289368f, 0.0346887447f, -0.528440595f, 0.141351014f, + 0.142632321f, -0.020770628f, -0.254111022f, -0.151052624f, -0.123036243f, 0.0471079983f, -0.163470685f, -0.237955168f, 0.0640946478f, 0.2516101f, + -0.124583326f, 0.0452026241f, 0.120984539f, -0.0191059783f, -0.387985796f, -0.245667681f, 0.148226291f, 0.23058629f, 0.133431524f, 0.278478712f, + 0.344880491f, 0.406576931f, 0.0923041403f, 0.0526719205f, 0.258579969f, -0.281099111f, 0.0463470705f, -0.100548699f, 0.153516889f, -0.181981117f, + -0.198302343f, 0.410530508f, 0.269025356f, -0.136715919f, 0.111296035f, 0.201592669f, -0.0113313757f, 0.216626182f, -0.137586161f, -0.075503476f, + -0.0781062394f, 0.209764063f, -0.249815166f, -0.0581801198f, 0.187960595f, -1.13624358f, 0.112325296f, -0.0672734827f, 0.142252296f, -0.657007992f, + -0.0467571057f, -0.0239185654f, -1.05630171f, -0.937819004f, 0.270939022f, -0.320499867f, -0.0394119956f, 0.0246572457f, -0.15713717f, 0.0374054089f, + 0.408243835f, -0.183315486f, -0.120398492f, -0.0780544803f, 0.0533233173f, -0.227762014f, 0.266392052f, 0.105120726f, 0.160356253f, -0.0686205849f, + 0.138027787f, 0.291730136f, -0.194335669f, 0.63245815f, 0.0460608825f, 0.105918109f, 0.0874074027f, 0.13675788f, 0.198296919f, -0.0661347359f, + -0.119509935f, 0.146695435f, -0.307960212f, -0.0938605145f, -0.131919369f, 0.0204172395f, 0.385824412f, -0.111468054f, 0.0828925446f, 0.051792711f, + 0.269370914f, 0.582583606f, 0.100114055f, 0.542199254f, -0.100287184f, -0.00849693269f, -0.0500634983f, -0.0923785418f, -0.113968015f, -0.0978075489f, + 0.739991546f, 0.0084507307f, 0.0276725907f, 0.057096377f, 0.149228171f, -0.0202030204f, 0.403134227f, 0.0289018936f, -0.0904502645f, -0.227995321f, + -0.503033698f, -0.202325925f, -0.175641716f, -0.151726767f, -0.0215259753f, 0.132320896f, 0.800908446f, -0.506207168f, 0.429227889f, 0.845378458f, + 0.1924676f, -0.226778314f, -0.169291228f, -0.590278685f, 0.176980317f, 0.65129143f, 0.328980774f, 0.445320189f, 0.0f, 0.0f, + 0.0f, 0.0163212363f, 0.106357932f, -0.125805721f, 0.0353311971f, 0.0533368923f, 0.0545999408f, -0.377992004f, -0.110487394f, -0.0327547342f, + -0.0611558594f, 0.0701475069f, -0.125140563f, -0.187350318f, -0.254486442f, -0.134125993f, -0.024985183f, 0.149665996f, -0.0932463855f, -0.29919523f, + -0.300769478f, -0.052414991f, 0.334184945f, 0.457124889f, -0.00833443925f, 0.142889023f, 0.269146681f, 0.212897271f, -0.217240229f, -0.5568012f, + -0.226409703f, -0.140002221f, 0.153151214f, 0.212489679f, -0.098508358f, -0.00133714802f, -0.0668717772f, 0.0980383381f, 0.207780644f, 0.205319643f, + 0.0765436217f, 0.0318532102f, 0.118826538f, -0.0612335615f, 0.0345225893f, 0.204710379f, 0.0839010924f, -0.061726857f, -0.0206766743f, 0.0518568903f, + 0.0199999996f}, + {0.271331042f, 0.836814284f, 0.404056132f, -0.302820712f, 0.218440369f, 0.115689225f, -0.109829441f, 0.160457209f, 0.107314207f, 0.0751823783f, + 0.0133726737f, 0.141474187f, -0.154044881f, -0.0113994442f, -0.0888248384f, 0.147319406f, 0.0161099471f, -0.0562763438f, -0.165012106f, -0.0339330286f, + 0.0262293741f, -0.00564136123f, 0.349707514f, 0.275483668f, -0.597585797f, -0.426680565f, 0.0145181715f, -0.0468846112f, 0.0884530693f, 0.0827419609f, + 0.534277618f, -0.251426518f, -0.0392054655f, 0.543294966f, 0.19887054f, 0.196103662f, -0.0781023204f, -0.368803591f, 0.0969305634f, 0.0185356103f, + -0.288371295f, -0.16167745f, -0.0122420816f, -0.206149712f, 0.00417279312f, 0.0155616142f, 0.0102281645f, -0.118762866f, 0.146760285f, 0.229737431f, + 0.106679596f, -0.197383836f, 0.176212549f, -0.116189368f, 0.214589119f, -0.233346745f, 0.245989874f, -0.0247738082f, -0.0570884161f, -0.0467009433f, + 0.0132474136f, -0.572090268f, -0.126734987f, -0.0391497165f, 0.0497098528f, -0.57846421f, -0.561450422f, 0.0169640575f, -0.302143246f, 0.151469707f, + 0.290574402f, -0.777828455f, -0.00876801461f, 0.00778493099f, 0.0220301747f, -0.110647418f, 0.208465293f, -0.0937001258f, -0.186318874f, 0.172616124f, + 0.125479683f, 0.0441176035f, -0.155376911f, -0.358695149f, -0.00669221999f, -0.0954416022f, 0.262207657f, -0.0338037871f, -0.391407549f, -0.239683956f, + 0.276984215f, 0.224270597f, -0.0402527265f, -0.322465479f, -0.288308829f, -0.232784927f, -0.0028729816f, 0.0658204257f, 0.0761740804f, -0.320359677f, + -0.0911280736f, -0.81411922f, -0.188413545f, 0.0615864731f, -0.196286574f, -0.15628092f, -0.451969564f, -0.0606482029f, -0.163759202f, 0.250829816f, + 0.472348481f, 0.244940668f, -0.0627044067f, -0.25690347f, 0.502962828f, 0.0752066374f, -0.0793915093f, 0.183370039f, 0.0912308395f, 0.290812105f, + 0.08689823f, 0.0711750835f, -0.125065997f, 0.220416963f, -0.1661883f, 0.208221346f, 0.387452632f, -0.299409688f, -0.540575027f, -0.0152008673f, + 0.054852508f, -0.0198010784f, 0.388232738f, 1.36804569f, -0.45269981f, -0.542170584f, 0.785598159f, -0.633094728f, -0.402905047f, 0.0434334613f, + -0.0195088275f, -0.0788040534f, 0.257048368f, -0.225514993f, -0.00260156463f, 0.0448352769f, 0.00511369668f, -0.139168829f, -0.0342828184f, -0.0101989796f, + 0.0515831187f, -0.244492069f, -0.214034989f, 0.292918921f, -0.0285015441f, -0.00304960832f, 0.110827245f, -0.116251819f, 0.0180722848f, 0.15263395f, + 0.145273715f, -0.105677068f, 0.338112921f, 0.017836852f, -0.0353082158f, -0.0158449151f, -0.0169309881f, 0.406428725f, 0.225544214f, 0.32305938f, + -0.976552188f, 0.171812922f, 0.322254777f, 0.0448909551f, 0.0208677351f, 0.145182952f, -0.0193940438f, 0.166858047f, 0.430750191f, -0.00649647322f, + -0.0360146798f, 0.00917242374f, -0.358612031f, -0.049678009f, 0.00550900353f, 0.269058287f, 0.0253328402f, 0.184449777f, -0.56608063f, -0.295630157f, + 0.0954311714f, 0.257107943f, 0.112533815f, -0.0343428254f, -0.378388524f, 0.607226193f, 0.143886656f, -0.253996313f, -0.0805992559f, -0.03128637f, + -0.5738585f, 0.0680266768f, 0.0216652136f, 0.0185794607f, 0.082000792f, -0.385225385f, 0.410502315f, 0.288563043f, -1.86235189f, 0.38954103f, + -0.956063211f, 0.354024142f, -0.0170178525f, 0.283852279f, -0.357161224f, 0.722223759f, 0.0239744093f, 0.0441604145f, 0.0119895507f, 0.389341116f, + -0.0136079611f, 0.106492095f, 0.0335511267f, 0.07729996f, -0.377567768f, 0.311715126f, -0.260910153f, -0.130527347f, 0.113837026f, -0.163783565f, + -0.0597279593f, -0.250338227f, -0.00734832976f, -0.353766233f, 0.0492933467f, -0.0132695772f, -0.0500983931f, 0.0892364979f, -0.0509718247f, 0.25758934f, + 0.0300225373f, -0.0513555296f, -0.0438113138f, 0.112870321f, -0.121174097f, 0.243393868f, -0.117872335f, -0.0489773192f, 0.215984672f, 0.00783056486f, + -0.218732893f, -0.49566707f, 0.0984075591f, 0.031941358f, -0.247678116f, 0.00643457379f, -0.0878645107f, -0.0473116226f, -0.0327571519f, -0.0867693499f, + 0.519420385f, -0.10871955f, 0.404574871f, -0.029074885f, -0.269479632f, -0.0450327434f, 0.219392478f, -0.129067376f, -0.24883014f, -0.0485361628f, + -0.103128299f, -0.368309289f, 0.271291882f, -0.0890500024f, -0.0723868534f, -0.100754492f, -0.2054331f, -0.337098032f, 0.308197677f, 0.185657337f, + -0.161848202f, -0.651924789f, 0.357761174f, -0.923027158f, -0.541214585f, 0.157629997f, -0.638057709f, -0.308187276f, 0.0122000016f, 0.0317831822f, + -0.0961373374f, -0.00989297777f, 0.0173508804f, -0.0382551588f, -0.0709398761f, 0.0573627204f, -0.942292571f, 0.263754219f, -0.245892689f, -0.227276489f, + 0.37110725f, 0.146419242f, -0.209197953f, -0.243775219f, -0.139627531f, -0.20419386f, -0.28809911f, -0.0657785237f, -0.452385634f, 0.0141065726f, + -0.0301528573f, 0.0201757569f, 0.0228409227f, 0.115125142f, -0.938751817f, -0.0598020405f, -0.00509683974f, 0.0181255136f, 0.114891358f, 0.512709975f, + -0.0576297864f, -0.0330908187f, 0.0270239152f, -0.116297692f, -0.302677721f, 0.118000798f, -0.0286913551f, 0.0335505866f, 0.0959156379f, 0.0102892891f, + 0.139140218f, -0.0306835752f, -0.250876009f, 0.137078404f, -0.0712177306f, 0.105222784f, -0.112280652f, -0.169682249f, -0.0380215496f, -0.169691071f, + -0.380340129f, -0.162759081f, -0.548679829f, 0.405155748f, 0.0399622656f, 0.0358354039f, 0.0207779128f, 0.0369194932f, -0.183213353f, -0.22787641f, + -0.0513690487f, -0.0154861184f, -0.499049395f, -0.329116017f, 0.0979859605f, -0.0950582996f, 0.651213467f, 0.689643204f, 0.0919044763f, 0.346154422f, + 0.0229265988f, 0.0377828181f, -0.0519206896f, -0.0255728755f, 0.0462512486f, -0.0610783957f, 0.0632237867f, 0.0744383186f, -1.03696835f, 0.0050780368f, + -0.122874357f, -0.0770357177f, -0.168554217f, -0.224419653f, -0.0121058682f, -0.037736252f, 0.087852262f, -0.103807218f, 0.132779136f, 0.162453815f, + 0.31931442f, -0.0889517069f, -0.0171351228f, 0.342632234f, 0.293103546f, 0.0198794194f, 0.201318949f, -0.324517399f, 0.122517563f, -0.168888628f, + -0.0528077893f, 0.240189299f, -0.271803081f, -0.291760057f, 0.256852925f, 0.253780156f, 0.126911253f, -0.361700743f, 0.10050375f, 0.208286375f, + 0.29995954f, -0.203195959f, -0.109716691f, 0.465702653f, -0.173883021f, -0.310836464f, -0.0623408332f, 0.0790932328f, -0.219477966f, 0.138760418f, + 0.0357402489f, 0.319382429f, -0.0395470262f, -0.317513257f, -0.133704752f, 0.101199299f, -0.0939607471f, -0.0964316651f, -0.154744312f, -0.118601307f, + 0.269616753f, 0.17347002f, -0.0700251982f, 0.636362493f, 0.433900237f, -0.0449789204f, 0.178502813f, 0.0234888606f, -0.711932182f, -0.315085918f, + 0.102368116f, -0.493779927f, 0.0259759221f, 0.0410149433f, 0.00229501305f, 0.0651620179f, -0.0981541798f, -0.0316615477f, -0.118494965f, 0.141551375f, + -0.334516972f, -0.0251858328f, 0.176094234f, 0.0300499257f, 0.0967352614f, -0.255754471f, -0.662379742f, 0.137622088f, -0.228479385f, -0.0753132775f, + -0.203106686f, 0.295881569f, -0.116373159f, -0.0430522747f, 0.00928364601f, 0.09562473f, 0.0749324709f, 0.208390385f, -0.0294778515f, -0.0434174873f, + -0.106162548f, -0.0940275863f, 0.0236352235f, -0.152533323f, 0.0221785475f, -0.0591014139f, 0.393868417f, -0.0901512727f, 0.278867126f, -0.00837293919f, + -0.109914795f, 0.0438530073f, 0.153661415f, 0.0205022581f, -0.0967278108f, -0.329206765f, -0.22017993f, -0.247602373f, 0.054341428f, 0.10154286f, + 0.0689218342f, -0.0208905637f, -0.264117718f, -0.17193675f, 0.27173692f, 0.471189916f, 0.0255439002f, 0.00710181287f, 0.157565758f, -0.0287449788f, + -0.140610963f, -0.0882861838f, -0.355750471f, -0.377352208f, -0.165645808f, 0.13205862f, 0.952257037f, -0.0282736365f, 0.657276511f, 1.04173028f, + 0.116032325f, 0.822461069f, 0.535598755f, -0.130458832f, 0.00469888886f, 0.0420403592f, 0.0480780117f, 0.126785368f, 0.066926226f, 0.00270390627f, + 0.0155333988f, 0.0911339f, 0.14958775f, -0.237260506f, -0.0266686138f, -0.392957956f, 0.026873922f, 0.117430225f, 0.00869826972f, -0.0305299591f, + 0.0488516837f, -0.242223606f, -0.139015928f, 0.0471221097f, 0.16691637f, -0.0671109408f, 0.505928814f, -0.108257256f, 0.111165799f, 0.147212595f, + -0.184736237f, -0.26546827f, -0.352366507f, -0.0390933827f, 0.181706309f, -0.0263555497f, -0.0599468723f, -0.0667298511f, 0.126351938f, -0.516238391f, + 0.0521811657f, 0.0050715832f, -0.331583411f, 0.728525698f, 0.0775418803f, 0.234845683f, -0.0380656831f, 0.232625648f, -0.315526038f, 0.194010779f, + 0.139427915f, 0.069184646f, -0.327680498f, -0.216781437f, 0.310993701f, -0.0933124572f, -0.154665932f, -0.0765950456f, 0.160255879f, 0.0815322921f, + 0.193832442f, -0.0986338183f, -0.124479204f, 0.141499713f, -0.299121171f, 0.359975964f, 0.0356372073f, -0.922082961f, 0.789734781f, 1.01456285f, + -0.360732406f, 0.125402421f, 1.07134008f, -0.801305711f, -1.10291779f, -0.896827757f, -0.0676390231f, -0.00308758439f, 0.0443510078f, -0.0564716309f, + -0.0823894888f, 0.20040217f, 0.16272451f, -0.0632216856f, 0.37349844f, 0.288903594f, 0.160327092f, 0.136486694f, -0.051624205f, 0.246982336f, + -0.145949647f, 0.0508672968f, -0.0617967062f, 0.288900226f, 0.214197606f, -0.170533478f, 0.12290962f, 0.297292769f, -0.1381924f, 0.0559648536f, + -0.213405341f, -0.676440775f, 0.0256053302f, 0.297036916f, 0.178512067f, 0.119114384f, 0.113891244f, 0.11421477f, -0.250009924f, 0.012961355f, + 0.0034437289f, -0.157886773f, -0.379305094f, 0.123690188f, 0.274434716f, 0.460545599f, 0.136675462f, -0.345611721f, 0.104565516f, 0.409634829f, + 0.160097227f, 0.0597821735f, -0.117575139f, -0.528492272f, -0.481877685f, -0.374721676f, -0.136203632f, 0.0317054503f, 0.0587112084f, -0.221329734f, + 0.172330558f, -0.042583622f, -0.106334403f, 0.00158806809f, 0.0744110793f, -0.142218068f, 0.662285566f, -0.788851798f, -1.05894959f, -0.611997485f, + 0.150492057f, -1.72741473f, -0.145649448f, -0.34918198f, -0.691168845f, -0.775849283f, -0.0407269858f, -0.291713446f, 0.0342637338f, -0.0327017754f, + 0.00902733207f, 0.337353766f, 0.142037556f, -0.105297469f, -0.00752908364f, 0.309572518f, 0.483771324f, -0.044100754f, -0.116091914f, 0.390754342f, + -0.0409133546f, -0.0465554036f, -0.309986293f, -0.00904681068f, 0.613548279f, -0.308192402f, -0.00622536568f, -0.344563723f, 0.102359243f, 0.181908697f, + -0.07224942f, 0.0992626026f, 0.138825476f, 0.167051762f, 0.237036452f, 0.105291963f, -0.191759333f, -0.156969398f, -0.276476145f, -0.0824975148f, + -0.315578818f, 0.347227454f, 0.166346818f, -0.12770164f, -0.0748078823f, 0.249088064f, -0.284507096f, -0.0423060432f, 0.0684402734f, 0.0222845059f, + 0.184564084f, -0.240805686f, 0.137982756f, 0.0382287167f, 0.0322521068f, 0.183491439f, 0.163963988f, 0.357970446f, -0.506689727f, -0.218078211f, + -0.216984853f, -0.253085345f, -0.22081922f, 0.288196683f, 0.418806225f, -0.114412084f, -0.152965054f, 0.0442940556f, -0.037437018f, -0.525641203f, + -0.295440018f, -0.0728712156f, -0.46996814f, -0.777540207f, -0.36242649f, 0.447346985f, -1.2289077f, -0.301133931f, -0.905366421f, 0.17534095f, + 0.0286422148f, -0.0282367673f, 0.0140908873f, -0.0894869417f, -0.283484489f, -0.172047094f, 0.204787508f, -0.0222762357f, 0.674428105f, 0.132432625f, + 0.139966816f, 0.100454375f, -0.161349282f, -0.118337914f, 0.926963985f, 0.261173218f, -0.0198429544f, 0.321644306f, -0.0784614682f, 0.246609718f, + -0.547117054f, 0.119087726f, -0.33107546f, 0.407496125f, 0.00548209948f, 0.0497890338f, -0.0214474164f, -0.0083425343f, 0.129373178f, -0.379404187f, + -0.189445689f, -0.0372736529f, 0.564705789f, 0.154472277f, 0.0630915388f, 0.0928517729f, -0.133534029f, -0.122801632f, -0.38297832f, 0.0245180205f, + 0.0711221099f, 0.042556487f, -0.495284349f, -0.288924068f, -0.0940222144f, 0.116297312f, -0.0167998895f, -0.250666142f, -0.200790778f, 0.488584697f, + -0.423032582f, 0.271379203f, 0.148730367f, -0.0571974814f, -0.297518551f, -0.170933649f, -0.340748787f, 0.114311002f, 0.0598128214f, 0.0345388167f, + -0.0875922516f, -0.180742338f, 0.401243389f, 0.614326954f, 0.634804368f, -0.0577314831f, 0.621843815f, -0.18877244f, -0.294811189f, -0.655919731f, + -0.255794823f, 0.408254325f, 0.0310511496f, 0.00899399072f, -0.012992423f, -0.0773184747f, 0.0874484032f, 0.0422454178f, 0.17966181f, 0.103418097f, + -0.535365701f, -0.226675168f, -0.296193659f, -0.286429375f, -0.156742021f, -0.0761714727f, -0.525990963f, -0.306683719f, -0.239961207f, -0.338933408f, + -0.0330806002f, -0.0449500866f, 0.531450748f, -0.0546266623f, -0.182149321f, -0.0957349688f, -0.173828974f, 0.0915292203f, 0.198347718f, 0.040950764f, + -0.00424639136f, -0.0113705816f, 0.210038275f, -0.192033529f, 0.386875629f, 0.0164374933f, -0.152446032f, -0.129901931f, 0.069174774f, -0.203453645f, + -0.230217919f, -0.0598830916f, 0.112329885f, 0.258606762f, -0.0223986991f, -0.111016475f, 0.153045848f, -0.046305079f, -0.0605582818f, -0.459723473f, + -0.112872407f, -0.322736621f, -0.0118533615f, -0.271848917f, -0.00331815588f, -0.286077023f, -0.15397048f, 0.00951057021f, -0.0516248271f, 0.0421418957f, + 0.0239617657f, -0.1774275f, 0.306014717f, -0.322431773f, -0.605714321f, -0.908136308f, 0.686210752f, 0.00359554566f, 0.97916019f, -0.492225647f, + 0.199957877f, 0.544739366f, 0.714238524f, 0.702375591f, 0.0695677176f, -0.0403649174f, -0.06211216f, -0.061084345f, -0.0267875288f, 0.0806795135f, + 0.00646146666f, 0.0304205064f, -0.187662855f, 0.210809067f, -0.273023397f, -0.260694087f, 0.256660342f, -0.00885008276f, -0.142653748f, -0.122812442f, + 0.13422887f, 0.0981836617f, -0.113086492f, 0.0757337809f, -0.529358625f, -0.0158147868f, -0.0178849474f, 0.00297797751f, -0.0346628428f, -0.0183247384f, + -0.585475087f, -0.0105384514f, -0.0491768494f, -0.0306109488f, -0.0499893092f, 0.0472304597f, 0.329422563f, -0.0614932254f, -0.0412716456f, -0.000110269335f, + -0.0521272048f, -0.0932833627f, 0.393389791f, 0.00107908901f, 0.0193157252f, 0.0468027554f, 0.0313604772f, 0.00492353225f, 0.395851225f, 0.00334235094f, + 0.0106768114f, -0.021603046f, 0.0215762202f, 0.110269383f, -0.0835928321f, -0.00778113166f, 0.0593142174f, 0.125672594f, 0.0778141394f, 0.00522257201f, + -0.320091724f, -0.0646557808f, -0.0702003911f, -0.0778922066f, -0.788071454f, 0.0559450835f, 0.195802361f, 0.190680787f, 0.947392821f, -0.227567628f, + 0.208239749f, -0.136859298f, 0.615455449f, 0.759806693f, -0.283142209f, 1.58148825f, 0.0178526398f, -0.0555657893f, 0.0106341476f, -0.0730781108f, + -0.0641926825f, -0.0729786232f, -0.0966110975f, 0.148120686f, -0.00537415361f, 0.306453824f, -0.0370939337f, 0.10620179f, 0.247488663f, -0.292117327f, + -0.245290786f, -0.10870304f, 0.0757847577f, -0.0392655879f, 0.0680073351f, -0.117249601f, -0.0714805797f, -0.00373797072f, -0.0297106318f, -0.00406931853f, + -0.027480647f, -0.0678323507f, -0.0535559282f, 0.0401962064f, 0.0866121575f, 0.12608327f, -0.125431433f, 0.0979750678f, -0.0822331831f, -0.0150237614f, + -0.0479134545f, -0.00760708191f, 0.329186916f, 0.156795382f, -0.343139321f, -0.272240371f, -0.158074379f, -0.105134815f, -0.163925126f, 0.0364979766f, + -0.177962482f, 0.066587083f, 0.395478278f, -0.487412363f, -0.0356068797f, -0.305973738f, 0.123659939f, -0.0773693398f, -0.47124669f, 0.117151f, + -0.239418045f, -0.415040076f, -0.124330111f, -0.143859923f, 0.0120164361f, -0.256729633f, 0.30926922f, -0.584826052f, 0.0514711514f, -0.407382607f, + 0.237749562f, 0.159478411f, -0.16581732f, 0.291583747f, -0.580438077f, -0.429486752f, 0.889857471f, -0.0472197048f, -0.0538516939f, -0.00788183883f, + -0.0166704729f, -0.092857942f, -0.0361354649f, 1.76862904e-05f, 0.0807934105f, 0.0270433892f, -0.118022583f, -0.12152575f, -0.00489879074f, -0.0761489198f, + -0.0894348621f, -0.0186458528f, 0.205516085f, 0.157313094f, 0.505360365f, 0.105837159f, -0.130523518f, 0.0801769197f, 0.00634182524f, -0.049748823f, + 0.0398929901f, -0.00953839719f, -0.0483126268f, 0.00482817041f, -0.180167079f, -0.245169699f, -0.126125738f, -0.605347812f, -0.420904249f, 0.623759329f, + 0.763782024f, 0.103222914f, -0.213252962f, 0.072837539f, -0.0999040827f, -0.0860050619f, 0.119179964f, -0.0596745387f, 0.174537361f, -0.0828591809f, + 0.0459940769f, -0.0984999612f, -0.217796773f, -0.287239879f, -0.151864037f, 0.0880677924f, -0.107101426f, -0.112044737f, 0.0903986841f, 0.0572482497f, + 0.048994422f, -0.0364074297f, 0.31195426f, -0.0681197196f, 0.182375669f, 0.170203209f, 0.532169998f, 0.619259179f, 0.751626313f, 0.52029705f, + -0.0961934626f, -0.150778532f, -0.14577648f, 0.323645562f, 0.095879063f, 0.0147776026f, -0.0741818696f, -0.027239386f, -0.0192660987f, 0.0205752328f, + -0.161192149f, 0.238026455f, -0.0771325305f, -0.111616947f, -0.152634025f, -0.114971146f, -0.0553324036f, 0.185513914f, -0.287677914f, -0.0505513437f, + 0.263174355f, -0.162589774f, -0.0373028144f, 0.00533136772f, -0.245288014f, 0.15671967f, -0.0418159664f, -0.352917045f, -0.366300851f, -0.447363943f, + -0.169537216f, 0.010056098f, 0.0635754988f, -0.157748312f, 0.323406547f, -0.0455841869f, -0.020671824f, 0.0730549172f, -0.0487707481f, -0.0157894474f, + 0.130241916f, 0.15131399f, 0.189302921f, 0.313461781f, 0.11768508f, -0.0631440133f, 0.181705877f, -0.0990022346f, 0.0179369282f, 0.0545454621f, + 0.173869178f, -0.225427642f, -0.0771434531f, -0.0793065652f, -0.068984881f, -0.361972749f, -0.0255069099f, -0.486442924f, -0.0763116106f, -0.0908813998f, + -0.168413594f, -0.343256146f, 0.121759519f, -0.114502937f, -0.133466527f, -0.0510521568f, -0.0455979817f, 0.137340561f, 0.226023778f, -0.257836163f, + -0.0183570646f, 0.169707209f, 0.00516771805f, 0.00463166507f, -0.316175818f, 0.0086355973f, -0.12160404f, 0.192989528f, -0.0708106309f, -0.222051859f, + -0.476192087f, 0.355660021f, 0.520933747f, 0.525013983f, 0.579233468f, -1.42884648f, -0.520767987f, 0.0252352338f, -0.204854265f, 0.243043974f, + -0.704614282f, -0.0691333786f, -0.11239031f, -0.00604736479f, -0.0456586741f, 0.0254989192f, -0.0368854776f, -0.106069513f, -0.108119056f, -0.154180303f, + -0.0928403139f, -0.108772352f, -0.067369394f, -0.0550626703f, 0.0774988383f, 0.1220873f, 0.136243939f, 0.0436543673f, 0.0447220467f, -0.059240628f, + -0.00762840221f, -0.0853234977f, -0.0976241082f, -0.109792016f, -0.190431982f, -0.0722540244f, -0.109200187f, -0.0380413942f, -0.0459354185f, 0.0182228014f, + -0.00749359326f, 0.076057516f, -0.114953607f, -0.0683989748f, -0.093954213f, -0.1358753f, -0.0973700359f, -0.218907401f, -0.174739152f, -0.0872309506f, + 0.0209568962f, -0.0185937602f, -0.0170521066f, 0.0308801513f, -0.0920772552f, 0.0148502504f, 0.0712064803f, 0.112727761f, 0.312675893f, 0.115624227f, + 0.117921166f, 0.156580374f, 0.101691365f, 0.0516754314f, -0.0375952683f, 0.0560189374f, -0.0999168307f, 0.0258958582f, -0.020738937f, -0.128564268f, + -0.16049698f, -0.281339496f, 0.0300807096f, 0.190192267f, 0.0316790566f, 0.032308124f, 0.0410592891f, -0.0386716053f, -0.104868256f, -0.214576006f, + -0.0495710298f, -0.15997313f, -0.047761634f, -0.0450353511f, 0.0282101613f, -0.0585173853f, -0.053867992f, -0.175348803f, -0.442692816f, -0.214476258f, + -0.21690093f, -0.178436458f, -0.381109685f, -0.320878088f, -0.164660618f, -0.181137905f, 0.0305697862f, -0.132276207f, -0.161072567f, -0.256843954f, + -0.222922638f, 0.0768773332f, -0.0595220253f, 0.317591161f, 0.0162438899f, 0.0954919904f, -0.138670757f, 0.0449100286f, -0.0988726839f, -0.00934005436f, + -0.0643475652f, 0.11953263f, -0.0264136344f, 0.0271871649f, 0.0612249263f, 0.0281680822f, 0.0616476387f, 0.124941871f, -0.652362823f, 0.0091011459f, + 0.117657095f, -0.229160815f, 0.0251531675f, -0.177725166f, -0.0468211658f, -0.144015059f, 0.166125283f, -0.0815600976f, -0.027952468f, 0.0227786712f, + -0.0178619791f, -0.0118006701f, 0.0950254127f, 0.192132041f, -0.132421866f, -0.204823479f, -0.168939099f, -0.195467725f, -0.123744972f, -0.0710812584f, + -0.156130522f, -0.175781041f, -0.186728194f, -0.21679531f, -0.155109569f, -0.174606189f, -0.218672469f, -0.38659963f, -0.37425971f, 0.0967351422f, + 0.404337496f, 0.046032913f, 0.141679555f, -0.220490441f, -0.0858343244f, 0.0691766217f, 0.221011758f, -0.772100985f, -0.243015602f, 0.220589712f, + 0.290129125f, -0.607103705f, 0.292958647f, 0.0389841944f, -0.0598102883f, -0.0105437888f, 0.151992321f, 0.346746713f, 0.338353366f, 0.769479215f, + 0.805350661f, 0.569448829f, 0.335456252f, 0.192588821f, 0.0955266729f, 0.359695703f, 0.240328163f, -0.397165924f, -0.287518293f, -0.13233462f, + -0.325752765f, 0.0287025254f, -0.0487956144f, -0.307775021f, 0.354962498f, -0.0398176722f, -0.132714614f, 0.0699312165f, -0.0660249814f, -0.145260677f, + -0.155802786f, 0.0348195881f, -0.0540057682f, 0.0795955211f, -0.195081562f, -0.0372970439f, 0.183307439f, -0.185910895f, 0.0959828869f, 0.246262625f, + -0.101132639f, 0.0822390318f, 0.468297362f, -0.091539517f, 0.086345613f, 0.0930749327f, 0.0648089275f, -0.101267122f, -0.502314806f, -0.0297264699f, + 0.0524961539f, 0.111397155f, -0.0232775547f, -0.18646954f, -0.59675467f, 0.203634411f, -0.0722391084f, 0.00965824351f, 0.141714096f, 0.00355717633f, + 0.369077563f, -0.0403817035f, -0.134528846f, 0.100510925f, -0.605288267f, -0.0541821085f, 0.685120046f, 0.524120271f, -0.0560326129f, 1.08935475f, + -0.802576244f, -0.342334092f, 0.265910953f, -0.799430132f, -1.19623029f, 0.179981261f, -0.156135947f, -0.028450409f, 0.252330959f, 0.167381302f, + 0.122402012f, -0.192476779f, 0.10886205f, -0.032951951f, 0.48486197f, -0.0144003136f, 0.163846463f, -0.249823451f, 0.0972202122f, 0.010484173f, + -0.0888884887f, 0.143123269f, -0.00221290323f, 0.0479210541f, -0.0374934487f, -0.0626474246f, 0.432420254f, -0.216285944f, 0.297251552f, -0.301287264f, + -0.0318114311f, -0.298541486f, 0.234433219f, 0.255685747f, 0.220610231f, 0.150976658f, -0.280209363f, 0.558796942f, 0.128153279f, -0.151130006f, + -0.12577647f, -0.181099549f, 0.0619005524f, -0.0269831382f, -0.14153932f, -0.247966439f, 0.0948006213f, 0.24220784f, -0.033888597f, -0.100068919f, + 0.186003998f, 0.122028075f, 0.00927191321f, 0.259424448f, -0.215044945f, -0.207223728f, -0.377437532f, -0.346905857f, -0.0750784352f, 0.0800188854f, + 0.280813754f, 0.203984603f, 0.63263011f, -0.149964631f, -0.158545539f, 0.0221896637f, 0.343903869f, 0.164436385f, 0.10325478f, -0.430238664f, + 0.493088812f, -0.293506801f, 0.378728211f, -0.109309614f, 0.137139603f, -0.782011747f, -0.301964641f, -0.35441792f, -0.0905498043f, 0.0894401595f, + 0.247636765f, 0.252523392f, -0.0411947481f, 0.298493564f, 0.0180029292f, -0.0415848084f, 0.40365836f, 0.00352695724f, 0.0279703289f, 0.396235794f, + 0.145219177f, -0.16306904f, -0.174683675f, 0.225457221f, -0.023024844f, -0.0186220426f, 0.0881270096f, 0.237729311f, 0.479748726f, -0.494881511f, + -0.0377871953f, -0.154705912f, 0.228288904f, 0.201902077f, -0.204412431f, -0.393695503f, -0.0318999328f, -0.30601263f, 0.0674094558f, 0.00698485551f, + -0.0757853091f, -0.0742330775f, -0.0389602073f, 0.118981808f, 0.144273072f, 0.172488511f, -0.111849561f, 0.132160529f, 0.0845420882f, -0.194855049f, + -0.0143634882f, -0.110970199f, 0.466853201f, -0.024720706f, -0.165371165f, 0.101183787f, 0.0443716235f, 0.134788021f, -0.2524966f, 0.140466899f, + 0.250247449f, -0.25952068f, -0.0367809795f, -0.231421202f, -0.770279765f, 0.192894697f, 0.103047132f, -0.898947656f, 0.30961436f, 0.827564359f, + 0.0806930587f, -1.20274675f, 0.457319558f, -0.614170671f, -0.0803238675f, -0.0283915959f, 0.767439961f, -0.25158295f, 0.248829871f, 0.818019211f, + -0.0691501498f, -0.0657889619f, -0.139831185f, 0.0216431282f, -0.0452979207f, -0.0838284865f, -0.140676633f, -0.0492232069f, 0.575919211f, 0.0382392965f, + -0.0559544861f, -0.0353542119f, -0.135602817f, 0.15679346f, -0.623912454f, -0.00740883034f, 0.0348652191f, -0.0238604508f, 0.0645988435f, -0.14206785f, + -0.631822705f, -0.257513076f, -0.155063495f, -0.188832834f, -0.170855105f, -0.430015922f, 0.0590549223f, -0.20527184f, -0.120811149f, -0.192324206f, + -0.247981191f, -0.51770246f, -0.183377936f, 0.0559382737f, 0.0346499421f, 0.125636384f, 0.202239305f, 0.262170464f, -0.705227733f, 0.226897612f, + 0.433264136f, 0.275757939f, 0.188794881f, -0.0477005914f, -0.216672957f, -0.252455562f, -0.216099352f, 0.0583473742f, -0.0244964492f, -0.0887138322f, + -0.362493396f, 0.135234028f, 0.121575251f, -0.0838968977f, 0.0456685871f, 0.0604592599f, 0.0822873637f, 0.143147752f, 0.154852018f, 0.1457638f, + 0.248810425f, -0.171770453f, -0.100277238f, -0.61425066f, -0.523518741f, 0.271296889f, -0.836184382f, -0.915187955f, 0.152276337f, -0.377340227f, + 0.0783340111f, -0.401181132f, 0.0756909177f, -0.288490683f, -0.145444632f, -0.288162649f, -0.233492494f, -0.366743863f, -0.315450251f, -0.370184451f, + 0.0407243669f, -0.0269878618f, 0.0527695417f, -0.0823731497f, -0.224401668f, -0.164762378f, -0.763901353f, 0.178852648f, 0.0441856906f, 0.350955099f, + 0.638444066f, 0.512373209f, -0.285839856f, 0.19677642f, 0.0762244761f, -0.018053947f, 0.0571839511f, 0.125828907f, 0.172515109f, 0.106192261f, + 0.0923421234f, -0.0479836054f, -0.0410989709f, -0.0360715427f, -0.0886907056f, 0.240838185f, 0.17323406f, 0.0889817327f, 0.0631293654f, 0.298146397f, + 0.245818704f, 0.0705742016f, 0.045833718f, 0.2975007f, 0.456900924f, 0.360606939f, -0.577783525f, -0.17375128f, -0.180366397f, -0.137858957f, + -0.0468069203f, 0.0765052438f, -0.704327822f, 0.316999793f, 0.235315487f, 0.0802239329f, -0.212876245f, -0.336106747f, -0.0591608882f, 0.0579039752f, + -0.314030558f, 0.414455742f, 0.586914897f, 0.0583876669f, 0.91579783f, -0.362354428f, 0.482291132f, 0.0977448002f, -0.0198144615f, -0.171262532f, + 0.0438375883f, -0.0707140863f, -0.0150033338f, -0.626800478f, 0.00812979881f, 0.150766388f, -0.383419603f, -0.0241108425f, 0.119620062f, 0.130144909f, + 0.0244152565f, -0.373541266f, 0.40131405f, 0.0701556578f, 0.00113302434f, 0.210757092f, 0.203776002f, -0.081090264f, -0.940009773f, -0.060166534f, + -0.0633710921f, -0.251617759f, -0.178969979f, 0.222267658f, -0.611365676f, -0.107451193f, -0.161501125f, -0.361987621f, -0.255813867f, 0.347898662f, + -0.511871517f, 0.135070428f, 0.0405251309f, -0.169842631f, -0.197546452f, -0.177608415f, 0.403699815f, -0.0939308703f, 0.0117656104f, 0.293900162f, + 0.251763642f, -0.0412922315f, -0.134684548f, 0.0169789325f, 0.0203814022f, -0.357786536f, -0.0904970616f, 0.270420611f, -0.26720044f, -0.0635845587f, + 0.0592079237f, 0.150097534f, 0.0980813578f, 0.0444612131f, -0.297819972f, 0.0641438067f, -0.0133967837f, 0.0423032865f, -0.0738558248f, -0.194767475f, + -0.289569974f, 0.265420109f, 0.157986313f, 0.195147753f, 0.217526749f, -1.20099556f, 0.140949473f, -0.0144790513f, 0.667499244f, -0.425745398f, + 0.0488706119f, 0.301857591f, -1.14423311f, -0.98059094f, -0.0257926341f, -0.520171404f, -0.0366240516f, 0.113176644f, -0.134298369f, 0.0914182812f, + 0.268955022f, -0.141189009f, -0.254027516f, 0.077094771f, 0.138365909f, -0.247495845f, 0.311900139f, 0.232561395f, 0.114937864f, 0.0233949274f, + -0.0223802906f, 0.243975997f, -0.0733948424f, 0.372098684f, -0.0144303842f, 0.122546472f, -0.0316174254f, 0.0677938238f, 0.317567289f, -0.1585747f, + -0.338900596f, -0.0671578199f, -0.362332344f, -0.156299561f, -0.0449222773f, -0.0530846603f, 0.261795729f, -0.156030431f, 0.0422026403f, -0.00253549148f, + 0.345645815f, 0.608090162f, 0.219927251f, 0.472805738f, -0.0511464477f, -0.0776522979f, 0.0591266081f, -0.288458586f, 0.00716940407f, -0.276293665f, + 0.147011071f, 0.0630501285f, 0.0553918295f, -0.0215875618f, 0.189942554f, 0.0924312919f, -0.0271163546f, -0.0124690617f, -0.0484433584f, 0.101308711f, + -0.114016682f, 0.0166824758f, -0.313998401f, -0.0206213631f, -0.0900594592f, 0.158031404f, 0.854827583f, -0.305067658f, 0.185465917f, 0.845378458f, + 0.1924676f, -0.226778314f, -0.169291228f, -0.590278685f, 0.176980317f, 0.65129143f, 0.328980774f, 0.445320189f, 0.0f, 0.0f, + 0.0f, -0.141146362f, 0.0601712614f, -0.0761591643f, -0.0338535309f, -0.0766490176f, -0.0226158183f, -0.103787161f, 0.0375294201f, 0.00169021846f, + -0.0797633901f, 0.0447744355f, 0.0762500763f, 0.0945864543f, -0.60773927f, -0.222633451f, 0.00393651845f, 0.129918143f, 0.00132478366f, -0.0510998033f, + -0.0223415289f, -0.070325233f, 0.087363936f, 0.175239772f, -0.1419705f, 0.0239179116f, -0.0017247888f, 0.0741626173f, 0.01597609f, -0.10642153f, + 0.0824269578f, 0.0669936463f, 0.197589651f, 0.160177991f, -0.0878141075f, 0.0990223959f, 0.046296753f, 0.104311511f, 0.0243016798f, 0.11431244f, + -0.0243350174f, -0.00627875794f, 0.148691118f, -0.0499025658f, -0.0314308926f, 0.248383671f, 0.010342055f, 0.0108889416f, 0.0756303519f, 0.164318189f, + 0.0199999996f}, + {0.298169196f, 0.834851742f, 0.566332042f, -0.281071961f, 0.244526163f, 0.146056563f, -0.0776393414f, 0.187925145f, 0.127435207f, 0.0989704877f, + 0.0408731364f, 0.172285408f, -0.122527532f, 0.0142100789f, -0.0711631551f, 0.179305688f, 0.0515339263f, -0.0179709047f, -0.126363859f, -0.00207504956f, + 0.0489747152f, 0.107055813f, 0.419555515f, 0.303775966f, -0.606004238f, -0.47729224f, -0.0560975298f, 0.0712259784f, 0.162400633f, 0.114247032f, + 0.528355658f, -0.29992345f, -0.109230027f, 0.663724422f, 0.271537006f, 0.222365394f, -0.0928931832f, -0.428937942f, 0.0119812265f, 0.0495484583f, + -0.280375332f, -0.180298269f, -0.0403306186f, -0.224385038f, 0.00424655015f, 0.0448402911f, 0.0151683679f, -0.141832158f, 0.113509409f, 0.205200851f, + 0.0986296535f, -0.171993524f, 0.175424755f, -0.145801559f, 0.172834322f, -0.268201917f, 0.226380855f, -0.0280655716f, -0.0084485868f, -0.0655144304f, + 0.0314487554f, -0.643471479f, -0.13472791f, -0.254179329f, 0.0633533075f, -0.403380156f, -0.273293197f, -0.00539862784f, -0.256401211f, 0.176673666f, + 0.28113693f, -0.642290592f, 0.0403129645f, 0.0336088985f, -0.00424549961f, -0.0216160789f, 0.257494956f, -0.0824537873f, -0.201830164f, 0.183283374f, + 0.109237805f, 0.137808338f, -0.0993204266f, -0.331138909f, -0.00249154097f, -0.062645629f, 0.272423476f, 0.0354523323f, -0.349283606f, -0.232732579f, + 0.259209663f, 0.221262425f, -0.064863123f, -0.0413531512f, 0.0216557477f, -0.0052449801f, 0.095826976f, -0.00707133533f, -0.0875503495f, -0.102563173f, + 0.166774973f, -0.649585307f, -0.149985656f, -0.0592957325f, -0.395894915f, -0.000555148115f, -0.271158367f, 0.0481899232f, -0.179924324f, 0.0662801638f, + 0.222538173f, 0.341768175f, 0.179625914f, -0.0155677721f, 0.60479635f, -0.0310807507f, -0.271542698f, 0.231184199f, 0.260230362f, 0.464116305f, + 0.160246268f, -0.0488673113f, -0.303553998f, 0.267425597f, 0.0515859127f, 0.432202965f, 0.453962415f, -0.47026059f, -0.819065869f, -0.066787079f, + -0.0900533125f, 0.0258398131f, 0.441631943f, 1.2018857f, -0.577404499f, -0.518202782f, 0.296377838f, -0.933797061f, -0.462781727f, -0.326133519f, + 0.0763871744f, -0.213769957f, -0.0627994835f, 0.197276697f, 0.0422177874f, 0.0151443947f, 0.000225830532f, 0.0551711991f, 0.103999026f, -0.0592864454f, + 0.118757635f, -0.210763916f, -0.165309623f, 0.212832049f, -0.112442791f, -0.0784578323f, 0.0624730736f, -0.120979235f, -0.00990713481f, 0.00872059911f, + 0.012876465f, -0.29305771f, 0.178190023f, -0.120290712f, -0.144244671f, 0.0785657093f, 0.109575532f, 0.373000294f, 0.102131777f, 0.247320294f, + -0.868397534f, 0.132656232f, 0.310953587f, 0.000715620408f, -0.0558510125f, 0.0795491263f, -0.0076799104f, 0.124969341f, 0.435166061f, 0.00337712001f, + -0.123777479f, -0.0592967533f, -0.258069396f, -0.211010396f, -0.185340747f, -0.16293633f, -0.221959397f, -0.146669179f, 0.0846537054f, -0.280040354f, + 0.0917584822f, 0.239846721f, 0.0662942678f, -0.129547387f, -0.325734377f, 0.68544203f, 0.23845306f, -0.21651569f, -0.118255801f, -0.0271774307f, + -0.481778771f, -0.111681849f, 0.0132080521f, -0.00610101363f, 0.136570409f, -0.353638411f, 0.48314783f, 0.612140834f, -1.74553418f, -0.212727055f, + -0.845184028f, 0.2967875f, 0.022819005f, 0.265018374f, -0.0707334653f, 0.294730783f, 0.00585397985f, 0.0449226759f, 0.00597409438f, 0.438480318f, + -0.0240816735f, -0.141900927f, -0.128786549f, 0.193627641f, -0.071466133f, 0.140378952f, -0.425630718f, -0.179941833f, 0.0293325502f, -0.305986047f, + -0.0507702827f, -0.187764943f, 0.0248261709f, -0.28714934f, -0.142342076f, -0.0965500474f, 0.0888821334f, 0.099601768f, 0.00266252877f, 0.161265597f, + 0.042704884f, 0.0114805605f, 0.00685742497f, -0.0450433306f, -0.198365092f, 0.184970587f, -0.164119706f, -0.0199678671f, 0.272441864f, -0.00208381121f, + -0.198710322f, -0.534377873f, 0.120762847f, 0.157915413f, -0.145285234f, 0.00362122338f, -0.0188507121f, -0.0870145038f, -0.118261665f, -0.0528423265f, + 0.469934165f, -0.272511631f, 0.40926677f, -0.222518444f, -0.417265058f, 0.236046597f, 0.105479322f, 0.115927204f, -0.0950777233f, -0.0832456648f, + -0.0607164055f, -0.147490278f, 0.233978599f, -0.105123661f, -0.101993978f, -0.0406325385f, -0.20440802f, -0.185874015f, 0.248718172f, 0.269853592f, + -0.148200125f, -0.532182693f, 0.0685282946f, -0.8411327f, -0.211341619f, 0.0951197147f, -0.539649904f, -0.171105787f, -0.0078930473f, 0.0221023038f, + -0.104236551f, 0.0471737236f, -0.0088037774f, 0.0334534682f, -0.0194742307f, 0.19390513f, -1.07284594f, 0.255925238f, -0.228480041f, -0.213329121f, + 0.110298119f, 0.326971203f, -0.182934493f, -0.200876296f, -0.0819330662f, -0.0673680156f, -0.246458098f, 0.300005972f, -0.295356661f, -0.00530845905f, + -0.0528683737f, 0.0440536402f, 0.0713275746f, -0.105033092f, 0.510254025f, 0.00957369525f, -0.0559504926f, 0.1692736f, 0.16361481f, 0.237132803f, + -0.255547822f, -0.11808525f, 0.268705428f, -0.0833294541f, 0.0183817688f, 0.0663535446f, -0.103250407f, 0.015433535f, -0.120360903f, 0.0363704264f, + 0.311527282f, 0.332135528f, 0.160235941f, -0.00164417131f, -0.0856503323f, 0.149635121f, -0.35646987f, -0.327435434f, -0.154604077f, -0.0542854071f, + -0.250975907f, 0.0456149615f, -0.37483269f, 0.324210972f, -0.0193702076f, 0.150985822f, -0.0876649618f, -0.070137769f, -0.242370114f, -0.391658545f, + -0.0927535966f, -0.129358634f, -0.494441748f, -0.390859783f, -0.112498939f, 0.174842402f, 0.755721331f, 0.537026346f, 0.120096318f, 0.00660834135f, + 0.0147610009f, 0.00130030024f, -0.07725095f, -0.041035492f, 0.0154455286f, -0.0349416621f, 0.0254740454f, 0.0459098518f, -1.05452454f, 0.0486139916f, + -0.0309966225f, 0.0129557718f, 0.0335132331f, -0.277030796f, -0.0490444042f, -0.0536809079f, 0.00592528144f, -0.0501820855f, 0.0606851056f, 0.103449933f, + 0.236130044f, -0.0103813177f, 0.00515061663f, 0.0177216511f, 0.0519857854f, -0.105305254f, 0.643158078f, 0.0112425266f, -0.0219879355f, 0.0401121192f, + 0.254376411f, 0.747833312f, -0.290835083f, -0.0204133894f, -0.0026124639f, 0.0273126196f, 0.0935040191f, -0.103599176f, -0.156855687f, 0.11890547f, + 0.0399832949f, -0.00610825513f, -0.057039313f, -0.0330515914f, -0.528661013f, -0.133778661f, -0.0771357119f, 0.0410562083f, -0.0836756155f, 0.128358707f, + 0.102443174f, 0.176632941f, 0.0506306961f, -0.0511166751f, -0.120332591f, -0.123963319f, 0.50142169f, -0.129736468f, 0.0724691451f, -0.0644240305f, + 0.353509784f, -0.00437153084f, -0.19943206f, 0.299408317f, 0.498145282f, -0.144841492f, -0.0229488946f, -0.056383796f, -0.690425038f, -0.494730055f, + -0.0558132492f, -0.460627049f, -0.0223156884f, -0.0302529596f, -0.0338462256f, -0.00168267381f, 0.000335806631f, -0.00421865098f, 0.00643063476f, 0.0163039826f, + -0.663913667f, 0.00379053783f, -0.00643124618f, 0.00294714025f, -0.000574376434f, -0.0394007638f, -0.24912554f, -0.0162898395f, -0.000179009279f, -0.0302190892f, + 0.0187883694f, 0.00951236021f, 0.169171453f, -0.00084672973f, -0.00124236301f, -0.00180311163f, -0.00892653503f, -0.0275068134f, -0.172065675f, -0.000384187209f, + 0.0231292117f, 0.00995507278f, 0.0209244844f, 0.0641363561f, 0.0641140416f, 0.00448447f, -0.00738537172f, 0.0332318507f, -0.0235815607f, -0.0347185098f, + 0.00622970844f, 0.0510900207f, -0.0945286974f, -0.031663768f, -0.152289927f, -0.109501593f, 0.0358143598f, -0.0636628419f, 0.173010141f, 0.373697549f, + 0.0573599227f, 0.354426652f, -0.0911287665f, 0.127101734f, 0.0902764946f, 0.314508677f, -0.154030055f, 0.00661288621f, 0.220766395f, 0.0690835789f, + 0.0702543408f, 0.0470685624f, -0.141622201f, -0.543231666f, -0.075602062f, 0.294369996f, 0.745032966f, -0.022982182f, 0.614924729f, 0.927964687f, + -0.00652894285f, 0.708422244f, 0.819657326f, -0.00695791049f, -0.00783300679f, -0.0217525437f, -0.0662474036f, 0.203977615f, 0.123936586f, 0.0414736755f, + 0.0373815782f, 0.0956978053f, 0.155547947f, -0.282795995f, -0.0625221059f, -0.426710665f, 0.00156202784f, 0.097490944f, -0.0178094506f, -0.0395911708f, + 0.0506466366f, -0.242744252f, -0.132286981f, 0.0689204559f, 0.195200637f, -0.140549228f, 0.448302299f, -0.0998842269f, 0.266651332f, 0.248021469f, + -0.113751419f, -0.179342359f, -0.274269998f, 0.00747251045f, 0.169489101f, -0.0185557473f, -0.0328719765f, 0.109475203f, 0.365624011f, -0.350982308f, + 0.0660348833f, 0.0886317268f, -0.206253245f, 0.782781124f, -0.145642936f, -0.0873920843f, -0.216567948f, 0.196102798f, -0.349371672f, 0.130019575f, + 0.112139329f, 0.034635637f, -0.36979875f, -0.228296593f, 0.304796636f, -0.374390066f, -0.204832911f, -0.0644070655f, 0.162559465f, 0.0565648936f, + 0.190242574f, -0.0854309574f, 0.0674673468f, 0.191782206f, -0.381501555f, 0.24912484f, 0.0223067813f, -1.19391918f, 0.528445363f, 1.13842475f, + -0.535534322f, -0.0683340952f, 1.09802616f, -0.203176364f, -0.987429976f, -0.809177041f, -0.0725280493f, 0.0271431748f, 0.0694802627f, -0.179432705f, + -0.178682014f, 0.182505921f, 0.119555429f, -0.0462232307f, 0.433885187f, 0.210271925f, 0.135048166f, 0.115157537f, -0.109511368f, 0.148892552f, + -0.221365303f, 0.160679668f, 0.0224168096f, 0.268882871f, 0.11540392f, -0.370543629f, -0.0858403221f, 0.135826573f, -0.455211759f, -0.28332147f, + -0.160017535f, -0.249935031f, 0.41067642f, 0.138513356f, 0.0251724143f, -0.105725855f, -0.187333986f, -0.0904291794f, -0.112023853f, 0.127429217f, + 0.154452577f, 0.145927548f, -0.235024661f, -0.125585079f, -0.15176335f, 0.422073126f, 0.0417372696f, -0.464129567f, 0.0100174416f, 0.339248896f, + 0.117869586f, 0.00525303977f, -0.155121014f, -0.562295794f, -0.537613571f, -0.417781025f, -0.114683107f, -0.0705674514f, 0.0142632406f, -0.144035116f, + 0.280048221f, 0.0538891591f, -0.0908107609f, -0.00517764315f, -0.0672351122f, -0.182711378f, 0.374016583f, -0.435665309f, -1.0896318f, -0.489523739f, + 0.0951082185f, -1.656286f, -0.0669075847f, -0.239211082f, -0.572116196f, -0.827369452f, -0.051353354f, -0.345038682f, 0.0177106652f, -0.0800005794f, + 0.0695083439f, 0.29819414f, 0.0893573985f, -0.451107919f, -0.269419432f, 0.288454175f, 0.353852749f, 0.221659854f, 0.148034558f, 0.471809715f, + -0.0213377718f, 0.0266992431f, -0.199267536f, 0.0220406931f, 0.7016837f, -0.152150124f, 0.0754881874f, -0.339391261f, 0.371072561f, 0.233786985f, + 0.00564093236f, 0.0706790611f, 0.0554684438f, 0.143198192f, 0.280894399f, -0.120796077f, -0.290451795f, -0.241605774f, -0.38646695f, -0.11882963f, + -0.174978852f, 0.354563445f, 0.226949275f, 0.156393826f, 0.167419761f, 0.385338336f, -0.161427572f, 0.0990072116f, 0.225354761f, -0.0288755596f, + 0.171168759f, 0.0447859503f, 0.197959006f, 0.0355545245f, 0.0622994341f, 0.139003158f, -0.0438596345f, 0.510690928f, -0.317927092f, -0.19054389f, + -0.264133722f, -0.375830203f, -0.373995572f, 0.581702411f, 0.480955958f, 0.0152332522f, -0.189679742f, -0.0600096583f, -0.0785360336f, -0.535336435f, + 0.0613784343f, 0.242245123f, -0.343030959f, -1.00634432f, -0.0578321666f, 0.304048657f, -1.39579678f, -0.310496449f, -1.05145085f, 0.288101763f, + 0.0447793864f, -0.00775484368f, 0.0492441207f, 0.0489328429f, -0.188869193f, -0.0962709114f, 0.131644934f, -0.017752273f, 0.657017946f, -0.060517177f, + 0.0387256444f, 0.00979625899f, -0.264118582f, -0.164008126f, 0.792860806f, -0.0916035697f, -0.059080869f, 0.240904585f, 0.0327610075f, 0.153407171f, + -0.583693266f, -0.00127380213f, -0.458919972f, 0.278281957f, -0.0712793842f, 0.0634020045f, -0.0887861177f, -0.077738978f, 0.378384382f, -0.359521121f, + -0.153853953f, 0.0296927094f, 0.773162186f, 0.0401539989f, 0.105878115f, 0.052010458f, -0.253520876f, -0.100746505f, -0.349070728f, 0.0367701426f, + 0.0716164485f, -0.0972739831f, -0.601323545f, -0.719588995f, 0.151709214f, 0.116946511f, -0.0805021152f, -0.24694179f, -0.197521552f, -0.0349361151f, + 0.29656589f, 0.254745841f, 0.262848049f, 0.197413608f, -0.158128202f, 0.13476254f, -0.237044528f, -0.0264277086f, -0.0216577761f, -0.327757537f, + -0.0658549294f, -0.0440194495f, 0.79995352f, 0.725023806f, 0.93119961f, -0.210997194f, 0.669896781f, -0.512034118f, -0.417972952f, 0.127149701f, + -0.0681142509f, 0.41567257f, -0.0107034147f, 0.0354501493f, 0.137563065f, -0.0467083268f, -0.000648529676f, -0.0172077715f, -0.00517317699f, -0.0394032076f, + -0.221803129f, 0.0430091769f, 0.0213497765f, -0.00138058595f, -0.0542128161f, -0.02022448f, -0.134720668f, -0.0823276639f, 0.0380705856f, -0.122257479f, + 0.0208893139f, 0.0572321899f, 0.232635319f, 0.0928023905f, -0.00213804562f, -0.0230949316f, 0.0268039517f, 0.176798716f, 0.481929243f, -0.106125832f, + 0.011608745f, 0.0733507723f, 0.00916041806f, -0.195342377f, 0.316624582f, 0.0978703052f, 0.00077561551f, 0.112641908f, 0.020324301f, -0.109420486f, + -0.108588591f, -0.141761467f, 0.0127809588f, 0.143780023f, -0.219248176f, -0.30891332f, 0.198368713f, 0.0647620782f, -0.0567613021f, -0.313880533f, + 0.0175972264f, 0.0291873198f, 0.117926247f, -0.340469986f, -0.102195308f, -0.294634074f, -0.0412032828f, 0.279982269f, 0.167771637f, 0.095120199f, + -0.18381238f, -0.109586976f, 0.0468081757f, 0.0844263434f, -0.518833995f, -0.242141277f, 0.347812027f, 0.133034647f, 0.814665854f, -0.726994812f, + 0.00428962102f, -0.165363863f, 0.827334583f, 0.678203881f, 0.0472462922f, 0.00267747277f, -0.0455134064f, -0.272734821f, -0.192036539f, -0.360284954f, + -0.106424458f, -0.0292809494f, -0.364261687f, 0.161073685f, -0.0660926476f, 0.0378280096f, 0.1469374f, -0.0830751508f, 0.1126692f, -0.668315351f, + -0.287303388f, -0.39515245f, -0.591318309f, -0.219926193f, -0.123615541f, -0.00300097466f, 0.00144916226f, 0.0149314776f, 0.00763681484f, -0.00179939065f, + -0.794626892f, -0.00426328741f, -0.024226401f, -0.0635840893f, -0.0242823604f, 0.0525177009f, -0.317714393f, 0.0417513214f, 0.0243405998f, 0.0259752832f, + 0.035489697f, 0.00682280213f, 0.339906663f, -0.0223095845f, -0.0301631615f, -0.0464555584f, 0.000477663387f, -0.440985203f, 0.0827429071f, 0.102965333f, + 0.116844811f, 0.112103641f, 0.0188879389f, 0.247774333f, 0.149313495f, -0.0195407942f, -0.0259025581f, -0.0814702511f, -0.0456460528f, -0.306350827f, + -0.199126512f, -0.277455628f, 0.0529001169f, -0.11402265f, -1.03757358f, -0.0611440279f, 0.288221449f, 0.636398315f, 0.904510319f, -0.0192345027f, + 0.379482895f, -0.0775645599f, 0.642606854f, 0.625261009f, -0.103441432f, 1.7846396f, -0.0485190973f, -0.0710109621f, -0.0265029334f, -3.6467176e-05f, + -0.00479829405f, -0.00149920187f, 0.00442227861f, -0.0102270003f, -0.704838037f, -0.00509493845f, 0.0250863302f, 0.0160278566f, 0.0246204976f, 0.0480655581f, + -0.442875087f, -0.00532114645f, -0.00990363583f, -7.87539136e-07f, 0.0200081654f, 0.0257469974f, -0.142979071f, -0.107200645f, -0.352174073f, -0.203734174f, + -0.319682002f, -0.0917085707f, -0.0949847624f, 0.33898434f, 0.34117499f, 0.0740995407f, 0.0139979096f, 0.416921675f, 0.00940294843f, -0.239929378f, + -0.362983376f, -0.108534545f, -0.125934109f, -0.604307115f, -0.27802667f, -0.0290709846f, 0.0432216451f, 0.0178605597f, 0.105589584f, 0.222296372f, + -0.0554858297f, -0.0620383509f, -0.0926993117f, -0.256051511f, -0.358382702f, -0.769361854f, 0.3543697f, 0.111729428f, 0.0707194209f, 0.18034409f, + 0.307736754f, 0.435062796f, -0.0863403603f, 0.119474404f, -0.20348227f, 0.0908874646f, -0.0991494879f, -0.439646631f, -0.193454504f, -0.7958498f, + 0.506684959f, 0.120817415f, 0.00309143914f, 0.374865234f, -0.330457479f, 0.35704118f, 0.971429169f, -0.479968429f, -0.0523643568f, 0.0414621904f, + -0.0325986333f, 0.000143615209f, -0.0220090579f, -0.0057210559f, 0.103392407f, 0.0124088367f, 0.045478642f, -0.186062649f, -0.206953794f, -0.330615669f, + -0.198935539f, -0.260905445f, -0.0820678025f, -0.0145647116f, 0.303714335f, -0.0454243273f, -0.139389932f, 0.0512519255f, 0.138009787f, 0.0616132021f, + -0.0876507461f, 0.00985632464f, -0.123885594f, -0.2030157f, -0.398933232f, -0.125297636f, 0.129968897f, 0.124631345f, 0.503600419f, 0.369588673f, + 0.180702865f, -0.0430132747f, -0.224977776f, 0.155870244f, 0.054585956f, 0.0247222185f, 0.198941782f, 0.0378100388f, 0.182806313f, -0.111644126f, + -0.00619497849f, -0.192084357f, -0.144440025f, -0.143351987f, -0.138370514f, -0.0941176191f, -0.334716767f, -0.286907613f, 0.0599342734f, 0.0357241556f, + -0.0369301699f, -0.0410424098f, 0.260082155f, -0.139023304f, 0.0183807481f, 0.0514914654f, 0.410344422f, 0.494946331f, 0.901759624f, 0.71025157f, + 0.170354962f, -0.030236803f, -0.234682947f, 0.190600917f, -0.0570140854f, -0.146582142f, -0.1532581f, 0.00717407698f, 0.195614204f, 0.36143747f, + 0.163554579f, 0.586324692f, 0.703630328f, 0.99685967f, 0.96818006f, 0.924353898f, 0.261771679f, 0.3871786f, -0.198873088f, -0.0163427573f, + 0.313370407f, -0.199249044f, -0.0239813328f, -3.0231311e-05f, -0.206337318f, 0.100910202f, -0.255293578f, -0.365251511f, -0.252499968f, -0.249602363f, + -0.147328049f, -0.168057576f, -0.0483406484f, -0.173329532f, 0.263977468f, -0.0410680287f, 0.0402535275f, 0.106343932f, -0.0164017249f, -0.033607278f, + -0.017611742f, 0.0414425991f, 0.0155380284f, 0.098398909f, -0.0810562968f, -0.124923505f, 0.342442214f, -0.0650876909f, 0.0579448864f, 0.0174591746f, + 0.269401848f, -0.110236086f, 0.0809090808f, 0.0929472223f, 0.151466563f, -0.209226191f, 0.120315462f, -0.312159151f, 0.195554256f, 0.181913584f, + 0.224258453f, -0.253993511f, 0.182856679f, -0.0766741782f, -0.172025919f, -0.0967547148f, -0.0989626274f, 0.00947175175f, 0.175485909f, -0.280120581f, + -0.0809108242f, 0.0942580551f, -0.115131818f, 0.0303536989f, -0.296331614f, 0.0049328669f, -0.219215006f, -0.0021577205f, 0.118399315f, -0.352976799f, + 0.051935669f, 0.144049987f, 1.09946418f, 0.573032737f, 0.321715295f, -0.524939477f, -0.31080392f, 0.39520967f, 0.636177123f, 0.0620804653f, + -0.659584284f, -0.0515510552f, 0.116134718f, -0.0923413262f, 0.0316197462f, 0.0294786505f, -0.0127007505f, 0.0379231721f, 0.024470685f, -0.00934881996f, + -0.0727926865f, -0.019765662f, 0.0114410231f, -0.0212843698f, -0.0793579966f, -0.112702079f, -0.0713064671f, 0.176346824f, 0.233571038f, 0.225713149f, + 0.131693676f, -0.00777844666f, 0.128570154f, 0.111460112f, 0.0262124185f, -0.0734669566f, 0.0478651375f, 0.04726265f, 0.111689083f, 0.148737103f, + 0.0411039926f, 0.178581715f, 0.191152781f, -0.0531429164f, 0.0016809646f, -0.0347319767f, 0.0525988713f, -0.0563757904f, -0.0741385594f, -0.022121327f, + 0.0771154612f, 0.0909821689f, -0.0271703899f, 0.192029268f, 0.0504828244f, 0.20669955f, 0.166594684f, -0.0162650123f, 0.0721386746f, 0.0566922426f, + 0.0517756641f, 0.121095888f, 0.0969378576f, 0.0647132248f, 0.0152588366f, 0.068242833f, 0.00279083825f, 0.070026949f, 0.0175695345f, -0.0904950052f, + -0.299651772f, -0.24285008f, -0.290676504f, 0.111341245f, -0.0354024917f, -0.00304864533f, 0.134295747f, 0.075233981f, 0.0587515607f, 0.0139603252f, + 0.0939016342f, -0.0195312649f, 0.13323155f, -0.047580231f, -0.0851856172f, -0.163328186f, 0.209106684f, -0.0263486505f, 0.0841646194f, -0.0597087629f, + 0.0607450381f, 0.0876147896f, -0.0877332687f, -0.0822636262f, 0.176634058f, -0.176392063f, -0.0502426587f, -0.165043235f, 0.0045453636f, -0.165693998f, + 0.0154810715f, 0.167365387f, 0.0575612597f, -0.0511045009f, -0.059789557f, 0.0145914536f, -0.0634398684f, 0.0183072593f, 0.0425175652f, 0.0583648905f, + 0.0450551584f, 0.126644373f, 0.118888192f, 0.186585233f, 0.134484172f, 0.143967018f, 0.102988482f, -0.190858841f, -0.762247741f, -0.261796504f, + -0.105104536f, -0.342866093f, -0.157857522f, -0.168563873f, -0.10848543f, -0.190719455f, 0.062415503f, -0.0726816058f, -0.0176734049f, -0.0108882859f, + 0.0732909814f, 0.101059236f, 0.165221244f, 0.475844085f, 0.100155234f, 0.00537673617f, 0.0255111698f, -0.077249065f, -0.083561033f, -0.0972701684f, + -0.0685811415f, -0.145825878f, -0.106883861f, -0.299757093f, -0.253247559f, -0.164823905f, -0.2827622f, -0.0465814658f, 0.0535463952f, 0.114095762f, + 0.17467171f, 0.0541034527f, 0.792957902f, -0.411149949f, -0.256236315f, 0.347439736f, 0.091454573f, -0.743203104f, -0.193631455f, 0.452057719f, + 0.737541378f, -0.700302005f, -0.116671361f, 0.062164817f, -0.0308772251f, 0.112868667f, -0.20913589f, 0.101936154f, 0.211876467f, 0.598281384f, + 0.708180785f, 0.545881391f, 0.483734369f, 0.132790059f, 0.0116151199f, 0.489270121f, 0.298836827f, -0.344663352f, -0.0821502432f, -0.17885448f, + -0.303747892f, 0.0455380976f, 0.0798422843f, -0.143281147f, 0.572489202f, 0.112850793f, 0.0311881844f, 0.297389984f, 0.135297284f, 0.0144666079f, + -0.052877903f, 0.0837326944f, 0.016843494f, -0.0660352856f, -0.358272135f, -0.0574264042f, 0.112442464f, -0.259691685f, 0.023369493f, 0.188611105f, + -0.194095537f, 0.00416838937f, 0.393043518f, 0.0142513588f, 0.366328537f, 0.526715994f, 0.591427922f, 0.273385257f, -0.0704654232f, -0.109819256f, + 0.300157666f, 0.260318547f, -0.0278854501f, 0.0853517428f, 0.0311426353f, 0.00456892513f, -0.197070494f, -0.163950086f, -0.0909872353f, -0.197140738f, + 0.285547763f, 0.0676472411f, 0.104983397f, 0.0136450585f, -0.396954536f, 0.630345166f, 0.198083758f, 0.645774543f, -0.0650100484f, 1.11351871f, + -0.93696171f, -0.673769653f, -0.0826378018f, -0.716573715f, -0.975305021f, 0.733206511f, -0.107828014f, 0.137885928f, -0.314836711f, 0.13326098f, + 0.146206319f, -0.182958782f, 0.0709537193f, -0.182197645f, 0.0696957186f, 0.00415856158f, 0.0845446885f, -0.28805536f, -0.00988093577f, 0.0374729335f, + -0.00144427258f, 0.151126847f, 0.0193470456f, 0.0790062249f, 0.115836419f, 0.0738210678f, -0.0954949781f, -0.0425963029f, 0.254089147f, -0.0757824481f, + -0.0953059345f, -0.258830696f, 0.0258806739f, 0.022589514f, 0.240865603f, 0.0697251558f, -0.306953609f, 0.239145413f, -0.161068112f, -0.0307254083f, + 0.0527046844f, -0.0106567191f, 0.142637491f, -0.0774019659f, -0.145175815f, -0.0355352089f, 0.0556858778f, 0.0770675912f, -0.0580948219f, -0.0308759045f, + 0.570211709f, -0.0295125768f, 0.0718758702f, 0.115950748f, -0.080830358f, -0.18190372f, -0.577831686f, 0.039849285f, 0.0358933434f, -0.0176930726f, + 0.0747682154f, 0.387708634f, 0.234503999f, -0.233537242f, -0.569590449f, -0.712043583f, 0.944416404f, 0.731313527f, 0.374553472f, -0.277990431f, + 0.072502397f, -1.1513555f, 0.183427677f, 0.0120646283f, 0.894046903f, -0.129011974f, -0.511648595f, 0.39702031f, -0.000560132146f, 0.0117789321f, + -0.20208165f, 0.0656537935f, -0.0636241436f, 0.171082094f, 0.132772699f, 0.0246953834f, 0.176253349f, 0.0380403362f, -0.172805458f, 0.170884013f, + 0.0714075863f, -0.0165108629f, 0.528248489f, 0.0909744352f, 0.0543293729f, -0.0895553008f, 0.0350604542f, -0.0704533011f, 0.0829755664f, -0.363258958f, + 0.0459019504f, -0.318933994f, -0.204992935f, 0.0305363964f, -0.29934895f, 0.00158079388f, -0.141911432f, -0.162612274f, 0.225413367f, -0.354422003f, + -0.35559684f, 0.346148968f, 0.283960491f, 0.412163377f, 0.46721676f, 0.504486322f, -0.13783516f, -0.0677227303f, -0.187755644f, -0.0617015772f, + 0.0894709229f, -0.32548815f, 0.206702799f, 0.283542097f, -0.0449485071f, 0.264255255f, 0.437749475f, 0.0187661238f, 0.198421448f, -0.0947791636f, + 0.297777116f, -0.235753477f, 0.21588704f, -0.325995654f, -0.802016616f, 0.27222985f, -0.184822887f, 0.206202731f, 0.290895611f, 1.45597744f, + -1.57192504f, -1.09051847f, 0.625292897f, 0.250822991f, -0.389522403f, 0.161905855f, 0.212820575f, -0.185566738f, 0.390745312f, 0.0429828241f, + -0.093816407f, -0.189630404f, -0.157632574f, 0.0299858656f, 0.00290334248f, -0.0012669682f, -0.0289928019f, -0.0212263968f, 1.13424242f, 0.137880817f, + 0.0626646578f, 0.0398956314f, -0.00662989169f, 0.0625688583f, -1.0105598f, -0.199731112f, -0.0849281996f, -0.124456428f, 0.0448234528f, -0.203418583f, + 0.239648581f, -0.0635680184f, 0.0333185121f, -0.0215264838f, 0.0210519619f, -0.150601164f, 0.185394958f, -0.235363156f, -0.00537328655f, -0.104509249f, + -0.07261502f, -0.51254034f, -0.484404236f, 0.164909914f, 0.00461372035f, -0.0356974639f, -0.0820915326f, 0.0459316894f, -0.817982972f, -0.0459545851f, + 0.0384216234f, 0.0697769225f, 0.0495006628f, 0.060977906f, 0.621946812f, -0.201845929f, -0.079770878f, 0.033990778f, -0.109762892f, -0.335492313f, + -0.345984101f, 0.286792338f, 0.40950048f, 0.23636356f, 0.273553908f, 0.261826873f, -0.377272218f, 0.177581534f, 0.0706941858f, 0.0139318286f, + 0.11985188f, -0.494495422f, -0.887050569f, -0.0860236734f, -0.212667137f, -0.298464894f, -0.933313191f, -0.934763432f, 0.902186036f, -0.610748649f, + -0.0206053331f, 0.300584108f, -0.361991674f, -0.196840718f, -0.228310734f, 0.107864074f, 0.158526599f, 0.120739371f, -0.0162532162f, -0.0561325587f, + -0.0918323845f, 0.182082132f, 0.255224347f, 0.195036352f, 0.0132022435f, -0.122032069f, -0.754805386f, -0.2428938f, -0.359453738f, -0.262373477f, + -0.037967246f, 0.178295478f, -0.315525323f, 0.718059182f, 0.373362094f, 0.653695464f, 0.406301707f, 0.580286026f, -0.118089423f, -0.288989037f, + 0.28534016f, 0.564326167f, 1.22338426f, 0.90376091f, -0.162966803f, 0.340125442f, 0.753317177f, 0.618475139f, 1.11350417f, 0.656930685f, + -0.257119775f, -0.234947637f, -0.293046415f, -0.611993968f, -0.263120413f, -0.263213336f, 0.210554555f, -0.225291908f, -0.330991924f, -0.418628901f, + -0.333083004f, -0.0958817825f, -0.434127778f, 0.146746844f, 0.14874424f, 0.0465566553f, 0.0951328129f, -0.171639472f, 0.106705025f, 0.476861984f, + -0.312458724f, 0.173833132f, 0.693789363f, 0.508736908f, 0.117975526f, -0.441011071f, 1.04021502f, -0.744854987f, -0.0457663797f, -0.308079898f, + -0.398846596f, -0.184597418f, -0.127753347f, -0.419683337f, -0.133025765f, 0.251542658f, -0.126285478f, 0.133532137f, 0.0773538798f, 0.109454997f, + 0.265535861f, 0.0506152958f, 0.330314398f, 0.0467683412f, -0.536711872f, 0.354304045f, 0.590463877f, -0.0925841257f, -0.255766809f, 0.022847699f, + 0.595481575f, 0.322591424f, -0.15601626f, -0.0578801967f, -0.140387759f, 0.114116102f, 0.0216514654f, -0.111813784f, 0.0717193112f, 0.201279372f, + 0.0481472872f, 0.0154395532f, 0.0123023773f, -0.0259636324f, -0.0925019979f, -0.0891250297f, -0.86723578f, -0.0672022998f, -0.0268024411f, 0.100097314f, + 0.110347323f, 0.00202648807f, -0.239212021f, -0.0263711382f, 0.226633161f, 0.235465437f, -0.11846979f, -0.603467464f, 0.00246148347f, -0.0832116455f, + 0.141216964f, 0.0675849989f, 0.0903528631f, -0.128742859f, -0.0447525419f, 0.161534667f, -0.205140144f, -0.0879647136f, -0.0764712766f, 0.0434754267f, + -0.287380904f, -0.165250733f, -0.218547538f, 0.12084683f, -0.218051836f, -1.21173859f, -1.15294647f, -0.140801892f, 0.558099687f, -0.922708094f, + 0.126126274f, 0.617101431f, -1.05384088f, -1.11221874f, 0.157019094f, -0.380628467f, 0.0516653992f, 0.206146449f, -0.134316206f, 0.092158325f, + 0.265836746f, -0.263401121f, -0.175384775f, -0.131484047f, 0.615283787f, -0.250084579f, 0.140374556f, -0.0230378136f, 0.172401235f, -0.133362457f, + 0.175349072f, 0.261127979f, -0.215552524f, 0.391297311f, -0.129526109f, 0.0639947951f, -0.139831021f, 0.201700866f, 0.130940929f, 0.0342011824f, + -0.117951579f, 0.135805175f, -0.483924538f, 0.0327126756f, -0.0948495269f, -0.257538378f, 0.239779085f, -0.266058832f, 0.0165624879f, 0.255320668f, + 0.368240654f, 0.464174777f, 0.0426507406f, 0.388809651f, -0.129960284f, -0.0816872194f, -0.0579896346f, -0.028162336f, -0.083234109f, 0.321596533f, + 0.249473348f, 0.101860143f, -0.0773077682f, 0.13385877f, 0.0622727871f, 0.123582877f, -0.115911134f, -0.142301962f, 0.0880153254f, -0.144623682f, + -0.138735086f, -0.0801471844f, -0.528679729f, -0.0385316797f, -0.222395703f, 0.130172774f, 0.737493038f, -0.10271854f, -0.0917340666f, 0.845378458f, + 0.1924676f, -0.226778314f, -0.169291228f, -0.590278685f, 0.176980317f, 0.65129143f, 0.328980774f, 0.445320189f, 0.0f, 0.0f, + 0.0f, -0.0764938146f, 0.0151796862f, -0.0781914219f, -0.0457426906f, -0.0405839272f, 0.0105183506f, -0.110311404f, 0.0489397757f, -0.019760685f, + -0.0472811162f, 0.0508822314f, 0.111977458f, 0.0268753376f, -0.532313526f, -0.224332884f, -0.145423859f, 0.0243865568f, -0.0299090501f, 0.0153436549f, + 0.00714792451f, -0.00590326637f, -0.0360594355f, 0.109589323f, -0.0267359279f, 0.0254245158f, 0.0431830958f, 0.0930503011f, 0.0601097681f, 0.0547712781f, + -0.416756302f, -0.252666503f, 0.187078148f, 0.0574199334f, 0.0111577827f, 0.0607488267f, 0.0261979755f, 0.0443256684f, 0.0365949906f, 0.0265433732f, + 0.0117496029f, 0.0177119002f, 0.0305213593f, 0.0222553685f, 0.0369776115f, 0.0444281586f, 0.0603946447f, 0.0220967364f, 0.0886266455f, 0.124788791f, + 0.0199999996f}, +}; diff --git a/engine/px_render.c b/engine/px_render.c index ee8b0e3..a34e3f9 100644 --- a/engine/px_render.c +++ b/engine/px_render.c @@ -60,6 +60,7 @@ int main(int argc, char **argv) { if(argc<3){ fprintf(stderr,"usage: %s in.wav out.wav [preset 1..%d] [amp 1..%d] [gain 0..100]\n",argv[0],px_preset_count(),PX_AMP_COUNT); return 1; } int npreset = argc>3 ? atoi(argv[3]) - 1 : 0; + if (getenv("PX_FX_INT")) px_fx_int = 1; /* the cabinet and drive filters in integers (slower on the pedal) */ int n; float sr; float *in = load_wav(argv[1], &n, &sr); if(!in){ fprintf(stderr,"unreadable WAV\n"); return 1; } diff --git a/firmware/build.sh b/firmware/build.sh index 506303d..a586676 100755 --- a/firmware/build.sh +++ b/firmware/build.sh @@ -37,6 +37,8 @@ $CC $FP -O2 -fno-builtin $DSPDEF $INC -c "$HERE/../engine/px_dsp.c" -o "$O/px_ds $CC $FP -O2 -fno-builtin -c "$HERE/px_math.c" -o "$O/px_math.o" # official JieLi I2S driver (LLVM bitcode from the AC79 SDK, Apache-2.0) -> pi32v2 object $CC -Os -c -x ir "$HERE/sdk/iis.bc" -o "$O/iis.o" +# a direct call between the flash code and the RAM code is out of the CPU's call range: refuse it with its name +python3 "$HERE/../tools/check_calls.py" "$O/crt0.o" "$O/vec.o" "$O/isr.o" $CPU1OBJ "$O/openpocket.o" "$O/px_dsp.o" "$O/px_math.o" "$TC/pi32v2/bin/ld" -T "$HERE/app.ld" "$O/crt0.o" "$O/vec.o" "$O/isr.o" $CPU1OBJ "$O/openpocket.o" "$O/px_dsp.o" "$O/px_math.o" "$O/iis.o" -o "$O/openpocket.elf" # symbol map: used to translate a crash address (PC) into a function name "$TC/common/bin/objdump" -t "$O/openpocket.elf" 2>/dev/null | sort > "$O/symbols.txt" || true diff --git a/firmware/inc/string.h b/firmware/inc/string.h index 05d765e..616186c 100644 --- a/firmware/inc/string.h +++ b/firmware/inc/string.h @@ -1,4 +1,5 @@ -/* OpenPocket X — minimal string header (implementation: px_audio.h) */ +/* OpenPocket X — minimal string header (implementation: felucca-bsp libc.c, linked through openpocket.c) */ #pragma once void *memset(void *d, int c, unsigned n); void *memcpy(void *d, const void *s, unsigned n); +int memcmp(const void *a, const void *b, unsigned n); /* felucca-bsp libc.c */ diff --git a/firmware/led_probe.h b/firmware/led_probe.h new file mode 100644 index 0000000..2d8565f --- /dev/null +++ b/firmware/led_probe.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: GPL-3.0-only + * OpenPocket — the LED map (issue #8): which bit of the 74HC595 (px_leds.h) lights which button? + * + * Built only with LED_PROBE 1 (openpocket.c). That build plays no sound. The knob steps through ALL 8 BITS, then + * BIT 0 .. BIT 7; the bits on screen blink at 2 Hz (the byte alternates between them and 0, so the one light that + * changes is theirs, whether it is lit by a 1 or by a 0: the others may stay lit) and the square at the top right is + * lit while they are 1. + * - Pressing the button whose light blinks writes it into the table at the bottom (FX, MOD, AMP, CAB, DLY, REV, + * HOME, the knob's PUSH, either footswitch); the same button again clears it. A photo of the table is the map. + * - Driven: PC5, PC6 and PC8 (the 595's shift clock, latch and data) and PC7, the lights' enable, low (px_leds.h + * leds_init, as the stock firmware). The earlier test builds of issue #8 lit nothing because PC7 stayed high: + * OpenPocket held it so as a screen line. + * - USB stays up, as in the normal build, so the web installer takes the pedal back to a normal OpenPocket or to + * the official firmware. + * + * Included by openpocket.c (LED_PROBE 1) and by tests/lpsim.c on the PC. The including file provides: PA_IN, PH_IN, + * PC_IN, ENC_MASK, PA_FX / PA_HOME / PA_FS_UP / PA_FS_DN, PH_PUSH / PH_MOD / PH_AMP, base_pa, base_ph, keys_decode, + * adc_read2, ADC_CH_KEYS, KEY_CAB / KEY_DLY / KEY_REV, QDEC, dbn_t / dbn_press, ms_now, fm1_delay_us, fm1_wdt_feed, + * px_usb_service, lcd_rect, ft_box / ft_width and the fonts (ui_text.h), b_str / b_num, guard, op_diag / ST_OK and + * the UI colours. */ +#pragma once +#include +#include "px_leds.h" + +#ifndef LP_TEXT_HOOK /* tests/lpsim.c checks that every line fits its box */ +#define LP_TEXT_HOOK(s, f, w) ((void)0) +#endif +#define LP_BLINK_MS 250u /* half a period: 2 Hz */ +#define LP_NPOS 9u /* ALL 8 BITS, BIT 0 .. BIT 7 */ + +enum { LB_FX, LB_MOD, LB_AMP, LB_CAB, LB_DLY, LB_REV, LB_HOME, LB_PUSH, LB_FSR, LB_FSL, LB_N }; +static const char *const LP_BTN[LB_N] = { "FX", "MOD", "AMP", "CAB", "DLY", "REV", "HOME", "PUSH", "R FOOT", "L FOOT" }; + +static struct { + uint32_t pos; /* 0 = all 8 bits, 1..8 = bit pos - 1 */ + uint32_t t_blink, t_keys; + int hi, dirty, key; + int32_t acc; + uint8_t enc; + uint8_t map[8]; /* per bit: the button that lit, + 1 (0 = none yet) */ + dbn_t b[LB_N]; +} lp; + +static uint8_t lp_mask(void) { return lp.pos ? (uint8_t)(1u << (lp.pos - 1u)) : 0xFFu; } +static void lp_show(void) { leds_write(lp.hi ? lp_mask() : 0u); } + +static void lp_hex2(char *d, uint32_t v) +{ + static const char H[] = "0123456789ABCDEF"; + while (*d) d++; + d[0] = H[(v >> 4) & 15u]; d[1] = H[v & 15u]; d[2] = 0; +} +static void lp_text(uint32_t x, uint32_t y, uint32_t w, const char *s, const op_font *f, uint16_t col, int align) +{ + LP_TEXT_HOOK(s, f, w); + ft_box(x, y, w, s, f, col, UI_BG, align); +} +static void lp_dot(void) { lcd_rect(222, 10, 14, 14, lp.hi ? UI_ACC : UI_PANEL); } +static void lp_draw(void) +{ + char l[44]; + uint32_t bit = lp.pos ? lp.pos - 1u : 0u; + int mapped = lp.pos && lp.map[bit]; + lp_text(20, 6, 200, "LED MAP", &FT_MD, UI_ACC, 1); + lp_dot(); + l[0] = 0; + if (lp.pos) { b_str(l, "BIT "); b_num(l, bit); } else b_str(l, "ALL 8 BITS"); + lp_text(0, 36, 240, l, &FT_NM, UI_TXT, 1); + l[0] = 0; + b_str(l, "BYTE "); lp_hex2(l, lp_mask()); b_str(l, " / 00, TWICE A SECOND"); + lp_text(0, 74, 240, l, &FT_SM, UI_ACC, 1); + l[0] = 0; + if (!lp.pos) b_str(l, "EVERY BUTTON LIGHT SHOULD BLINK"); + else if (mapped) { b_str(l, "BIT "); b_num(l, bit); b_str(l, " LIGHTS: "); b_str(l, LP_BTN[lp.map[bit] - 1u]); } + else b_str(l, "PRESS THE BUTTON THAT BLINKS"); + lp_text(0, 96, 240, l, &FT_SM, mapped ? UI_OK : UI_TXT, 1); + lp_text(0, 114, 240, !lp.pos ? "KNOB: ONE BIT AT A TIME" : mapped ? "SAME BUTTON AGAIN: CLEAR" : "KNOB: NEXT BIT", + &FT_SM, UI_DIM, 1); + for (uint32_t i = 0; i < 8u; i++) { /* the map: bits 0-3 left, 4-7 right */ + uint16_t col = (lp.pos && i == bit) ? UI_ACC : lp.map[i] ? UI_TXT : UI_DIM; + l[0] = 0; + b_str(l, "BIT "); b_num(l, i); b_str(l, ": "); b_str(l, lp.map[i] ? LP_BTN[lp.map[i] - 1u] : "--"); + lp_text(i < 4u ? 24u : 136u, 140u + (i & 3u) * 18u, 100u, l, &FT_SM, col, 0); + } + lp_text(0, 218, 240, "SQUARE LIT = BITS AT 1", &FT_SM, UI_DIM, 1); +} + +static void lp_init(void) +{ + lp.pos = 0; + lp.hi = 1; + lp.acc = 0; + lp.key = KEY_NONE; + lp.enc = (uint8_t)(PC_IN & ENC_MASK); + for (int i = 0; i < 8; i++) lp.map[i] = 0; + for (int i = 0; i < LB_N; i++) lp.b[i].stab = lp.b[i].last = lp.b[i].cnt = 0; + guard.pending = 0; /* a reset here is not a failed boot */ + guard.failed = 0; /* (no UBOOT, no safe mode screen) */ + op_diag.stage = ST_OK; + leds_init(); + lp.t_blink = lp.t_keys = ms_now(); + lp_show(); + lcd_rect(0, 0, 240, 240, UI_BG); + lp.dirty = 1; +} + +static void lp_step(uint32_t now) /* one pass of the loop */ +{ + fm1_wdt_feed(); + px_usb_service(now); /* the web installer, as in the normal build */ + { /* the knob: one detent, one step (the main loop's decoding) */ + uint8_t s = (uint8_t)(PC_IN & ENC_MASK); + if (s != lp.enc) { + int dd = 0; + lp.acc -= QDEC[(lp.enc << 2) | s]; + lp.enc = s; + if (lp.acc >= 4) { lp.acc -= 4; dd = 1; } else if (lp.acc <= -4) { lp.acc += 4; dd = -1; } + if (dd) { + lp.pos = dd > 0 ? (lp.pos + 1u) % LP_NPOS : (lp.pos + LP_NPOS - 1u) % LP_NPOS; + lp.hi = 1; + lp.t_blink = now; + lp_show(); + lp.dirty = 1; + } + } + } + { /* the buttons (pressed = differs from the idle state); CAB / DLY / REV are the analog keypad, every 10 ms */ + uint32_t pa = (PA_IN & 0xFFFFu) ^ base_pa, ph = (PH_IN & 0xFFFFu) ^ base_ph; + int hit = -1, keys = now - lp.t_keys >= 10u; + int raw[LB_N] = { + (pa & PA_FX) != 0, (ph & PH_MOD) != 0, (ph & PH_AMP) != 0, 0, 0, 0, + (pa & PA_HOME) != 0, (ph & PH_PUSH) != 0, (pa & PA_FS_UP) != 0, (pa & PA_FS_DN) != 0 }; + if (keys) { lp.t_keys = now; lp.key = keys_decode(adc_read2(ADC_CH_KEYS)); } + raw[LB_CAB] = lp.key == KEY_CAB; raw[LB_DLY] = lp.key == KEY_DLY; raw[LB_REV] = lp.key == KEY_REV; + for (int i = 0; i < LB_N; i++) { + if ((i == LB_CAB || i == LB_DLY || i == LB_REV) && !keys) continue; + if (dbn_press(&lp.b[i], raw[i]) && hit < 0) hit = i; + } + if (hit >= 0 && lp.pos) { + uint8_t *m = &lp.map[lp.pos - 1u]; + *m = (*m == (uint8_t)(hit + 1)) ? 0u : (uint8_t)(hit + 1); + lp.dirty = 1; + } + } + if (now - lp.t_blink >= LP_BLINK_MS) { + lp.t_blink = now; + lp.hi = !lp.hi; + lp_show(); + lp_dot(); + } + if (lp.dirty) { lp.dirty = 0; lp_draw(); } +} + +static void led_probe_run(void) +{ + lp_init(); + for (;;) lp_step(ms_now()); +} diff --git a/firmware/openpocket.c b/firmware/openpocket.c index 2a1956f..04aff18 100644 --- a/firmware/openpocket.c +++ b/firmware/openpocket.c @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-3.0-only * OpenPocket X — Milestone 1 (boot + screen) — Donner Pocket X. * SCREEN (reverse-engineered from the stock firmware): SOFTWARE SPI on PORT B - * CS = PB1, D/C = PB5, CLK = PB6, DO = PB7 (+ PC7 driven, reset/backlight?) + * CS = PB1, D/C = PB5, CLK = PB6, DO = PB7 (PC7 is not the screen's: the button lights' enable, px_leds.h) * (the FM-1 used port C: that was the cause of the black screen.) * Init sequence + 40-line offset: taken verbatim from the Pocket X firmware. * Safety net: 2 failed boots -> UBOOT (re-flashable), + backup fm1-1.bin. @@ -144,7 +144,7 @@ static void lcd_init(void) PB_DIR &= ~(CS | DC | CLK | DO); /* outputs */ PC_DIR &= ~PC7; PB_OUT |= CS; PB_OUT &= ~CLK; /* CS high, CLK low */ - PC_OUT |= PC7; /* PC7 high (reset released / backlight?) */ + PC_OUT |= PC7; /* PC7 high: the button lights off (their enable, low = on: px_leds.h) */ #if LCD_HW lspi_init(); #endif @@ -253,6 +253,7 @@ static void lcd_text(uint32_t x, uint32_t y, const char *str, uint16_t fg, uint1 } /* ---- preset: the v2 engine's struct (engine/px_dsp.h), edited directly by the UI ---- */ #include "px_dsp.h" +#include "px_nam.h" /* v37: NAM A2-Lite (the engine includes px_nam.c) */ static px_preset_t PRESET; static uint32_t cur_preset = 0; static uint32_t master_vol = 80; /* 0..100, follows the MASTER knob (ADC channel 2) */ @@ -302,10 +303,11 @@ static void fm1_fault(const fm1_crash_t *c) #define PH_PU (*(volatile uint32_t *)0x501D0u) #define PH_DIR (*(volatile uint32_t *)0x501C8u) #define ENC_MASK 0x3u /* PC0=A, PC1=B */ -#define OP_VERSION_NUM "36" +#define OP_VERSION_NUM "37" #define OP_VERSION "v" OP_VERSION_NUM /* shown at boot: changes with every released build */ #define PROBE 0 /* 1 = GPIO diagnostic: shows the pins that change at the bottom */ #define ADC_PROBE 0 /* 1 = ADC diagnostic: shows the channels that move at the bottom (C2:512) */ +#define LED_PROBE 0 /* 1 = LED map (issue #8, led_probe.h): the knob picks a bit of the lights' 595, it blinks; no sound */ #define PA_PD (*(volatile uint32_t *)0x50014u) /* ---- Controls mapped on the real pedal (diagnostic) ---- @@ -335,7 +337,7 @@ static void input_init(void) PH_DIE |= 0xFFFFu; PH_PU |= 0xFFFFu; PB_DIE |= 0xFF1Du; PB_PU |= 0xFF1Du; /* except PB1/5/6/7 (screen) */ #endif - PC_DIR &= ~PC7; PC_OUT |= PC7; /* PC7 drives the screen: always an output at 1 */ + PC_DIR &= ~PC7; PC_OUT |= PC7; /* PC7, the button lights' enable: high = off until px_leds.h turns them on */ } static void input_baseline(void) { @@ -531,19 +533,34 @@ static const int8_t QDEC[16] = {0,-1,1,0, 1,0,0,-1, -1,0,0,1, 0,1,-1,0}; #if AUDIO_PROBE #include "audio_probe.h" #else +#include "px_cacheram.h" /* v37: data-cache ways as RAM (melodee's routine): the NAM network's vector-unit buffers */ #include "px_audio.h" #endif #if !AUDIO_PROBE #include "ui.h" +#include "px_lights.h" /* the button lights follow the blocks (issue #8; px_leds.h drives them) */ +#define PX_LIGHTS_OFF() lights_off() #include "px_usb.h" /* USB-MIDI + update entry (web installer) */ #include "px_store.h" /* the user's presets in flash */ +#include "px_models.h" /* v37: the NAM user models in flash */ #if !AUDIO_PROBE static uint32_t ed_load(void) { return a_bypass ? a_peak : a_load; } /* PING: the DSP load, as at the bottom right */ static uint32_t ed_flags(void) { return (a_bypass ? 1u : 0u) | (a_c1 ? 2u : 0u); } +static void nm_changed(uint32_t s) /* v37: a user model was written or erased: the engine reloads it if it plays it */ +{ + if (g_eng.nam_idx == (int)(PX_NAM_NFACT + s)) g_eng.nam_idx = -1; + audio_apply(); +} #include "px_editor.h" /* the web editor (docs/EDITOR-PROTOCOL.md) */ #endif #endif +#if LED_PROBE +#if AUDIO_PROBE +#error "LED_PROBE needs the normal build: USB (the web installer) is the way back" +#endif +#include "led_probe.h" /* the LED map (issue #8) */ +#endif /* P3_RST_SRC as read at boot: why the chip last reset (fm1_sys.h) */ static void rst_names(char *l, uint32_t r) @@ -568,6 +585,12 @@ static void app_main(void) uint32_t push_t = 0, clk_t = 0; int clk_pend = 0; /* chain page: a PUSH waiting to see if a 2nd one makes it a double-click */ int32_t master_raw = -100; +#if !AUDIO_PROBE + { /* before the second core starts: the data-cache ways as RAM (through a pointer: it is RAM code) */ + void (*volatile f)(void) = pxc_init; + f(); + } +#endif #if DSP_CPU1 fm1_cpu1_bar_build(27u); /* a new build gives the 2nd core another chance */ fm1_cpu1_start(); /* at boot, before audio and interrupts (Felucca) */ @@ -641,13 +664,26 @@ static void app_main(void) keys_capture_idle(); op_stage(ST_PRESET, "PRESET..."); load_preset(cur_preset); +#if LED_PROBE + px_usb_start(); /* USB-MIDI + update entry: the web installer is the way back */ + px_store_boot(); + fm1_irq_enable_all(); /* audio_start does it in the normal build; here no audio is started */ + led_probe_run(); /* never returns */ +#endif #if AUDIO_PROBE audio_probe_run(); #else a_hold = 1; /* DSP bypassed until the UI is up and 1.5 s have passed */ px_usb_start(); /* USB-MIDI device + update entry (web installer) */ px_store_boot(); /* the saved presets; start on the last one saved */ + nm_scan(); /* v37: the NAM user models (names, levels) */ +#if DSP_CPU1 + px_nam_helper(a_hrun, a_hwait); /* v37: CPU1 can take a part of the NAM network */ +#endif + if (pxc_status == PXC_READY) px_nam_fast((void *)PXC_BEGIN, PXC_END - PXC_BEGIN); /* the vector unit's inputs */ + px_nam_check(b_ticks); /* v37: the NAM routines by hand checked, its fastest way to run chosen */ audio_start(); /* guitar -> DSP engine -> output, amp enabled */ + leds_init(); /* the button lights: all off loaded, then on (PC7 low), as stock */ op_stage(ST_UI, "SCREEN..."); lcd_rect(0, 0, 240, 240, UI_BG); ui_invalidate(); @@ -661,7 +697,8 @@ static void app_main(void) #if !AUDIO_PROBE px_usb_service(now); /* web installer: handshake, update, UBOOT soft key */ audio_poll(now); /* the sound follows the UI (preset, settings, volume) */ - if (ui_mode != M_TUNER) { /* DSP load at the bottom right: "C1 42%" (2nd core), "C0" or BYP */ + lights_update(&PRESET, ui_mode == M_TUNER, now); /* the button lights follow the blocks */ + if (ui_mode != M_TUNER) { /* DSP load at the bottom right: "C1 42%" (2nd core), "2C" (NAM pipelined), "C0" or BYP */ static uint32_t t_cpu; if (now - t_cpu >= 500u) { t_cpu = now; @@ -670,6 +707,7 @@ static void app_main(void) if (l > 999u) l = 999u; if (safe) { c[i++]='S'; c[i++]='A'; c[i++]='F'; c[i++]='E'; c[i++]=' '; } else if (a_bypass) { c[i++]='B'; c[i++]='Y'; c[i++]='P'; c[i++]=' '; } + else if (a_c1 && px_nam_dual(&g_eng)) { c[i++]='2'; c[i++]='C'; c[i++]=' '; } /* NAM: both cores */ else { c[i++]='C'; c[i++]=(char)(a_c1 ? '1' : '0'); c[i++]=' '; } if (l >= 100u) c[i++] = (char)('0' + l / 100u); if (l >= 10u) c[i++] = (char)('0' + (l / 10u) % 10u); diff --git a/firmware/px_audio.h b/firmware/px_audio.h index 183714e..40f3432 100644 --- a/firmware/px_audio.h +++ b/firmware/px_audio.h @@ -18,7 +18,7 @@ #pragma once #include #ifndef BENCH_AT_BOOT -#define BENCH_AT_BOOT 0 /* 1 = DSP benchmark screen at boot */ +#define BENCH_AT_BOOT 0 /* 1 = DSP benchmark screen at boot (diagnostics) */ #endif #include #include "px_dsp.h" @@ -98,6 +98,8 @@ static int a_running; /* DSP work for one block: a_in -> a_res (gain, clipping) + load measurement. Runs on the 2nd core (CPU1) * when available, otherwise on CPU0 in the interrupt. */ +static void dsp_out(void); +static void dsp_load(uint32_t t0, uint32_t lim); static void dsp_block(void) { uint32_t t0 = fm1_ticks(); @@ -107,6 +109,11 @@ static void dsp_block(void) } else { for (uint32_t i = 0; i < A_FR; i++) a_out[i] = a_in[i]; } + dsp_out(); + dsp_load(t0, 85u); +} +static void dsp_out(void) /* a_out -> a_res: safety net, mutes, volume */ +{ /* safety net: a NaN/Inf would poison the filters forever (silence). Output silence and * the main loop resets the engine (audio_poll). */ for (uint32_t i = 0; i < A_FR; i++) { @@ -128,11 +135,14 @@ static void dsp_block(void) if (v > 8388607.0f) v = 8388607.0f; else if (v < -8388608.0f) v = -8388608.0f; a_res[i] = (int32_t)v; } +} +static void dsp_load(uint32_t t0, uint32_t lim) /* the block's load, the safety bypass (over lim % 8 blocks running) */ +{ uint32_t pct = (fm1_ticks() - t0) * 100u / A_BUDGET; a_load = (a_load * 7u + pct) / 8u; if (pct > a_peak) a_peak = pct; if (!a_bypass && !a_hold) { - if (pct > 85u) { if (++a_over >= 8u) a_bypass = 1; } else a_over = 0; + if (pct > lim) { if (++a_over >= 8u) a_bypass = 1; } else a_over = 0; } a_blocks++; } @@ -146,6 +156,65 @@ static uint8_t a_job; /* a block is in progress #if DSP_CPU1 static void dsp_job(uint32_t arg) { (void)arg; dsp_block(); } #endif +#if DSP_CPU1 +/* the NAM network's helper core (CPU1), for its two-core modes: the job functions (px_nam_helper) */ +static int a_hrun(void (*fn)(uint32_t), uint32_t arg) { return fm1_cpu1_run(fn, arg); } +static int a_hwait(void) { return fm1_cpu1_wait(); } +/* v37: a NAM amp on two cores, pipelined (one block more latency: 2.9 ms). In each block's interrupt CPU1 first runs + * the blocks after the amp on the previous block's network output (and makes its output), while CPU0 runs the blocks + * before the amp on this block; then both run the network on this block (CPU1 as its helper). PRE and POST never touch + * the same block's state (tests/engine/pipe_test.c: the same output as one core, one block later). */ +static float a_nb[2][A_FR]; /* the network's output: being made / the previous block's */ +static uint8_t a_nbi, a_nbv, a_prun; /* a_nb[a_nbi] is this block's; a_nbv: the other one holds one */ +static void post_job(uint32_t prev) +{ + if (a_prun && a_nbv) { + for (uint32_t o = 0; o < A_FR; o += PX_MAX_BLOCK) + px_engine_part(&g_eng, a_nb[prev] + o, a_out + o, PX_MAX_BLOCK, PX_PART_POST); + } else if (!a_prun) { + for (uint32_t i = 0; i < A_FR; i++) a_out[i] = a_in[i]; + } else for (uint32_t i = 0; i < A_FR; i++) a_out[i] = 0.0f; /* the pipeline's first block */ + dsp_out(); +} +/* diagnostic 22: CPU1 then goes straight on to the network (pxn_serve), taking the last frames of each 32-frame block + * while CPU0 takes the first ones and never waits; CPU0 takes more frames in the first blocks by how late CPU1 came + * to the network in the blocks before (a_late, ticks: POST's end against PRE's) */ +static volatile uint32_t a_tpost; /* (CPU1) when POST was done */ +static int32_t a_late; +static void pipe_job(uint32_t prev) +{ + post_job(prev); + a_tpost = fm1_ticks(); + pxn_serve(); +} +static void dsp_pipe_run(int run) /* run: the engine on (else bypassed) */ +{ + const uint32_t prev = a_nbi ^ 1u; + a_prun = (uint8_t)run; + if (run) pxn_srv_begin(a_late > 0 ? a_late : 0); + const int job = fm1_cpu1_run(run ? pipe_job : post_job, prev); + if (run && !job) pxn_srv_end(); + if (run) for (uint32_t o = 0; o < A_FR; o += PX_MAX_BLOCK) + px_engine_part(&g_eng, a_in + o, a_nb[a_nbi] + o, PX_MAX_BLOCK, PX_PART_PRE); + const uint32_t tpre = fm1_ticks(); + if (!job) post_job(prev); /* (CPU1 off: here) */ + if (run) for (uint32_t o = 0; o < A_FR; o += PX_MAX_BLOCK) + px_engine_part(&g_eng, a_nb[a_nbi] + o, a_nb[a_nbi] + o, PX_MAX_BLOCK, PX_PART_NAM); + if (job) { + if (run) pxn_srv_end(); + if (fm1_cpu1_wait() < 0) { a_c1 = 0; post_job(prev); } /* (dropped: here, and one core from now on) */ + else if (run) a_late += ((int32_t)(a_tpost - tpre) - a_late) / 4; + } + a_nbv = (uint8_t)run; + a_nbi = (uint8_t)prev; +} +static void dsp_pipe(void) +{ + uint32_t t0 = fm1_ticks(); + dsp_pipe_run(!a_bypass && !a_hold); + dsp_load(t0, 93u); /* (CPU0's whole block here, the UI gets the rest) */ +} +#endif static void a_collect(void) /* collects the block in progress on CPU1 */ { #if DSP_CPU1 @@ -223,8 +292,14 @@ static void a_enc(void *priv, uint8_t *data, int len, uint8_t ch) /* guitar } tn_capture(a_in, A_FR); #if DSP_CPU1 - if (a_c1 && fm1_cpu1_run(dsp_job, 0)) { a_job = 1; return; } - a_c1 = 0; + /* a NAM amp on two cores (px_nam_dual): pipelined here (dsp_pipe), CPU1 its helper */ + if (a_c1 && !px_nam_dual(&g_eng)) { + a_nbv = 0; + if (fm1_cpu1_run(dsp_job, 0)) { a_job = 1; return; } + a_c1 = 0; + } + if (a_c1) { dsp_pipe(); return; } + a_nbv = 0; #endif dsp_block(); } @@ -299,9 +374,21 @@ static uint32_t b_engine(const px_preset_t *pp) /* % of the real-time bud fm1_wdt_feed(); return dt * 100u / A_BUDGET; } +static void b_fix2(char *d, uint32_t v100) /* 123 -> "1.23" */ +{ + b_num(d, v100 / 100u); + b_str(d, "."); + if (v100 % 100u < 10u) b_str(d, "0"); + b_num(d, v100 % 100u); +} +static uint32_t b_ticks(void) { return fm1_ticks(); } +/* v37: what the NAM network costs on the pedal, piece by piece (cycles at 360 MHz: ticks x 15). Off by default: + * BENCH_AT_BOOT 1 (at the top of this file) shows it for 12 s at boot. */ static void audio_bench(void) { +#if BENCH_AT_BOOT char l[48]; + uint32_t y = 26; lcd_rect(0, 0, 240, 240, UI_BG); lcd_text(4, 4, "DSP BENCH " OP_VERSION, UI_ACC, UI_BG, 2); /* integer loop and float loop: time per iteration (ns) */ @@ -313,28 +400,94 @@ static void audio_bench(void) for (uint32_t i = 0; i < 100000u; i++) fa = fa * fb + fc; uint32_t tf = fm1_ticks() - t0; fm1_wdt_feed(); - l[0] = 0; b_str(l, "INT 100K LOOPS: "); b_num(l, ti / 24u); b_str(l, " US"); - lcd_text(4, 30, l, UI_TXT, UI_BG, 1); - l[0] = 0; b_str(l, "FLOAT 100K LOOPS: "); b_num(l, tf / 24u); b_str(l, " US"); - lcd_text(4, 42, l, UI_TXT, UI_BG, 1); - /* engine cost, block by block */ + (void)ti; (void)tf; + l[0] = 0; b_str(l, "NAM ROUTINE: "); b_str(l, pxn_asm_in_use() ? "HAND (OK)" : "C (CHECK FAILED)"); + lcd_text(4, y, l, pxn_asm_in_use() ? GRN : RED, UI_BG, 1); y += 14; + /* v37 diagnostic 22: the ways of running the network as timed at start-up (% of real time, NAM alone): the CPU, the + * unit in turn, both at once with the CPU taking 0, 4 or 8 frames of 16; two cores (CPU1 taking 16 or 12 frames of + * 32), with the unit beside CPU0 or not. RDOT: the layer read straight from its ring (no gather), against the gathered + * X rows (the CPU alone); FAST RAM: the vector unit's inputs in the data-cache ways (px_cacheram.h) */ + { + l[0] = 0; b_str(l, "RDL "); /* diagnostic 20: a layer's groups in one call */ + if (pxn_rdl_state()) b_num(l, pxn_rdot_ticks(3) * 100u / (A_BUDGET * 2u)); else b_str(l, "FAIL"); + b_str(l, "% RDQ "); b_str(l, pxn_rdq_checked() ? "" : "(FAILED) "); + b_num(l, pxn_rdot_ticks(2) * 100u / (A_BUDGET * 2u)); b_str(l, "% RDOT "); + b_num(l, pxn_rdot_ticks(1) * 100u / (A_BUDGET * 2u)); + b_str(l, pxn_rdl_state() == 2 ? "% >L" : pxn_rdq_in_use() ? "% >Q" : pxn_rdot_chosen() ? "% >R" : "% >G"); + lcd_text(4, y, l, UI_TXT, UI_BG, 1); y += 12; + fm1_wdt_feed(); + static const char *M[PXN_MODES] = {"C", " V", " B0 ", " B4 ", " B8 ", "2C ", " V12 ", " V16 ", " V12C4 ", + " 2C20 ", " 2C24 "}; + for (int m = 0; m < PXN_MODES; m++) { + if (m == 0 || m == 5 || m == 9) l[0] = 0; + uint32_t t = px_nam_tuned(m); + b_str(l, M[m]); + if (t) b_num(l, t * 100u / (A_BUDGET * 2u)); else b_str(l, "-"); + if (m == 4 || m == 8) { lcd_text(4, y, l, GRN, UI_BG, 1); y += 12; } + } + b_str(l, " >"); b_num(l, (uint32_t)pxn_mode()); + lcd_text(4, y, l, GRN, UI_BG, 1); y += 12; + /* diagnostic 18: where the CPU alone (mode 0) spends it: input, tap tables, kernel (groups of 4 frames), the + * gathered 1..3-frame rests, post, the head (groups, rest, rings + output), the whole */ +#define B_P(k) (pxn_prof_ticks(k) * 100u / (A_BUDGET * 2u)) + const uint32_t g1 = pxn_prof_ticks(1), g8 = pxn_prof_ticks(8); + l[0] = 0; b_str(l, "IN "); b_num(l, B_P(0)); b_str(l, " TBL "); b_num(l, B_P(8)); + b_str(l, " KER "); b_num(l, (g1 > g8 ? g1 - g8 : 0u) * 100u / (A_BUDGET * 2u)); + b_str(l, " REST "); b_num(l, B_P(2)); + lcd_text(4, y, l, YEL, UI_BG, 1); y += 12; + l[0] = 0; b_str(l, "POST "); b_num(l, B_P(3)); b_str(l, " HEAD "); b_num(l, B_P(6)); b_str(l, "+"); + b_num(l, B_P(7)); b_str(l, "+"); b_num(l, B_P(4)); b_str(l, " ALL "); b_num(l, B_P(5)); + lcd_text(4, y, l, YEL, UI_BG, 1); y += 12; + { /* the new post (post3) against post2, mode 0; >3 when it is the one used */ + const int p3 = pxn_post3_state(); + l[0] = 0; b_str(l, "POST2 "); b_num(l, pxn_post_ticks(0) * 100u / (A_BUDGET * 2u)); + b_str(l, " POST3 "); + if (p3) b_num(l, pxn_post_ticks(1) * 100u / (A_BUDGET * 2u)); else b_str(l, "FAILED"); + b_str(l, p3 == 2 ? " >3" : " >2"); + lcd_text(4, y, l, p3 ? YEL : RED, UI_BG, 1); y += 14; + } +#undef B_P + } + fm1_wdt_feed(); + /* diagnostic 21: the network alone, then every factory preset as the audio interrupt runs it (with a NAM amp: + * pipelined on the two cores; otherwise the whole chain on one core), % of real time: green up to 80, yellow up + * to 85, red above (the safety bypass: 93 pipelined, 85 otherwise) */ px_preset_t pp; - static const char *NAMES[4] = {"AMP ONLY ", "+ CAB ", "+ DRIVE/GATE ", "ALL ON "}; - for (int c = 0; c < 4; c++) { - px_preset_factory(&pp, 17); /* 5150 RHYTHM: 4-stage 5150 */ - for (int z = 0; z < PX_NBLK; z++) pp.on[z] = 0; - pp.on[PX_B_AMP] = 1; - if (c >= 1) pp.on[PX_B_CAB] = 1; - if (c >= 2) { pp.on[PX_B_DRIVE] = 1; pp.on[PX_B_GATE] = 1; } - if (c >= 3) { for (int z = 0; z < PX_NBLK; z++) pp.on[z] = 1; pp.type[PX_B_MOD] = PX_MOD_ROTARY; pp.type[PX_B_PITCH] = PX_PIT_POLYOCT; - pp.type[PX_B_REVERB] = PX_REV_SHIMMER; pp.type[PX_B_DELAY] = PX_DLY_SPACE; } + px_preset_factory(&pp, 17); + for (int z = 0; z < PX_NBLK; z++) pp.on[z] = 0; + pp.on[PX_B_AMP] = 1; + { uint32_t pct = b_engine(&pp); - l[0] = 0; b_str(l, NAMES[c]); b_num(l, pct); b_str(l, " %"); - lcd_text(4, 64u + (uint32_t)c * 16u, l, pct <= 85u ? GRN : RED, UI_BG, 2); + l[0] = 0; b_str(l, "NAM AMP ONLY "); b_num(l, pct); b_str(l, " % PRESETS:"); + lcd_text(4, y, l, pct <= 85u ? GRN : RED, UI_BG, 1); y += 12; } - lcd_text(4, 140, "100% = REAL TIME (2.9 MS / BLOCK)", UI_TXT, UI_BG, 1); - lcd_text(4, 160, "PLEASE TAKE A PHOTO OF THIS SCREEN", UI_ACC, UI_BG, 1); - for (int i = 0; i < 60; i++) { fm1_wdt_feed(); fm1_delay_ms(100); } + for (int f = 0; f < 24; f++) { + px_preset_factory(&pp, f); + uint32_t pct = b_engine(&pp); +#if DSP_CPU1 + if (px_nam_dual(&g_eng)) { + a_nbv = 0; + uint32_t dt = 0; + a_late = 0; + for (int r = 0; r < 16; r++) { + uint32_t t0 = fm1_ticks(); + dsp_pipe_run(1); + if (r >= 8) dt += fm1_ticks() - t0; + } + a_nbv = 0; + fm1_wdt_feed(); + pct = dt / 8u * 100u / A_BUDGET; + } +#endif + l[0] = 0; + if (f < 9) b_str(l, "0"); + b_num(l, (uint32_t)f + 1u); b_str(l, " "); b_num(l, pct); + lcd_text(4 + (uint32_t)(f % 5) * 48u, y, l, pct <= 80u ? GRN : pct <= 85u ? YEL : RED, UI_BG, 1); + if (f % 5 == 4 || f == 23) y += 12; + } + lcd_text(4, y + 4, "100% = REAL TIME. PLEASE TAKE A PHOTO", UI_ACC, UI_BG, 1); + for (int i = 0; i < 120; i++) { fm1_wdt_feed(); fm1_delay_ms(100); } +#endif } static struct iis_platform_data a_pd; @@ -343,6 +496,7 @@ static void audio_start(void) #if BENCH_AT_BOOT px_engine_init(&g_eng, 44100.0f); audio_bench(); /* benchmark screen (diagnostic): off by default */ + px_nam_check(b_ticks); /* (the bench used the NAM memory) */ #endif op_stage(ST_ENG_INIT, "ENGINE INIT..."); px_engine_init(&g_eng, 44100.0f); diff --git a/firmware/px_cacheram.h b/firmware/px_cacheram.h new file mode 100644 index 0000000..29f964a --- /dev/null +++ b/firmware/px_cacheram.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-3.0-only + * Cache RAM init: Copyright (C) 2026 Kerem Kilic (Ellic Studio), from melodee firmware/hal/fm1_cache.h + * (github.com/keremimo/melodee, GPL-3.0), which follows the AC79 SDK's sdk_ld_sfc.c / cache_way_config. + * OpenPocket v37 — seven of the eight 4 KiB data-cache ways as plain RAM at 0x01F28000..0x01F2F000 (the data cache + * sits in front of the flash only): the NAM network's vector unit reads its inputs there, away from the RAM the CPUs + * work in (px_nam.c, pxn_set_fast). All instruction ways stay. At boot only, before the second core starts and before anything uses that memory; it refuses + * external-memory setups, checks the registers and the whole bank, and puts everything back on a failure. */ +#pragma once +#include + +enum { PXC_OFF, PXC_READY, PXC_EXTERNAL, PXC_TIMEOUT, PXC_WAY_FAILED, PXC_MEMORY_FAILED }; +static volatile uint32_t pxc_status; +#define PXC_BEGIN 0x01F28000u +#define PXC_END 0x01F2F000u + +/* wholly in RAM (the instruction cache is reconfigured under it), calls nothing: word loops, no memset */ +__attribute__((noinline, section(".ram_text"))) static void pxc_init(void) +{ +#define FC_READ(a) (*(volatile uint32_t *)(uintptr_t)(a)) +#define FC_WRITE(a, v) (*(volatile uint32_t *)(uintptr_t)(a) = (v)) +#define FC_SYNC() __asm__ volatile("csync; ssync" ::: "memory") + const uint32_t FC_CON = 0x01EEE008u, FC_DATA = 0x01EEE00Cu, FC_INSTRUCTION = 0x01EEE010u, FC_TICKS = 0x00010804u; + uint32_t start, spins, a, pass, want, dc, ic, con; + con = FC_READ(FC_CON); dc = FC_READ(FC_DATA); ic = FC_READ(FC_INSTRUCTION); + if ((FC_READ(0x00040400u) & 0x800u) || (FC_READ(0x00040500u) & 1u)) { pxc_status = PXC_EXTERNAL; return; } + start = FC_READ(FC_TICKS); + for (spins = 0; !(FC_READ(FC_CON) & 0x4000u); spins++) + if (spins >= 100000u || (uint32_t)(FC_READ(FC_TICKS) - start) >= 240000u) { pxc_status = PXC_TIMEOUT; return; } + FC_WRITE(FC_CON, con & ~0x300u); FC_SYNC(); + FC_WRITE(FC_DATA, (dc & 0xFF000000u) | 0x00808080u); + FC_WRITE(FC_INSTRUCTION, (ic & 0xFFFF0000u) | 0xFFFFu); + for (a = 0x01F00000u; a < 0x01F04000u; a += 4u) FC_WRITE(a, 0); /* the tag/valid memory (CPU0, CPU1, DMA) */ + for (a = 0x01F08000u; a < 0x01F0A200u; a += 4u) FC_WRITE(a, 0); + for (a = 0x01F0B000u; a < 0x01F0B200u; a += 4u) FC_WRITE(a, 0); + FC_SYNC(); + FC_WRITE(FC_CON, (con & ~0x300u) | 0x100u); FC_SYNC(); + if (FC_READ(FC_DATA) != ((dc & 0xFF000000u) | 0x00808080u) || FC_READ(FC_INSTRUCTION) != ((ic & 0xFFFF0000u) | 0xFFFFu) || + (FC_READ(FC_CON) & 0x300u) != 0x100u) { pxc_status = PXC_WAY_FAILED; goto failed; } + for (pass = 0; pass < 2u; pass++) { + for (a = PXC_BEGIN; a < PXC_END; a += 4u) { want = a ^ 0xA55A3CC3u; FC_WRITE(a, pass ? ~want : want); } + FC_SYNC(); + for (a = PXC_BEGIN; a < PXC_END; a += 4u) { + want = a ^ 0xA55A3CC3u; + if (FC_READ(a) != (pass ? ~want : want)) { pxc_status = PXC_MEMORY_FAILED; goto failed; } + } + } + for (a = PXC_BEGIN; a < PXC_END; a += 4u) FC_WRITE(a, 0); + FC_SYNC(); + pxc_status = PXC_READY; + return; +failed: + FC_WRITE(FC_CON, FC_READ(FC_CON) & ~0x300u); FC_SYNC(); + FC_WRITE(FC_DATA, dc); FC_WRITE(FC_INSTRUCTION, ic); FC_SYNC(); + FC_WRITE(FC_CON, con); FC_SYNC(); +#undef FC_READ +#undef FC_WRITE +#undef FC_SYNC +} diff --git a/firmware/px_editor.h b/firmware/px_editor.h index 5fe89d8..adbd9b3 100644 --- a/firmware/px_editor.h +++ b/firmware/px_editor.h @@ -9,19 +9,21 @@ * editor made itself is not echoed back. * The including file provides: PRESET, cur_preset, load_preset, ui_blk / ui_mode / ui_item (ui.h), st_gen, the * store (px_store.h), BLK_COL (ui_colors.h), ota_frame_get / ota_frame_done / ota_wire_send, ms_now, OP_VERSION, - * FELUCCA_ID_PTR, and ed_load / ed_flags (the DSP load for PING). + * FELUCCA_ID_PTR, ed_load / ed_flags (the DSP load for PING), and (v37) the NAM user models (px_models.h) with + * nm_changed(slot), called after a slot was written or erased. */ #pragma once #define ED_H0 0x7Du #define ED_H1 0x4Fu #define ED_H2 0x50u -#define ED_PROTO 1u +#define ED_PROTO 2u /* 2: v37, NAM models (NAM_LIST .. NAM_ERASE) */ #define ED_NAME_MAX 13u #define ED_P_SIZE 110u typedef char ed_size_check[sizeof(px_preset_t) == ED_P_SIZE ? 1 : -1]; enum { ED_INFO = 1, ED_CAT_BLOCK, ED_CAT_TYPE, ED_TEXTS, ED_STATE, ED_SET, ED_ORDER, ED_NAME, ED_PUT, ED_SELECT, - ED_FOCUS, ED_LIST, ED_SLOT_GET, ED_SLOT_PUT, ED_COMMIT, ED_SAVE, ED_WATCH, ED_PING }; + ED_FOCUS, ED_LIST, ED_SLOT_GET, ED_SLOT_PUT, ED_COMMIT, ED_SAVE, ED_WATCH, ED_PING, + ED_NAM_LIST, ED_NAM_WRITE, ED_NAM_COMMIT, ED_NAM_ERASE }; static uint8_t ed_out[1024]; static uint32_t ed_n; @@ -231,6 +233,25 @@ static void ed_handle(const uint8_t *a, uint32_t n) /* a: the args, after the case ED_PING: ed_b(ed_load() > 127u ? 127u : ed_load()); ed_b(ed_flags()); break; + case ED_NAM_LIST: { /* v37: every model, factory first, then the user slots */ + char nm[12]; + ed_b(PX_NAM_NFACT); ed_b(PX_NAM_NUSER); + for (k = 0; k < PX_NAM_N; k++) { rc = px_nam_name((int)k, nm); ed_b(rc ? 1u : 0u); ed_str(nm, 11); } + break; + } + case ED_NAM_WRITE: /* piece (2 bytes, 7 bits each), then 128 packed bytes */ + if (n < 2u) return; + i = a[0] | (uint32_t)a[1] << 7; + rc = nm_write_piece(i, a + 2, n - 2u); + ed_b(a[0]); ed_b(a[1]); ed_b((uint32_t)rc); + break; + case ED_NAM_COMMIT: + case ED_NAM_ERASE: + if (n < 1u) return; + rc = cmd == ED_NAM_COMMIT ? nm_commit(a[0]) : nm_erase(a[0]); + nm_changed(a[0]); /* a sound playing that slot reloads it */ + ed_b(a[0]); ed_b((uint32_t)rc); + break; default: return; } @@ -251,7 +272,7 @@ static void ed_service(uint32_t now) if (!ota_frame_get(&p, &n) || n < 4u || p[0] != ED_H0 || p[1] != ED_H1 || p[2] != ED_H2) return; { - static uint8_t f[160]; /* the longest request: SLOT_PUT, 4 + 2 + 110 bytes */ + static uint8_t f[160]; /* the longest requests: NAM_WRITE 4 + 1 + 2 + 128, SLOT_PUT */ uint32_t k = n > sizeof f ? sizeof f : n, i; for (i = 0; i < k; i++) f[i] = p[i]; ota_frame_done(); /* free the frame buffer before replying */ diff --git a/firmware/px_leds.h b/firmware/px_leds.h new file mode 100644 index 0000000..acb4868 --- /dev/null +++ b/firmware/px_leds.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-3.0-only + * OpenPocket — the button lights (issue #8): one 74HC595 shift register, 8 outputs, on port C, and PC7, the lights' + * enable. + * + * Pins and timing as the stock firmware drives them (BlackBox_016, _020 and _021 have the same routine, read with + * JieLi's objdump; isod89 read it first, and finds PocketX_016's the same): + * DS (data) = PC8, SHCP (shift clock) = PC5, STCP (latch) = PC6. + * PC7 = the lights' enable, low = on (the 595's OE, by how the stock code uses it). The 595 init sets PC7 high + * with the three pins and loads the first byte; then the lights go on with PC7 low: in 016 / 020 as the first + * step of the screen init, which leaves it low, in 021 right after that first byte. 021 also sets PC7 high again + * on its way off. OpenPocket used to keep PC7 high as a screen line: it is not one (the stock screen runs with it + * low), and with it high the lights stay dark whatever the 595 holds. Every probe before this one kept it high. + * A byte, MSB first: STCP low; for each bit SHCP low, DS = the bit, wait, SHCP high, wait; then STCP high, whose + * rising edge puts the byte on the outputs. Stock waits about 4 to 8 us at each step: LEDS_WAIT is 5 us. + * Stock sends its byte inverted (DS = 1 for a 0 bit): its logical byte has bit 0 a blink signal (a timer), bits + * 1..6 the six effect lights, bit 7 always 0; at power-off it writes logical 0, FF on the wire. leds_write here + * takes the byte as it goes on the wire. + * Confirmed on a BlackBox (2026-11-06): with PC7 low after the first byte the lights follow the 595; not tried on a + * Pocket X yet (the same firmware, and the stock routine is the same there). + * + * Every edge is a read-modify-write of PORTC OUT, so these are called from the main loop only (no interrupt writes + * port C). tests/lpsim.c checks the bit order and the waits against a model of the 595. */ +#pragma once +#include + +#ifndef LEDS_PC /* PORTC register r: OUT +0x00, DIR +0x08 (1 input, 0 output), PU +0x10, PD +0x14 */ +#define LEDS_PC(r) (*(volatile uint32_t *)(0x50080u + (uint32_t)(r))) +#endif +#ifndef LEDS_WAIT +#define LEDS_WAIT() fm1_delay_us(5u) +#endif +#ifndef LEDS_EDGE /* tests/lpsim.c: the 595 model sees each edge */ +#define LEDS_EDGE() ((void)0) +#endif +#define LEDS_DS (1u << 8) /* PC8: data */ +#define LEDS_SH (1u << 5) /* PC5: shift clock, DS is taken on its rising edge */ +#define LEDS_ST (1u << 6) /* PC6: latch, the outputs change on its rising edge */ +#define LEDS_PINS (LEDS_DS | LEDS_SH | LEDS_ST) +#define LEDS_EN (1u << 7) /* PC7: the lights' enable, low = on */ +#define LEDS_OFF 0xFFu /* the stock's power-off byte on the wire (logical 0, inverted) */ + +static uint8_t leds_byte; /* what the outputs show now */ + +static void leds_pin(uint32_t m, uint32_t hi) +{ + if (hi) LEDS_PC(0x00) |= m; + else LEDS_PC(0x00) &= ~m; + LEDS_EDGE(); +} +/* The pins are parameters so that a test build can try other roles (led_probe.h); the driver is leds_init / + * leds_write with the pins above. */ +static void leds_shift(uint8_t v, uint32_t ds, uint32_t sh, uint32_t st) +{ + leds_pin(st, 0u); + for (int i = 7; i >= 0; i--) { + leds_pin(sh, 0u); + leds_pin(ds, ((uint32_t)v >> i) & 1u); + LEDS_WAIT(); + leds_pin(sh, 1u); + LEDS_WAIT(); + } + leds_pin(st, 1u); +} +static void leds_setup(uint32_t ds, uint32_t sh, uint32_t st) +{ + uint32_t m = ds | sh | st; + LEDS_PC(0x10) &= ~m; /* no pull-ups (the boot leaves them on) */ + LEDS_PC(0x14) &= ~m; /* no pull-downs */ + LEDS_PC(0x00) = (LEDS_PC(0x00) & ~m) | sh; /* SHCP 1, STCP 0, DS 0, as stock */ + LEDS_PC(0x08) &= ~m; /* outputs */ + LEDS_EDGE(); + LEDS_WAIT(); /* SHCP high for a while, even if it was low */ +} +static void leds_write(uint8_t v) +{ + leds_shift(v, LEDS_DS, LEDS_SH, LEDS_ST); + leds_byte = v; +} +static void leds_enable(uint32_t on) /* PC7 an output: low = lights on */ +{ + if (on) LEDS_PC(0x00) &= ~LEDS_EN; + else LEDS_PC(0x00) |= LEDS_EN; + LEDS_PC(0x08) &= ~LEDS_EN; + LEDS_EDGE(); +} +static void leds_init(void) /* as stock: load with the lights off, then on */ +{ + leds_enable(0u); + leds_setup(LEDS_DS, LEDS_SH, LEDS_ST); + leds_write(LEDS_OFF); + leds_enable(1u); +} diff --git a/firmware/px_lights.h b/firmware/px_lights.h new file mode 100644 index 0000000..ac9c939 --- /dev/null +++ b/firmware/px_lights.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-3.0-only + * OpenPocket — what the button lights show (issue #8). px_leds.h drives them; this decides them, once per main-loop + * pass, from the preset being played: + * FX lit while any block of the FX button's group is on (UI_FXB: drive, SFX, synth, + * pitch, comp, gate, EQ) + * AMP, MOD, DLY, REV, CAB lit while their block is on + * HOME blinks (2 Hz) while the tuner is open, dark otherwise + * The bits are the LED map's, read on a BlackBox (2026-11-06): 0 HOME, 1 FX, 2 AMP, 3 MOD, 4 DLY, 5 REV, 6 CAB, + * 7 none: the panel's order (a Pocket X may differ: not checked there yet). On the wire a 0 lights, so the byte + * goes out inverted (as the stock firmware sends it), and only when it changes. Confirmed on a BlackBox: each + * light follows its block, HOME blinks in the tuner. Not yet: a setting to switch the lights off (it belongs with + * the settings store isod89/openpocket#10 adds). + * Included by openpocket.c (after ui.h: UI_FXB) and by tests/lightsim.c. */ +#pragma once +#include +#include "px_leds.h" + +enum { LT_HOME, LT_FX, LT_AMP, LT_MOD, LT_DLY, LT_REV, LT_CAB }; /* the light on each bit */ +#define LT_BLINK_MS 250u /* the tuner's HOME blink: half a period */ + +static uint8_t lights_of(const px_preset_t *p, int tuner, uint32_t now) /* the lit lights, 1 = lit */ +{ + uint8_t v = 0; + for (int i = 0; i < 7; i++) + if (p->on[UI_FXB[i]]) v |= 1u << LT_FX; + if (p->on[PX_B_AMP]) v |= 1u << LT_AMP; + if (p->on[PX_B_MOD]) v |= 1u << LT_MOD; + if (p->on[PX_B_DELAY]) v |= 1u << LT_DLY; + if (p->on[PX_B_REVERB]) v |= 1u << LT_REV; + if (p->on[PX_B_CAB]) v |= 1u << LT_CAB; + if (tuner && !((now / LT_BLINK_MS) & 1u)) v |= 1u << LT_HOME; + return v; +} +static void lights_show(uint8_t lit) /* written only when the byte changes */ +{ + uint8_t wire = (uint8_t)~lit; + if (wire != leds_byte) leds_write(wire); +} +static void lights_update(const px_preset_t *p, int tuner, uint32_t now) { lights_show(lights_of(p, tuner, now)); } +static void lights_off(void) { lights_show(0u); } diff --git a/firmware/px_models.h b/firmware/px_models.h new file mode 100644 index 0000000..75d8d14 --- /dev/null +++ b/firmware/px_models.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-3.0-only + * OpenPocket — the NAM user models in flash (v37). + * + * 16 slots of 8 KiB at 0xC0000..0xE0000 (below the update loader's staging area, above the app area; the update + * loader leaves this range alone: loader/ldr_core.c LDR_NAM_LO/HI). A slot: a 64-byte header, then the 1871 float + * weights of an A2-Lite network in the .nam file's order (engine/px_nam.h), 7548 bytes in all: + * magic "OPNM", version 1, 1871, name (11 chars + 0), level trim (0.01 dB), CRC16 of the weights. + * The web editor sends a model in pieces (NAM_WRITE) into nm_stage, then NAM_COMMIT checks it (every weight finite, + * the CRC) and writes the slot: two sectors erased, programmed, read back, with the audio held as for a preset save. + * The names and levels are read once at boot into RAM (the screen asks for them often); the weights are read from + * the flash only when a preset picks the model (px_engine_set, called with the audio held: the flash cannot be read + * through SPI while the second core runs the engine from XIP). + */ +#pragma once + +#define NM_BASE 0xC0000u +#define NM_SLOT 0x2000u +#define NM_MAGIC 0x4D4E504Fu /* "OPNM" */ +#define NM_HDR 64u +#define NM_BYTES (NM_HDR + PXN_NW * 4u) /* 7548 */ +#define NM_CHUNK 112u /* bytes per NAM_WRITE (7-bit packed: 128) */ + +typedef struct { + uint32_t magic; + uint16_t ver, nw; + char name[12]; + int16_t level_cdb; /* level trim, 0.01 dB */ + uint16_t crc; /* CRC16 (ota_crc16) of the weights */ + uint8_t pad[NM_HDR - 24u]; +} nm_hdr_t; +typedef char nm_hdr_check[sizeof(nm_hdr_t) == NM_HDR ? 1 : -1]; + +static uint8_t nm_stage[NM_BYTES] __attribute__((aligned(4))); +static struct { uint8_t ok; char name[12]; float level; } nm_cache[PX_NAM_NUSER]; +static uint32_t nm_gen; /* bumps when a slot changes */ + +static int nm_hdr_ok(const nm_hdr_t *h) +{ + return h->magic == NM_MAGIC && h->ver == 1u && h->nw == PXN_NW; +} +static void nm_name_clean(char *d, const char *s) +{ + uint32_t i; + for (i = 0; i < 11u && s[i]; i++) d[i] = (s[i] >= 32 && s[i] <= 126) ? s[i] : '?'; + for (; i < 12u; i++) d[i] = 0; +} +/* boot (and after each write): the headers into nm_cache */ +static void nm_scan(void) +{ + nm_hdr_t h; + for (uint32_t s = 0; s < PX_NAM_NUSER; s++) { + nm_cache[s].ok = 0; + if (ota_fread(NM_BASE + s * NM_SLOT, &h, sizeof h) || !nm_hdr_ok(&h)) continue; + nm_cache[s].ok = 1; + nm_name_clean(nm_cache[s].name, h.name); + nm_cache[s].level = (float)h.level_cdb * 0.01f; + } + nm_gen++; +} + +/* the engine's hook (engine/px_dsp.h): name and level from the cache, the weights from the flash (checked) */ +int px_nam_user(int slot, char *name12, float *level_db, float *w) +{ + if (slot < 0 || slot >= (int)PX_NAM_NUSER || !nm_cache[slot].ok) return 0; + memcpy(name12, nm_cache[slot].name, 12); + *level_db = nm_cache[slot].level; + if (w) { + nm_hdr_t h; + uint32_t off = NM_BASE + (uint32_t)slot * NM_SLOT; + if (ota_fread(off, &h, sizeof h) || !nm_hdr_ok(&h)) return 0; + if (ota_fread(off + NM_HDR, w, PXN_NW * 4u)) return 0; + if ((uint16_t)ota_crc16((const uint8_t *)w, PXN_NW * 4u, 0) != h.crc) return 0; + } + return 1; +} + +/* 7-bit unpacking: groups of 8 bytes (a byte of high bits, then 7 bytes), as the editor packs them */ +static uint32_t nm_unpack7(const uint8_t *s, uint32_t n, uint8_t *d, uint32_t max) +{ + uint32_t o = 0; + for (uint32_t i = 0; i + 1u < n && o < max; i += 8u) { + uint8_t hi = s[i]; + for (uint32_t j = 0; j < 7u && i + 1u + j < n && o < max; j++) + d[o++] = (uint8_t)(s[i + 1u + j] | ((hi >> j & 1u) << 7)); + } + return o; +} + +/* NAM_WRITE: piece `idx` (NM_CHUNK bytes each) of the staging buffer; 0 = ok */ +static int nm_write_piece(uint32_t idx, const uint8_t *packed, uint32_t n) +{ + uint32_t off = idx * NM_CHUNK; + if (off >= NM_BYTES) return 1; + uint32_t want = NM_BYTES - off < NM_CHUNK ? NM_BYTES - off : NM_CHUNK; + return nm_unpack7(packed, n, nm_stage + off, want) == want ? 0 : 1; +} + +/* NAM_COMMIT: the staged model into slot s. 0 ok, 1 invalid, 2 flash */ +static int nm_commit(uint32_t s) +{ + nm_hdr_t *h = (nm_hdr_t *)nm_stage; + const uint32_t *w = (const uint32_t *)(nm_stage + NM_HDR); + if (s >= PX_NAM_NUSER || !nm_hdr_ok(h)) return 1; + for (uint32_t i = 0; i < PXN_NW; i++) if ((w[i] & 0x7F800000u) == 0x7F800000u) return 1; /* NaN / Inf */ + if ((uint16_t)ota_crc16(nm_stage + NM_HDR, PXN_NW * 4u, 0) != h->crc) return 1; + nm_name_clean(h->name, h->name); + uint32_t base = NM_BASE + s * NM_SLOT, k; + int rc = 0; + st_audio_hold(1); + if (fl_erase4k(base, &k) || fl_erase4k(base + 0x1000u, &k)) rc = 2; + if (!rc && fl_write(base + NM_HDR, nm_stage + NM_HDR, NM_BYTES - NM_HDR)) rc = 2; + if (!rc && fl_write(base, nm_stage, NM_HDR)) rc = 2; /* header last: a cut write leaves no valid slot */ + if (!rc) { /* read back */ + static uint8_t chk[256]; + for (uint32_t o = 0; !rc && o < NM_BYTES; o += sizeof chk) { + uint32_t m = NM_BYTES - o < sizeof chk ? NM_BYTES - o : sizeof chk; + if (ota_fread(base + o, chk, m) || memcmp(chk, nm_stage + o, m)) rc = 2; + } + } + st_audio_hold(0); + nm_scan(); + return rc; +} + +/* NAM_ERASE: slot s emptied. 0 ok, 1 invalid, 2 flash */ +static int nm_erase(uint32_t s) +{ + uint32_t k; + int rc = 0; + if (s >= PX_NAM_NUSER) return 1; + st_audio_hold(1); + if (fl_erase4k(NM_BASE + s * NM_SLOT, &k) || fl_erase4k(NM_BASE + s * NM_SLOT + 0x1000u, &k)) rc = 2; + st_audio_hold(0); + nm_scan(); + return rc; +} diff --git a/firmware/px_usb.h b/firmware/px_usb.h index 851134a..ae34afc 100644 --- a/firmware/px_usb.h +++ b/firmware/px_usb.h @@ -17,8 +17,10 @@ #define FELUCCA_USB_PRODUCT "OpenPocket" #define FELUCCA_USB_MANUFACTURER "OpenPocket" #define RING_PUBLISH() __asm__ volatile("" ::: "memory") -/* the app may only write the OTA staging area (its loader + update record) and the preset store (px_store.h) */ -#define FL_RANGE_OK(off, n) (FL_IN(off, n, FL_OTA_LO, FL_OTA_HI) || FL_IN(off, n, 0xF0000u, 0xF4000u)) +/* the app may only write the OTA staging area (its loader + update record), the preset store (px_store.h) and, + * v37, the NAM user models (px_models.h) */ +#define FL_RANGE_OK(off, n) (FL_IN(off, n, FL_OTA_LO, FL_OTA_HI) || FL_IN(off, n, 0xF0000u, 0xF4000u) || \ + FL_IN(off, n, 0xC0000u, 0xE0000u)) /* the package identity, patched by pxpkg.py ("OP-PRODUCT:" + identity, 32 bytes, exactly once in the app) */ static const volatile char OP_PRODUCT[32] __attribute__((used, aligned(4))) = "OP-PRODUCT:PocketX_9" OP_VERSION_NUM; @@ -43,6 +45,10 @@ void fm1_timer5_irq(void) /* 10 kHz; USB at 2 kHz */ } extern void isr_timer5(void); +#ifndef PX_LIGHTS_OFF /* the button lights off while an update runs (openpocket.c: px_lights.h) */ +#define PX_LIGHTS_OFF() ((void)0) +#endif + /* ---- ota.c hooks ---- */ static uint32_t ota_now_ms(void) { return ms_now(); } static void ota_idle(void) { fm1_wdt_feed(); } @@ -78,6 +84,7 @@ static int ota_fread(uint32_t off, void *p, uint32_t n) static void ota_show(uint32_t step, int32_t code) { static const char *const STEP[] = {"", "PACKAGE", "CHECK", "LOADER", "CONFIRM", "RESTART"}; + PX_LIGHTS_OFF(); lcd_rect(0, 0, 240, 240, UI_BG); ft_box(0, 92, 240, "UPDATE", &FT_MD, UI_ACC, UI_BG, 1); if (step < 9u) { diff --git a/firmware/ui.h b/firmware/ui.h index 960d2e8..ea1459e 100644 --- a/firmware/ui.h +++ b/firmware/ui.h @@ -74,7 +74,7 @@ static uint16_t ui_dark(uint16_t c) /* a colour at ~1/3: the "off" version of static struct { int full, screen; /* screen: 0 PLAY, 1 EDIT */ uint32_t preset, vol; char name[14]; - int dirty, amp_t, cab_t, amp_on, cab_on; + int dirty, amp_t, cab_t, amp_on, cab_on, amp_m; uint8_t tile_on[PX_NBLK], tile_sel[PX_NBLK], tile_blk[PX_NBLK], tile_mv[PX_NBLK]; int info_b, info_t, info_on; int blk, type, np, item, mode, on; @@ -174,9 +174,13 @@ static void draw_play_top(int force) uc.preset = cur_preset; } int at = PRESET.type[PX_B_AMP], ct = PRESET.type[PX_B_CAB], ao = PRESET.on[PX_B_AMP], co = PRESET.on[PX_B_CAB]; - if (force || at != uc.amp_t || ao != uc.amp_on) { - ft_box(94, P_NUM_Y + 4u, 142, ao ? px_type_name(PX_B_AMP, at) : "NO AMP", &FT_MD, ao ? BLK_COL[PX_B_AMP] : UI_DIM, UI_BG, 0); - uc.amp_t = at; uc.amp_on = ao; + int am = at == PX_AMP_NAM ? px_nam_model(PRESET.p[PX_B_AMP][0]) : -1; /* v37: a NAM amp shows its model */ + if (force || at != uc.amp_t || ao != uc.amp_on || am != uc.amp_m) { + char nm[12]; + const char *an = px_type_name(PX_B_AMP, at); + if (am >= 0) { px_nam_name(am, nm); an = nm; } + ft_box(94, P_NUM_Y + 4u, 142, ao ? an : "NO AMP", &FT_MD, ao ? BLK_COL[PX_B_AMP] : UI_DIM, UI_BG, 0); + uc.amp_t = at; uc.amp_on = ao; uc.amp_m = am; } if (force || ct != uc.cab_t || co != uc.cab_on) { ft_box(94, P_NUM_Y + 29u, 88, co ? px_type_name(PX_B_CAB, ct) : "NO CAB", &FT_SM, UI_DIM, UI_BG, 0); @@ -464,11 +468,12 @@ static void ui_preset_step(int dd) if (ui_mode == M_EDIT) ui_mode = M_BLOCK; if ((int)ui_item >= ui_nitems()) ui_item = 0; } +/* the FX button's blocks, in its order (the FX light follows them: px_lights.h) */ +static const uint8_t UI_FXB[7] = {PX_B_DRIVE, PX_B_SFX, PX_B_SYN, PX_B_PITCH, PX_B_COMP, PX_B_GATE, PX_B_EQ}; static void ui_fx_cycle(void) /* FX: DRV -> SFX -> SYN -> PIT -> CMP -> GT -> EQ */ { - static const uint8_t FXB[7] = {PX_B_DRIVE, PX_B_SFX, PX_B_SYN, PX_B_PITCH, PX_B_COMP, PX_B_GATE, PX_B_EQ}; uint32_t nx = PX_B_DRIVE; - for (int i = 0; i < 7; i++) if (FXB[i] == ui_blk) nx = FXB[(i + 1) % 7]; + for (int i = 0; i < 7; i++) if (UI_FXB[i] == ui_blk) nx = UI_FXB[(i + 1) % 7]; ui_blk = nx; ui_mode = M_BLOCK; ui_item = 0; } diff --git a/loader/ldr_core.c b/loader/ldr_core.c index 662530a..e1dc0ee 100644 --- a/loader/ldr_core.c +++ b/loader/ldr_core.c @@ -36,6 +36,8 @@ #define LDR_REC_HI 0xFF000u /* ... and below key_mac (Pocket X); OpenPocket stages at 0xE0000 */ #define LDR_DATA_LO 0xF0000u /* OpenPocket's preset store (px_store.h, copies A and B): */ #define LDR_DATA_HI 0xF4000u /* user data, never erased even if a sector ends like a record */ +#define LDR_NAM_LO 0xC0000u /* v37: OpenPocket's NAM user models (firmware/px_models.h): */ +#define LDR_NAM_HI 0xE0000u /* user data as well */ #define LDR_NSEC ((LDR_APP_HI - LDR_APP_LO) >> 12) #define LDR_FL_MAX 0x100000u /* flash.bin: at most the 1 MiB part */ @@ -176,6 +178,8 @@ static int ldr_session(void) uint8_t r[80]; if (s - 0x1000u >= LDR_DATA_LO && s - 0x1000u < LDR_DATA_HI) continue; /* Felucca's store: user data that may look like one */ + if (s - 0x1000u >= LDR_NAM_LO && s - 0x1000u < LDR_NAM_HI) + continue; /* the NAM models (v37) */ if (ldr_fread(s - 0x100u, r, 80)) break; if (ota_rd16(r + 6) == 0x5441u && ota_rd16(r) && ota_rd16(r) == ota_crc16(r + 2, 78, 0)) diff --git a/tests/edsim.c b/tests/edsim.c index e9a3b43..8804f39 100644 --- a/tests/edsim.c +++ b/tests/edsim.c @@ -21,11 +21,12 @@ #include #include #include "../engine/px_dsp.h" +#include "../engine/px_nam.h" static uint8_t nor[0x100000]; #define FL_IN(off, n, lo, hi) ((uint32_t)(off) >= (lo) && (uint32_t)(off) <= (hi) && (uint32_t)(n) <= (hi) - (uint32_t)(off)) -#define OP_VERSION "v36" -static const char *FELUCCA_ID_PTR = "PocketX_936"; +#define OP_VERSION "v37" +static const char *FELUCCA_ID_PTR = "PocketX_937"; static uint32_t ms_now(void) { @@ -44,20 +45,21 @@ static uint32_t ota_crc16(const uint8_t *p, uint32_t n, uint32_t c) /* as ota. return c; } -/* ---- flash (only the preset store may be written, as FL_RANGE_OK on the pedal) ---- */ +/* ---- flash (only the preset store and, v37, the NAM model slots may be written, as FL_RANGE_OK on the pedal) ---- */ +#define ED_FL_OK(off, n) (FL_IN(off, n, 0xF0000u, 0xF4000u) || FL_IN(off, n, 0xC0000u, 0xE0000u)) static int writes_ok = 1; static int ota_fread(uint32_t off, void *p, uint32_t n) { if (off + n > sizeof nor) return -1; memcpy(p, nor + off, n); return 0; } static int fl_erase4k(uint32_t off, uint32_t *took) { *took = 0; - if (!FL_IN(off, 0x1000u, 0xF0000u, 0xF4000u) || (off & 0xFFFu)) { writes_ok = 0; return -1; } + if (!ED_FL_OK(off, 0x1000u) || (off & 0xFFFu)) { writes_ok = 0; return -1; } memset(nor + off, 0xFF, 0x1000u); return 0; } static int fl_write(uint32_t off, const void *p, uint32_t n) { const uint8_t *s = p; - if (!FL_IN(off, n, 0xF0000u, 0xF4000u)) { writes_ok = 0; return -1; } + if (!ED_FL_OK(off, n)) { writes_ok = 0; return -1; } for (uint32_t i = 0; i < n; i++) nor[off + i] &= s[i]; return 0; } @@ -98,6 +100,8 @@ static int ota_wire_send(const uint8_t *p, uint32_t n) } #include "../firmware/px_store.h" +#include "../firmware/px_models.h" +static void nm_changed(uint32_t s) { (void)s; } #include "../firmware/px_editor.h" static int hexv(int c) { return c <= '9' ? c - '0' : (c | 32) - 'a' + 10; } @@ -164,6 +168,7 @@ int main(int argc, char **argv) } st_ok = 1; st_load(); + nm_scan(); cur_preset = st_last; load_preset(cur_preset); printf("#port OpenPocket\n"); diff --git a/tests/engine/nam_test.c b/tests/engine/nam_test.c new file mode 100644 index 0000000..515d9d8 --- /dev/null +++ b/tests/engine/nam_test.c @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-3.0-only + * OpenPocket — engine/px_nam.c on the PC: nam_test weights.f32 in.f32 out.f32 [block] (tests/test_nam.py) + * weights.f32: the 1871 A2-Lite weights (float32, file order); in/out: float32 samples. + * NAM_GATHER=1: the CPU's layers through gathered X rows instead of rdot. + * NAM_PIPE=m: mode m (2..8: the vector unit beside the CPU, a second core) with a simulated unit and core (built with + * -DPXN_EMUVEC). + * NAM_SRV=1|2: the two-core pipeline's mode (CPU1 serving, the last frames of each block, CPU0 given 0..12 more frames + * as CPU1's lateness cycles), CPU1 simulated running each layer as soon as allowed (1) or only when waited for (2). */ +#include +#include +#include "px_nam.h" +static pxn_model m; +void pxn_emu_on(int mode); +void pxn_emu_helper(void); +void pxn_emu_gather(void); +void pxn_emu_srv(int eager); +static int32_t ring[PXN_RING_BYTES / 4 + 4096]; /* + 16 KB: two pieces never pack perfectly (NAM_SPLIT=1) */ +static float *rd(const char *p, long *n) +{ + FILE *f = fopen(p, "rb"); + if (!f) { perror(p); exit(1); } + fseek(f, 0, SEEK_END); *n = ftell(f) / 4; fseek(f, 0, SEEK_SET); + float *b = malloc(*n * 4); + if (fread(b, 4, *n, f) != (size_t)*n) exit(1); + fclose(f); + return b; +} +int main(int argc, char **argv) +{ + long nw, n; + float *w = rd(argv[1], &nw), *x = rd(argv[2], &n); + int blk = argc > 4 ? atoi(argv[4]) : 64; + if (nw != PXN_NW) { fprintf(stderr, "%ld weights, want %d\n", nw, PXN_NW); return 1; } + /* the rings in one piece of exactly PXN_RING_BYTES, as on the pedal; NAM_SPLIT=1: two pieces (3/4 + the rest) */ + if (getenv("NAM_GATHER")) pxn_emu_gather(); + if (getenv("NAM_PIPE")) { pxn_emu_on(atoi(getenv("NAM_PIPE"))); pxn_emu_helper(); } + const int srv = getenv("NAM_SRV") ? atoi(getenv("NAM_SRV")) : 0; + if (srv) { pxn_emu_on(5); pxn_emu_helper(); pxn_emu_srv(srv == 1); } + unsigned n0 = getenv("NAM_SPLIT") ? (PXN_RING_BYTES * 3 / 4 & ~3u) : PXN_RING_BYTES; + int r = pxn_load(&m, w, ring, n0, ring + n0 / 4, getenv("NAM_SPLIT") ? PXN_RING_BYTES + 16384u - n0 : 0); + if (r) { fprintf(stderr, "load %d\n", r); return 1; } + float *y = malloc(n * 4); + for (long i = 0, k = 0; i < n; i += blk, k++) { + if (srv) pxn_srv_begin((int32_t)(k % 9) * 8); /* lateness: 0 .. 64 frames x 2 */ + pxn_process(&m, x + i, y + i, (int)(n - i < blk ? n - i : blk)); + if (srv) pxn_srv_end(); + } + FILE *o = fopen(argv[3], "wb"); + fwrite(y, 4, n, o); + fclose(o); + return 0; +} diff --git a/tests/engine/pipe_test.c b/tests/engine/pipe_test.c new file mode 100644 index 0000000..40cc40b --- /dev/null +++ b/tests/engine/pipe_test.c @@ -0,0 +1,46 @@ +/* v37: the two-core pipeline (firmware/px_audio.h, dsp_pipe) against the plain engine: per 128-frame block, the blocks + * after the amp on the previous block's network output (POST), then the blocks before it (PRE) and the network (NAM) on + * this block. Every factory preset with a NAM amp: the same output bit for bit, one block (128 frames) later. */ +#include +#include +#include +#include "px_dsp.h" +#define FR 128 +#define NB 120 +static px_engine e; +static float sig[FR * NB], ref[FR * NB], got[FR * NB]; +int main(void) +{ + unsigned s = 7; + for (int i = 0; i < FR * NB; i++) { + s = s * 1103515245u + 12345u; + sig[i] = 0.3f * sinf((float)i * 0.0157f) * (i % 9000 < 5000) + 0.02f * (((s >> 8) & 65535) / 32768.0f - 1.0f); + } + int bad = 0, n = 0; + for (int f = 0; f < 24; f++) { + px_preset_t p; + px_preset_factory(&p, f); + if (!p.on[PX_B_AMP] || p.type[PX_B_AMP] != PX_AMP_NAM) continue; + px_engine_init(&e, 44100.0f); px_engine_set(&e, &p); + for (int b = 0; b < NB * 2; b++) px_engine_process(&e, sig + 64 * b, ref + 64 * b, 64); + px_engine_init(&e, 44100.0f); px_engine_set(&e, &p); + static float nb[2][FR]; + int cur = 0; + memset(got, 0, sizeof got); + for (int b = 0; b < NB; b++) { + if (b) for (int o = 0; o < FR; o += 64) px_engine_part(&e, nb[cur ^ 1] + o, got + FR * (b - 1) + o, 64, PX_PART_POST); + for (int o = 0; o < FR; o += 64) px_engine_part(&e, sig + FR * b + o, nb[cur] + o, 64, PX_PART_PRE); + for (int o = 0; o < FR; o += 64) px_engine_part(&e, nb[cur] + o, nb[cur] + o, 64, PX_PART_NAM); + cur ^= 1; + } + n++; + if (memcmp(ref, got, sizeof(float) * FR * (NB - 1))) { + bad++; + int i = 0; + while (ref[i] == got[i]) i++; + printf("preset %02d: differs from frame %d (%g against %g)\n", f + 1, i, ref[i], got[i]); + } + } + printf("pipeline: %d NAM presets, %d differ\n", n, bad); + return bad != 0; +} diff --git a/tests/lightsim.c b/tests/lightsim.c new file mode 100644 index 0000000..66a3ff6 --- /dev/null +++ b/tests/lightsim.c @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-3.0-only + * OpenPocket — the button lights in the normal firmware (firmware/px_lights.h over px_leds.h, issue #8) on the PC, + * against fake port C registers and a model of the 74HC595 with its output enable on PC7: + * cc -O1 -Wall -Iengine -Ifirmware -o build/lightsim tests/lightsim.c && build/lightsim + * Checks: after leds_init the lights are enabled (PC7 low) with all of them dark; every one of the twelve blocks, + * alone, lights exactly its button (the FX group's seven lights FX); all on lights the six effect buttons and not + * HOME; HOME blinks at 2 Hz in the tuner and only there; bit 7 is never lit; the byte is written only when it + * changes; lights_off darkens all; only PC5, PC6, PC7 and PC8 are ever touched. */ +#include +#include +#include +#include "px_dsp.h" + +/* the FX button's group, written out again here (ui.h's UI_FXB is the firmware's): drive, SFX, synth, pitch, comp, + * gate, EQ */ +static const uint8_t UI_FXB[7] = { PX_B_DRIVE, PX_B_SFX, PX_B_SYN, PX_B_PITCH, PX_B_COMP, PX_B_GATE, PX_B_EQ }; + +/* ---- port C and the 595: DS PC8, SHCP PC5, STCP PC6, OE PC7 (low = outputs on); a 0 on an output lights it */ +enum { R_OUT = 0, R_DIR = 2, R_PU = 4, R_PD = 5 }; +static uint32_t pc[16], pc_start[16]; +static uint32_t lv_prev; +static uint8_t sr, q; +static unsigned long latches, waits; +static uint32_t pad(void) { uint32_t d = pc[R_DIR]; return (pc[R_OUT] & ~d) | (pc[R_PU] & d); } +static void edge(void) +{ + uint32_t lv = pad(), rise = lv & ~lv_prev; + if (rise & (1u << 5)) sr = (uint8_t)((sr << 1) | ((lv >> 8) & 1u)); + if (rise & (1u << 6)) { q = sr; latches++; } + lv_prev = lv; +} +static int enabled(void) { return !(pc[R_DIR] & (1u << 7)) && !(pad() & (1u << 7)); } +static uint8_t lit(void) { return enabled() ? (uint8_t)~q : 0u; } /* what the eye sees: 1 = lit */ +#define LEDS_PC(r) (pc[(r) / 4u]) +#define LEDS_WAIT() (waits++) +#define LEDS_EDGE() edge() +#include "px_lights.h" + +static int failed; +static void ok(int c, const char *what) { printf("%-66s %s\n", what, c ? "ok" : "FAIL"); if (!c) failed++; } +/* the LED map read on a BlackBox (2026-11-06), written out again here: bit 0 HOME, 1 FX, 2 AMP, 3 MOD, 4 DLY, 5 REV, + * 6 CAB, 7 none */ +enum { W_HOME = 0, W_FX = 1, W_AMP = 2, W_MOD = 3, W_DLY = 4, W_REV = 5, W_CAB = 6 }; +static uint8_t want_of(int b) /* the light a block alone should light */ +{ + for (int i = 0; i < 7; i++) if (UI_FXB[i] == b) return 1u << W_FX; + switch (b) { + case PX_B_AMP: return 1u << W_AMP; + case PX_B_MOD: return 1u << W_MOD; + case PX_B_DELAY: return 1u << W_DLY; + case PX_B_REVERB: return 1u << W_REV; + case PX_B_CAB: return 1u << W_CAB; + } + return 0u; +} +static int only_our_pins(void) +{ + for (int r = 0; r < 16; r++) { + uint32_t may = (r == R_OUT || r == R_DIR) ? 0x1E0u : (r == R_PU || r == R_PD) ? 0x160u : 0u; + if ((pc[r] ^ pc_start[r]) & ~may) return 0; + } + return 1; +} + +int main(void) +{ + static px_preset_t p; + memset(pc, 0, sizeof pc); + pc[R_OUT] = 0x5A5Au | 0x80u; pc[R_DIR] = 0xFFFFu & ~0x80u; /* PC7 an output, high, as lcd_init left it */ + pc[R_PU] = 0xFFFFu; + memcpy(pc_start, pc, sizeof pc); + lv_prev = pad(); sr = 0x5Au; q = 0x00u; /* a 595 holds garbage at power-on */ + + leds_init(); + ok(enabled() && lit() == 0u, "after leds_init: the lights enabled, all dark"); + + memset(&p, 0, sizeof p); + lights_update(&p, 0, 0); + ok(lit() == 0u && latches == 1u, "no block on: all dark, nothing written again"); + { + int good = 1, every = 1; + for (int b = 0; b < PX_NBLK; b++) { + memset(&p, 0, sizeof p); p.on[b] = 1; + lights_update(&p, 0, 0); + if (lit() != want_of(b)) { printf(" block %d lit %02X, wanted %02X\n", b, lit(), want_of(b)); good = 0; } + if (!want_of(b)) every = 0; + } + ok(good, "each block alone lights its own button"); + ok(every, "every block has a light (the FX group's seven: FX)"); + } + memset(&p, 0, sizeof p); + for (int b = 0; b < PX_NBLK; b++) p.on[b] = 1; + lights_update(&p, 0, 0); + ok(lit() == 0x7Eu, "all on: FX AMP MOD DLY REV CAB lit, HOME dark"); + { + unsigned long l0 = latches; + for (uint32_t t = 0; t < 2000u; t++) lights_update(&p, 0, t); + ok(latches == l0, "nothing changes: nothing written"); + } + { + int flips = 0, others = 1; uint8_t last = lit(); + for (uint32_t t = 0; t < 2000u; t++) { + lights_update(&p, 1, t); + if ((lit() ^ last) & (1u << W_HOME)) flips++; + if ((lit() & 0x7Eu) != 0x7Eu) others = 0; + last = lit(); + } + ok(flips >= 7 && flips <= 9, "tuner: HOME blinks at 2 Hz"); + ok(others, "tuner: the effect lights stay as they are"); + lights_update(&p, 0, 0); + ok(!(lit() & (1u << W_HOME)), "tuner closed: HOME dark"); + } + ok(!(lit() & 0x80u) && (q & 0x80u), "bit 7 never lit"); + lights_off(); + ok(lit() == 0u && enabled(), "lights_off: all dark"); + ok(only_our_pins(), "only PC5, PC6, PC7 and PC8 touched"); + ok(waits > 0u, "the 595 timing waits are used"); + printf("\n%s\n", failed ? "lights tests FAILED" : "all lights tests passed"); + return failed ? 1 : 0; +} diff --git a/tests/lpsim.c b/tests/lpsim.c new file mode 100644 index 0000000..204f39c --- /dev/null +++ b/tests/lpsim.c @@ -0,0 +1,310 @@ +/* SPDX-License-Identifier: GPL-3.0-only + * OpenPocket — the LED map (firmware/led_probe.h) and the lights' driver (px_leds.h, issue #8) on the PC, against + * fake GPIO registers and a model of the 74HC595 with its output enable on PC7: + * cc -O1 -Wall -Wno-unused-function -Ifirmware -o build/lpsim tests/lpsim.c && build/lpsim build/lp + * Checks: the driver alone (leds_init from pins with pulls, PC7 an input: PC5/6/8 outputs without pulls, the all-off byte FF + * latched while PC7 is high, then PC7 low; leds_write puts each byte on the outputs, MSB first). The LED map: only + * PC5, PC6, PC8 and PC7 are ever changed (every other register bit of PA, PB, PC and PH as at start); PC7 ends an + * output, low; every shift clock edge and the latch's rise have a wait before them, DS is an output and the latch is + * low while shifting; the byte on the outputs is always the one the screen names, blinking at 2 Hz between the bits + * on screen and 0, lit right after a turn; the knob wraps both ways over the 9 positions; each button writes itself + * into the table, again clears it, another replaces it, nothing is written on ALL 8 BITS; the analog keys (CAB, DLY, + * REV) are read every 10 ms; USB is serviced; the boot is not counted as failed; every line of text fits its box. + * Writes PPM screenshots to OUTDIR. */ +#include +#include +#include + +enum { RED = 0xF800, GRN = 0x07E0, BLU = 0x001F, WHT = 0xFFFF, BLK = 0x0000, CYN = 0x07FF, YEL = 0xFFE0, ORG = 0xFD20 }; +enum { UI_BG = 0x0841, UI_PANEL = 0x18E3, UI_SEL = 0xFB00, UI_ACC = 0xFD20, UI_TXT = 0xEF7D, UI_DIM = 0x8410, UI_OK = 0x4E6B, UI_OFF = 0x2124 }; + +/* ---- screen: as tests/uisim.c */ +static uint16_t fb[240 * 240]; +static uint32_t wx, wy, ww, wi; +static void lcd_win(uint32_t x, uint32_t y, uint32_t w, uint32_t h) { (void)h; wx = x; wy = y; ww = w; wi = 0; } +static void lcd_px(uint16_t c) +{ + uint32_t x = wx + wi % ww, y = wy + wi / ww; + if (x < 240u && y < 240u) fb[y * 240u + x] = c; + wi++; +} +static void lcd_end(void) { } +static void lcd_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t c) +{ + if (w == 0u || h == 0u || x >= 240u || y >= 240u) return; + if (x + w > 240u) w = 240u - x; + if (y + h > 240u) h = 240u - y; + for (uint32_t j = 0; j < h; j++) for (uint32_t i = 0; i < w; i++) fb[(y + j) * 240u + x + i] = c; +} +static void fm1_wdt_feed(void) { } + +/* ---- the pedal around the LED map: gpio[port p (0 A, 1 B, 2 C, 7 H)][register r / 4] */ +enum { R_OUT = 0, R_DIR = 2, R_PU = 4, R_PD = 5 }; /* register index: OUT +0, DIR +8, PU +0x10, PD +0x14 */ +static uint32_t gpio[8][16]; +static uint32_t pa_in, ph_in, pc_in; /* the buttons as pressed, the knob */ +static uint32_t sim_pa_in(void) /* as the pad reads: an output pin reads back its own level */ +{ + uint32_t dir = gpio[0][R_DIR]; + return (pa_in & dir) | (gpio[0][R_OUT] & ~dir); +} +#define PA_IN sim_pa_in() +#define PH_IN ph_in +#define PC_IN pc_in +#define ENC_MASK 0x3u +#define PA_FX (1u << 0) /* as openpocket.c */ +#define PA_HOME (1u << 1) +#define PA_FS_UP (1u << 2) +#define PA_FS_DN (1u << 3) +#define PH_PUSH ((1u << 4) | (1u << 6)) +#define PH_MOD ((1u << 7) | (1u << 8)) +#define PH_AMP (1u << 9) +static uint32_t base_pa, base_ph; +enum { KEY_NONE = 0, KEY_CAB, KEY_DLY, KEY_REV }; +#define ADC_CH_KEYS 9u +static int sim_key; /* the analog key held down */ +static unsigned long adc_calls; +static int32_t adc_read2(uint32_t ch) { if (ch == ADC_CH_KEYS) adc_calls++; return sim_key; } +static int keys_decode(int32_t v) { return (int)v; } +static const int8_t QDEC[16] = {0,-1,1,0, 1,0,0,-1, -1,0,0,1, 0,1,-1,0}; +typedef struct { uint8_t stab, last, cnt; } dbn_t; +static int dbn_press(dbn_t *d, int raw) /* as openpocket.c */ +{ + if (raw == d->last) { if (d->cnt < 5u) d->cnt++; } + else { d->cnt = 0; d->last = (uint8_t)raw; } + if (d->cnt >= 3u && raw != d->stab) { d->stab = (uint8_t)raw; return raw; } + return 0; +} +static uint32_t sim_ms; +static uint32_t ms_now(void) { return sim_ms; } +static unsigned long usb_calls; +static void px_usb_service(uint32_t now) { (void)now; usb_calls++; } +static struct { uint32_t magic, pending, failed; } guard; +enum { ST_OK = 8 }; +static struct { uint32_t stage; } op_diag; +static void b_num(char *d, uint32_t v) +{ + char t[10]; int n = 0; + while (*d) d++; + do { t[n++] = (char)('0' + v % 10u); v /= 10u; } while (v && n < 9); + while (n) *d++ = t[--n]; + *d = 0; +} +static void b_str(char *d, const char *s) { while (*d) d++; while (*s) *d++ = *s++; *d = 0; } + +/* ---- the 74HC595, from its data sheet: DS is shifted in on SHCP's rising edge (the first bit in ends at Q7), the + * outputs take the shift register on STCP's rising edge. A pin's level: its OUT bit when an output, else its pull. */ +#define M_DS (1u << 8) +#define M_SH (1u << 5) +#define M_ST (1u << 6) +#define M_EN (1u << 7) +static uint32_t lv_prev; +static uint8_t sr, q; +static unsigned long waits, w_sh, latches; +static int e_wait, e_latch, e_dir; +static uint32_t pc_level(void) { uint32_t d = gpio[2][R_DIR]; return (gpio[2][R_OUT] & ~d) | (gpio[2][R_PU] & d); } +static void sim_wait(void) { waits++; } +static int en_falls, en_rises; /* PC7, the output enable (low = on): its edges */ +static uint8_t q_at_enable = 0x5Au; /* the outputs' byte when PC7 went low */ +static unsigned long latches_at_enable; +static void sim_edge(void) +{ + uint32_t lv = pc_level(), rise = lv & ~lv_prev, fall = ~lv & lv_prev; + if (fall & M_EN) { en_falls++; q_at_enable = q; latches_at_enable = latches; } + if (rise & M_EN) en_rises++; + if (rise & M_SH) { + if (waits == w_sh) e_wait++; /* no wait while SHCP was low (or since the start) */ + if (lv & M_ST) e_latch++; /* shifting with the latch high: the outputs would ripple */ + if (gpio[2][R_DIR] & M_DS) e_dir++; /* DS not driven */ + sr = (uint8_t)((sr << 1) | ((lv & M_DS) ? 1u : 0u)); + w_sh = waits; + } + if (fall & M_SH) { if (waits == w_sh) e_wait++; w_sh = waits; } /* no wait while SHCP was high */ + if (rise & M_ST) { if (waits == w_sh) e_wait++; q = sr; latches++; } /* a wait after the last shift too */ + lv_prev = lv; +} +#define LEDS_PC(r) (gpio[2][(r) / 4u]) +#define LEDS_WAIT() sim_wait() +#define LEDS_EDGE() sim_edge() + +static int failed, clipped; +#define LP_TEXT_HOOK(s, f, w) do { \ + if (ft_width((f), (s)) > (w) || strlen(s) > 40u) { printf("text too wide: \"%s\"\n", (s)); clipped++; } \ + } while (0) +#include "ui_text.h" +#include "led_probe.h" + +/* ---- the checks */ +static const int PORTS[4] = { 0, 1, 2, 7 }; +static uint32_t snap[8][16]; +static int want, want2 = -1; /* the position the test expects (0 all, 1..8 bit want - 1); mid-turn either */ +static void ok(int c, const char *what) { if (!c) { printf("FAIL: %s\n", what); failed++; } } +static void reset_gpio(void) /* a distinctive start; PC5, PC6, PC8 inputs with pull-ups, as booted */ +{ + memset(gpio, 0, sizeof gpio); + for (int k = 0; k < 4; k++) { + int p = PORTS[k]; + gpio[p][R_OUT] = 0x5A5Au ^ (uint32_t)(k * 0x1111); + gpio[p][R_DIR] = 0xFFFFu & ~(0x0101u << k); + gpio[p][R_PD] = 0x3030u >> k; + gpio[p][R_PU] = 0xFFFFu & ~gpio[p][R_PD]; + } + gpio[1][R_DIR] &= ~0x00E2u; /* the screen pins PB1/5/6/7 and PC7: outputs, PC7 high */ + gpio[2][R_DIR] &= ~(1u << 7); gpio[2][R_OUT] |= 1u << 7; + gpio[2][R_DIR] |= M_DS | M_SH | M_ST; gpio[2][R_PU] |= M_DS | M_SH | M_ST; gpio[2][R_PD] &= ~(M_DS | M_SH | M_ST); + gpio[0][R_DIR] |= 0x000Fu; /* the buttons are inputs, as input_init leaves them */ + gpio[7][R_DIR] |= PH_PUSH | PH_MOD | PH_AMP; + memcpy(snap, gpio, sizeof snap); + pa_in = ph_in = pc_in = 0; sim_key = KEY_NONE; + base_pa = sim_pa_in() & 0xFFFFu; base_ph = ph_in; /* as input_baseline */ + lv_prev = pc_level(); + sr = 0x5Au; q = 0xA5u; /* a 595 holds garbage at power-on */ +} +static int only_595_pins(void) /* every register bit as at start, but PC5/6/8's OUT, DIR, PU, PD, PC7's OUT, DIR */ +{ + for (int k = 0; k < 4; k++) + for (int r = 0; r < 16; r++) { + uint32_t may = (PORTS[k] == 2 && (r == R_OUT || r == R_DIR || r == R_PU || r == R_PD)) ? (M_DS | M_SH | M_ST) : 0u; + if (PORTS[k] == 2 && (r == R_OUT || r == R_DIR)) may |= M_EN; /* PC7: the lights' enable */ + if ((gpio[PORTS[k]][r] ^ snap[PORTS[k]][r]) & ~may) return 0; + } + return 1; +} +static uint8_t mask_of(int pos) { return pos ? (uint8_t)(1u << (pos - 1)) : 0xFFu; } +static void run(uint32_t ms) /* the loop for ms milliseconds, checking every pass */ +{ + for (uint32_t t = 0; t < ms; t++) { + sim_ms++; + lp_step(ms_now()); + if (!only_595_pins()) { ok(0, "a pin other than PC5 / PC6 / PC8 was changed"); return; } + if (q != 0u && q != mask_of(want) && !(want2 >= 0 && q == mask_of(want2))) { + ok(0, "the 595 shows a byte other than the bits on screen"); return; + } + } +} +static void turn(int dir) /* one detent: 0 1 3 2 0 is one step forward (the main loop's sign) */ +{ + static const uint8_t FWD[4] = { 1, 3, 2, 0 }, BACK[4] = { 2, 3, 1, 0 }; + want2 = dir > 0 ? (want + 1) % 9 : (want + 8) % 9; + for (int k = 0; k < 4; k++) { pc_in = (pc_in & ~3u) | (dir > 0 ? FWD[k] : BACK[k]); run(2); } + want = want2; want2 = -1; + ok(lp.pos == (uint32_t)want, "the knob moves one position per detent"); + ok(q == mask_of(want), "lit right after a turn"); +} +static void go(int pos) { for (int k = 0; k < 9 && want != pos; k++) turn(+1); } +static void press_pa(uint32_t m) { pa_in ^= m; run(20); pa_in ^= m; run(20); } +static void press_ph(uint32_t m) { ph_in ^= m; run(20); ph_in ^= m; run(20); } +static void press_key(int k) { sim_key = k; run(60); sim_key = KEY_NONE; run(60); } +static int map(int bit) { return lp.map[bit] ? lp.map[bit] - 1 : -1; } +static void shot(const char *dir, const char *name) +{ + static int n; + char path[512]; + snprintf(path, sizeof path, "%s/%02d_%s.ppm", dir, n++, name); + FILE *f = fopen(path, "wb"); + if (!f) { printf("cannot write %s\n", path); failed++; return; } + fprintf(f, "P6\n240 240\n255\n"); + for (int i = 0; i < 240 * 240; i++) { + uint16_t c = fb[i]; + uint8_t rgb[3] = { (uint8_t)(((c >> 11) & 31u) * 255u / 31u), (uint8_t)(((c >> 5) & 63u) * 255u / 63u), + (uint8_t)((c & 31u) * 255u / 31u) }; + fwrite(rgb, 1, 3, f); + } + fclose(f); +} + +int main(int argc, char **argv) +{ + const char *dir = argc > 1 ? argv[1] : "build/lp"; + + /* the driver alone (px_leds.h): from inputs with pulls (PC8's a pull-down), then bytes MSB first */ + reset_gpio(); + gpio[2][R_PU] &= ~M_DS; gpio[2][R_PD] |= M_DS; + gpio[2][R_DIR] |= M_EN; gpio[2][R_PU] |= M_EN; /* PC7 untouched here: an input with its pull-up */ + memcpy(snap, gpio, sizeof snap); + lv_prev = pc_level(); + leds_init(); + ok(q == 0xFFu && leds_byte == 0xFFu && latches == 1u, "leds_init: the all-off byte FF shifted out"); + ok(!(gpio[2][R_DIR] & (M_DS | M_SH | M_ST)) && !(gpio[2][R_PU] & (M_DS | M_SH | M_ST)) && + !(gpio[2][R_PD] & (M_DS | M_SH | M_ST)), "leds_init: PC5, PC6, PC8 outputs, no pulls"); + ok(en_falls == 1 && q_at_enable == 0xFFu && latches_at_enable == 1u && !(gpio[2][R_OUT] & M_EN) && + !(gpio[2][R_DIR] & M_EN), "leds_init: PC7 an output, low, once the byte is latched"); + { + static const uint8_t V[5] = { 0xA5u, 0x01u, 0x80u, 0x3Cu, 0x00u }; + int good = 1; + for (int i = 0; i < 5; i++) { leds_write(V[i]); if (q != V[i] || leds_byte != V[i]) good = 0; } + ok(good, "leds_write: each byte on the outputs, MSB first"); + } + ok(only_595_pins(), "the driver touches only PC5, PC6, PC8 and PC7"); + latches = 0; en_falls = en_rises = 0; latches_at_enable = 0; q_at_enable = 0x5Au; + + /* the LED map */ + reset_gpio(); + guard.pending = 1; guard.failed = 1; op_diag.stage = 3; + lp_init(); + ok(guard.pending == 0u && guard.failed == 0u && op_diag.stage == ST_OK, "not counted as a failed boot"); + ok(!(gpio[2][R_DIR] & (M_DS | M_SH | M_ST)), "PC5, PC6, PC8 are outputs"); + ok(!(gpio[2][R_PU] & (M_DS | M_SH | M_ST)) && !(gpio[2][R_PD] & (M_DS | M_SH | M_ST)), "without pulls"); + ok(latches == 2u && q == 0xFFu, "the all-off byte FF at start (as stock), then ALL 8 BITS lit"); + ok(en_falls == 1 && en_rises == 0 && q_at_enable == 0xFFu && latches_at_enable == 1u, + "the lights on (PC7 low) once, after the all-off byte is latched"); + ok(!(gpio[2][R_DIR] & M_EN) && !(gpio[2][R_OUT] & M_EN), "PC7 an output, low"); + ok(only_595_pins(), "nothing else touched by the start"); + run(5); + ok(usb_calls > 0u, "USB serviced"); + shot(dir, "all_bits"); + + { /* 2 Hz: 8 changes in 2 s, always the bits on screen or 0 */ + int flips = 0; uint8_t last = q; + for (int t = 0; t < 2000; t++) { run(1); if (q != last) { flips++; last = q; } } + ok(flips >= 7 && flips <= 9, "2 Hz: 8 changes in 2 s"); + } + { /* each bit alone, MSB first (an LSB-first driver would light bit 7 - n) */ + for (int b = 0; b < 8; b++) { turn(+1); run(300); } + ok(want == 8, "at BIT 7"); + turn(+1); + ok(lp.pos == 0u, "past BIT 7: ALL 8 BITS"); + turn(-1); + ok(lp.pos == 8u && q == 0x80u, "back from ALL: BIT 7"); + turn(+1); + } + { /* the table: every button, again clears, another replaces, none on ALL */ + unsigned long a0 = adc_calls; uint32_t t0 = sim_ms; + press_key(KEY_DLY); + ok(memcmp(lp.map, "\0\0\0\0\0\0\0\0", 8) == 0, "nothing written on ALL 8 BITS"); + unsigned long n = adc_calls - a0, t = (sim_ms - t0) / 10u; + ok(n + 1u >= t && n <= t + 1u, "the keys every 10 ms"); + go(1); + shot(dir, "bit0"); + press_pa(PA_FX); + ok(map(0) == LB_FX, "FX on BIT 0"); + shot(dir, "bit0_fx"); + press_pa(PA_FX); + ok(map(0) < 0, "FX again clears it"); + press_pa(PA_FX); + go(2); press_pa(PA_FS_UP); + ok(map(1) == LB_FSR, "right footswitch on BIT 1"); + go(3); press_pa(PA_FS_DN); + ok(map(2) == LB_FSL, "left footswitch on BIT 2"); + go(4); press_ph(PH_AMP); + ok(map(3) == LB_AMP, "AMP on BIT 3"); + go(5); press_key(KEY_CAB); + ok(map(4) == LB_CAB, "CAB (analog) on BIT 4"); + go(6); press_ph(1u << 6); + ok(map(5) == LB_PUSH, "PUSH (PH6 alone) on BIT 5"); + go(7); press_key(KEY_REV); press_pa(PA_HOME); + ok(map(6) == LB_HOME, "HOME replaces REV on BIT 6"); + go(8); press_ph(1u << 8); + ok(map(7) == LB_MOD, "MOD (PH8 alone) on BIT 7"); + ok(map(0) == LB_FX && map(3) == LB_AMP, "the table keeps the others"); + shot(dir, "map"); + go(0); + press_pa(PA_FX); + ok(map(0) == LB_FX, "a press on ALL changes nothing"); + } + ok(e_wait == 0, "a wait on each side of every shift clock edge"); + ok(e_latch == 0, "the latch is low while shifting"); + ok(e_dir == 0, "DS is driven while shifting"); + ok(clipped == 0, "every line fits its box"); + printf("LED map: %s (%d failures, %lu latches, %lu USB passes)\n", failed ? "FAIL" : "ok", failed, latches, usb_calls); + return failed ? 1 : 0; +} diff --git a/tests/run_tests.sh b/tests/run_tests.sh index ff82108..1d75fd4 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -3,7 +3,11 @@ # tests/run_tests.sh [PocketX_016.fwsc] # - engine: every block x model x extreme knob, signal / silence / overload, with the pedal's own libm (px_math.c): # no NaN; long runs (3 s pluck + 8 s silence): nothing runs away (only delays at FDBK 100 hold on, by design) +# - the two-core pipeline (PRE / NAM / POST stages) gives the plain engine's output one block later +# - NAM: engine/px_nam.c against tools/nam_a2.py with every factory model (needs numpy) # - preset store: save / reload / power cut at every step of a save (firmware/px_store.h on a simulated flash) +# - LED map + lights driver (led_probe.h, px_leds.h): PC7 enable after the first byte, the 595 timing, the table +# - button lights (px_lights.h): each block lights its button, FX for its group, HOME blinks in the tuner # - packages: tools/pxpkg.py rebuilds the official PocketX_016 app area byte for byte (needs the official file) # - installer: docs/pxota.js + docs/pxpkg.js against a simulated pedal running the real update code (ota.c, ldr_core.c) # - page: docs/index.html in headless Chromium (needs Playwright: npm i playwright && npx playwright install chromium) @@ -14,10 +18,19 @@ CC="${CC:-cc}" echo "== engine" $CC -O2 -Iengine tests/engine/sweep2.c engine/px_dsp.c firmware/px_math.c -lm -o build/sweep && build/sweep | tail -1 $CC -O2 -Iengine tests/engine/long.c engine/px_dsp.c firmware/px_math.c -lm -o build/long && build/long | tail -1 +$CC -O2 -Iengine tests/engine/pipe_test.c engine/px_dsp.c firmware/px_math.c -lm -o build/pipe_test && build/pipe_test | tail -1 +echo "== NAM (fixed point against the float reference, every factory model)" +$CC -O2 -DPXN_EMUVEC -Iengine tests/engine/nam_test.c engine/px_nam.c -o build/nam_test +if python3 -c "import numpy" 2>/dev/null; then mkdir -p build/nam; python3 tests/test_nam.py build/nam_test > build/nam/log.txt || { cat build/nam/log.txt; exit 1; }; tail -1 build/nam/log.txt; else echo "(numpy not installed: NAM comparison skipped)"; fi echo "== preset store" $CC -O1 -Iengine tests/test_store.c engine/px_dsp.c firmware/px_math.c -lm -o build/test_store && build/test_store | tail -2 echo "== screen (every page fully drawn)" mkdir -p build/ui && $CC -O1 -Wall -Wno-unused-function -Iengine -Ifirmware -o build/uisim tests/uisim.c engine/px_dsp.c firmware/px_math.c -lm && build/uisim build/ui > build/ui/log.txt && if grep -q "never drawn" build/ui/log.txt; then grep "never drawn" build/ui/log.txt; echo "screen: FAIL"; else echo "screen: $(wc -l < build/ui/log.txt) pages ok (build/ui/*.ppm)"; fi +echo "== LED map and the lights driver (LED_PROBE build, issue #8)" +mkdir -p build/lp && $CC -O1 -Wall -Wno-unused-function -Ifirmware -o build/lpsim tests/lpsim.c && build/lpsim build/lp +echo "== button lights in the normal firmware (px_lights.h, issue #8)" +$CC -O1 -Wall -Wno-unused-function -Iengine -Ifirmware -o build/lightsim tests/lightsim.c +build/lightsim > build/lightsim.log || { cat build/lightsim.log; exit 1; }; tail -1 build/lightsim.log echo "== simulated pedal" $CC -O1 -Wall -Wno-unused-function -o build/devsim tests/devsim.c if [ -n "$1" ]; then echo "== packages"; python3 tests/test_pxpkg.py "$1"; fi diff --git a/tests/test_editor.mjs b/tests/test_editor.mjs index 1673cdb..34be0fa 100644 --- a/tests/test_editor.mjs +++ b/tests/test_editor.mjs @@ -8,6 +8,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; import { Editor, presetToJSON, presetFromJSON, filePresets, parsePresetFile, clonePreset } from "../docs/pxedit.js"; +import { parseNam, levelTrim, packModel, readDi, a2Run, KERNELS, DILATIONS, NW } from "../docs/pxnam.js"; const ROOT = fileURLToPath(new URL("..", import.meta.url)); const SIM = process.env.EDSIM || join(ROOT, "build", "edsim"); @@ -54,12 +55,12 @@ let s = sim(["--dump", flash1]); await s.ready; let ed = new Editor(s.access); const info = await ed.connect(); -ok(info && info.proto === 1 && info.version === "v36" && info.identity === "PocketX_936", `INFO: ${info && `${info.version} ${info.identity}`}`); +ok(info && info.proto === 2 && info.version === "v37" && info.identity === "PocketX_937", `INFO: ${info && `${info.version} ${info.identity}`}`); ok(info && info.nblk === 12 && info.npar === 5 && info.nslot === 52 && info.nameMax === 13, "INFO: 12 blocks, 5 parameters, 52 slots, names of 13"); const t0 = Date.now(); const cat = await ed.catalog(); const ntypes = cat.blocks.reduce((n, b) => n + b.types.length, 0); -ok(cat.blocks.length === 12 && cat.blocks[5].label === "AMP" && cat.blocks[5].types.length === 8, `catalogue: 12 blocks, ${ntypes} types (${Date.now() - t0} ms)`); +ok(cat.blocks.length === 12 && cat.blocks[5].label === "AMP" && cat.blocks[5].types.length === 9 && cat.blocks[5].types[8].name === "NAM", `catalogue: 12 blocks, ${ntypes} types (${Date.now() - t0} ms)`); ok(cat.blocks[11].label === "SYN" && cat.blocks[11].color === "#ff1494", `catalogue: the SYN block and its tile colour (${cat.blocks[11].color})`); const withTexts = cat.blocks.flatMap((b) => b.types.flatMap((t) => t.params.filter((p) => p.texts))).length; ok(withTexts > 0 && cat.blocks[9].types[0].params.some((p) => p.texts && p.texts.some((x) => /ms|\d/.test(x))), `catalogue: value texts for ${withTexts} parameters (delay time...)`); @@ -72,7 +73,7 @@ const v1 = await ed.setParam(amp, 0, 77); st = await ed.state(); ok(v1 === 77 && st.preset.p[amp][0] === 77 && st.dirty, "SET: AMP's 1st knob = 77, the sound is now changed (*)"); ok(await ed.setParam(amp, 1, 120) === 100, "SET: a value above 100 is clamped to 100"); -ok(await ed.setType(amp, 99) === 7, "SET: a type out of range is clamped to the last one"); +ok(await ed.setType(amp, 99) === 8, "SET: a type out of range is clamped to the last one (NAM)"); await ed.setOn(9, 1); ok((await ed.state()).preset.on[9] === 1, "SET: the delay switched on"); ok(await ed.name("my toneé longer than thirteen") === "my tone? long", "NAME: 13 characters at most, other characters become ?"); @@ -143,6 +144,45 @@ await s.ready; ed = new Editor(s.access); await ed.connect(); list = await ed.list(); + +// ---- 7. v37: NAM models (an A2 file -> a user slot -> the AMP block's NAM type) ---- +{ + let seed = 7; + const rnd = () => { seed = (seed * 1103515245 + 12345) >>> 0; return seed / 4294967296 - 0.5; }; + const w = Array.from({ length: NW }, () => rnd() * 0.6); + w[NW - 1] = 0.02; // head_scale + const layer = { input_size: 1, condition_size: 1, head: { out_channels: 1, kernel_size: 16, bias: true }, channels: 3, + kernel_sizes: KERNELS, dilations: DILATIONS, activation: KERNELS.map(() => ({ type: "LeakyReLU", negative_slope: 0.01 })), + bottleneck: 3, head1x1: { active: false }, layer1x1: { active: true }, gating_mode: KERNELS.map(() => "none") }; + const a2 = { version: "0.7.0", architecture: "WaveNet", config: { layers: [layer], head: null, head_scale: 0.02 }, weights: w, sample_rate: 48000 }; + const file = JSON.stringify({ architecture: "SlimmableContainer", config: { submodels: [{ max_value: 0.5, model: a2 }] } }); + let m = null, why = ""; + try { m = parseNam(file, "My Test Amp.nam"); } catch (e) { why = e.message; } + ok(m && m.name === "MY TEST AMP" && m.weights.length === NW && /semitones/.test(m.note), `NAM: an A2 file's A2-Lite part is read (${m ? m.name : why})`); + let a1why = ""; + try { parseNam(JSON.stringify({ architecture: "WaveNet", config: { layers: [{ channels: 16 }] }, weights: [1] }), "a1.nam"); } catch (e) { a1why = e.message; } + ok(/not an A2 model/.test(a1why), "NAM: an A1 capture is refused, with the reason"); + const di = readDi(readFileSync(join(ROOT, "docs", "nam_di.wav")).buffer); + const lv = levelTrim(m.weights, di); + ok(Number.isFinite(lv) && Math.abs(lv) <= 24, `NAM: level measured on the DI clip (${lv.toFixed(2)} dB)`); + let nl = await ed.namList(); + ok(nl.nfact === 12 && nl.nuser === 16 && nl.models.filter((x) => !x.user && x.used).length === 12 && nl.models.every((x) => !x.user || !x.used), + "NAM_LIST: 12 factory models, 16 empty user slots"); + const rc = await ed.namUpload(4, packModel(m.name, m.weights, lv)); + nl = await ed.namList(); + ok(rc === 0 && nl.models[12 + 4].used && nl.models[12 + 4].name === "MY TEST AMP", "NAM: the model is written into user slot 5"); + await ed.catalog(); + const nt = cat.blocks[amp].types.findIndex((t) => t.name === "NAM"); + await ed.namTexts(); + const texts = ed.cat.blocks[amp].types[nt].params[0].texts; + const kv = texts.indexOf("MY TEST "); + ok(nt === 8 && kv >= 0, `NAM: the AMP block's NAM type offers it as a MODEL (knob ${kv})`); + await ed.setType(amp, nt); + ok(await ed.setParam(amp, 0, kv) === kv && (await ed.state()).preset.type[amp] === nt, "NAM: a sound uses it"); + const bad = packModel(m.name, m.weights, lv); bad[64 + 100] ^= 0x55; // a weight changed: the CRC no longer matches + ok(await ed.namUpload(5, bad) === 1 && !(await ed.namList()).models[12 + 5].used, "NAM: a damaged model is refused, the slot stays empty"); + ok(await ed.namErase(4) === 0 && !(await ed.namList()).models[12 + 4].used, "NAM: the slot is cleared again"); +} ok(list[20].name === "STAGED A" && list[21].name === "STAGED B" && list[20].saved && !list[4].saved, "power cycle: the saved slots are still there"); st = await ed.state(); ok(st.slot === 4, "power cycle: the pedal starts on the last slot SAVEd (imports do not move it)"); diff --git a/tests/test_editor_page.mjs b/tests/test_editor_page.mjs index a2323f0..bf50d2e 100644 --- a/tests/test_editor_page.mjs +++ b/tests/test_editor_page.mjs @@ -80,7 +80,7 @@ startSim(["--dump", join(TMP, "flash.bin")]); await sleep(200); await page.click("#connect"); await page.waitForSelector("#ui:not([hidden])", { timeout: 20000 }); -ok(/PocketX · OpenPocket v36/.test(await page.textContent("#status")), `status: ${await page.textContent("#status")}`); +ok(/PocketX · OpenPocket v37/.test(await page.textContent("#status")), `status: ${await page.textContent("#status")}`); ok(await page.locator("#list .row").count() === 52, "52 presets listed"); ok(await page.inputValue("#name") === "TWIN CLEAN" && await page.textContent("#num") === "01", "header: 01 TWIN CLEAN"); ok(await page.locator("#tiles .tile").count() === 12, "12 tiles"); @@ -212,6 +212,77 @@ ok((await pedalState()).slot === 8, "Cancel: still on the same slot"); ok((await pedalState()).writesOk, "the flash was written only inside the preset store"); await shot("editor_5_imported.png"); +// ---- v37: a NAM A2 capture into a user slot ---- +{ + const KS = [6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 15, 15, 6, 6, 6, 6, 6, 6, 6]; + const DS = [1, 3, 7, 17, 41, 101, 239, 1, 3, 7, 17, 41, 101, 239, 1, 13, 1, 3, 7, 17, 41, 101, 239]; + let seed = 3; const rnd = () => { seed = (seed * 1103515245 + 12345) >>> 0; return seed / 4294967296 - 0.5; }; + const w = Array.from({ length: 1871 }, () => rnd() * 0.6); w[1870] = 0.02; + const nam = { version: "0.7.0", architecture: "WaveNet", sample_rate: 44100, weights: w, config: { head: null, head_scale: 0.02, layers: [{ + input_size: 1, condition_size: 1, head: { out_channels: 1, kernel_size: 16, bias: true }, channels: 3, bottleneck: 3, + kernel_sizes: KS, dilations: DS, activation: KS.map(() => ({ type: "LeakyReLU", negative_slope: 0.01 })), + head1x1: { active: false }, layer1x1: { active: true }, gating_mode: KS.map(() => "none") }] } }; + const fn = join(TMP, "Page Amp.nam"); + writeFileSync(fn, JSON.stringify(nam)); + ok(await page.locator("#namlist .row").count() === 28, "NAM models: 12 factory + 16 user slots listed"); + const [chooser] = await Promise.all([page.waitForEvent("filechooser"), page.locator("#namlist .row").nth(12).locator("button").first().click()]); + await chooser.setFiles(fn); + await page.waitForFunction(() => /is in user slot 1/.test(document.getElementById("msg").textContent), null, { timeout: 20000 }); + ok((await page.locator("#namlist .row").nth(12).textContent()).includes("PAGE AMP"), "NAM: an A2 file loaded into user slot 1 from the page"); + ok((await pedalState()).writesOk, "the flash was written only inside the preset store and the model slots"); + await shot("editor_6_nam.png"); +} + +// ---- v37: TONE3000's Select flow (their site simulated: sign-in pop-up, PKCE, tone, A2 models, download) ---- +{ + const { createHash } = await import("node:crypto"); + const namText = readFileSync(join(TMP, "Page Amp.nam"), "utf8").replace('"version"', '"metadata":{"name":""},"version"'); + const T3K = "https://www.tone3000.com"; + let challenge = "", authOk = false, tokenOk = false, bearerOk = true; + const cors = { "access-control-allow-origin": "*", "access-control-allow-headers": "authorization, content-type", + "access-control-allow-methods": "GET, POST, OPTIONS" }; + const json = (route, o) => route.fulfill({ status: 200, headers: { ...cors, "content-type": "application/json" }, body: JSON.stringify(o) }); + await ctx.route(`${T3K}/**`, async (route) => { + const r = route.request(), u = new URL(r.url()); + if (r.method() === "OPTIONS") return route.fulfill({ status: 204, headers: cors }); + if (u.pathname === "/api/v1/oauth/authorize") { + const q = u.searchParams; + challenge = q.get("code_challenge"); + authOk = q.get("client_id") === "page-test" && q.get("prompt") === "select_tone" && q.get("architecture") === "2" && + q.get("format") === "nam" && q.get("code_challenge_method") === "S256" && /\/t3k\.html$/.test(q.get("redirect_uri")); + return route.fulfill({ status: 302, headers: { location: `${q.get("redirect_uri")}?code=C0DE&state=${q.get("state")}&tone_id=42` } }); + } + if (u.pathname === "/api/v1/oauth/token") { + const f = new URLSearchParams(r.postData() || ""); + const v = createHash("sha256").update(f.get("code_verifier") || "").digest("base64url"); + tokenOk = f.get("grant_type") === "authorization_code" && f.get("code") === "C0DE" && v === challenge; + return json(route, tokenOk ? { access_token: "AT", refresh_token: "RT", token_type: "bearer", expires_in: 3600 } : { error: "invalid_grant" }); + } + if (r.headers()["authorization"] !== "Bearer AT") bearerOk = false; + if (u.pathname === "/api/v1/tones/42") + return json(route, { id: 42, title: "Plexi Lead", gear: "amp", format: "nam", images: null, url: `${T3K}/tones/plexi-42`, + user: { username: "capturer", display_name: null, avatar_url: null, url: `${T3K}/capturer` } }); + if (u.pathname === "/api/v1/models") + return json(route, { data: [{ id: 7, name: "Plexi Lead A2", size: "standard", architecture_version: "2", + model_url: `${T3K}/files/plexi.nam`, tone_id: 42 }], page: 1, page_size: 100, total: 1, total_pages: 1 }); + if (u.pathname === "/files/plexi.nam") return route.fulfill({ status: 200, headers: cors, body: namText }); + return route.fulfill({ status: 404, headers: cors }); + }); + await page.evaluate(() => { window.__t3kClientId = "page-test"; }); + ok(await page.isVisible("#t3kbrowse"), "TONE3000: its Browse button in the NAM panel"); + await page.click("#t3kbrowse"); + await page.waitForSelector("#t3kcard:not([hidden])", { timeout: 10000 }); + ok(authOk && tokenOk, "TONE3000: Select pop-up (A2, .nam), sign-in with PKCE, back to the page"); + ok(/Plexi Lead/.test(await page.textContent("#t3kcard")) && /capturer/.test(await page.textContent("#t3kcard")) && + /AMP · NAM/.test(await page.textContent("#t3kcard")), "TONE3000: the tone's card (title, gear, format, creator)"); + ok(await page.inputValue("#t3kcard select") === "1", "TONE3000: the first empty user slot proposed (U02)"); + await page.locator("#t3kcard .mrow button").first().click(); + await page.waitForFunction(() => /is in user slot 2/.test(document.getElementById("msg").textContent), null, { timeout: 20000 }); + ok((await page.locator("#namlist .row").nth(13).textContent()).includes("PLEXI LEAD") && bearerOk, + "TONE3000: the A2 model downloaded (with the token) into user slot 2"); + await shot("editor_7_tone3000.png"); +} + // ---- phone width ---- await page.setViewportSize({ width: 390, height: 844 }); await sleep(200); diff --git a/tests/test_nam.py b/tests/test_nam.py new file mode 100644 index 0000000..8301b44 --- /dev/null +++ b/tests/test_nam.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-3.0-only +# OpenPocket — the NAM engine (engine/px_nam.c, fixed point, the pedal's C path) against the float reference +# (tools/nam_a2.py), with each factory model's weights (engine/px_nam_factory.h): DI clip (docs/nam_di.wav) at the +# pedal's input level, several block sizes, the rings in one piece and in two. Wants SNR > 80 dB. Modes 2..8 (the +# vector unit beside the CPU, a second core, simulated: tests/engine/nam_test.c) must give exactly the same output as the CPU alone. +# python3 tests/test_nam.py build/nam_test +import os, re, subprocess, sys, wave +import numpy as np + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, os.path.join(ROOT, "tools")) +import nam_a2 # noqa: E402 + +exe = sys.argv[1] +out = os.path.join(ROOT, "build", "nam") +os.makedirs(out, exist_ok=True) +src = open(os.path.join(ROOT, "engine", "px_nam_factory.h")).read() +names = re.search(r"PXN_FNAME\[PX_NAM_NFACT\] = \{(.*?)\};", src).group(1) +names = re.findall(r'"([^"]*)"', names) +body = src[src.index("PXN_FW[PX_NAM_NFACT][PXN_NW] = {"):] +models = [np.array([float(v.rstrip("f")) for v in re.findall(r"[-+0-9.eE]+f", m)], np.float32) + for m in re.findall(r"\{([^{}]*)\}", body)] +w = wave.open(os.path.join(ROOT, "docs", "nam_di.wav")) +x = (np.frombuffer(w.readframes(w.getnframes()), np.int16) / 32768.0).astype(np.float32)[:44100] +x = x / 0.15 * 0.5 # about the level the engine feeds the network (rc_nam) +x.tofile(os.path.join(out, "in.f32")) +bad = 0 +for k, (name, wt) in enumerate(zip(names, models)): + if len(wt) != 1871: + print("%-10s %d weights" % (name, len(wt))); bad += 1; continue + wt.tofile(os.path.join(out, "w.f32")) + ref = nam_a2.run(nam_a2.unpack(wt.astype(np.float64), 3), x.astype(np.float64)) + worst = 1e9 + outs = {} + runs = [(64, 0, 0), (37, 1, 0), (1, 0, 0)] + [(64, 0, md) for md in range(1, 11)] + [(37, 1, 4), (37, 1, 6)] + for blk, split, pipe in runs: + env = dict(os.environ) + if split: env["NAM_SPLIT"] = "1" + if pipe: env["NAM_PIPE"] = str(pipe) + subprocess.run([exe, os.path.join(out, "w.f32"), os.path.join(out, "in.f32"), os.path.join(out, "out.f32"), + str(blk)], check=True, env=env) + y = np.fromfile(os.path.join(out, "out.f32"), np.float32) + outs[blk, pipe] = y + snr = 10 * np.log10(np.sum(ref ** 2) / max(np.sum((y - ref) ** 2), 1e-30)) + worst = min(worst, snr) + for srv in (1, 2): # the two-core pipeline's mode: CPU1 serving, eager or late + subprocess.run([exe, os.path.join(out, "w.f32"), os.path.join(out, "in.f32"), os.path.join(out, "out.f32"), + "128"], check=True, env=dict(os.environ, NAM_SRV=str(srv))) + outs[128, "s%d" % srv] = np.fromfile(os.path.join(out, "out.f32"), np.float32) + for pipe in (0, 5): # the CPU's layers through gathered X rows instead of rdot + env = dict(os.environ, NAM_GATHER="1", **({"NAM_PIPE": str(pipe)} if pipe else {})) + subprocess.run([exe, os.path.join(out, "w.f32"), os.path.join(out, "in.f32"), os.path.join(out, "out.f32"), + "64"], check=True, env=env) + outs[64, "g%d" % pipe] = np.fromfile(os.path.join(out, "out.f32"), np.float32) + same = all(np.array_equal(outs[b, 0], outs[b, p]) for b, _, p in runs if p) and \ + np.array_equal(outs[64, 0], outs[64, "g0"]) and np.array_equal(outs[64, 0], outs[64, "g5"]) and \ + np.array_equal(outs[64, 0], outs[128, "s1"]) and np.array_equal(outs[64, 0], outs[128, "s2"]) + ok = worst > 80 and same + if not same: print("%-10s modes 2..8 differ from the CPU alone" % name) + bad += not ok + print("%-10s fixed point vs float: SNR %.1f dB %s" % (name, worst, "ok" if ok else "FAIL")) +print("NAM: %d models, %s" % (len(models), "all ok" if not bad else "%d FAILED" % bad)) +sys.exit(1 if bad else 0) diff --git a/tools/check_calls.py b/tools/check_calls.py new file mode 100644 index 0000000..6266702 --- /dev/null +++ b/tools/check_calls.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-3.0-only +# OpenPocket — refuses a build with a direct call between the flash code (.text*) and the RAM code (.ram_text, +# .c1_text) of the pi32v2 objects given: the call instruction (R_PI32V2_LONG_JUMP_23M2) reaches +-4 MiB, and the flash +# (0x02xxxxxx) is just out of reach of the RAM (0x01C0xxxx). Such a call must go through a pointer (FL_FAR in +# fm1_flash.h). The linker would also refuse it, but names only the first one and not why. +# check_calls.py OBJ.o... (firmware/build.sh, before linking; Python standard library only) +import struct, sys + +R_LONG_JUMP = 2 # R_PI32V2_LONG_JUMP_23M2 +RAM = (b".ram_text", b".c1_text") + + +def read(path): + d = open(path, "rb").read() + if d[:4] != b"\x7fELF" or d[4] != 1 or d[5] != 1: + raise SystemExit("%s: not a 32-bit little-endian ELF" % path) + shoff, = struct.unpack_from("> 4, st_shndx)) + relas = [] + for i, s in enumerate(secs): + if s[1] == 4: # SHT_RELA + for k in range(s[5] // 12): + off, info, _ = struct.unpack_from("> 8, info & 0xFF)) # (patched section, offset, symbol, type) + return names, syms, relas + + +def main(): + objs = [(p, read(p)) for p in sys.argv[1:]] + in_ram = {} # global symbol -> defined in RAM code + for p, (names, syms, _) in objs: + for nm, bind, shndx in syms: + if nm and bind != 0 and 0 < shndx < 0xFF00: + in_ram[nm] = names[shndx].startswith(RAM) + bad = [] + for p, (names, syms, relas) in objs: + for sec, off, si, typ in relas: + if typ != R_LONG_JUMP or not names[sec].startswith((b".text", b".ram_text", b".c1_text")): + continue + nm, bind, shndx = syms[si] + if 0 < shndx < 0xFF00: + dst = names[shndx].startswith(RAM) + elif nm in in_ram: + dst = in_ram[nm] + else: + continue # defined elsewhere (not one of these objects) + src = names[sec].startswith(RAM) + if src != dst: + bad.append("%s: %s+0x%x calls %s (%s)" % (p, names[sec].decode(), off, + (nm or names[shndx]).decode(), "flash -> RAM" if dst else "RAM -> flash")) + for b in bad[:40]: + print(b) + if bad: + raise SystemExit("ERROR: %d direct call(s) between the flash and the RAM code (out of the CPU's call range): " + "call through a pointer (FL_FAR, fm1_flash.h) or keep both sides in the same place" % len(bad)) + print("calls: no direct call between the flash and the RAM code") + + +if __name__ == "__main__": + main() diff --git a/tools/gen_rdq.py b/tools/gen_rdq.py new file mode 100644 index 0000000..9b8f4c7 --- /dev/null +++ b/tools/gen_rdq.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-3.0-only +# OpenPocket — writes the rdq routines of engine/px_nam.c (pi32v2 assembly, as C string lines): a NAM layer's rows for 4 +# frames straight from the history ring, unrolled for 6, 15 and 16 taps, each multiply-add using a value loaded 2 to 4 +# steps before (on the pedal a multiply-add paired with the load of the value it needs next costs 3.2 cycles, without +# that wait 2.2). Paste its output into px_nam.c's asm block (the lines after "rdq6, rdq15, rdq16"). +# python3 tools/gen_rdq.py > rdq.inc (rdq6, rdq15, rdq16) +# python3 tools/gen_rdq.py --rdl > rdl.inc (rdl6, rdl15, rdl16: a whole layer's groups in one call) +ACC = ["r9_r8", "r11_r10", "r13_r12", "r15_r14"] +X = ["r3", "r4", "r6", "r7"] +def gen(K): + n = "pxn_rdq%d_asm" % K + L = [] + a = L.append + a("\t.global %s" % n) + a("%s:" % n) + a("\t[--sp] = {rets, r15-r4}") + a("\tsp += -16") + a("\t[sp+0] = r0") + a("\tr7 = [r0+20]\n\t[sp+4] = r7") + a("\tr7 = [r0+16]\n\t[sp+8] = r7") + a("\tr7 = [r0+4]\n\t[sp+12] = r7") + a("\tr0 = [r0+0]") + a(".L%so:" % n) + a("\tr4 = [sp+0]\n\tr7 = [r4+12]") + a("\tr5 = [r0++=4]\n\tr6 = [r0++=4]") + for f in range(4): + a("\tr3 = [r7+%d]" % (4 * f)) + a("\t%s = r3 * r5 (s)" % ACC[f]) + a("\tr3 = 1048576") + for f in range(4): + a("\t%s += r3 * r6 (s)" % ACC[f]) + a("\tr1 = [sp+12]\n\tr1 = [r1+0]") + a("\tr5 = [r0++=4]") + for f in range(4): + a("\t%s = [r1+%d]" % (X[f], 12 * f)) + for k in range(K): + A = "r1" if k % 2 == 0 else "r2" + B = "r2" if k % 2 == 0 else "r1" + last = k == K - 1 + for c in range(3): + if c < 2: + base, off = A, 4 * (c + 1) + else: + base, off = B, 0 + for f in range(4): + if f < 3: + if c == 2 and last: + a("\t%s += %s * r5 (s)" % (ACC[f], X[f])) + else: + a("\t%s += %s * r5 (s) # %s = [%s+%d]" % (ACC[f], X[f], X[f], base, off + 12 * f)) + else: + a("\t%s += %s * r5 (s) # r5 = [r0++=4]" % (ACC[f], X[f])) + if not (c == 2 and last): + a("\tr7 = [%s+%d]" % (base, off + 36)) + if c == 0 and not last: + a("\t%s = [sp+12]\n\t%s = [%s+%d]" % (B, B, B, 4 * (k + 1))) + a("\tr0 += -4") + for f in range(4): + a("\t%s >>= 24" % ACC[f]) + a("\tr4 = [sp+8]") + a("\t[r4+0] = r8\n\t[r4+12] = r10\n\t[r4+24] = r12\n\t[r4+36] = r14") + a("\tr4 += 4\n\t[sp+8] = r4") + a("\tr7 = [sp+4]\n\tr7 += -1\n\t[sp+4] = r7") + a("\tif (r7 != 0) goto .L%so" % n) + a("\tsp += 16") + a("\t{pc, r15-r4} = [sp++]") + out = [] + for ln in "\n".join(L).split("\n"): + out.append(' "%s\\n"' % ln.replace("\t", "\\t")) + return "\n".join(out) +def genl(K): + """rdl: the same rows for a whole layer's groups of 4 frames in one call (diagnostic 20): the tap table copied onto + the stack ([sp+20+4k], one load per tap instead of two), the u and z pointers moved on in the job, and every tap's + pointer 4 frames on after each group, brought back by the ring's length past its end (job +28 end, +32 minus the + ring's length in bytes; the ring's first frames are mirrored after its end). [sp+12] groups left.""" + n = "pxn_rdl%d_asm" % K + F = 20 + 4 * K + L = [] + a = L.append + a("\t.global %s" % n) + a("%s:" % n) + a("\t[--sp] = {rets, r15-r4}") + a("\tsp += -%d" % F) + a("\t[sp+0] = r0") + a("\tr7 = [r0+24]\n\t[sp+12] = r7") + a("\tr1 = [r0+4]") + for k in range(K): + a("\tr7 = [r1+%d]\n\t[sp+%d] = r7" % (4 * k, 20 + 4 * k)) + a(".L%sg:" % n) + a("\tr4 = [sp+0]") + a("\tr7 = [r4+20]\n\t[sp+4] = r7") + a("\tr7 = [r4+16]\n\t[sp+8] = r7") + a("\tr0 = [r4+0]") + a(".L%so:" % n) + a("\tr4 = [sp+0]\n\tr7 = [r4+12]") + a("\tr5 = [r0++=4]\n\tr6 = [r0++=4]") + for f in range(4): + a("\tr3 = [r7+%d]" % (4 * f)) + a("\t%s = r3 * r5 (s)" % ACC[f]) + a("\tr3 = 1048576") + for f in range(4): + a("\t%s += r3 * r6 (s)" % ACC[f]) + a("\tr1 = [sp+20]") + a("\tr5 = [r0++=4]") + for f in range(4): + a("\t%s = [r1+%d]" % (X[f], 12 * f)) + for k in range(K): + A = "r1" if k % 2 == 0 else "r2" + B = "r2" if k % 2 == 0 else "r1" + last = k == K - 1 + for c in range(3): + if c < 2: + base, off = A, 4 * (c + 1) + else: + base, off = B, 0 + for f in range(4): + if f < 3: + if c == 2 and last: + a("\t%s += %s * r5 (s)" % (ACC[f], X[f])) + else: + a("\t%s += %s * r5 (s) # %s = [%s+%d]" % (ACC[f], X[f], X[f], base, off + 12 * f)) + else: + a("\t%s += %s * r5 (s) # r5 = [r0++=4]" % (ACC[f], X[f])) + if not (c == 2 and last): + a("\tr7 = [%s+%d]" % (base, off + 36)) + if c == 0 and not last: + a("\t%s = [sp+%d]" % (B, 20 + 4 * (k + 1))) + a("\tr0 += -4") + for f in range(4): + a("\t%s >>= 24" % ACC[f]) + a("\tr4 = [sp+8]") + a("\t[r4+0] = r8\n\t[r4+12] = r10\n\t[r4+24] = r12\n\t[r4+36] = r14") + a("\tr4 += 4\n\t[sp+8] = r4") + a("\tr7 = [sp+4]\n\tr7 += -1\n\t[sp+4] = r7") + a("\tif (r7 != 0) goto .L%so" % n) + a("\tr4 = [sp+0]") + a("\tr7 = [r4+12]\n\tr7 += 16\n\t[r4+12] = r7") + a("\tr7 = [r4+16]\n\tr7 += 48\n\t[r4+16] = r7") + a("\tr2 = [r4+28]\n\tr3 = [r4+32]") + for k in range(K): + a("\tr1 = [sp+%d]\n\tr1 += 48\n\tr5 = r1 + r3" % (20 + 4 * k)) + a("\tif (r1 >= r2) {\n\tr1 = r5\n\t}") + a("\t[sp+%d] = r1" % (20 + 4 * k)) + a("\tr7 = [sp+12]\n\tr7 += -1\n\t[sp+12] = r7") + a("\tif (r7 != 0) goto .L%sg" % n) + a("\tsp += %d" % F) + a("\t{pc, r15-r4} = [sp++]") + out = [] + for ln in "\n".join(L).split("\n"): + out.append(' "%s\\n"' % ln.replace("\t", "\\t")) + return "\n".join(out) +import sys +if "--rdl" in sys.argv: + print("\n".join(genl(K) for K in (6, 15, 16))) +else: + print("\n".join(gen(K) for K in (6, 15, 16))) diff --git a/tools/mk_nam_factory.py b/tools/mk_nam_factory.py new file mode 100644 index 0000000..e6ba3ef --- /dev/null +++ b/tools/mk_nam_factory.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-3.0-only +# OpenPocket — writes engine/px_nam_factory.h: the factory NAM models (A2-Lite weights, names, level trims). +# mk_nam_factory.py LIST.txt DIR [DI.wav] +# LIST.txt: one model a line, "id|NAME|source capture"; DIR/id.nam: the trained A2-Lite (tools/train_a2.py). +# Level trim: every model at the same loudness (ITU BS.1770, K-weighted) on the DI clip played at the captures' level, +# so that switching models keeps the volume (tools/nam_level.py does the same for the web editor's user models). +import json, os, sys +import numpy as np + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import nam_a2, nam_level + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +def cfloat(v): + """a C float literal that round-trips the float32 (0 -> 0.0f, 1e-05 -> 1e-05f)""" + s = "%.9g" % float(v) + if not any(c in s for c in ".en"): + s += ".0" + return s + "f" + + +def main(): + lst, d = sys.argv[1], sys.argv[2] + di = sys.argv[3] if len(sys.argv) > 3 else None + rows = [l.rstrip("\n").split("|") for l in open(lst) if l.strip()] + names, lv, ws, srcs = [], [], [], [] + for mid, name, src in rows: + j = json.load(open(os.path.join(d, mid + ".nam"))) + m, c = nam_a2.pick(j, "lite") + if c != 3: + raise SystemExit("%s: not A2-Lite" % mid) + w = np.asarray(m["weights"], dtype=np.float32) + ws.append(w) + names.append(name[:11]) + srcs.append("%s (val ESR %s)" % (src, (m.get("metadata") or {}).get("val_esr", "?"))) + lv.append(nam_level.trim_db(nam_a2.unpack(w.astype(np.float64), 3), di)) + print("%-10s level trim %+.2f dB" % (name, lv[-1])) + if len(ws) != 12: + raise SystemExit("want 12 models, got %d" % len(ws)) + out = ["/* SPDX-License-Identifier: GPL-3.0-only", + " * OpenPocket — the factory NAM models (generated by tools/mk_nam_factory.py: do not edit).", + " * A2-Lite networks trained by tools/train_a2.py on real DI guitar (Alec-Wright/Automated-GuitarAmpModelling,", + " * GPL v3) through NAM community captures (pelennor2170/NAM_models, GPL v3), at 44.1 kHz:"] + for n, s in zip(names, srcs): + out.append(" * %-10s %s" % (n, s)) + out += [" */", "#pragma once", + "static const char *const PXN_FNAME[PX_NAM_NFACT] = {%s};" % ", ".join('"%s"' % n for n in names), + "static const float PXN_FLVL[PX_NAM_NFACT] = {%s};" % ", ".join("%.2ff" % v for v in lv), + "static const float PXN_FW[PX_NAM_NFACT][PXN_NW] = {"] + for w in ws: + vals = [cfloat(v) for v in w] + lines = [", ".join(vals[i:i + 10]) for i in range(0, len(vals), 10)] + out.append(" {" + ",\n ".join(lines) + "},") + out.append("};") + open(os.path.join(ROOT, "engine", "px_nam_factory.h"), "w").write("\n".join(out) + "\n") + print("engine/px_nam_factory.h: %d models" % len(ws)) + + +if __name__ == "__main__": + main() diff --git a/tools/nam_a2.py b/tools/nam_a2.py new file mode 100644 index 0000000..1af1253 --- /dev/null +++ b/tools/nam_a2.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-3.0-only +# OpenPocket — an independent NumPy implementation of Neural Amp Modeler's A2 network (the 2026 "A2-Lite" / "A2-Full" +# WaveNet), written from the published architecture. Used as the reference for the pedal's fixed-point engine +# (engine/px_nam.c) and by the web editor's converter tests. +# +# A2 (one layer array, 23 layers, LeakyReLU 0.01, no gating, no FiLM): +# x0 = rechannel(input) 1 -> C, no bias +# per layer i (kernel K_i, dilation d_i): +# z = conv_dilated(x) + bias C -> C, causal, taps at t - (K-1-k) d +# z += mixin * input 1 -> C, no bias +# a = LeakyReLU(z, 0.01) +# head_sum += a +# x = x + layer1x1(a) + bias C -> C +# y = head_scale * (head_conv(head_sum) + bias) C -> 1, kernel 16, causal +# Weights, in file order: rechannel [C]; per layer conv [C_out][C_in][K], conv bias [C], mixin [C], +# layer1x1 [C_out][C_in], layer1x1 bias [C]; head [C][16], head bias; head_scale (the last value). +# nam_a2.py MODEL.nam in.wav out.wav [lite|full] (renders at the model's rate, no resampling) +import json, sys +import numpy as np + +KERNELS = [6] * 14 + [15, 15] + [6] * 7 +DILATIONS = [1, 3, 7, 17, 41, 101, 239] * 2 + [1, 13] + [1, 3, 7, 17, 41, 101, 239] +HEAD_K = 16 +SLOPE = 0.01 + + +def submodels(j): + """The WaveNet entries of a .nam: a plain WaveNet, or each submodel of a SlimmableContainer (A2 files hold + A2-Lite, 3 channels, and A2-Full, 8 channels).""" + if j.get("architecture") == "SlimmableContainer": + return [s["model"] for s in j["config"]["submodels"]] + return [j] + + +def is_a2(m): + if m.get("architecture") != "WaveNet": + return 0 + cfg = m["config"] + if cfg.get("head") is not None or len(cfg.get("layers", [])) != 1: + return 0 + L = cfg["layers"][0] + c = L.get("channels") + ok = (L.get("kernel_sizes") == KERNELS and L.get("dilations") == DILATIONS and L.get("bottleneck") == c + and L.get("input_size") == 1 and L.get("condition_size") == 1 + and (L.get("head") or {}).get("kernel_size") == HEAD_K and (L.get("head") or {}).get("out_channels") == 1 + and (L.get("head") or {}).get("bias") is True + and not (L.get("head1x1") or {}).get("active") and (L.get("layer1x1") or {}).get("active", True) + and all(g in (None, "none") for g in (L.get("gating_mode") or ["none"])) + and all((a or {}).get("type") == "LeakyReLU" and abs((a or {}).get("negative_slope", 0) - SLOPE) < 1e-9 + for a in (L.get("activation") or [None]))) + for k in ("conv_pre_film", "conv_post_film", "input_mixin_pre_film", "input_mixin_post_film", + "activation_pre_film", "activation_post_film", "layer1x1_post_film", "head1x1_post_film"): + if (L.get(k) or {}).get("active"): + ok = False + return c if ok else 0 + + +def pick(j, size="lite"): + """The A2 submodel of the wanted size: (model dict, channels). Raises if the file has no A2 network.""" + found = [(m, is_a2(m)) for m in submodels(j)] + found = [(m, c) for m, c in found if c] + if not found: + raise ValueError("not an A2 model") + found.sort(key=lambda mc: mc[1]) + return found[0] if size == "lite" else found[-1] + + +def unpack(weights, C): + w = np.asarray(weights, dtype=np.float64) + i = 0 + + def take(n): + nonlocal i + r = w[i:i + n] + if len(r) != n: + raise ValueError("not enough weights") + i += n + return r + net = {"C": C, "rechannel": take(C), "layers": []} + for K, d in zip(KERNELS, DILATIONS): + conv = take(C * C * K).reshape(C, C, K) # out, in, tap (tap K-1 = now) + cb = take(C) + mix = take(C) + one = take(C * C).reshape(C, C) # out, in + ob = take(C) + net["layers"].append((K, d, conv, cb, mix, one, ob)) + net["head"] = take(C * HEAD_K).reshape(C, HEAD_K) + net["head_b"] = float(take(1)[0]) + net["head_scale"] = float(take(1)[0]) + if i != len(w): + raise ValueError("weights left over: %d of %d used" % (i, len(w))) + return net + + +def n_weights(C): + return C + sum(C * C * K + 3 * C + C * C for K in KERNELS) + C * HEAD_K + 2 + + +def causal_conv(x, w, d): + """x [C_in, T]; w [C_out, C_in, K]; y[:, t] = sum_k w[:, :, k] x[:, t - (K-1-k) d] (zeros before 0).""" + Cout, Cin, K = w.shape + T = x.shape[1] + y = np.zeros((Cout, T)) + for k in range(K): + s = (K - 1 - k) * d + if s >= T: + continue + y[:, s:] += w[:, :, k] @ x[:, :T - s] + return y + + +def run(net, inp): + u = np.asarray(inp, dtype=np.float64)[None, :] + x = net["rechannel"][:, None] * u + hs = np.zeros_like(x) + for K, d, conv, cb, mix, one, ob in net["layers"]: + z = causal_conv(x, conv, d) + cb[:, None] + mix[:, None] * u + a = np.where(z >= 0, z, z * SLOPE) + hs += a + x = x + one @ a + ob[:, None] + y = causal_conv(hs, net["head"][None, :, :], 1)[0] + net["head_b"] + return net["head_scale"] * y + + +def load(path, size="lite"): + j = json.load(open(path)) + m, C = pick(j, size) + net = unpack(m["weights"], C) + net["sr"] = float(m.get("sample_rate") or j.get("sample_rate") or 48000.0) + net["meta"] = m.get("metadata") or j.get("metadata") or {} + return net + + +if __name__ == "__main__": + import wave + path, src, dst = sys.argv[1:4] + size = sys.argv[4] if len(sys.argv) > 4 else "lite" + net = load(path, size) + w = wave.open(src) + n, ch, sw = w.getnframes(), w.getnchannels(), w.getsampwidth() + raw = np.frombuffer(w.readframes(n), dtype={2: np.int16, 4: np.int32}[sw]).astype(np.float64) + x = raw.reshape(-1, ch)[:, 0] / (32768.0 if sw == 2 else 2147483648.0) + y = run(net, x) + o = wave.open(dst, "wb") + o.setnchannels(1); o.setsampwidth(2); o.setframerate(int(net["sr"])) + o.writeframes((np.clip(y, -1, 1) * 32767).astype(np.int16).tobytes()) + print("%s: C=%d, %d samples, peak %.3f" % (path, net["C"], len(y), np.max(np.abs(y)))) diff --git a/tools/nam_level.py b/tools/nam_level.py new file mode 100644 index 0000000..7d548f2 --- /dev/null +++ b/tools/nam_level.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-3.0-only +# OpenPocket — the level trim of a NAM model: the same loudness for every model. The model plays docs/nam_di.wav +# (6 s of real DI guitar, Alec-Wright/Automated-GuitarAmpModelling, GPL v3) at its own level; trim = REF - loudness +# (ITU BS.1770 K-weighting, 400 ms blocks, absolute and relative gates). docs/pxedit.js computes the same for the +# models the web editor loads (namLevelTrim): keep the two in step. +import os, sys, wave +import numpy as np + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +SR = 44100 +REF = -20.0 # LUFS of the model's own output after the trim (v37: NAM + cabinet ~ the fitted amps at noon) +CLAMP = 24.0 + + +def kweight(x): + # BS.1770 pre-filter + RLB high-pass at 44.1 kHz (same coefficients as tools/calib_levels.py) + from scipy import signal + f0, G, Q = 1681.974450955533, 3.999843853973347, 0.7071752369554196 + K = np.tan(np.pi * f0 / SR); Vh = 10 ** (G / 20); Vb = Vh ** 0.4996667741545416; a0 = 1 + K / Q + K * K + y = signal.lfilter([(Vh + Vb * K / Q + K * K) / a0, 2 * (K * K - Vh) / a0, (Vh - Vb * K / Q + K * K) / a0], + [1, 2 * (K * K - 1) / a0, (1 - K / Q + K * K) / a0], x) + f0, Q = 38.13547087602444, 0.5003270373238773; K = np.tan(np.pi * f0 / SR); a0 = 1 + K / Q + K * K + return signal.lfilter([1, -2, 1], [1, 2 * (K * K - 1) / a0, (1 - K / Q + K * K) / a0], y) + + +def lufs(x): + y = kweight(x); blk, hop = int(0.4 * SR), int(0.1 * SR) + z = np.array([np.mean(y[i:i + blk] ** 2) for i in range(0, len(y) - blk + 1, hop)]) + z = z[-0.691 + 10 * np.log10(z + 1e-20) > -70] + if not len(z): + return -99.0 + rel = -0.691 + 10 * np.log10(np.mean(z)) - 10 + z = z[-0.691 + 10 * np.log10(z) > rel] + return float(-0.691 + 10 * np.log10(np.mean(z))) + + +def di(path=None): + w = wave.open(path or os.path.join(ROOT, "docs", "nam_di.wav")) + return np.frombuffer(w.readframes(w.getnframes()), dtype=np.int16).astype(np.float64) / 32768.0 + + +def trim_db(net, path=None): + sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + import nam_a2 + y = nam_a2.run(net, di(path)) + t = REF - lufs(y) + return float(max(-CLAMP, min(CLAMP, t))) + + +if __name__ == "__main__": + sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + import nam_a2 + for p in sys.argv[1:]: + print("%s: trim %+.2f dB" % (p, trim_db(nam_a2.load(p)))) diff --git a/tools/train_a2.py b/tools/train_a2.py new file mode 100644 index 0000000..c8be742 --- /dev/null +++ b/tools/train_a2.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-3.0-only +# OpenPocket — trains an A2-Lite network (NAM's 2026 architecture, 3 channels; tools/nam_a2.py) to sound like a +# reference, at the pedal's rate (44.1 kHz). Used for the factory models: the reference is a NAM A1 capture from +# the GPL v3 community collection (pelennor2170/NAM_models), played on real DI guitar (Alec-Wright's GPL v3 data). +# +# train_a2.py --capture "X.nam" --di train.wav --val val.wav --out model.nam [--steps 3000] [--seconds 120] +# +# 1. The DI (44.1 kHz) is resampled to the capture's 48 kHz, played through the A1 capture (tools/nam_a1.py) and +# the result resampled back: the target, at 44.1 kHz. +# 2. A2-Lite is trained on (DI, target) with Adam (JAX): error-to-signal ratio on the pre-emphasised signals plus a +# multi-resolution spectral term, random 1.2 s segments. +# 3. The result is written as a standard .nam file (a WaveNet entry the NAM plugin and tools/nam_a2.py read), with +# the validation error and the loudness of the output in its metadata. +import argparse, json, os, sys, time, wave +import numpy as np +from scipy.signal import resample_poly + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import nam_a1, nam_a2 + +SR = 44100 +C = 3 +RF = 1 + sum((k - 1) * d for k, d in zip(nam_a2.KERNELS, nam_a2.DILATIONS)) + nam_a2.HEAD_K - 1 # 6347 + + +def read_wav(path): + w = wave.open(path) + n, ch, sw, sr = w.getnframes(), w.getnchannels(), w.getsampwidth(), w.getframerate() + raw = np.frombuffer(w.readframes(n), dtype={2: np.int16, 4: np.int32}[sw]).astype(np.float64) + x = raw.reshape(-1, ch)[:, 0] / (32768.0 if sw == 2 else 2147483648.0) + if sr != SR: + raise ValueError("%s: %d Hz, want %d" % (path, sr, SR)) + return x + + +def reference(capture, x, cache): + if os.path.exists(cache): + y = np.fromfile(cache, dtype=np.float32).astype(np.float64) + if len(y) == len(x): + return y + m = nam_a1.load(capture) + sr = int(m["sr"]) + x48 = resample_poly(x, sr // 300, SR // 300) if sr != SR else x # 44100 -> 48000: 160 / 147 + y48 = nam_a1.run(m, x48) + y = resample_poly(y48, SR // 300, sr // 300)[:len(x)] if sr != SR else y48 + y = np.concatenate([y, np.zeros(len(x) - len(y))]) if len(y) < len(x) else y + os.makedirs(os.path.dirname(cache) or ".", exist_ok=True) + y.astype(np.float32).tofile(cache) + return y + + +# ------------------------------------------------------------------------------------------------ JAX model --- +def build(): + import jax + import jax.numpy as jnp + from jax import lax + + def conv(x, w, d): # x [B, Cin, T], w [Cout, Cin, K] -> [B, Cout, T - (K-1) d] + return lax.conv_general_dilated(x, w, (1,), "VALID", rhs_dilation=(d,), + dimension_numbers=("NCH", "OIH", "NCH")) + + def forward(p, u): # u [B, T] -> y [B, T - RF + 1] + u3 = u[:, None, :] + x = p["rech"][None, :, None] * u3 + hs = None + for i, (K, d) in enumerate(zip(nam_a2.KERNELS, nam_a2.DILATIONS)): + L = p["layers"][i] + z = conv(x, L["conv"], d) + T = z.shape[2] + z = z + L["cb"][None, :, None] + L["mix"][None, :, None] * u3[:, :, -T:] + a = jnp.where(z >= 0, z, 0.01 * z) + hs = a if hs is None else hs[:, :, -T:] + a + x = x[:, :, -T:] + jnp.einsum("oc,bct->bot", L["one"], a) + L["ob"][None, :, None] + y = conv(hs, p["head"][None, :, :], 1)[:, 0, :] + p["hb"] + return p["scale"] * y + + return jax, jnp, forward + + +def init_params(rng): + p = {"rech": rng.normal(0, 1.0, C), "layers": []} + for K in nam_a2.KERNELS: + s = 1.0 / np.sqrt(C * K) + p["layers"].append({"conv": rng.normal(0, s, (C, C, K)), "cb": np.zeros(C), "mix": rng.normal(0, 0.5, C), + "one": rng.normal(0, 1.0 / np.sqrt(C), (C, C)), "ob": np.zeros(C)}) + p["head"] = rng.normal(0, 1.0 / np.sqrt(C * nam_a2.HEAD_K), (C, nam_a2.HEAD_K)) + p["hb"] = np.zeros(()) + p["scale"] = np.array(0.02) + return p + + +def flatten(p): + """The .nam weight list (file order, see nam_a2.py).""" + w = [np.asarray(p["rech"]).ravel()] + for L in p["layers"]: + w += [np.asarray(L["conv"]).ravel(), np.asarray(L["cb"]).ravel(), np.asarray(L["mix"]).ravel(), + np.asarray(L["one"]).ravel(), np.asarray(L["ob"]).ravel()] + w += [np.asarray(p["head"]).ravel(), np.asarray(p["hb"]).ravel(), np.asarray(p["scale"]).ravel()] + w = np.concatenate(w).astype(np.float64) + assert len(w) == nam_a2.n_weights(C), len(w) + return w + + +def unflatten(w): + """flatten's inverse: a .nam weight list -> the parameters (to go on training a model: --init)""" + w = np.asarray(w, dtype=np.float64) + i = 0 + + def take(shape): + nonlocal i + n = int(np.prod(shape)) if shape else 1 + v = w[i:i + n].reshape(shape) if shape else np.array(w[i]) + i += n + return v + p = {"rech": take((C,)), "layers": []} + for K in nam_a2.KERNELS: + p["layers"].append({"conv": take((C, C, K)), "cb": take((C,)), "mix": take((C,)), "one": take((C, C)), + "ob": take((C,))}) + p["head"] = take((C, nam_a2.HEAD_K)) + p["hb"] = take(()) + p["scale"] = take(()) + assert i == len(w) + return p + + +def nam_json(weights, meta): + layer = {"input_size": 1, "condition_size": 1, "head": {"out_channels": 1, "kernel_size": nam_a2.HEAD_K, "bias": True}, + "channels": C, "kernel_sizes": nam_a2.KERNELS, "dilations": nam_a2.DILATIONS, + "activation": [{"type": "LeakyReLU", "negative_slope": 0.01}] * len(nam_a2.KERNELS), + "bottleneck": C, "head1x1": {"active": False, "out_channels": 1, "groups": 1}, + "layer1x1": {"active": True, "groups": 1}, "groups_input": 1, "groups_input_mixin": 1, + "gating_mode": ["none"] * len(nam_a2.KERNELS), "secondary_activation": [None] * len(nam_a2.KERNELS), + "slimmable": None} + for k in ("conv_pre_film", "conv_post_film", "input_mixin_pre_film", "input_mixin_post_film", + "activation_pre_film", "activation_post_film", "layer1x1_post_film", "head1x1_post_film"): + layer[k] = {"active": False, "shift": True, "groups": 1} + return {"version": "0.7.0", "architecture": "WaveNet", "metadata": meta, + "config": {"layers": [layer], "head": None, "head_scale": float(weights[-1])}, + "weights": [float(v) for v in weights], "sample_rate": SR} + + +def preemph(x, jnp): + return x[:, 1:] - 0.85 * x[:, :-1] + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--capture", required=True) + ap.add_argument("--di", required=True) + ap.add_argument("--val", required=True) + ap.add_argument("--out", required=True) + ap.add_argument("--name", default="") + ap.add_argument("--steps", type=int, default=3000) + ap.add_argument("--seconds", type=float, default=120.0) + ap.add_argument("--batch", type=int, default=8) + ap.add_argument("--seg", type=int, default=8192) + ap.add_argument("--seed", type=int, default=1) + ap.add_argument("--lr", type=float, default=4e-3) + ap.add_argument("--init", help="start from this A2-Lite .nam (go on training it) instead of random weights") + a = ap.parse_args() + t0 = time.time() + cache = os.path.join(os.path.dirname(os.path.abspath(a.out)), "cache") + tag = os.path.splitext(os.path.basename(a.capture))[0].replace(" ", "_").replace(",", "_") + x = read_wav(a.di)[: int(a.seconds * SR)] + xv = read_wav(a.val)[: 20 * SR] + y = reference(a.capture, x, os.path.join(cache, "%s_train_%d.f32" % (tag, len(x)))) + yv = reference(a.capture, xv, os.path.join(cache, "%s_val_%d.f32" % (tag, len(xv)))) + print("%s: reference ready (%.0f s), peaks in %.2f out %.2f" % (tag, time.time() - t0, np.max(abs(x)), np.max(abs(y))), + flush=True) + + jax, jnp, forward = build() + import optax + rng = np.random.default_rng(a.seed) + if a.init: + m0, c0 = nam_a2.pick(json.load(open(a.init)), "lite") + assert c0 == C, "--init: not an A2-Lite" + params = jax.tree_util.tree_map(jnp.asarray, unflatten(m0["weights"])) + else: + params = jax.tree_util.tree_map(jnp.asarray, init_params(rng)) + # the output scale stays fixed (NAM keeps head_scale outside training); the rest learns + win = a.seg + RF - 1 + + def stft_mag(s, n): + hop = n // 4 + frames = jnp.stack([s[:, i:i + n] for i in range(0, s.shape[1] - n + 1, hop)], axis=1) + return jnp.abs(jnp.fft.rfft(frames * jnp.hanning(n), axis=-1)) + + def loss_fn(p, u, t): + yhat = forward(p, u) + e1 = preemph(yhat, jnp) - preemph(t, jnp) + esr = jnp.sum(e1 ** 2) / (jnp.sum(preemph(t, jnp) ** 2) + 1e-9) + spec = 0.0 + for n in (256, 1024, 2048): + A, B = stft_mag(yhat, n), stft_mag(t, n) + spec = spec + jnp.mean(jnp.abs(jnp.log(A + 1e-5) - jnp.log(B + 1e-5))) + return esr + 0.002 * spec + + sched = optax.warmup_cosine_decay_schedule(0.0, a.lr, 100, a.steps, a.lr * 0.02) + opt = optax.chain(optax.clip_by_global_norm(1.0), optax.adam(sched)) + frozen = {"scale"} + st = opt.init(params) + + @jax.jit + def step(p, s, u, t): + l, g = jax.value_and_grad(loss_fn)(p, u, t) + g = dict(g); g["scale"] = jnp.zeros_like(g["scale"]) + upd, s = opt.update(g, s, p) + return optax.apply_updates(p, upd), s, l + + fwd = jax.jit(forward) + + def val_esr(p): + # whole validation clip in pieces with their warm-up + out = [] + n = 4 * SR + xp = np.concatenate([np.zeros(RF - 1), xv]) + for i in range(0, len(xv), n): + seg = xp[i:i + n + RF - 1] + if len(seg) < RF: + break + out.append(np.asarray(fwd(p, jnp.asarray(seg[None, :]))[0])) + yh = np.concatenate(out)[:len(yv)] + return float(np.sum((yh - yv) ** 2) / np.sum(yv ** 2)), yh + + best = (1e9, None) + xs = np.concatenate([np.zeros(RF - 1), x]) + for it in range(1, a.steps + 1): + idx = rng.integers(0, len(x) - a.seg, a.batch) + u = np.stack([xs[i:i + win] for i in idx]) + t = np.stack([y[i:i + a.seg] for i in idx]) + params, st, l = step(params, st, jnp.asarray(u), jnp.asarray(t)) + if it % 250 == 0 or it == a.steps: + ev, _ = val_esr(params) + if ev < best[0]: + best = (ev, jax.tree_util.tree_map(np.asarray, params)) + print(" step %5d loss %.4f val ESR %.4f (%.0f s)" % (it, float(l), ev, time.time() - t0), flush=True) + ev, p = best + w = flatten(p) + net = nam_a2.unpack(w, C) + yh = nam_a2.run(net, xv) + esr = float(np.sum((yh - yv) ** 2) / np.sum(yv ** 2)) + meta = {"name": a.name or tag, "trained_from": os.path.basename(a.capture), "val_esr": round(esr, 5), + "loudness": float(10 * np.log10(np.mean(yh ** 2) + 1e-12)), "trainer": "OpenPocket tools/train_a2.py", + "licence": "GPL-3.0 (derived from a GPL-3.0 capture of pelennor2170/NAM_models)"} + json.dump(nam_json(w, meta), open(a.out, "w")) + print("%s -> %s: val ESR %.4f (%.0f s)" % (tag, a.out, esr, time.time() - t0), flush=True) + + +if __name__ == "__main__": + main()