Failure Cases and Shipping Checklist
1. Common failure cases
| Failure | Cause | Fix |
|---|---|---|
| Null active buffer | No active document | Guard ActiveDocument/Buffer before edit operations. |
| Cross-thread UI exception | Worker thread touching controls | Use InvokeRequired + BeginInvoke. |
| UI stalls while dragging graph | DSP on drag events | Move processing to PointsEditCommitted. |
| Preview keeps playing after close | No explicit stop on close/unload | Always send stop with same PreviewOwnerId. |
| Wrong document modified | Active doc changed during dialogue | Capture document id at open, re-check before commit. |
| Presets feel inconsistent | Plugin-specific ad-hoc persistence | Use IPresetStore for all plugin presets. |
1.1 Fix pattern: UI thread marshal
private void OnPlaybackStateChanged(object? sender, PlaybackState state)
{
if (_statusLabel is null) return;
if (_statusLabel.InvokeRequired)
{
_statusLabel.BeginInvoke(new Action(() => OnPlaybackStateChanged(sender, state)));
return;
}
_statusLabel.Text = state.IsPlaying
? $\"Playing @ {state.CurrentFrame}\"
: \"Stopped\";
}
1.2 Fix pattern: safe preview stop on close/unload
private const string PreviewOwnerId = \"my-plugin.preview\";
private void StopPreview()
{
_context.AudioSystemBus.RequestPlayback(new PlaybackCommand(
PlaybackCommandType.Stop,
PreviewOwnerId: PreviewOwnerId));
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
StopPreview();
base.OnFormClosing(e);
}
public void OnUnload()
{
StopPreview();
// unsubscribe handlers here
}
2. Document edit invariants
- Use frame ranges with
endExclusive. - For channel-scoped operations, use effective-range methods or channel-specific replace APIs.
- All mutation should flow through
IDocumentService. - Set an action label when mutating buffer to support history clarity.
3. Preview lifecycle checklist
- Capture start/end and source buffer once per dialogue open.
- Create preview session.
- Apply preview buffer to session as settings change.
- Play preview with stable owner id.
- On Apply: commit session, stop preview playback.
- On Cancel/Close: cancel session, stop preview playback.
- On plugin unload: stop preview playback and detach event handlers.
4. Menu and pane consistency rules
- Main menu entries go through
AddMenuContribution. - Context menu entries go through
AddContextMenuContribution. - View/Show actions for panes should use consistent grouping.
- Use sort values intentionally (root order and group order).
5. Shipping checklist
- Manifest correct (
assembly,entryType, id/version). - Plugin loads and unloads cleanly.
- No leaked event handlers.
- No cross-thread UI warnings.
- Preview, apply, cancel all tested.
- Preset load/save/delete/last-used tested.
- Menu enabled/disabled predicates tested.
- Large-buffer operation tested for responsiveness.