termtab-0.1.0.0: TUI guitar tablature and score editor
Safe HaskellNone
LanguageGHC2021

Termtab.Audio.PlaybackThread

Description

Background-thread transport for playing back a whole Song with pause/resume/stop, driven from the UI without blocking it.

The design: startPlayback forks one "tick" thread that walks the song's measures/beats and sleeps between them; all coordination with that thread happens through the STM TVars in PlaybackEnv rather than by killing and restarting it on every command — pausePlayback, stopPlayback, and resumePlayback just post a PlaybackCommand that the tick thread notices between beats (see playMeasureBeats in the internals). startPlayback is the one exception: it kills any already-running tick thread before forking a new one, since "start" means "play from here," not "resume."

Synopsis

Documentation

data PlaybackCommand Source #

A message posted to peCommandVar for the running tick thread to act on at its next beat boundary. Distinct from AudioCommand — that type is for a queue-based design that isn't what this module implements; this one is consumed directly out of a single-slot TVar.

data PlaybackEnv Source #

Shared state between the caller (typically the UI) and the tick thread forked by startPlayback. All fields are TVars so both sides can read/write them without explicit locking.

Constructors

PlaybackEnv 

initPlaybackEnv :: AudioConfig -> IO () -> IO PlaybackEnv Source #

Start a FluidSynth AudioEngine with cfg and build a fresh, stopped PlaybackEnv around it. notify is stashed as peNotify and invoked by the tick thread on every position/status change — pass whatever hook wakes the UI's event loop (e.g. a Brick BChan write).

destroyPlaybackEnv :: PlaybackEnv -> IO () Source #

Kill any running tick thread and shut down the underlying AudioEngine. Call this once when playback is no longer needed at all (not for pausing — use pausePlayback for that).

startPlayback :: PlaybackEnv -> Song -> MeasureIndex -> IO () Source #

Kill any tick thread already running under env, then fork a fresh one (tickThread) that plays song starting at startMeasure from beat 0. Marks peStatusVar Playing immediately, without waiting for the new thread to actually begin.

pausePlayback :: PlaybackEnv -> IO () Source #

Ask the running tick thread to pause at its next beat boundary (silences all notes and records the current position; does not stop the thread). No-op if nothing is playing.

stopPlayback :: PlaybackEnv -> IO () Source #

Ask the running tick thread to stop at its next beat boundary (silences all notes and resets peStatusVar to Stopped). Unlike startPlayback, this does not kill the thread directly — it just posts the command and lets the thread exit on its own.

resumePlayback :: PlaybackEnv -> MeasureIndex -> IO () Source #

Resume a thread that is currently blocked waiting inside waitForResume after a pause, continuing from measure mi (in practice the measure it was paused at). Has no effect on a thread that isn't paused, since nothing is polling peCommandVar for a resume in that state.