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:

JavaScriptPython
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 update or draw is 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.cutoff reads 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")