Resources, images & sound¶
Name the thing you made. Let the runner decide how this machine should carry it.
A picture is not a pointer. A sound is not a device register. In D/BASIC, media begins as a logical resource identity inside the application package. The runner resolves that identity to bytes it has validated, chooses the richest representation it can honestly present, and keeps the loaded form close to the renderer or audio device.
That is how the same poster can be true colour in a browser, indexed colour on a classic composed head, and legible monochrome on a one-bit display—without three editions of the program.
Resources are package members¶
A resource name such as asset://dwrite/cover-1 identifies a package member. It is deliberately not:
- a path on the developer's laptop;
- a borrowed address in process memory;
- a browser URL fetched behind the user's back; or
- a native image, font, or sound object smuggled into D/BASIC state.
The package binds the logical name to exact bytes, media metadata, a content digest, and any alternate representations. The runner validates that binding before the program can use it.
Here is a document-owned image reference using the standard D/Works media model:
IMPORT dworks.document_media
DIM Cover AS WorksDocumentImage
Cover = NEW WorksDocumentImage("image.cover.1", "Embedded image", "asset://dwrite/cover-1")
Cover.SetDocumentBounds 24, 32, 128, 72
PRINT Cover.Caption
PRINT Cover.AssetReference
END
StableId belongs to the document. AssetReference belongs to the package/resource boundary. Keeping those identities separate lets a document move or resize an image without pretending that a host path is document data.
The load-once rule¶
LOADRESOURCE is the runner operation beneath an owning D/Works media adapter. The adapter supplies the logical name; the runner associates an opaque lease with that adapter's app-owned identity. D/BASIC code never has to declare, copy, inspect, serialize, or persist the lease itself—and neither a TYPE nor a CLASS field can hide one.
Keep the source-facing adapter object, such as WorksDocumentImage, alive for as long as the media is useful. Its first load resolves the asset; later paints reuse it; assigning the last owning reference to NOTHING or closing the application releases the host state. Do not construct a fresh adapter on every DRAW turn. On a D/OS machine with a pool or cart-side compositor, the important result is that a loaded asset does not cross the bus again; later frames carry a compact resource-and-geometry request.
The failure cases are named:
| Situation | Result |
|---|---|
| logical name is absent | NotFound |
| package bytes or digest are wrong | Integrity |
| no representation can preserve the contract | Unsupported |
| the resource store cannot be read | Io |
Required resources are preflighted before visible output. A program does not draw half a screen and discover that its other half never existed.
Images: one identity, several honest forms¶
A package may carry multiple variants of one logical image:
| Representation | What it carries | Natural home |
|---|---|---|
Mono1 |
one bit per pixel | monochrome and memory-tight heads |
Indexed4 |
packed 4-bit pixels plus a 16-entry RGB565 palette | palette-oriented classic heads |
Rgb565 |
direct 16-bit colour | compact colour compositors |
Rgb565A1 |
RGB565 plus one-bit transparency | sprites and shaped artwork |
The runner chooses the richest compatible form in the order Rgb565A1 → Rgb565 → Indexed4 → Mono1. Every variant keeps the same logical geometry. If the route supports scaling, the default is aspect-fit inside the requested rectangle; if it does not, the runner centers the intrinsic image at 1:1 and clips honestly.
Colour lowering is presentation, not application logic. A monochrome route may use deterministic luma and pattern cues; an indexed route may choose its declared palette mapping. It may not reinterpret which image was requested.
Packaged images versus caller pixels¶
These are related but different jobs:
- a packaged resource is resolved once by logical identity and stays pool/renderer-side; and
GFX.BLIT_RESOURCEdraws a bounded raster supplied in a D/BASIC array for generated pixels, small masks, and conformance work.
The raw form names every fact needed to interpret the carrier:
DIM Checker%(0 TO 7)
Checker%(0) = 170
Checker%(1) = 85
Checker%(2) = 170
Checker%(3) = 85
Checker%(4) = 170
Checker%(5) = 85
Checker%(6) = 170
Checker%(7) = 85
' Pixels, x, y, width, height, format, stride, foreground, background
INTENT GFX.BLIT_RESOURCE(Checker%(), 24, 24, 8, 8, 0, 1, -1, 0)
END
That example uses format 0 (Mono1) and one byte of stride. The unfortunate historical word “resource” in BLIT_RESOURCE does not make the caller array a package asset. Use the package loader when the same art will appear again.
Fonts are resources with semantic jobs¶
D/BASIC text chooses a font role, not a host font filename:
| Role | Meaning |
|---|---|
0 |
UI |
1 |
UI Small |
2 |
Native Mono |
3 |
UI Chrome |
A rich runner can upgrade those roles to real browser or desktop outlines, rasterized at the display's density. A constrained runner can lower them to its hinted resident face. The advance, line box, clip, and coverage contract remain stable, so changing the rasterizer cannot move a text-field caret or alter hit testing.
The browser playground demonstrates this rule: it substitutes browser fonts at high resolution, preserves Native Mono's exact 4-pixel advance, and fits editable UI Chrome glyphs to the text field's declared 6-pixel cell grid. The canonical UI Chrome raster itself is proportional; the editable control's cell grid is the reason its browser lowering must keep caret and pointer geometry together.
Sound has two useful levels¶
Tones: say what should be heard¶
Tone events are tiny and wonderfully portable. A note names a logical voice, frequency in hertz, volume from 0 to 255, waveform, and duration in scheduler ticks:
APP "CHIME"
LABEL "Door Chime"
NEEDS SOUND
END APP
' Voice 0, A4, medium-loud, sine, thirty ticks.
INTENT AUDIO.NOTE_ON(0, 440, 192, 3, 30)
END
Waveforms are 0 Square, 1 Triangle, 2 Sawtooth, 3 Sine, and 4 Noise. A zero duration sustains the voice until NOTE_OFF, another note replaces it, or the application exits. A runner exposes up to four app-scoped logical voices and never lets one application silence another's.
The tone family is:
| Intent | Purpose |
|---|---|
AUDIO.QUERY_CAPS |
discover voices, waveforms, rates, latency, and feature limits |
AUDIO.NOTE_ON |
begin or atomically replace one voice |
AUDIO.NOTE_OFF |
stop one voice |
AUDIO.PROGRAM |
choose a semantic voice program |
AUDIO.VOLUME |
change an app-scoped voice level |
AUDIO.SILENCE |
stop all sound owned by this application |
PCM: stream with a clock¶
PCM is for recorded effects, speech, and music. Its lifecycle is intentionally explicit:
PCM_OPEN takes hertz, not a sound-chip divisor. The route either honors that exact advertised rate or refuses; it never silently retunes the clip. PCM_WRITE may accept only part of a carrier, so producers retain the remainder and yield. PCM_STOP is idempotent and drops queued frames; PCM_CLOSE releases the stream. PCM_STATS reports starvation and staged-versus-read counters so a glitch is observable rather than folklore.
The feature query keeps capabilities independent: semantic tones, native-chip tones, bounded PCM, full-rate PCM, mixing, simultaneous tones and PCM, a media clock, and capture. Code must not infer one from another.
How runners adapt media¶
| Runner | Honest upgrade or lowering |
|---|---|
| browser | decode validated image/audio bytes, use high-density outline fonts, present through canvas and browser audio policy |
| Windows / Linux / macOS | use native decoders, font rasterizers, mixers, and GPU-backed presentation while retaining logical metrics |
| rich D/OS route | keep assets pool/compositor-side and issue compact draw or playback requests |
| constrained D/OS route | select a declared low-bit-depth image, resident font, waveform, or bounded PCM rate |
Capability adaptation can improve fidelity and capacity. It cannot borrow ambient files, substitute a different logical asset, silently change a required sample rate, or claim completion before presentation/playback admission.
A practical media checklist¶
- Give every durable asset a stable logical identity.
- Package alternate representations under that identity.
- Declare
NEEDS GFXorNEEDS SOUNDwhen the application cannot function without it. - Query optional audio features instead of guessing from the platform name.
- Load reusable assets outside
DRAWand reuse them. - Keep document metadata—caption, alt text, crop, placement—separate from decoded bytes.
- Close streams and release owning adapters on every normal, cancelled, and refused path.
Next: Gaming & GX →