FoxDot.lib.Players¶
Players are what make FoxDot make music. They are similar in design to SuperCollider’s PDef and PBind combo but with slicker syntax. FoxDot uses SuperCollider to actually make the sound and does so by triggering predefined SynthDefs - sort of like definitions of a digital instruments. To have a look at the list of SynthDefs, you can just print them to the console:
print(SynthDefs)
Each one of these represents a SynthDef object. These objects are then given to Players to play - like giving an instrument to someone in your orchestra. To give someone the instrument, pads, you use a double arrow some code syntax like this:
p1 >> pads()
To stop a Player, use the stop method e.g. p1.stop(). If you want to stop all players, you can use the command Clock.clear() or the keyboard shortcut Ctrl+., which executes this command.
p1 is the name of a predefined player object. At startup, FoxDot reserves all one- and two-character variable names, such as x, p1, or bd for player objects but these can be repurposed if you like. If you want to use a variable name for a player object with more than two characters, you just instantiate a new Player object:
foo = Player()
foo >> pads()
Changing parameters¶
By default, player objects play the first note of their default scale (more below) with a duration of 1 beat per note. To change the pitch just give the SynthDef a list of numbers.
p1 >> pads([0,7,6,4])
Play multiple pitches together by putting them in round brackets:
p1 >> pads([0,2,4,(0,2,4)])
When you start FoxDot up, your clock is ticking at 120bpm and your player objects are all playing in the major scale. With 8 pitches in the major scale, the 0 refers to the first pitch and the 7 refers to the pitch one octave higher because Python, like most programming languages, uses zero-indexing. To change your scale you can specify a new scale as a keyword argument (see the documentation on Scales for more information on scales) or change the default scale for all player objects.
# Changing scale as a keyword argument
p1 >> pads([0,7,6,4], scale=Scale.minor)
# Changing the default scalew (the following are equivalent)
Scale.default.set("minor")
Scale.default.set(Scale.minor)
Scale.default.set([0,2,3,5,7,8,10])
# See a list of scales
print Scale.names()
# Change the tempo (this takes effect at the next bar)
Clock.bpm = 144
To change the rhythm of your player object, specify the durations using the dur keyword. Other keywords can be specified, such as oct for the octave and sus for the sustain, which is the same as the duration by default.
p1 >> pads([0,7,6,4], dur=[1,1/2,1/4,1/4], oct=6, sus=1)
# See a list of possible keyword arguments
print(Player.get_attributes())
Using the play SynthDef¶
There is a special case SynthDef object called play which allows you to play short audio files rather than specify pitches. In this case you use a string of characters as the first argument where each character refers to a different folder of audio files. You can see more information by evaluating print(Samples). The following line of code creates a basic drum beat:
d1 >> play("x-o-")
To play multiple patterns simultaneously, you can create a new play object. This is useful if you want to have different attributes for each player.
bd >> play("x( x) ", dur=1)
hh >> play("---[--]", dur=[1/2,1/2,1/4], rate=4)
sn >> play(" o ", rate=(.9,1), pan=(-1,1))
Grouping characters in round brackets laces the pattern so that on each play through of the sequence of samples, the next character in the group’s sample is played. The sequence (xo)— would be played back as if it were entered x—o—. Using square brackets will force the enclosed samples to played in the same time span as a single character e.g. –[–] will play two hi-hat hits at a half beat then two at a quarter beat. You can play a random sample from a selection by using curly braces in your Play String like so:
d1 >> play("x-o{-[--]o[-o]}")
FoxDot Player Object Keywords¶
dur - Durations (defaults to 1 and 1/2 for the Sample Player)
sus - Sustain (defaults to dur)
amp - Amplitude (defaults to 1)
rate - Variable keyword used for misc. changes to a signal. E.g. Playback rate of the Sample Player (defaults to 1)
delay - A duration of time to wait before sending the information to SuperCollider (defaults to 0)
sample - Special keyword for Sample Players; selects another audio file from the bank of samples for a sample character.
- class FoxDot.lib.Players.EmptyPlayer(name)[source]¶
Bases:
objectPlace holder for Player objects created at run-time to reduce load time.
- class FoxDot.lib.Players.Player(name=None)[source]¶
Bases:
RepeatableFoxDot generates music by creating instances of Player and giving them instructions to follow. At startup FoxDot creates many instances of Player and assigns them to any valid two character variable. This is so that when you start playing you don’t have to worry about typing myPlayer = Player() and myPlayer_2 = Player() every time you want to do something new. Of course there is nothing stopping you from doing that if yo so wish.
Instances of Player are given instructions to generate music using the >> syntax, overriding the bitshift operator, and should be given an instance of SynthDefProxy. A SynthDefProxy is created when calling an instance of SynthDef - these are the “instruments” used by player objects and are written in SuperCollider code. You can see more information about these in the SCLang module. Below describes how to assign a SynthDefProxy of the SynthDef pads to a Player instance called p1:
# Calling pads as if it were a function returns a # pads SynthDefProxy object which is assigned to p1 p1 >> pads() # You could store several instances and assign them at different times proxy_1 = pads([0,1,2,3], dur=1/2) proxy_2 = pads([4,5,6,7], dur=1) p1 >> proxy_1 # Assign the first to p1 p1 >> proxy_2 # This replaces the instructions being followed by p1
- accompany(other, values=[0, 2, 4], debug=False)[source]¶
Similar to “follow” but when the value has changed
- addfx(**kwargs)[source]¶
Not implemented - add an effect to the SynthDef bus on SuperCollider after it has been triggered.
- after_update_methods = ['stutter']¶
- alias = {'char': 'degree', 'pitch': 'degree'}¶
- alt_dur(dur)[source]¶
Used to set a duration that changes linearly over time. You should use a linvar but any value can be used. This sets the dur to 1 and uses the bpm attribute to seemingly alter the durations
- attrmap(key1, key2, mapping)[source]¶
Sets the attribute for self.key2 to self.key1 altered with a mapping dictionary.
- bang(**kwargs)[source]¶
Triggered when sendNote is called. Responsible for any action to be triggered by a note being played. Default action is underline the player.
There is a video on YouTube demonstrating this functionality.
Open FoxDotEditor and run the .bang() function as a parameter, for example:
d1 >> play('x', dur=2) d1.bang(underline=True)
I recommend experimenting with the parameters:
overstrike=1 underline=1 foreground='red' background='#e24329' font=('Consolas', 30)
Here is a table with all the options:
OPTION
DESCRIPTION
background
The background color for text with this tag. Note that you can’t use bg as an abbreviation.
bgstipple
To make the background appear grayish, set this option to one of the standard bitmap names (see Section 5.7, “Bitmaps”). This has no effect unless you also specify a background.
borderwidth
Width of the border around text with this tag. Default is 0. Note that you can’t use bd as an abbreviation.
fgstipple
To make the text appear grayish, set this option a bitmap name.
font
The font used to display text with this tag. See Section 5.4, “Type fonts”.
foreground
The color used for text with this tag. Note that you can’t use the fg abbreviation here.
justify
The justify option set on the first character of each line determines how that line is justified: tk.LEFT (the default), tk.CENTER, or tk.RIGHT.
lmargin1
How much to indent the first line of a chunk of text that has this tag. The default is 0. See Section 5.1, “Dimensions” for allowable values.
lmargin2
How much to indent successive lines of a chunk of text that has this tag. The default is 0.
offset
How much to raise (positive values) or lower (negative values) text with this tag relative to the baseline. Use this to get superscripts or subscripts, for example. For allowable values, see Section 5.1, “Dimensions”.
overstrike
Set overstrike=1 to draw a horizontal line through the center of text with this tag.
relief
Which 3-D effect to use for text with this tag. The default is relief=tk.FLAT; for other possible values see Section 5.6, “Relief styles”.
rmargin
Size of the right margin for chunks of text with this tag. Default is 0.
spacing1
This option specifies how much extra vertical space is put above each line of text with this tag. If a line wraps, this space is added only before the first line it occupies on the display. Default is 0.
spacing2
This option specifies how much extra vertical space to add between displayed lines of text with this tag when a logical line wraps. Default is 0.
spacing3
This option specifies how much extra vertical space is added below each line of text with this tag. If a line wraps, this space is added only after the last line it occupies on the display. Default is 0.
tabs
How tabs are expanded on lines with this tag. See Section 24.6, “Setting tabs in a Text widget”.
underline
Set underline=1 to underline text with this tag.
wrap
How long lines are wrapped in text with this tag. See the description of the wrap option for text widgets, above.
Table taken from the tkinter.Text().tag_config() documentation.
- base_attributes = ('sus', 'fmod', 'pan', 'rate', 'amp', 'midinote', 'channel')¶
- count(time=None, event_after=False)[source]¶
Counts the number of events that will have taken place between 0 and time. If time is not specified the function uses self.metro.now(). Setting event_after to True will find the next event after time
- debug = 0¶
- default_root = 0¶
- default_scale = P[0, 2, 4, 5, 7, 9, 11]¶
- degrade(amount=0.5)[source]¶
Sets the amp modifier to a random array of 0s and 1s amount=0.5 weights the array to equal numbers
- envelope_keywords = ('atk', 'decay', 'rel', 'legato', 'curve', 'gain')¶
- fx_attributes = ('vib', 'vibdepth', 'slide', 'sus', 'slidedelay', 'slidefrom', 'glide', 'glidedelay', 'bend', 'benddelay', 'coarse', 'striate', 'buf', 'rate', 'pshift', 'hpf', 'hpr', 'lpf', 'lpr', 'swell', 'bpf', 'bpr', 'bpnoise', 'chop', 'tremolo', 'beat_dur', 'echo', 'echotime', 'spin', 'cut', 'room', 'mix', 'formant', 'shape', 'drive')¶
- fx_keys = ('vib', 'slide', 'slidefrom', 'glide', 'bend', 'coarse', 'striate', 'pshift', 'hpf', 'lpf', 'swell', 'bpf', 'chop', 'tremolo', 'echo', 'spin', 'cut', 'room', 'formant', 'shape', 'drive')¶
- classmethod get_attributes()[source]¶
Returns a list of possible keyword arguments for FoxDot players and effects
- get_event_length(event=None, **kwargs)[source]¶
Returns the largest length value in the event dictionary
- get_prime_funcs(event)[source]¶
Finds and PGroupPrimes in event and returns the modulated event dictionary
- get_synth_name(buf=0)[source]¶
Returns the real SynthDef name of the player. Useful only for “play” as there is a play1 and play2 SynthDef for playing audio files with one or two channels respectively.
- internal_keywords = ('oct', 'freq', 'dur', 'delay', 'buf', 'blur', 'amplify', 'scale', 'bpm', 'sample', 'env')¶
- keywords = ('degree', 'oct', 'freq', 'dur', 'delay', 'buf', 'blur', 'amplify', 'scale', 'bpm', 'sample', 'env')¶
- largest_attribute(**kwargs)[source]¶
Returns the length of the largest nested tuple in the current event dict
- map(other=None, /, *, k=None, d=0, **mappings)[source]¶
Map a value to a given condition.
Abbreviation of:
d1 >> play(PwRand(['-', 'o'], [80, 20])) b1 >> dbass(dur=1/2, oct=d1.degree.map({'-': 5, 'o': 6}))
map another player
d1 >> play(PwRand(['-', 'o'], [80, 20])) b1 >> dbass(dur=1/2).map(d1, oct={'-': 5, 'o': 6})
or itself
s1 >> space(P[:7:2]).map(oct={0: var([6, 5])})
play by char
d2 >> play('{xX}').map(sample={'x': 2, 'V': var([2,4], [3,1])})
loop by pshift
l1 >> loop('foxdot', pshift=PWalk(2,3)).map(rate={0: 2}, lpf={3: 5000, 0: 1000}, hpf={-3: 800})
synth by degree
s1 >> space(P[:7]).map(root={0: P(4,5), 3: P^P[:10:3]})
or define which attr should be used with k=
k1 >> saw(tremolo=PSine(4)).map(root={0.0: 1, -1.0: -2}, k='tremolo')
define the default value (default: 0) with d=
d1 >> play('xs:h', dur=1) v1 >> donk(pan=PWhite(-1, 1)) v1.map(d1, degree={':': P(var([-2,4],8),0,2), 'h': P*(-2,-4,0,1)}, d=var(P[:2]))
the value of d= can be a function that will receive the current value and should return the new value
f1 >> space(dur=1/2).degrade(.1).map(v1, degree={}, d=lambda val: 6 if (val >= 3) else 4)
in addition to d=, the mapping keys can also be a function that will receive the current value and return True or False
f2 >> swell(dur=2).map(v1, degree={lambda val: val >= 3: 6})
values can also receive functions and, like the functions for d=, will receive the current value and should return the new value
f3 >> dirt(cut=.25, dur=PDur(3,8)).map(v1, degree={bool: lambda val: 3 if val > 8 else 9})
- metro = <FoxDot.lib.TempoClock.TempoClock object>¶
- new_message_header(event, **kwargs)[source]¶
Returns the header of an osc message to be added to by osc_message()
- now(attr='degree', x=0, **kwargs)[source]¶
Calculates the values for each attr to send to the server at the current clock time
- num_key_references()[source]¶
Returns the number of ‘references’ for the attr which references the most other players
- penta(switch=1)[source]¶
Shorthand for setting the scale to the pentatonic mode of the default scale
- push_osc_to_server(packet, timestamp, verbose=True, **kwargs)[source]¶
Adds message head, calculating frequency then sends to server if verbose is True and amp/bufnum values meet criteria
- required_keys = ('amp', 'sus')¶
- reset()[source]¶
Sets all Player attributes to 0 unless their default is specified by an effect. Also can be called by using a tilde before the player variable. E.g. ~p1
- samples = <BufferManager>¶
- send(timestamp=None, verbose=True, **kwargs)[source]¶
Goes through the current event and compiles osc messages and sends to server via the tempo clock
- send_osc_message(event, index, timestamp=None, verbose=True, **kwargs)[source]¶
Compiles and sends an individual OSC message created by recursively unpacking nested PGroups
- set(**kwargs)[source]¶
Set multiple arguments on a single line.
What allows you to go from this:
p1.slide = 2 p1.slidedelay = .2 p1.cut = .5 p1.delay = .5
To this:
p1.set(slide=2, slidedelay=.2, cut=.5, delay=.5)
- set_queue_block(queue_block)[source]¶
Gives this player object a reference to the other items that are scheduled at the same time
- solo(action=1)[source]¶
Silences all players except this player. Undo the solo by using Player.solo(0)
- stop(N=0)[source]¶
Removes the player from the Tempo clock and changes its internal playing state to False in N bars time - When N is 0 it stops immediately
- stutter(amount=None, _beat_=None, **kwargs)[source]¶
Plays the current note n-1 times. You can specify keywords.
- test_for_circular_reference(value, attr, last_player=None, last_attr=None)[source]¶
Used to raise an exception if a player’s attribute refers to itself e.g. p1 >> pads(dur=p1.dur)
- unduplicate_durs(event)[source]¶
Converts values stored in event[“dur”] in a tuple/PGroup into delays
- unison(unison=2, detune=0.125)[source]¶
Like spread(), but can specify number of voices(unison) Sets pan to (-1,-0.5,..,0.5,1) and pshift to (-0.125,-0.0625,…,0.0625,0.125) If unison is odd, an unchanged voice is added in the center Eg : p1.unison(4, 0.5) => pshift=(-0.5,-0.25,0.25,0.5), pan=(-1.0,-0.5,0.5,1.0) p1.unison(5, 0.8) => pshift=(-0.8,-0.4,0,0.4,0.8), pan=(-1.0,-0.5,0,0.5,1.0)
- unpack(item)[source]¶
Converts a pgroup to floating point values and updates and time var or playerkey relations
- update(synthdef, degree, **kwargs)[source]¶
Updates the attributes of the player. Called using the >> syntax.
- update_all_player_keys(ignore=[], event=None, **kwargs)[source]¶
Updates the internal values of player keys that have been accessed e.g. p1.pitch. If there is a delay, then schedule a function to update the values in the future.
- update_player_key_relation(item)[source]¶
Called during ‘now’ to update any Players that a player key is related to before using that value
- versus(other_key, rule=<function Player.<lambda>>, attr=None)[source]¶
Sets the ‘amplify’ key for both players to be dependent on the comparison of keys
- versus_old(other, key=<function Player.<lambda>>, f=<built-in function max>)[source]¶
Takes another Player object and a function that takes two player arguments and returns one, default is the higher pitched
- wait(n=0)[source]¶
Wait n beats to release the player.
d0 >> play('.-.-').wait() d1 >> play('x...').wait(8) d2 >> play('..o.').wait(16)
- wait_bars(n=0)[source]¶
Wait n bars to release the player.
Clock.meter = 4,4 # is used by `wait_bars`/`futureBar` e0 >> play('.-.-').wait_bars() e1 >> play('x...').wait_bars(2) e2 >> play('..o.').wait_bars(4)
- widget = None¶