Changing Parameters in Forking Thread

I am wondering if it’s possible to change parameters in the function after it’s been forked. Or if it’s possible to define variables within the forking function at a later time.

For instance, loop_part_one is the function that’s meant to be forked, below. There are some variables like number_loop_repeats, seq, or rhythm that I’d like to define from the command line. Is there a way to do this?

def loop_part_one():
	# rhy = [0.125, 0.25, 0.33, 0.5, 0.66, 1, 2, 0.75, 0.8]
	rhy = rhythm
	env = [0.25, 0.5, 0.75, 1]
	for i in range(number_loop_repeats):
		for s in seq:
			#treble.play_chord(s, 1.0, random.choice(rhy))
			for i in range(number_articulations):
				treble.play_chord(s, random.choice(env), random.choice(rhy))

Thank you

The easiest way I know of to update parameters in a function that’s already been forked is to use a global variable. Something like this, maybe?

import random
import scamp

# global variables
RHYTHM = [0.125, 0.25, 0.33, 0.5, 0.66, 1, 2, 0.75, 0.8]
NUMBER_LOOP_REPEATS = 2
NUMBER_ARTICULATIONS = 1
SEQ = [[60, 64, 67], [59, 62, 67]]

def loop_part_one(treble):
	while True:
		env = [0.25, 0.5, 0.75, 1]
		for i in range(NUMBER_LOOP_REPEATS):
			for s in SEQ:
				for i in range(NUMBER_ARTICULATIONS):
					treble.play_chord(s, random.choice(env), random.choice(RHYTHM))
		scamp.wait(2)

s = scamp.Session()
treble = s.new_part("piano")
s.fork(loop_part_one, args = [treble])

s.wait(10)
NUMBER_ARTICULATIONS = 3

s.wait_forever()

If you want to be able to modify a global variable from the command line while the script is running, I might fork another function using the very handy fork_unsynchronized() method which Marc recently mentioned on the forum—this new function will be responsible for checking for command line input and updating the variable accordingly:

import random
import scamp

# global variables
RHYTHM = [0.125, 0.25, 0.33, 0.5, 0.66, 1, 2, 0.75, 0.8]
NUMBER_LOOP_REPEATS = 1
NUMBER_ARTICULATIONS = 1
SEQ = [[60, 64, 67], [59, 62, 67]]

def loop_part_one(treble):
	while True:
		env = [0.25, 0.5, 0.75, 1]
		for i in range(NUMBER_LOOP_REPEATS):
			for s in SEQ:
				for i in range(NUMBER_ARTICULATIONS):
					treble.play_chord(s, random.choice(env), random.choice(RHYTHM))
		scamp.wait(2)

def update_variable():
	global NUMBER_ARTICULATIONS	
	while True:
		print("Enter a new value for NUMBER_ARTICULATIONS when desired:")
		val = input()
		NUMBER_ARTICULATIONS = int(val)

s = scamp.Session()
treble = s.new_part("piano")
s.fork(loop_part_one, args = [treble])
s.fork_unsynchronized(update_variable)

s.wait_forever()

Sometimes you can run into some unexpected scenarios when multiple threads are either updating or reading from a global variable at the same time. For instance, maybe you only want an update to NUMBER_ARTICULATIONS to take effect once a new loop starts. To do that you could use a lock:

import random
import scamp
import threading

# global variables
RHYTHM = [0.125, 0.25, 0.33, 0.5, 0.66, 1, 2, 0.75, 0.8]
NUMBER_LOOP_REPEATS = 1
NUMBER_ARTICULATIONS = 1
SEQ = [[60, 64, 67], [59, 62, 67]]
MY_LOCK = threading.Lock()

def loop_part_one(treble):
	while True:
		env = [0.25, 0.5, 0.75, 1]
		with MY_LOCK:
			for i in range(NUMBER_LOOP_REPEATS):
				for s in SEQ:
					for i in range(NUMBER_ARTICULATIONS):
						treble.play_chord(s, random.choice(env), random.choice(RHYTHM))
		scamp.wait(2)

def update_variable():
	global NUMBER_ARTICULATIONS	
	while True:
		print("Enter a new value for NUMBER_ARTICULATIONS when desired:")
		val = input()
		with MY_LOCK:
			NUMBER_ARTICULATIONS = int(val)

s = scamp.Session()
treble = s.new_part("piano")
s.fork(loop_part_one, args = [treble])
s.fork_unsynchronized(update_variable)

s.wait_forever()

Does that help?

2 Likes

Yes that helps so much! Thank you

1 Like