Using dials with Python
pydials is the same controls for Pyctures scenes. Every program on these pages has a Python tab. This page is what is different in Python, in one place.
A Python scene with controls runs in Circuitry's preview as a JavaScript one does, on a computer, an iPad or an iPhone. Outside Circuitry it is run with Pyctures: pyctures run panel.py.
The imports
A scene with controls starts with these lines. The third is for a scene that also makes sound.
from pyctures import *
from pydials import *
from synths import *
lead = make_synth("lead")
dial("cutoff", lead, "cutoff")
keyboard(lead, octave=4)
def draw():
background("midnightblue")
Options are given by name
Where JavaScript has braces, Python has names, and a capital becomes an underscore:
| JavaScript | Python |
|---|---|
dial("points", 3, 12, 5, { step: 1 }) | dial("points", 3, 12, 5, step=1) |
keyboard(lead, { octave: 4, hints: false }) | keyboard(lead, octave=4, hints=False) |
layout({ at: "bottom" }) | layout(at="bottom") |
{ onChange: changed } | on_change=changed |
{ onNoteOn: pressed } | on_note_on=pressed |
button("go", start) | button("go", start), or on_press=start |
A control is its value
In Python a dial can be used wherever a number is wanted, with no .value:
from pyctures import *
from pydials import *
size = dial("size", 10, 150, 60)
trail = toggle("trail")
def draw():
background("rgba(16, 24, 48, 0.08)" if trail else "midnightblue")
circle(width / 2, height / 2, size, "gold") # the dial is the radius
size * 2, size > 100 and circle(x, y, size) all work, and if trail: asks a switch. size.value is the number itself, for when a real number is needed, and size.value = 100 sets it.
A function to call
from pyctures import *
from pydials import *
count = 0
def more():
global count
count += 1
button("more", more)
def draw():
background("midnightblue")
text(str(count), width / 2, height / 2, "white", 60, "centre")
on_change on a dial, a slider, a toggle or a select is called with the new value when a hand changes it.
What comes back, and when
Python does not touch the page. The page draws the controls and feels the fingers, so a dial turns smoothly however busy Python is, and what a hand changes comes back to Python with the next frame.
- A value read in
updateordrawis the value as of this frame. - A control tied to a synth acts on the synth in the page: a key sounds the moment it is touched and a dial is heard as it turns, with no trip through Python. Python is told a frame later, so
lead.cutoffreads what the dial says. - A scope or a meter fed by a Python function (
scope(my_function)) is asked for its numbers once for each frame the page has drawn.
Groups are made with with
Where JavaScript gives group, row, column, grid and page a function, Python uses with. What is made inside is in the box:
lead = make_synth("lead")
with group("filter", colour="deepskyblue"):
dial("cutoff", lead, "cutoff", size="large")
with column():
dial("resonance", lead, "resonance", size="small")
dial("sweep", lead, "sweep", size="small")
layout() and room() give back what the page last said (the width, height and scale; the rectangle no control is on), which is a frame late: in a scene's very first lines the scale is still 1 and the room is the whole picture. Laying out a panel has every part in both languages.
What Python does not have
over(x, y) is in dials.js only. In a Pyctures scene a press on a control is still the control's alone: on_mouse_down is not called for it.
A dictionary is a target
A control tied to a dictionary reads and writes the key you name, and one tied to any other object reads and writes its attribute:
from pyctures import *
from pydials import *
ball = {"radius": 40}
dial("size", ball, "radius", min=5, max=120)
def draw():
background("midnightblue")
circle(width / 2, height / 2, ball["radius"], "gold")