Getting Started
This web application is designed to assemble FXCoreASM assembly code into machine instructions. Generated machine code may be saved locally for later use, or sent to a SandboxFX hardware target to hear the results.
- Enter FXCore source code into the editor area, or select a file or example. Press the Assemble button to verify and assemble the code into a HEX file
- Press the Download HEX to save the resulting HEX file to your local Downloads folder. Check the Build Results for success or error messages.
- Download C Headers outputs the assembled data in a C Header format for use with more advanced applications and is not used with SandboxFX hardware
- When satisfied with your source code, press the Save Source... button to download a local copy.
Connecting to Hardware
Connect your SandboxFX pedal to your computer using a suitable USB cable. A new removable drive labeled SANDBOX-FX should appear.
- Press the Connect button, then select the SandboxFX device from the list. You may need to allow this web app to access USB devices.
- Press the Run from RAM button to audition your assembled program on your SandboxFX
- Press Exit Run from RAM to return to normal operation when finished
- Open the Hardware Options panel and tap the Select Program Target to choose one of the 16 available program locations to write. This will save the assembled code to the slot and will persist even if the power is removed.
Troubleshooting
Errors and warnings will appear in the Build Results window and are often helpful for troubleshooting. Scroll up to the top to see previous messages
- Error information not helpful - use Editor Options - Show full build results to see more detailed info
- File transfer problems - ensure proper directory permissions
- Assembly errors - check syntax and register usage
- Connection issues - verify USB cable and HID device selection
Test Drive (the simulator)
The TEST DRIVE panel runs your assembled program in the browser, so you can hear it without a pedal attached. Press Assemble, then Play.
- Source - what the program is fed: a tone (sine, saw or square), noise, a click train, a plucked string, an audio file, or this computer's audio input. Clicks puts one sample high every second, which shows a delay's taps and a reverb's early reflections as plainly as anything can. Pluck is a plucked string, retuned by the Freq box and struck every two seconds, so a delay or reverb tail is heard on its own between notes rather than buried under a steady tone.
- Naming controls - put a tag in a comment and the pot, switch, tap and LED labels follow it as you type:
; #POT0 Reverb time, ; #SW1 Freeze, ; #TAP Tempo, ; #LED0 Bypass (or #USER0). Tags are read from the comment part of a line, so they never collide with code. Hover a renamed control to see which one it is.
- ENABLE - drives the part's ENABLE/nBypass pin. Off routes the inputs straight to the outputs, the way the pedal's bypass does, while the program keeps running so its delay tails survive.
- What is modelled - the FXCore core, delay RAM, pots, LFOs, ramps, switches and tap tempo. CHR and PITCH are modelled on the equivalent FV-1 structures, since neither is described internally by any published document: they sound right but are not yet confirmed against hardware, and the PITCH crossfade shapes XF0-XF3 are all treated as linear. Programs that drive external hardware over the second I2S bus will not behave as they do on a real board.
Watching the Program Run
The simulator can be watched as well as heard. Everything here lives under Debug Tools in the TEST DRIVE tab; click the heading to unfold it.
- Open register viewer - opens a second window showing ACC32, ACC64 and FLAGS, the audio in and out, the pots, the LFOs and ramps, the switches, tap tempo and USER pins, R0-R15 and the memory registers, each as the value it holds and the 32-bit word behind it. Registers are named after the .rn lines in your source, so R5 reads as R5 feedback. It is a real window: drag it to a second display and leave it there while you edit. In Chrome and Edge it floats above the editor with no address bar; Always on top in its header turns that off for an ordinary window. Where the browser allows neither - some embedded browsers, or popups blocked - it opens as a panel over the page instead, which you can drag by its title and resize from the corner.
- Show as - in the viewer's header. fraction reads a register as a fraction of full scale, which is right for audio; integer reads it as a plain signed number, which is right for counters and masks. The word in hex is always shown beside it, and the editor's trace follows the same setting.
- Only the memory registers that hold something, or that you have named, are listed, since most programs use a handful of the 128. list all 128 shows the rest.
- Click a register name in the viewer to plot it over time. The Window menu sets how much time the plot covers, from 64 ms to 16 s. An audio-rate signal shows as its envelope and an LFO as its shape, so a sweep that is too fast, a filter state that never settles, or a feedback path ringing up are all visible at a glance.
- Result of each line in editor - writes what each instruction produced at the end of its line, live, while the program plays: R3 +0.25, MR1 -0.01, OUT0 +0.5, ACC64 .... A jump line says jumped or not taken, the lines it went over say skipped, and a line whose result had to be clamped shows clip with the share of recent samples on which that happened - a line pinned at 100% is saturating, one at 2% is catching peaks. When a library call has expanded to several instructions, its line shows the last of them.
- The trace belongs to the build the simulator is running. Edit the source and it disappears until you assemble again, rather than drifting onto the wrong lines.
Halting and Stepping
The Debug section under Debug Tools stops the simulator where it stands and lets you step it one instruction at a time. Breakpoints only fire while the simulator is running, so assemble and press Play first.
- Halt freezes the core at the end of the current sample. The panel shows where it stopped, a ▶ in the editor's margin marks the next instruction, and every line above it shows what it just produced; lines below show … because they have not run yet this sample. If the register viewer is open it shows the halted state too.
- Step runs one instruction. Sample runs the rest of this pass and stops at the top of the next one. Run to line carries on until that line is next, across samples if it has to - but a line a jump goes over may never come round, so it gives up after a few thousand samples and says so. Stepping off the last instruction lands on end of sample; one more step starts the next.
- Resume (the Halt button, renamed) carries on from wherever the stepping got to. While halted the output is silent and the input is held at the sample it halted on, so stepping through a delay tail shows what the program does with that one input value rather than continuing the tone. The pots and switches stay live: move one and the next step uses it.
- Reset, or re-assembling with Reset on assemble ticked, clears a halt: the core that was being stepped no longer exists. Stop lets it go too.
- An instruction a library call expanded to is on the line of the call, so stepping through one shows the same line for as many presses as the subroutine has instructions.
Breakpoints are conditions rather than places. Every instruction that is not jumped over runs every sample, so a breakpoint on a line by itself halts on the very next sample - a fraction of a millisecond after you set it. That is fine when the point is to step through the program from there; for anything else, give it a condition. Two ways to set one:
- Click the margin just left of a line number. A red dot appears and the line halts on the next sample. Click again to remove it.
- Use the form under Breakpoints for something more specific. Pick a kind, fill in the fields, press Add:
- Line with first run halts only on sample 0 - the way to inspect initialisation code. With on sample # it halts on exactly that sample: 48000 is one second in at 48 kHz. A line a jump skips never halts.
- Clip halts the first time an instruction saturates. Leave the line blank for any line.
- Jump halts when a jump on that line goes the way you name, taken or not taken. A line that is not a jump never matches.
- Register halts when a value crosses a threshold - ACC32 > 0.9, R5 < -0.5, FLAGS == 0x8. Any register will do: ACC32, FLAGS, R0-R15, MR0-MR127 or an SFR, listed with their .rn names. Write the value as a fraction from -1 to 1 (0.5), a hex word (0x400) or an integer with an i (5i). They fire when the condition becomes true, not while it stays true, so a register sitting above its threshold does not halt again on the instruction after every resume.
Each breakpoint in the list has a checkbox to leave it set but quiet, and ✕ to remove it. Click one to jump to its line. A breakpoint on a line with no instruction - a comment, a blank line, a .rn - is shown greyed until a build gives that line one. Breakpoints follow their lines as you edit above them, and are matched to the build again on every assemble.
MIDI Control
A MIDI controller plugged into this computer can move the simulator's pots and its bypass, which is a good deal closer to playing the pedal than dragging sliders with a mouse.
The map is fixed. Every switch has all three of the things a foot does to one - hold it down while the pedal is down, toggle it and leave it there, or tap it - so each function gets its own run of controllers:
- CC50-CC55 - POT0-POT5.
- CC93 - tap tempo: one tap of the TAP pin.
- CC102 - ENABLE: 0-63 bypassed, 64-127 engaged.
- CC103-CC108 - hold SW0, SW1, SW2, SW3, SW4, TAP: 64-127 presses and holds, 0-63 releases.
- CC109-CC114 - toggle the same seven, in the same order: 64-127 flips the switch and leaves it, 0-63 is ignored so a footswitch's release does not flip it back.
- CC115-CC119 - tap SW0-SW4: a press and release the program reads as one push edge. TAP's own tap is CC93.
- The switch CCs sit in 102-119, which the MIDI spec leaves undefined, so nothing else can claim them.
- Press Enable MIDI once and allow the browser's MIDI prompt. The chosen input and channel are remembered, and the button becomes Rescan Devices for a controller plugged in later.
- Channel defaults to Omni. Set it when more than one thing is talking on the same port.
- Web MIDI needs Chrome, Edge or Firefox. Safari has none, so the section is shown but inert there.
- The levels are not mapped, and the SandboxFX pedal itself has no MIDI input - this drives the simulator only.
Using Libraries
Point the assembler at a folder of .fxl libraries with Editor Options - Select Library Folder, and any subroutine in them can be called from your source as @library.subroutine(arg, arg). There are three ways to write that call without having to remember its arguments:
- The Library Subroutines list - once a folder is loaded, this Options panel grows a list of every subroutine found, grouped by library, with a filter box above it. Click one and its call is pasted at the cursor with the argument names in place as editable placeholders; press Tab to step from one to the next.
- Editor completions - type
@ in the editor to be offered every subroutine, or @library. to narrow it to one library. The call arrives with the same placeholders.
- Hover - point at an existing
@library.subroutine call to see what it does and what each argument expects.
- The folder is rescanned whenever this window regains focus, so a
.fxl edited in another program is picked up without re-selecting it. The browser cannot remember the folder between sessions, so it has to be chosen again each time.
What do these Options do?
These are some settings that change various editor and hardware settings
Editor Options
- Select Library Folder: Load a folder of
.fxl libraries, and list their subroutines - see Using Libraries above
- Large editor window: Expands editor text area to show more instructions
- Show editor mini-map: Show a small navigation map in editor
- Show full build results: Show complete debug information in Build Results window
- Enable dark mode: Use dark colour theme, follows system theme
Hardware Options
- Select Hardware Mode: Toggles communication mode between USB-HID and USB Disk Mode
- File - Select Output Directory: Specify the folder location of your SandboxFX hardware (typically /SANDBOX-FX)
- File - Select Serial Port: Open SandboxFX serial port to allow hardware debugging information
- HID - FXCore address: Set I2C address of FXCore IC, defaults to 0x30
- Select Program Target: Press to select Run from RAM target or a program slot on SandboxFX hardware