# Crash BASIC 1.47.0 — The "Ride the Wave" Release

Instruments just grew a third voice. Alongside the classic oscillator and sampled-WAV playback, a layer can now be a **wavetable** — a stack of single-cycle waveforms you sweep through to morph the tone. This is the real thing, not a gimmick: band-limited so it stays clean all the way up the keyboard, and it speaks the same format the rest of the industry does, so tables you already have drop straight in.

## Wavetable synthesis

A wavetable is a series of single-cycle "snapshots" of a waveform — a **morph position** picks where you sit in that stack, blending between neighbouring frames. Slide the position from one end to the other and the timbre transforms: hollow to bright, mellow to gnarly, sine to saw and everything between.

Add one to any instrument layer in its `.cbi` definition:

```json
"wavetable": {
  "source": { "wav": { "wavPath": "wt/mytable.wav" } },
  "position": 0.5
}
```

The layer's envelope, filter, LFOs, FM, volume, detune, octave and pan all still apply — a wavetable is just a new *sound source* under the same modulation shell you already know.

**It uses the format everyone else uses.** Wavetables are plain WAV files of single-cycle frames concatenated together — the Serum/Vital convention that Bitwig, Ableton Wavetable and the rest read and write. Frame size is auto-detected from the file's `clm ` chunk, so a table you download or export from another synth **just works** — no re-slicing, no guessing the frame length. (No chunk? It falls back to a sensible default and, failing that, tells you loudly instead of mangling the audio.)

**Bring your own.** Because it's the standard format, you're not starting from scratch: grab one of the many **free wavetable packs** floating around (search "free Serum wavetables"), pull from an open library like **WaveEdit Online** or the **Surge XT** collection, or export a table from any wavetable synth you already own. If it's a single-cycle-frame WAV, Crash BASIC loads it.

**It's alias-free.** Playing a single cycle at high pitch normally folds its upper harmonics back down as harsh digital "fizz" — the difference between a toy and a real synth. Crash BASIC builds band-limited versions of each table per octave and picks the right one for the note you're playing, crossfading between them so sweeps stay smooth. Your high notes stay clean.

**It plays everywhere.** Wavetables work in the live synth *and* in pre-rendered music (`PLAYMUSIC`), on native desktop/mobile **and** in the browser (WASM) — same tables, same sound, one shared engine. Nothing to special-case per platform.

## Notes

- Old instrument banks are untouched — the wavetable layer is purely additive; every existing `.cbi` loads and sounds exactly as before.
- Morph **position** is set per-instrument for now. Modulating it live from an envelope or LFO — for real-time sweeps mid-note — is on the way in a later release.

## Aseprite: pull layers out as separate sprites

`.ase` support gained a companion to last release's tags and slices: `LOADIMG … LAYERS(…)` composites **only the source layers you name** into the loaded image, so one multi-layer Aseprite file becomes several independent sprites. Draw a turret over its base, or a character with a detachable arm, in a single file — then load it once per piece:

```
LOADIMG "turret.ase", "BASE" LAYERS("turret_base")
LOADIMG "turret.ase", "HEAD" LAYERS("turret_head")
```

Now the head can rotate while the base stays put. Pick layers by name (case-insensitive) or by 0-based index, mixed freely — `LAYERS("Turret", 0)`. Blend modes, opacity and layer order are honored exactly as Aseprite renders them, and an explicitly named layer composites even if you've toggled its eye icon off. It composes with `TAG` (that tag's frames, only those layers), and a misspelled layer name fails loud with the list of what's actually in the file.

## Also in this release: faster, smoother, fewer surprises

Under the wavetables, this build carries a big performance-and-polish pass. No syntax changed and nothing was removed — update, and your existing games just run better.

**Everything runs smoother, especially on Windows.** Your program and the engine's behavior and pattern system run side by side, and they used to quietly get in each other's way every single frame — the more sprites and behaviors you had updating at once, the more they stalled one another. That's gone. Spawning and animating a crowd of sprites while patterns and behaviors tick no longer bogs down, and the difference is most dramatic on Windows, where the old slowdown hurt worst. Same game, same code, smoother frames. Windows also switched its default graphics backend to **Vulkan**, which handles the engine's many small per-frame GPU updates far better than the old DirectX 12 path — busy, particle-heavy scenes stay smooth even on modest, older Intel graphics.

**Pace your loops however you like.** `YIELD` holds about 60fps by default — enough of a breather that an unpaced game loop can't run away and swamp the graphics pipeline — and the new `SET YIELD <ms>` tunes that hand-off: `SET YIELD 1` frees the loop to run as fast as the machine allows once you're pacing your own rendering. For finer control, `COOLDOWN` now takes a resolution — `COOLDOWN 1, 240` runs its block at most once every 1/240 second — so you can gate expensive work to an exact rate instead of only whole 1/60-second ticks.

**Smoother in the browser, too.** The WebAssembly build could flood its own renderer with draw commands and stutter under heavy load; draws are now grouped into each frame, so scrolling and busy scenes stay smooth in the browser the same way they do natively.

**Rock-solid on phones and tablets.** Busy mobile scenes — scrolling layers with a screen full of sprites and particles — now stay smooth and steady no matter how long you play. The renderer paces itself to the display and reuses its GPU work frame to frame instead of rebuilding it every time, so motion is fluid and memory holds flat even on modest hardware.

**Intro and splash videos behave.** `WAITVIDEO` now actually waits. Before, a video — especially a splash clip handing off to a second one, like splash → title — could come up as a black screen and crawl until it finished, or jump ahead before it was done. Back-to-back videos now transition cleanly, and playback pacing is fixed on Windows.

**Sprites from `ENABLE SPRITE` land on the right layer.** A sprite first brought to life with `ENABLE SPRITE` used to default onto layer 0. If something was happening on layer 0 — say a `CLS … EFFECT(DISSOLVE)` — your new sprite would quietly land *on* it and composite against it. The classic symptom: a solid block of the transition color showing through the transparent background of a `TEXTTOIMAGE` announcement. `ENABLE SPRITE` now places the sprite on your current layer, right where you'd expect — and an explicit `SET SPRITE … LAYER` still wins.

**Load a sound once, keep it loaded.** `LOADWAV` and `LOADMP3` are now one-way trips: loading the same clip again — say, a `LOADWAV` that slipped into a game loop — is a no-op instead of decoding a fresh copy every time, so a stray repeat load can't quietly pile up memory.

**Shader swizzles don't care about case.** Texture-coordinate swizzles like `UV.xy`, `UV.YX`, and `.uv` now work no matter how you capitalize them.

---

*Ten octaves of alias-free harmonics and the first thing I tested it on was a saw growl. Priorities. — Crash-tan*
