Incremental redo of tiny-sc.
Started on [2016-01-28 Thu 00:09]
SynthPlayer PatternPlayer
// play function as Synth in SynthPlayer
Function +> Symbol;
// play any pattern-capable object as stream in key in EventStreamPlayer
Pattern +> Symbol;
Starting implementation for EventStreamPlayer 1 Jun 2017 20:00.
- State “STARTED” from “TODO” [2016-03-17 Thu 12:33]
started
- Playing
+>
- Start playing something in a SynthLink.
Note: If the first (left) operand is an event, it adds or sets the EventPattern of an EventPlayer that is attached to the TaskPlayer as player. The default name of the player is
player
. Another name is used if it is provided as adverb to the+>
operator. +>>
- Set the pattern of the TaskPlayer in the SynthLink, and start. Do not add any EventPlayer to the TaskPlayer.
- Modifying args
For TaskPlayer, these modify the EventStream of the default EventPlayer or the player specified in the adverb to the operator.
%>
- Add args to event or arg-array
!%>
- Replace event or arg-array
- Modifying pattern of the TaskPlayer
These modify the pattern and stream of the TaskPlayer, not of any EventPlayer.
>>
- …
!>>
- …
- Linking SynthLinks
@>
- …b・・・
<@
- …
@
- …
@+
+@
Play function into SynthPlayer - in SynthLink:
{ } +> \symbol
Play named and loaded SynthDef into SynthPlayer - in SynthLink:
\default +> \symbol
Play Event into TaskPlayer - in SynthLink:
( ) +> \symbol // Plays through default EventPlayer as TaskPlayer-player ( ) +> \symbol // Plays through default EventPlayer as TaskPlayer-player
Possibly:
number +> \symbol
- use number as duration to start TaskPlayer in SynthLink
pattern +> \symbol
- use pattern as duration to start TaskPlayer in SynthLink
() %> \symbol
++>
- Set source of SynthLink but do not play now
%%>
- change args in SynthLink, but do not send them to player now.
Notification class.
- State “DONE” from “” [2016-03-20 Sun 18:58]
Methods Node:onStart, Node:onEnd.
Hold a node, monitor if it runs, replace with other node on request, notify when it starts and stops running
- State “DONE” from “” [2016-03-20 Sun 18:58]
Class SimpleSynthPlayer
Done in class SimpleSynthPlayer.
addNode { | argNode |
NodeWatcher.register(argNode);
// Release previous node if playing,
// but prevent that node from triggering a stopped notification when it ends.
if (this.isPlaying) {
node.releaseDependants; // do not notify when you end: next node is on the way
this.prStop;
argNode addDependant: { | changer, message |
switch (message,
// do not notify when started
// \n_go, { this.changed(\started) },
\n_end, {
node = nil;
this.changed(\stopped);
}
);
}
}{
argNode addDependant: { | changer, message |
switch (message,
\n_go, { this.changed(\started) },
\n_end, {
node = nil;
this.changed(\stopped);
}
);
}
};
node = argNode;
}
See file
- State “DONE” from “STARTED” [2016-03-20 Sun 18:57]
- State “STARTED” from “” [2016-01-28 Thu 12:37]
includes inputs and outputs
Stores a Function that is the source for creating Synths. It substitutes { }.play
by a mechanism that caches the SynthDef created from the function, so that any new Synths from the same Function can be created by Synth("defName")
. This is much more efficient than compiling the SynthDef from the Function and sending it to the Server each time that a new Synth is created.
Behavior:
When receiving the message play
, the FunctionSynthSource creates a Synth and returns it immediately. If the SynthDef from the Function stored in the FunctionSynthSource is already loaded in the server, then the Synth is created in the usual manner, with the Synth("defName")
. If however the Function is not yet loaded, the Synth is created with Synth.basicNew
and the actual Synth instance on the scserver is created as soon as the SynthDef is loaded.
When a FunctionSynthSource is created, it adds the given Function - or a default - as SynthDef, and sends it to the Server.
Upon sending a SynthDef to the server, the FunctionSynthSource sets its waiting_for_def flag to true.
The algorithm for the method play
is as follows:
if (waiting_for_def) {
^node ?? {
node = Synth.basicNew(defName, server);
}
}{
^Synth(defName, *args);
}
loadAndPlayMethod
is one of the following:
- Set the
f = FuncNodeSource.new;
f.play;
- State “DONE” from “STARTED” [2016-03-23 Wed 13:19]
- State “STARTED” from “TODO” [2016-03-23 Wed 13:18]
Imported Registry class from tiny-sc.
See Registry
class.
- State “STARTED” from “TODO” [2016-03-21 Mon 17:20]
started …
- State “STARTED” from “TODO” [2016-03-22 Tue 23:08]
basic concept and syntax
\writer @> \reader; // move output of writer to input of reader
\writer <@ \reader; // move input of reader to output of writer
// operator specifies output, adverb specifies input:
\writer@\out1 @>.in2 \reader; // specify output/input params out1 and in2
Possible extra operators:
\writer @+ \reader; // branch output of writer to reader with i/o copy synth
\writer +@ \reader; // branch to input of reader with i/o copy synth
\writer
and \reader
are unique group/rank and input/output bus holders accessible through their symbols. They can store a SynthPlayer or a TaskPlayer - interchangeably. Class: SynthLink
Structure of SynthLink:
SynthLink {
var <server;
var <rank = 0; // smaller numbers mean earlier synth order
var <group; // the actual group. Used as target for player.
var <inputs; // Dictionary of Inputs (param: input, param2: input)
var <outputs; // Dictionary of Outputs
var <player; // SynthPlayer, TaskPlayer, or similar/compatible object
getGroup {
if (inputs.isNil and: { outputs.isNil }) {
rank = 0
}{
rank = this.allWriters.collect(_.rank).maxItem + 1;
this.moveToGroup;
};
}
moveToGroup {
this.readers do: _.moveAfter(rank);
this.setGroup;
}
moveAfter { | argRank |
if (rank <= argRank) {
rank = argRank + 1;
this.moveToGroup;
}
}
setGroup {
group = PlayerGroup(server, rank);
player !? { player.target = group };
}
getArgs {
}
}
Input {
var <parameter; // name of input parameter
var <bus;
var <readerNode; // the SynthLink that has this input
var <writers; // set of Outputs that write to this input
}
Output {
var <parameter; // name of input parameter
var <bus;
var <writerNode; // the SynthLink that has this output
var <readers; // set of Inputs that read from this output
}
PlayerGroup {
var <server, <groups;
*new { | server, rank = 0 |
^Registry(this, server, { this.newCopyArgs(server, []) })
.getGroup(rank);
};
getGroup { | rank |
var root;
root = server.rootNode;
rank - groups.size + 1 max: 0 do: {
groups = groups add: Group.tail(root);
};
^groups[rank];
}
}
- State “STARTED” from “TODO” [2016-04-23 Sat 11:56]
- Only in SynthLink, not in SynthPlayer or TaskPlayer
- start
- start if not playing
- restart
- stop previous process and start again
To watch:
player pattern should copy
To watch:
How exactly is the EventPlayer produced, and where, in the chain of method calls, when the TaskPatternPlayer is produced.