Skip to content

Resources, images & sound

Name the thing you made. Let the runner decide how this machine should carry it.

This page is about the pictures, fonts and sounds a program ships with. After reading it you will know how to package a picture under a name, load it once and reuse it, pick a font by its job rather than its filename, play a simple tone, and stream recorded sound. You will also know what happens when a machine cannot show or play something as intended.

A picture is not a pointer. A sound is not a hardware register. In d/BASIC, a piece of media begins as a named resource inside the application package. The d/OS runtime, the program that runs your compiled code, turns that name into bytes it has checked, picks the richest form it can honestly show, and keeps the loaded form close to the screen or the sound hardware.

That is how one poster can be full colour in a browser, a limited palette on a classic display, and legible black and white on a one-bit screen, without three editions of the program.

Resources are package members

A resource name such as asset://dwrite/cover-1 names a member of the package. It is deliberately not:

  • a path on the developer's laptop;
  • a borrowed address in memory;
  • a web URL fetched behind the user's back; or
  • a native image, font or sound object hidden inside d/BASIC state.

The package ties the name to exact bytes, media metadata, a content digest and any alternative forms. The runtime checks that binding before the program can use the resource.

Here is an image reference owned by a document, using the standard media model from d/Works, the office suite being written in d/BASIC (d/Write, d/Calc, d/Present):

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. Keeping the two apart lets a document move or resize an image without pretending that a host path is part of the document.

The load-once rule

LOADRESOURCE is the runtime operation beneath a d/Works media object that owns the resource. The object supplies the name; the runtime attaches a lease, an opaque token for the loaded asset, to that object. Your d/BASIC code never declares, copies, inspects, serialises or stores the lease, and neither a TYPE nor a CLASS field can hide one.

Keep the owning object, such as WorksDocumentImage, alive for as long as you need the media. Its first load resolves the asset; later paints reuse it; setting the last owning reference to NOTHING, or closing the application, releases the host's copy. Do not build a fresh object on every DRAW. On a d/OS machine whose display is driven from a memory pool or from the cartridge that carries a modern processor into the 8-bit machine, the payoff is that a loaded asset never crosses the bus a second time; later frames send only a compact "this resource, at this rectangle" request.

The ways a load can fail are named:

Situation Result
the name is not in the package NotFound
the package bytes or digest are wrong Integrity
no available form can be shown faithfully on this route Unsupported
the resource store cannot be read Io

Required resources are checked before anything is drawn. A program does not paint half a screen and then discover the other half never existed.

Images: one identity, several honest forms

A package may carry several forms of one logical image:

Representation What it carries Natural home
Mono1 one bit per pixel black-and-white and memory-tight displays
Indexed4 packed 4-bit pixels plus a 16-entry RGB565 palette classic displays that use a palette
Rgb565 direct 16-bit colour compact colour displays
Rgb565A1 RGB565 plus one-bit transparency sprites and shaped artwork

The runtime picks the richest form the display supports, in the order Rgb565A1 → Rgb565 → Indexed4 → Mono1. Every form has the same logical size. If the route can scale, the default is to fit the image inside the requested rectangle keeping its proportions; if it cannot, the runtime centres the image at its natural size and clips the edges plainly.

Reducing colour is presentation, not application logic. A black-and-white route may use fixed brightness thresholds and patterns; a palette route may use the mapping it declares. Neither may change which image was asked for.

Packaged images versus caller pixels

These are related but different jobs:

  • a packaged resource is resolved once by name and stays on the display side; and
  • GFX.BLIT_RESOURCE draws a small bitmap supplied in a d/BASIC array, for generated pixels, small masks and test programs.

The raw form names every fact needed to read the array:

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 a stride of one byte. The unfortunate historical word "resource" in BLIT_RESOURCE does not make the caller's array a package asset. Use the package loader whenever the same art will appear again.

Fonts are resources with semantic jobs

d/BASIC text chooses a font role, a job description for the text, rather than a host font filename:

Role Meaning
0 UI
1 UI Small
2 Native Mono
3 UI Chrome

A rich runtime can turn those roles into real browser or desktop outline fonts, drawn at the display's density. A small one can fall back to its built-in bitmap face. The character advance, line box, clip and coverage rules stay the same, so swapping the rasterizer cannot move a text field's caret or change what the pointer hits.

The browser playground shows the rule in action: it substitutes browser fonts at high resolution, keeps Native Mono's exact 4-pixel advance, and fits the editable UI Chrome glyphs to the text field's declared 6-pixel cell grid. The reference UI Chrome bitmap itself is proportional; the editable control's cell grid is why its browser version 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, a frequency in hertz, a volume from 0 to 255, a waveform and a 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 holds the voice until NOTE_OFF, until another note replaces it, or until the application exits. A runtime offers up to four logical voices per application 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 one voice, or replace it in a single step
AUDIO.NOTE_OFF stop one voice
AUDIO.PROGRAM choose a named voice program
AUDIO.VOLUME change the level of one of this application's voices
AUDIO.SILENCE stop all sound owned by this application

PCM: stream with a clock

PCM is sampled sound: recorded effects, speech and music. Its lifecycle is deliberately explicit:

QUERY_CAPS → PCM_OPEN at an exact advertised rate → WRITE / prefill → START → STOP → CLOSE

PCM_OPEN takes a rate in hertz, not a sound-chip divisor. The route either honours exactly the rate it advertised or declines; it never quietly retunes the clip. PCM_WRITE may accept only part of what you offer, so keep the remainder and yield. PCM_STOP is safe to repeat and drops queued frames; PCM_CLOSE releases the stream. PCM_STATS reports starvation and staged-versus-read counters, so a glitch is something you can measure rather than folklore.

The feature query keeps each ability separate: simple tones, native-chip tones, bounded PCM, full-rate PCM, mixing, tones and PCM at the same time, a media clock, and capture. Code must not infer one from another.

How runners adapt media

Where it runs Honest upgrade or lowering
browser decode the checked image and audio bytes, use high-density outline fonts, present through the canvas and the browser's audio rules
Windows / Linux / macOS use native decoders, font rasterizers, mixers and GPU-backed presentation while keeping the logical metrics
a well-equipped d/OS machine keep assets on the display side and send compact draw or playback requests
a small d/OS machine choose a declared low-bit-depth image, the built-in font, a waveform, or a bounded PCM rate

Adapting to the machine can improve fidelity and capacity. It cannot borrow files lying around, substitute a different asset, quietly change a required sample rate, or claim something was shown or played before the display or audio route actually accepted it.

A practical media checklist

  1. Give every lasting asset a stable name.
  2. Package alternative forms under that name.
  3. Declare NEEDS GFX or NEEDS SOUND when the application cannot work without it.
  4. Query optional audio features instead of guessing from the platform name.
  5. Load reusable assets outside DRAW and reuse them.
  6. Keep document metadata (caption, alt text, crop, placement) separate from decoded bytes.
  7. Close streams and release owning objects on every normal, cancelled and declined path.

Next: Gaming & GX →