Operator SDK
Build MIDI processing and UI modes for the Operator device
Loading...
Searching...
No Matches
op::sim Namespace Reference

The mock device a mode is tested against on a host machine. More...

Functions

const OperatorApi * get_api ()
 The mock OperatorApi, ready to hand to a mode's init.
void reset_state ()
 Put the device back to how it starts: the clock at zero, the queues and the framebuffer empty, every param zero, no seeded files.
void apply_param_defaults (const ::op::modes::ParamSpec *specs, std::uint8_t count)
 Seed the params with the defaults a mode declares, the way the device does before it starts one.
void advance_tick (std::uint32_t microseconds)
 Move the virtual clock forward, in microseconds.
void set_pulse_count (std::uint32_t pulse)
 Set what api->get_pulse_count() reads.
void set_beat_position (float beat)
 Set the pulse count in beats.
void set_clock_state (std::uint8_t state)
 Set what api->get_clock_state() reads.
std::uint32_t get_last_clock_period_us ()
 Read the period a mode last asked for with api->set_clock_period_us().
void set_output_active (std::uint8_t output_index, bool active)
 Take one output away, so a mode meets an output that is not there.
std::uint16_t drain_outgoing_midi (std::uint8_t output_index, OpMidiMessage *out, std::uint16_t max_messages)
 Read back the MIDI a mode sent to one output, up to max_messages of it, and empty the queue.
void capture_framebuffer (std::uint8_t out[kFramebufferBytes])
 Copy the framebuffer out, as it stands after every draw a mode has made since the last reset_state().
void seed_extras_file (const char *mode_name, const char *filename, const std::uint8_t *data, std::uint32_t size)
 Put a file where a mode will find it, at /extras/<mode name>/<filename>.
void pick_filename (std::uint8_t param_id, const char *filename)
 Pick a file for a FilePicker param, as a player would on the device.
void set_current_mode_name (const char *mode_name)
 Name the mode, which is what scopes its storage to /extras/<mode name>/.

Variables

constexpr std::size_t kFramebufferBytes = 1024
 The size of the framebuffer, so a capture buffer can be stack-allocated.

Detailed Description

The mock device a mode is tested against on a host machine.

Function Documentation

◆ advance_tick()

void op::sim::advance_tick ( std::uint32_t microseconds)

Move the virtual clock forward, in microseconds.

api->get_tick() reads the total. It only ever moves forward.

◆ apply_param_defaults()

void op::sim::apply_param_defaults ( const ::op::modes::ParamSpec * specs,
std::uint8_t count )

Seed the params with the defaults a mode declares, the way the device does before it starts one.

reset_state() zeroes the params, because the harness holds no table of its own. A mode whose first read expects its declared default (a Numeric that starts at 64, an Enum that starts on its second option) needs this, called after reset_state() and before mode_init.

Slots are walked the way the device walks them, so what is seeded lines up with what get_param_value(slot) reads back. A Section holds no value and takes no slot. A Range or NoteRange takes two, seeded low then high, so the pair starts as a valid range.

◆ capture_framebuffer()

void op::sim::capture_framebuffer ( std::uint8_t out[kFramebufferBytes])

Copy the framebuffer out, as it stands after every draw a mode has made since the last reset_state().

The layout is the device's: byte page * 128 + column, lowest bit at the top row.

◆ drain_outgoing_midi()

std::uint16_t op::sim::drain_outgoing_midi ( std::uint8_t output_index,
OpMidiMessage * out,
std::uint16_t max_messages )

Read back the MIDI a mode sent to one output, up to max_messages of it, and empty the queue.

Returns how many messages were written into out.

◆ get_api()

const OperatorApi * op::sim::get_api ( )

The mock OperatorApi, ready to hand to a mode's init.

The pointer is stable for the life of the process and survives reset_state(), so a fixture can hold on to it.

◆ get_last_clock_period_us()

std::uint32_t op::sim::get_last_clock_period_us ( )

Read the period a mode last asked for with api->set_clock_period_us().

This is how a clock-generating mode is checked: at 120 BPM it should ask for 20833 microseconds. Reads 0 until a mode asks for something, as on the device.

◆ pick_filename()

void op::sim::pick_filename ( std::uint8_t param_id,
const char * filename )

Pick a file for a FilePicker param, as a player would on the device.

Storage is read-only and a mode never lists a directory, so a FilePicker mode is stood up with both halves: seed_extras_file puts the contents in place, and this says which file was picked. Call it after mode_init and before the first mode_process, so the mode's first read sees it. A null or empty filename clears the slot back to empty.

◆ reset_state()

void op::sim::reset_state ( )

Put the device back to how it starts: the clock at zero, the queues and the framebuffer empty, every param zero, no seeded files.

Call this at the top of every test. The tick starts at zero, so a mode that seeds a random sequence from it runs the same way every time.

◆ seed_extras_file()

void op::sim::seed_extras_file ( const char * mode_name,
const char * filename,
const std::uint8_t * data,
std::uint32_t size )

Put a file where a mode will find it, at /extras/<mode name>/<filename>.

Seeding the same file twice overwrites it.

◆ set_beat_position()

void op::sim::set_beat_position ( float beat)

Set the pulse count in beats.

A beat is 24 pulses, so a beat of 2.5 is a pulse count of 60.

◆ set_clock_state()

void op::sim::set_clock_state ( std::uint8_t state)

Set what api->get_clock_state() reads.

The value is a clock state: 0 for Active (a clock is running), 1 for NoClock (idle), or 2 for Mode (the clock source is a mode with no clock generator loaded).

◆ set_current_mode_name()

void op::sim::set_current_mode_name ( const char * mode_name)

Name the mode, which is what scopes its storage to /extras/<mode name>/.

Reads as "default" until it is set.

◆ set_output_active()

void op::sim::set_output_active ( std::uint8_t output_index,
bool active )

Take one output away, so a mode meets an output that is not there.

Every output is present after reset_state().

◆ set_pulse_count()

void op::sim::set_pulse_count ( std::uint32_t pulse)

Set what api->get_pulse_count() reads.

The pulse count is the timing a mode works from, at 24 pulses to the beat, and a mode finds the beat and the bar inside it by modulus.

Variable Documentation

◆ kFramebufferBytes

std::size_t op::sim::kFramebufferBytes = 1024
constexpr

The size of the framebuffer, so a capture buffer can be stack-allocated.

The display is 128 columns across 8 pages of 8 rows, one bit per pixel.