-
Notifications
You must be signed in to change notification settings - Fork 0
Drawn Waveform
Drawn is each patch's editable 512-internal-cycle-sample waveform. It is deliberately open-ended: you can draw it, import audio, copy an FWG source, hand-edit a short JSON recipe, machine-generate 512 arbitrary samples, or use a compact construction and then transform the completed waveform.
A mathematical recipe is a shortcut for getting to a waveform. It is not a restriction on what Drawn may eventually contain.
- New to Drawn? Start with What Drawn is for, First hands-on use, and the hand-editing mini-tutorial.
- Want classic shapes, slew, Cardinal, Fourier, Haar, Walsh, and listening experiments? See Drawn Wave-Shape Recipes.
- Want every valid mode/parameter, selector domain, formula, numerical rule, and comparison table? See Drawn Mathematical Reference.
- Want sidecar/import/export details? See Saving, Loading, and JSON Sidecars.
Drawn has three overlapping identities.
- A waveform or control shape. At runtime it is a table of 512 internal cycle samples, each represented as a 32-bit floating-point (Float32) amplitude value.
-
A compact construction system. A few explicit values plus
steps,linear,pow,pow-symmetric,superellipse, neighbour-awarecardinal/cardinal-limit/cardinal-clip, or periodicfourierreconstruction can generate useful complete shapes without spelling out all 512 values. - An exploration space. Draw something, import browser-decodable audio, hand-edit a mini-sequence, machine-generate 512 arbitrary values, bend only part of a transition, feed an FWG render back into Drawn, or use one result as the starting point for another. FWG does not require a waveform to be tidy, canonical, or mathematically pure before it can be interesting.
Those identities are useful because the same Drawn shape can participate in FWG in several different ways:
- As audio: route Drawn to Input 1 or Input 2 and hear it directly.
- As a Wavetable Type input: route Drawn on one input and another source on the other, then let a two-input Wavetable Type (WT) splice, multiply, compare, fold, select, or otherwise combine them.
- As the LFO for a Scanning generator: the endpoint's Drawn shape becomes the low-frequency oscillator (LFO) that drives the Scanning trajectory.
- As part of START or END: Morph START and END can carry different Drawn states. Any of the uses above can therefore become part of a larger START→END Morph rather than remaining an isolated Drawn sound.
A mathematical construction is only a shortcut for getting to a waveform. It is not a restriction on what Drawn may eventually contain. Once you want to depart from the formula, Drawn remains editable sample data.
You can populate or replace Drawn by:
- drawing/editing it in FWG;
- importing a standalone Drawn
.json/.json.gz; - importing a WAV or another audio file your browser can decode;
- copying/populating it from Input 1 where that workflow is offered;
- creating a hand-written or machine-generated numeric sequence;
- importing a compact mathematical construction;
- exporting audio from FWG and importing that audio back into Drawn.
That last route creates a useful feedback loop:
FWG patch → rendered audio → Import Drawn… → new 512-internal-cycle-sample Drawn shape → edit/reuse → new FWG patch
The imported result may be simple, noisy, repetitive, awkward, unexpectedly musical, or apparently useless until another operation changes its role. Exploration is part of the point.
🎹 A quick way to understand Drawn is to use one shape in more than one role.
- In Playground, open Drawn Waveform and make an obvious custom shape.
- Route Drawn to Input 1 with Wavetable Type = 0 – Input 1 and audition it as the oscillator source.
- Put another source on Input 2 and choose a two-input Wavetable Type. Listen to the same Drawn shape as one ingredient in a source interaction.
- Choose a Scanning generator. The endpoint's Drawn table can now control the Scanning LFO, whether or not Drawn is also routed as audio.
- Copy the endpoint to Morph START and END, change Drawn in only one endpoint, and audition START, END, then the Morph.
The Drawn summary tells you when it is audio-routed, being used as an LFO shape, or both. “Not audio-routed” does not mean dormant when another part of the endpoint is consuming Drawn.
This tutorial starts from FWG itself, so you do not have to guess what a Drawn file is supposed to look like.
In Playground or either Morph endpoint:
- Open Drawn Waveform.
- Change the default sine into any obviously non-default shape. Drag a few points, use Clear, or import any browser-decodable audio. The exact shape does not matter; you are only making a recognisable template.
- Press Export Drawn. FWG downloads a standalone Drawn
.json.gz. - Decompress the
.json.gzwith your normal archive utility. Rename the resulting file to something useful such asdrawn-eight-steps.json. - Open that
.jsonfile in a plain-text editor.
Import Drawn… accepts uncompressed .json, so you do not need to recompress the file while experimenting.
The exported file contains metadata and 512 literal Float32 values. For this tutorial, the part you are going to replace is just the Drawn record. Conceptually, these are the important lines:
"drawn_waveform": {
"data": [0.75, -0.25, 0.50, -0.75, 1.00, 0.00, -0.50, 0.25],
"resample_mode": "steps",
"wrap": true
}You may leave the rest of the exported template in place and replace its drawn_waveform object with that one.
Or, to see how little FWG actually requires, replace the whole file with this minimal standalone Drawn JSON:
{
"schema_version": 13,
"document_kind": "drawn_waveform",
"drawn_waveform": {
"data": [0.75, -0.25, 0.50, -0.75, 1.00, 0.00, -0.50, 0.25],
"resample_mode": "steps",
"wrap": true
}
}Save the file.
Press Import Drawn… and choose drawn-eight-steps.json.
With steps, the eight explicit amplitudes become an eight-step contour. Steps is intrinsically cyclic, so the example says wrap:true explicitly:
Now listen to the same Drawn data in two different roles.
As audio:
- Route Drawn to Input 1.
- Choose Wavetable Type 0 – Input 1.
- Audition the endpoint.
As a Scanning LFO:
- Choose any Scanning – … generator.
- Keep the same Drawn waveform.
- Adjust LFO Rate so you can clearly hear the pattern moving through the generator.
- Adjust LFO Depth from shallow to deep.
- Move Scan Centre and notice that the same LFO shape explores a different part of the underlying generator.
The same eight values can therefore be directly audible waveform material or a control trajectory. A change that seems minor in one role can be much more obvious in the other.
This tutorial becomes easier to hear when START and END are treated as two comparison slots.
- Put the same basic patch in START and END. Copy → Both from Playground is a quick way to begin with identical endpoints.
- Press
3to collapse MORPH / EXPORT. The third panel is not needed while you are comparing Drawn constructions. - Import one Drawn JSON into START and another into END.
- Press
Sto audition START andEto audition END. Switch between them as often as necessary;ESCstops the current audition.
Keep the generator, routing, Scanning recipe, LFO Rate, and LFO Depth identical when you want to compare only the Drawn shape. Then deliberately vary Rate or Depth after you understand the shape difference.
Save each hand-edited variant under a new filename. For example:
drawn-eight-steps.json
drawn-eight-steps-linear.json
drawn-eight-steps-rounded.json
drawn-eight-steps-late.json
drawn-eight-steps-early.json
That gives you a tiny file-based library you can load into START and END for fast S / E comparisons.
steps deliberately has no rounded edge: each value is simply held until the next step.
To make a plateau and a short transition, first repeat each logical step several times, then change the interpolation mode. Identical neighbouring anchors remain flat; only the interval whose value changes becomes a transition.
Edit the Drawn record to use four copies of each logical level:
"data": [
0.75, 0.75, 0.75, 0.75,
-0.25, -0.25, -0.25, -0.25,
0.50, 0.50, 0.50, 0.50,
-0.75, -0.75, -0.75, -0.75,
1.00, 1.00, 1.00, 1.00,
0.00, 0.00, 0.00, 0.00,
-0.50, -0.50, -0.50, -0.50,
0.25, 0.25, 0.25, 0.25
],
"resample_mode": "linear",
"wrap": trueSave that as drawn-eight-steps-linear.json, import it into one endpoint, and compare it with the hard-step version in the other.
The first three quarters of each logical step are flat. The last quarter moves toward the next level.
Leave the 32-value data array unchanged and edit only:
"resample_mode": "pow-symmetric=2"Save as drawn-eight-steps-rounded.json, import it, then press S / E to compare it with the straight-transition version.
The plateau length has not changed. Only the geometry of the short edge has changed.
Listen again both ways: as direct audio, and as a Scanning LFO. Then vary LFO Rate and Depth. Rounding a corner can be a small drawing change and a large sound-design change.
With the same 32 anchors, try:
"resample_mode": "pow=4"and:
"resample_mode": "pow=-4"Positive pow stays near the old level longer and makes more of its move late in the interval. Negative pow moves away earlier and settles toward the new level.
pow=4 example · pow=-4 example
A/B them in START and END. Then ask what happens with pow=2, pow=8, pow=-2, or pow=-8. The parameter is not a list of presets; it is a continuum to explore.
To give the transition more of each logical step, use only two copies of each logical value and keep a curved interpolation mode such as pow-symmetric=2:
"data": [
0.75, 0.75,
-0.25, -0.25,
0.50, 0.50,
-0.75, -0.75,
1.00, 1.00,
0.00, 0.00,
-0.50, -0.50,
0.25, 0.25
],
"resample_mode": "pow-symmetric=2",
"wrap": trueNow about half of each logical step is a plateau and half is a rounded transition:
This is different from merely switching away from steps: the repeated anchors determine how much time is held flat; the reconstruction function determines how the changing interval is shaped.
Interpolation only decides what happens between explicit anchors. If you want a midpoint spike, dip, accent, plateau, asymmetry, or irregularity, add or edit anchors directly:
At this point you are no longer merely choosing among interpolation functions. You are composing the control/waveform data itself.
That is the larger lesson behind the tutorial: formulaic recipes are shortcuts. You are always free to hand-edit or machine-generate the eventual 512-internal-cycle-sample Float32 waveform however you like. Put related versions in START and END; use them as audio, Scanning LFOs, or Wavetable Type inputs; feed results back into Drawn; and keep asking what another small change does.
So far the tutorial has changed stage-1 construction: the authored values stayed recognisable while steps, Linear, and Power-family curves decided how the complete waveform was built. A transform asks a different question after that waveform already exists.
Take one of the rounded versions and add one transform field after wrap:
"resample_mode": "pow-symmetric=2",
"wrap": true,
"transform": "haar=:4"Now compare the same stage-1 construction with:
fourier=:8
haar=:4
walsh=16:
Then try component inversion without changing the source construction:
fourier=:8,-3
haar=:5,-5
walsh=:80,-37
The useful A/B discipline is the same as before: hold data, resample_mode, and wrap fixed, change only transform, and listen. The transform always receives the already completed canonical 512-internal-cycle-sample Float32 stage-1 waveform.
resample_mode answers roughly:
Given these authored points, what completed waveform do they describe?
transform answers roughly:
Given this complete 512-sample waveform, which basis components should rebuild it?
Current stage-1 construction includes local interpolation/shape modes, the Cardinal family, Steps, and Fourier. The v3 stage-2 transform collection is Fourier, Haar, and Walsh-Hadamard.
Fourier is intentionally unusual: it works both as a sparse stage-1 construction rule and as a stage-2 transform. Haar and Walsh are transform-only.
See Drawn Mathematical Reference for the complete mode list, selector grammar, component domains, inversion behavior, Haar alignment sensitivity, Walsh sequency, and -clip behavior.
Drawn keeps one saved waveform authority at a time.
While a construction pipeline remains pristine, a full schema-13 sidecar may retain the recipe fields:
data
resample_mode
wrap (where applicable)
transform (where present)
normalise (when true)
The runtime 512-sample table is derived from that recipe.
On the first ordinary Drawn canvas edit, FWG clears the complete construction pipeline authority. The current literal 512-sample Float32 table then becomes the saved waveform authority instead.
Standalone Export Drawn always flattens the current result to 512 literal editable internal cycle samples. It does not retain active transform or normalise instructions that could run again on re-import.
The Drawn module uses one Import Drawn… control for both browser-decodable audio and standalone FWG Drawn .json / .json.gz files. Export Drawn writes only the current Drawn waveform; it does not replace or export Morph/render state.
A full schema-13 sidecar may retain a pristine construction pipeline. Standalone Export Drawn is deliberately different: it flattens the current result to the literal editable 512-sample Drawn table, so re-import cannot accidentally run a retained transform or normalise:true a second time. Current numeric exports do not need a redundant numeric-array format label.
A minimal hand-authored open ramp is therefore simply:
{
"schema_version": 13,
"document_kind": "drawn_waveform",
"drawn_waveform": {
"data": [1, -1],
"resample_mode": "linear"
}
}Change only linear to steps and the same two values become two held states. Add wrap:true to a topology-sensitive local construction when you want the final authored point to connect back to the first. Add transform only when you want to analyse/rebuild the completed stage-1 waveform; add normalise:true only when you want final uniform peak gain.
Importing a standalone Drawn JSON file replaces that patch's Drawn waveform state. It does not replace generator, routing, Morph, render, or Scanning-recipe state.
Import Drawn… is not WAV-only. It can accept a WAV or another audio file that the current browser can decode.
One especially useful FWG-native experiment is to render something in FWG and feed the result back into Drawn. The example below comes from a real FWG render that was imported as audio and then exported as a literal Drawn waveform:
Standalone Drawn JSON derived from the real import
It is not a clean textbook waveform, and that is part of its value as an example. Long rendered audio can collapse into plateaus, dense oscillatory regions, abrupt transitions, ramps, noise-like detail, or other unexpected 512-internal-cycle-sample structures. Try the result as audio, as a Scanning LFO, as one Wavetable Type input against another source, or as one side of a Morph. Then edit it.
🔧 When Import Drawn… receives browser-decodable audio, FWG intentionally performs a different operation from JSON sequence reduction.
It takes 512 evenly spaced positions across the complete decoded duration, linearly interpolates between neighbouring decoded samples at each position, averages the channels at that position, and writes those 512 values.
So audio import is not:
- chopping the file into 512 blocks and averaging each block;
- an anti-aliased mastering-quality downsampler;
- a slice selector.
This point-sampled behaviour is deliberate sound-design contour extraction. Proper low-pass/block-average reduction of several seconds of ordinary zero-centred audio could erase much of the bipolar high-frequency structure that makes long audio interesting as a Drawn source. Edit or trim the source beforehand when only one region should be represented.
Imported audio sets the retained Drawn authoring hint to linear.
Audio-to-Drawn is intentionally bounded because the result is always only 512 internal cycle samples. FWG rejects a selected file above 8 MiB before reading or decoding it. After browser decoding, it rejects more than:
- 8 channels;
- 48,000,000 decoded PCM sample frames;
- 10 minutes duration;
- 256 MiB of projected Float32 PCM work.
The decoded checks occur before channel views are collected for sampling. They bound FWG's work after decoding, but they cannot prevent allocation or CPU use inside the browser decoder itself. A highly compressed file below 8 MiB can expand substantially while decodeAudioData() is running and only then be rejected by the duration, channel, decoded-PCM-sample-frame, or projected-PCM limit.
A newer import supersedes an older pending import, and Reset, JSON replacement, or another patch replacement invalidates an in-progress decode so it cannot report success against stale state.
drawn_waveform reference is missing from the top-level registry, its record is malformed, or its numeric data/mode cannot be decoded, FWG aborts the import visibly. A schema-13 endpoint whose effective routing or Scanning wrapper actually consumes Drawn must also contain a valid drawn_waveform dependency. Omitting the field is not permission to inherit the default sine.
An unused source selector may still say DRAWN without creating a false requirement when the selected Wavetable Type does not consume that input; dependency follows effective routing.
FWG does not silently substitute the built-in sine. This is intentionally stricter than internal live-state safety fallback: internal canonicalisation may keep application-owned state render-safe, but imported authoritative dependencies must reconstruct as claimed or fail.
The same principle applies to explicit current custom Scanning recipe dependencies; see Scanning Recipes.
🎹 Copying Input 1 to Drawn captures the currently generated Input 1 source as literal editable samples and resets the retained authoring hint to linear.
When Input 1 is a generated tap, the Drawn record may preserve six fields describing the population event:
engine_familyengine_variantpot1pot2pot3tap
The FWG version identifies the generator implementation.
🔧 A Drawn table may hold only one of:
initialised_from_file
initialised_from_input_1
Rules:
- importing a file sets
initialised_from_fileand removes the Input 1 record; - copying generated Input 1 sets
initialised_from_input_1and removes the file record; - a later population event replaces either older record;
- Reset to Sine clears the record and returns
resample_modetolinear; - subsequent hand drawing or other edits leave the population record unchanged.
The metadata records how Drawn was most recently populated. It is not an edit history and does not claim that the current waveform still matches that source. Waveform authority is separate: a pristine retained construction is authoritative while it exists; after editing/flattening, the literal Drawn table is authoritative; an exact canonical sine with no retained construction may use the compact built-in representation.
🎹 The Drawn canvas represents the literal editable 512-internal-cycle-sample domain. Unlike generated oscillator previews, it does not add a duplicate closure point after internal cycle sample 512. The editor uses a display-size/device-pixel-ratio backing canvas so enlarging it remains sharp without changing the stored waveform.
A seam, jump, flat section, offset, or impulse is part of the data. Downstream Wavetable Types, windows, modulation, filtering, and export cleanup can transform it, but the source itself is not silently repaired.
Hand editing a literal 512-internal-cycle-sample Drawn table does not need to change its retained resample_mode; the mode matters only if a later JSON editor changes the number of supplied values.
🎹 Silence and DC are valid Drawn data. FWG does not “repair” them in stored Drawn state.
🔧 A later structural audio-output stage still invokes Table Safety when the routed result lacks meaningful AC. Pointer drawing is a continuous edit, so the live preview/audition may temporarily reuse that endpoint's one bounded previous-valid table if the gesture crosses or ends on a collapsed state. Whole-table Drawn actions — Copy Input 1 Source → Drawn, Reset to Sine, Clear, Undo, and a completed Import Drawn… — are structural replacements: they clear the old live standby before the new Drawn source is evaluated. An invalid whole-table replacement therefore uses the safety square rather than borrowing the old Drawn output. During a Scanning/Morph audition or render, each structural owner likewise uses its previous valid table when one exists, otherwise the safety square. This is a runtime safety decision, not a rewrite of the stored Drawn source.
🔧 Public v2.9c/schema-12 Drawn data used the old 256-internal-cycle-sample periodic domain. v3 treats that as a historical sampled wavetable, not as a new schema-13 control-point recipe.
Its 256 points are therefore migrated to 512 with cyclic linear interpolation. Every old sample is preserved exactly at an even destination index, with one interpolated sample inserted between neighbours, including across the old periodic seam.
There is no universally correct migration for every discontinuous/square-like legacy table; zero-order hold would preserve hard edges better, while interpolation better preserves the sampled periodic trajectory. The cyclic rule is the defined compatibility choice. It does not change the schema-13 meaning of [1, -1].
Older 0–256 window data is separately migrated to the current inclusive 1–512 position model using its declared control range.
🎹 Good uses include:
- imported acoustic or synthetic contours;
- deliberate discontinuities;
- impulses and sparse patterns;
- asymmetric or DC-offset source experiments;
- hand- or machine-authored
linearLFO trajectories; -
stepsmini-sequences and stepped modulation; - hand-designed modulation sources for START-mod-END;
- copying a generated source into a literal editable table.
🎹 Drawn can act as the Drawn LFO contour formed from 512 internal cycle samples for generator-control automation. The wrapper reads the current contour value at the current LFO phase; the ordinary base generator receives only the resulting current three-pot coordinate.
🔧 A standalone reusable Scanning recipe deliberately does not include Drawn waveform data. Drawn belongs to endpoint patch state. Drawn-bearing Morph/Explorer/result JSON preserves custom Drawn separately whether active or dormant, so a Scanning sound can be reconstructed later.
Explorer START and END have compact read-only Drawn previews and can copy a snapshot from Playground, Morph START or Morph END. The snapshot includes the literal table and retained Drawn authoring/provenance metadata.
See Scanning Recipes and Scanning Generator Wrapper Architecture.
🔧 Drawn samples participate in Morph PCM cache identity only when the active route or Scanning wrapper consumes Drawn. Editing an unrouted Drawn table therefore preserves matching cached audio.
resample_mode is even more deliberately excluded from PCM cache identity: once Drawn has been mapped into its 512 literal samples, changing the retained future-editing hint cannot change the currently rendered sound, even when Drawn is audible.
A direct literal Drawn route bypasses ordinary generator construction, so generator family, variant, pots, tap, and generator-only settings can be dormant for that endpoint. Combined Wavetable-Type paths and Scanning can still use generator/finalisation settings; cache dependency follows the actual route rather than a blanket “Drawn means generator irrelevant” rule.
The complete custom Drawn state remains stored in patch state and Drawn-bearing JSON even when dormant.
A mathematically valid Drawn recipe is not automatically appropriate for every audible generated-table context. Drawn legality answers whether the requested waveform can become finite bounded current Drawn state. Existing Loop Safety and Table Safety separately decides whether a completed audible table is structurally usable downstream.
Transform legality does not bypass Table Safety.
Documentation rule: The executable code is authoritative. This Wiki describes the supported Fractured Wavetable Generator v3.0 contract and workflows.
- Generator Families
- Classic Waveforms
- Classic Split
- Drawn Waveform
- Drawn Wave-Shape Recipes
- Source Taps and Routing
- Wavetable Types
- Modulation and Filter
- Pitch, MIDI, and Pitch Offset
- Source and Result Windows
- Visualisers
- Morph Render Modes
- Morph Curve and Cycle Stepping
- Phase-Coherent Mode
- Loop Safety and Table Safety
- Creating Wavetables
- Creating Samples, Drones, Hits, Transitions, and Multisamples
- MPC Wavetable Mode
- Installing and Auditioning on MPC
- Render and Export Settings
- Auditioning, Curation, and Building a Personal Library
- Saving, Loading, and JSON Sidecars
- Sharing and Cleaning JSON Sidecars
- Randomisation and Seeds
- Keyboard Shortcuts
- Browser Requirements and Performance
- Troubleshooting
- FAQ
- Glossary
- Compatibility and Versioning
- Version 3 Release Notes
- Drawn Mathematical Reference
- Signal Path and Core Concepts
- Meditations on the 512-Sample Core
- Scanning Generator Wrapper Architecture
- Deterministic Randomisation — Technical Reference
- Render Diagnostics and Support
- Proof of Zero Prior-Work Knowledge and Forensic Evidence
- Authenticating and Timestamping FWG Outputs
- License, Provenance, and Outputs







