Skip to content

stmevent

Reads the event history of a runner, one event per call.

Unlike stmonenter and stmonexit, which only see the latest transition, stmevent returns every event in order and reports when some were lost.

Syntax

kkind, kseq, koverflow, kavailable, kfrom, kto = stmevent(irunner)
kkind, kseq, koverflow, kavailable, kfrom, kto stmevent irunner

Initialization

irunner -- a runner handle, returned by stminstance.

Performance

kavailable -- 1 if an unread event was returned, 0 if there was none. When it is 0, kkind, kseq, kfrom and kto keep their previous values.

kkind -- the kind of event:

Kind Event
1 Transition to another node
2 Self transition
3 Reset to the entry node
4 Recall of a saved state
5 Pause
6 Resume
7 Delete

kseq -- the sequence number of the event. The first event of a runner is 1, and each following event adds 1.

kfrom, kto -- the ids of the node before and after the event. For pause, resume and delete they are both the current node.

koverflow -- 1 if events were lost before this one, 0 otherwise.

Each opcode instance has its own read position, so several observers can read the same history independently. Reading starts with the first event after the opcode was initialized. Each call returns one event, so read in a loop to get all the events of a control period, as in the example below.

A runner keeps its last 10 events. If more than 10 happen between two reads, the oldest are lost: the next call sets koverflow to 1 and continues from the oldest event still kept.

This opcode only reads the runner. Any number of instruments can use it at the same time.

Examples

One instrument drives a runner through transitions, a pause, a resume and a deletion. A second instrument watches it with stmonenter, stmonexit and stmevent. It uses the file stm-events.csd.

Watching transitions and events.
<CsoundSynthesizer>
<CsOptions>
-n -d -m0
</CsOptions>
<CsInstruments>
sr = 48000
ksmps = 480
nchnls = 1
0dbfs = 1

; Watching a runner: stmonenter and stmonexit fire on transitions, and
; stmevent reads every runner event in order, including pause, resume
; and delete. The writer and the observers are in different instruments.

; A <-> B, plus a self edge on B
builder:i = stmcreate()
stmaddnode(builder, "A")    ; id 0
stmaddnode(builder, "B")    ; id 1
stmaddedge(builder, "A", "B")
stmaddedge(builder, "B", "A")
stmaddedge(builder, "B", "B")
gi_runner@global:i = stminstance(stmcompile(builder))

; the writer: a scripted sequence of requests and controls
instr 1
  r:i = gi_runner
  cycle:k init 0
  cycle += 1

  if cycle == 1 then
    stmnext(r, "B")
  elseif cycle == 2 then
    stmnext(r, "B")               ; self transition
  elseif cycle == 4 then
    stmnext(r, "A")               ; ignored: the runner is paused
  elseif cycle == 6 then
    stmnext(r, "A")
  elseif cycle == 8 then
    stmnext(r, "B")               ; ignored: the runner is deleted
  endif

  stmpause(r, cycle == 3 ? 1 : 0)
  stmresume(r, cycle == 5 ? 1 : 0)
  stmdelete(r, cycle == 7 ? 1 : 0)

  status:k, from:k, to:k = stmadvance(r)
  printks("cycle %d: advance status %d\n", 0, cycle, status)
endin

; an observer, scheduled after the writer in each control period
instr 2
  r:i = gi_runner
  enterB:k = stmonenter(r, "B")
  exitB:k = stmonexit(r, "B")
  if enterB == 1 || exitB == 1 then
    printks("  enter B %d, exit B %d\n", 0, enterB, exitB)
  endif

  ; drain every event published since the previous pass
  more:k = 1
  while more == 1 do
    kind:k, seq:k, lost:k, more, from:k, to:k = stmevent(r)
    if more == 1 then
      printks("  event %d: kind %d, %d -> %d, overflow %d\n", 0, seq, kind, from, to, lost)
    endif
  od
endin
</CsInstruments>
<CsScore>
i 1 0 0.09
i 2 0 0.09
e
</CsScore>
</CsoundSynthesizer>

Its output is:

cycle 1: advance status 1
  enter B 1, exit B 0
  event 1: kind 1, 0 -> 1, overflow 0
cycle 2: advance status 3
  enter B 1, exit B 1
  event 2: kind 2, 1 -> 1, overflow 0
cycle 3: advance status 5
  event 3: kind 5, 1 -> 1, overflow 0
cycle 4: advance status 5
cycle 5: advance status 0
  event 4: kind 6, 1 -> 1, overflow 0
cycle 6: advance status 1
  enter B 0, exit B 1
  event 5: kind 1, 1 -> 0, overflow 0
cycle 7: advance status 6
  event 6: kind 7, 0 -> 0, overflow 0
cycle 8: advance status 6
cycle 9: advance status 6

Event kinds: 1 transition, 2 self transition, 5 pause, 6 resume, 7 delete. The self transition in cycle 2 fires both the enter and the exit trigger of B. The request in cycle 4 is ignored because the runner is paused, and the one in cycle 8 because it is deleted. Pause, resume and delete appear as events but do not fire the enter and exit triggers.

See also

State Machine Graphs

stmonenter, stmonexit, stmadvance

Credits

Author: Pasquale Mainolfi
Italy
New in Csound version 7.0
October 2026