Native App Model
Properties
Off by default. Applies to instances registered afterwards; existing devices are unchanged.
AppModel's own blocklist — the list the Plugin Selector shows. A standalone ScanTool keeps a separate one. BlocklistEntry.timestamp in uapmd has no counterpart in uapmd_blocklist_entry_t, so it is not carried across.
UMP devices the model has instantiated.
AppModel::documentProvider(), which addins pick and read documents through.
Also reports busy while an asynchronous plug-in mutation is still capturing state, so shortcuts cannot race the capture.
Turning this off is not a plain stopAudio(): the model stops the transport, mutes the output, lets release/reverb tails drain inaudibly, then deactivates plugins on the main thread and resets processing state, so a restart cannot resume stale voices.
AppModel::jsfxPluginFormat(); null when the build has no JSFX.
The last scanning error, or null.
Empty when the last clipboard call succeeded.
Reading counterpart to ProjectCommands.setMasterTrackMarkers.
The project's tempo curve, as the engine derived it from the master track. Read this rather than assembling one from the master tempo points, so that display and playback can never be working from different maps.
AppModel::pluginScanTool(). Borrowed: the model owns it, and closing it does nothing.
Owned by the model; do not close.
AppModel::showVirtualMidiDevices: invoked on the model thread when the addin's command asks the host to toggle its window. Set it before the addin initializes, and clear it (null) before the host goes away.
Progress of the slow scan. isScanning alone cannot tell a long scan from a stuck one, which is why uapmd-app's selector shows these.
The span the timeline's content actually occupies.
True while the Virtual MIDI Devices addin is active.
Functions
AppModel::addClipToTrack. Ownership of reader transfers to the engine, so do not close it afterwards - a successful call consumes it, and a failed one reports reader not found or already consumed if the same reader is offered twice.
AppModel::addDeviceInputToTrack, returning the new source node id, or a negative value on failure. The undoable counterpart is ProjectCommands.addDeviceInputToTrack, which takes the node id this returns; prefer that one from a UI.
AppModel::addMidiClipFromData, for a clip built in memory rather than read from a file - what a generator or a step sequencer produces.
AppModel::addMidiClipToTrack, reading an SMF or SMF2 from disk.
False leaves the reason in lastTimelineClipError.
Creates an empty MIDI 2.0 clip; tickResolution is ticks per quarter.
Instantiates pluginId and attaches it to trackIndex; a negative index creates a new track. The callback runs once, on the thread that finishes instantiation.
cut copies the selection before deleting it.
The device hosting a plug-in instance, or null when it has none.
Registers the instance as a virtual MIDI 2.0 device where the platform supports it. Fails while the Virtual MIDI Devices addin is not active (see registerVirtualMidiDevicesAddin).
Switches the track from the simple linear chain to the editable graph.
Reading counterpart to ProjectCommands.setClipMarkers/setClipAudioWarps.
A hidden track is skipped by paste and by the track list, but still plays.
Plug-in state to and from a file. Prefer these over the *Sync variants: a plug-in's state can be slow to produce, and on Android reading it from the main thread can deadlock.
The blocking variants, for tools and tests that have no loop to post a completion to. See the warning on loadPluginState.
Android's document-picker path: resolves a content:// handle token.
Marks the track owning this instance dirty, so the next save rewrites it.
Discards the current project and starts an empty one. Asks nothing and always replaces: whether unsaved changes may be discarded is the caller's decision. Unlike TimelineFacade.newProject this also tears down what the outgoing project instantiated and rebuilds the model's view of the result.
Startup lifecycle; uapmd-app calls both once the UI exists.
Owned by the model and shared between callers; do not close.
Runs asynchronously; watch isScanning. ScanMode.Remote launches a separate scanner process on desktop and is unavailable on WebAssembly.
The caller owns the snapshot and must close it.
Commit-source tracking.
AppModel::refreshFastScannedPlugins(): rebuilds the catalog entries of the formats that scan by reading files rather than loading them (JSFX among them), re-reading registered JSFX folders first. It is what a change to where those formats look needs. completed runs on the main thread once the catalog is rebuilt, with why re-reading a registered folder failed, or null.
Master-track tempo map. getTimelineState().tempo is a single value and cannot describe a project whose tempo changes; a beats view needs these. Rebuild once with refreshMasterTempoMap, then read the lists — they stay valid until the next refresh.
Asks the host to bring up this track's graph editor.
The MIDI clip an editor is open on, tracked separately from the selection.
Writes the master markers and reports why a rejected set was rejected, which ProjectCommands.setMasterTrackMarkers reduces to a boolean. This path is not undoable.
False when a render is already running or the settings are unusable.
AppModel::stopPluginScanning(): cancels a scan in progress and waits for its worker to finish, running queued main-thread tasks meanwhile. Call on the main thread before tearing down anything the scan's completion callbacks reach; cleanupAppModel does it as a last resort.
AppModel::syncJsfxRegisteredFolders(): re-reads every registered JSFX folder and rebuilds its mirror. completed runs on the main thread, with the number of files written and the first error, or null. It completes at once when no folder is registered, or without JSFX.
Which tracks a paste would land on, without performing it. originalTracks pastes each clip back onto the track it came from instead of onto trackIndex.