@@ -24,9 +24,9 @@ We will change that in the next step.
24
24
In order to control other modules from our Python script module, we need it to have an output
25
25
port to even emit data. Double-click the Python module or click on * Settings* after selecting it).
26
26
27
- A new window opens which lets you edit the Python code. We ignore that for now and click on
28
- * Ports → Edit* in the window's main menu . A new * Port Editor* dialog opens, which allows for adding
29
- new ports to our script module.
27
+ A new window opens which lets you edit the Python code. We ignore that for now and click on the
28
+ * Edit Ports * button in the window's toolbar at the top . A new * Port Editor* dialog opens, which allows
29
+ for adding new ports to our script module.
30
30
Since we want to add an output port, click on * Add Output Port* .
31
31
32
32
In the next step, you will be asked which kind of data the output port emits. Select ` ControlCommand `
@@ -42,22 +42,25 @@ input port of your *Audio Source* as usual!
42
42
43
43
## 3. Module coding basics
44
44
45
- Now we can look at the Python script itself! The default script is quite large due to its many annotations, but
46
- using it is really quite simple: 4 functions exists that Syntalos may call at different stages of an experiment run.
45
+ Now we can look at the Python script itself! The default script is larger than it needs to be due to annotations
46
+ to help you get started. Writing the script is a lot simpler than it may first appear though:
47
+ 4 functions exists that Syntalos may call at different stages of an experiment run.
47
48
The ` prepare() ` function is called when the experimence is started, but before all modules are ready, the
48
- ` start() ` function is called immediately before data starts being acquired, ` loop ` is called continuously during
49
- the experiment until the function returns ` False ` , and ` stop() ` is called when the experiment is stopped.
50
- We are primarily concerned with the ` loop() ` function here, as we do not need to prepare any data or device
51
- in our script. Interaction with Syntalos happens via the ` syio ` module, which is imported by default.
49
+ ` start() ` function is called immediately before data starts being acquired, ` run ` is called when the experiment
50
+ is started and mainly handles communication with Syntalos, and ` stop() ` is called when the experiment is stopped.
51
+ We are primarily concerned with the ` prepare() ` function here, as we do not need to prepare any data or device
52
+ in our script. Interaction with Syntalos happens via the ` syntalos_mlink ` module, which is imported by default
53
+ as ` syl ` .
52
54
53
55
First, we need to get a Python reference to the ` control-out ` output port that we just defined in the port editor.
54
- This needs to happen before even ` prepare() ` is called, so we put it at the top of the Python file:
56
+ This should happen before even ` prepare() ` is called, so we put it at the top of the Python file:
55
57
56
58
``` python
57
- oport = sy .get_output_port(' control-out' )
59
+ oport = syl .get_output_port(' control-out' )
58
60
```
59
61
60
- Using ` get_output_port() ` with the internal port name, we now can emit messages on this port.
62
+ The ` get_output_port() ` method takes the internal port name as parameter, that we previously defined in the port editor.
63
+ With the reference we obtained on the output port, we can now can emit messages on this port.
61
64
62
65
## 4. Controlling a module
63
66
@@ -67,45 +70,56 @@ This is useful for example if you only want to record a video for a selected amo
67
70
For now though, we just want to emit a 2 sec audio cue every 5 seconds. This can be done with this simple snippet
68
71
of Python code (this is the whole script file):
69
72
70
- ``` python {linenos=table,hl_lines=[10,14]}
71
- import syio as sy
72
- from syio import InputWaitResult, ControlCommand, ControlCommandKind
73
+ ``` python {linenos=table,hl_lines=[9,14,16,21]}
74
+ import syntalos_mlink as syl
73
75
74
76
75
- oport = sy .get_output_port(' control-out' )
77
+ oport = syl .get_output_port(' control-out' )
76
78
77
79
78
- def loop () -> bool :
79
- ctl = ControlCommand()
80
- ctl.kind = ControlCommandKind.START
80
+ def start ():
81
+ """ Called by Syntalos immediately when the experiment is started."""
82
+ send_beep()
83
+
84
+
85
+ def send_beep ():
86
+ ctl = syl.ControlCommand()
87
+ ctl.kind = syl.ControlCommandKind.START
81
88
ctl.duration = 2000 # run for 2 sec
82
- while True :
83
- oport.submit(ctl)
84
- sy.wait_sec(5 )
85
- if not sy.check_running():
86
- return False
89
+ oport.submit(ctl)
90
+
91
+ if not syl.is_running():
92
+ return False
87
93
88
- return True
94
+ # run again in 5 sec
95
+ syl.schedule_delayed_call(5 * 1000 , send_beep)
89
96
```
90
97
91
- The ` loop() ` function is called permanently while the experiment runs. We first define a ` ControlCommand ` that we want to
98
+ The ` start() ` function is called immediately when the experiment is started and has to complete immediately.
99
+ To launch our custom code, we define a function called ` send_beep() ` that we run once the experiment was started.
100
+
101
+ In ` send_beep() ` we first define a ` ControlCommand ` that we want to
92
102
send to the * Audio Source* , and tell it to be of kind ` START ` and instruct it to hold that state for ` 2000 ` milliseconds
93
- before falling back to its previous state.
94
- Then, we just loop endlessly and submit the control command on our predefined output port ` oport ` , wait 5 seconds and then
95
- repeat the process.
96
- Any datatypes you can use with output ports, and commands you can use on input ports can be found in the
103
+ before falling back to its previous state (via ` ctl.duration ` ).
104
+
105
+ Using ` oport.submit(ctl) ` , we send this command out on the previously defined output port ` oport ` .
106
+ If we are no longer running (if ` syl.is_running() ` returns ` False ` ), we stop doing anything. If we are still running though,
107
+ we instruct Syntalos to call ` send_beep() ` again in 5 seconds, via ` syl.schedule_delayed_call() ` .
108
+
109
+ Datatypes you can use with output ports, and commands you can use on input ports can be found in the
97
110
[ syntalos_mlink API documentation] ({{< ref "/docs/pysy-mlink-api" >}}) for reference.
98
111
99
112
{{< callout type="info" >}}
100
113
While using Python's own wait functions, like ` time.sleep() ` , is possible for delays, it is recommended to use
101
- functions from ` syio ` for that purpose. That way Syntalos knows about the waiting state of the module,
114
+ functions from ` syntalos_mlink ` for that purpose. That way Syntalos knows about the waiting state of the module,
102
115
and can disrupt a sleeping module to stop it instead of waiting for it. It also allows Syntalos to make smarter
103
116
scheduling and queueing decisions.
104
117
{{< /callout >}}
105
118
106
- By calling ` sy.check_running() ` in our endless loop, we can check if the Syntalos experiment is still running, and
107
- terminate voluntarily in case it is not. Otherwise, Syntalos will interrupt script execution if a script does not react
108
- in time to a stop request.
119
+ While checking whether we are still running with ` syl.is_running() ` is not strictly necessary, it allows for a cleaner
120
+ shutdown procedure when Syntalos interrupts the running code at the end of the experiment.
121
+ An alternative to this check would be to implement the ` stop() ` function, and stop emitting new control commands once that
122
+ function has been called.
109
123
110
124
## 5. Run it!
111
125
0 commit comments