File: ScoreStreamPlayer.sc

package info (click to toggle)
supercollider 1%3A3.10.0%2Brepack-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 45,496 kB
  • sloc: cpp: 283,513; lisp: 74,040; ansic: 72,252; sh: 23,016; python: 7,175; makefile: 1,087; perl: 766; java: 677; yacc: 314; lex: 175; ruby: 136; objc: 65; xml: 15
file content (115 lines) | stat: -rw-r--r-- 2,774 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*

ScoreStreamPlayer collects OSC commands from an EventStream into a Score. It is derived from server to provide allocation of nodeIDs, bufums, etc.

It implements the functionality of a TempoClock, to support tempo changes and time based patterns.

Patterns that play on multiple servers are not directly supported, but can be managed.
For example, assuming the server is explicitly identified in the pattern:

arrayOfScores = arrayOfServers.collect { | server |
		Pchain(
			Pbind(\freq,
				Pfunc({| ev |
					if (ev[\server] == server)
						{ ev[\freq] }
						{ \rest}
				})
			),
			pattern
		).asScore
}

*/


ScoreStreamPlayer : Server {

	var <>beats, <>tempo;
	var <>bundleList, <>maxTime;

	*new {
		^super.new("record").initScoreStreamPlayer
	}

	initScoreStreamPlayer {
		this.latency_(0);
		Server.all.remove(this); // we do not want to be part of the server list
	}

	beats2secs { | beats | ^beats }
	secs2beats { | beats | ^beats }

	add { | beats, args |
		beats = beats min: maxTime;
		if(beats.isArray) {
			beats.do { |each, i|
				// because of the way events multichannel expand their values
				// before calling ~schedBundle, the args are already flopped.
				// so in this case we just select one for each beat value
				bundleList = bundleList.add([each, args.wrapAt(i)])
			}
		} {
			bundleList = bundleList.add([beats] ++ args)
		}
	}

	prepareEvent { | event |
		event = event.copy;
		event.use({
			~schedBundle = { | lag, offset, server ... bundle |
				this.add(offset * tempo + lag + beats, bundle)
			};
			~schedBundleArray = { | lag, offset, server, bundle |
				this.add(offset * tempo + lag + beats, bundle)
			};
		});
		^event
	}

	makeScore { | stream, duration = 1, event, timeOffset = 0 |
		var ev, startTime, proto;
		proto = (
			server: this,

			schedBundle: { | lag, offset, server ... bundle |
				this.add(offset * tempo + lag + beats, bundle)
			},
			schedBundleArray: { | lag, offset, server, bundle |
				this.add(offset * tempo + lag + beats, bundle)
			}
		);

		event = event ?? { Event.default };
		event = event.copy.putAll(proto);
		beats = timeOffset;
		tempo = 1;
		bundleList = [];
		maxTime = timeOffset + duration;

		// call from a routine so that the stream has this as clock
		Routine {
			thisThread.clock = this;
			while {
				thisThread.beats = beats;
				ev = stream.next(event.copy);
				(maxTime >= beats) and: { ev.notNil }
			} {
				ev.putAll(proto);
				ev.play;
				beats = ev.delta * tempo + beats
			}
		}.next;

		bundleList = bundleList.sort { | a, b | b[0] >= a[0] };

		if((startTime = bundleList[0][0]) < 0) {
			timeOffset = timeOffset - startTime;
		};

//		bundleList.do { | b | b[0] = b[0] + timeOffset }

		^Score(bundleList.add([duration + timeOffset, [\c_set, 0, 0]]))
	}

}