-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgraa_language_functions.py
359 lines (299 loc) · 12.2 KB
/
graa_language_functions.py
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
import sys, os
from datetime import datetime
from infix import shift_infix as infix
from graa_session import GraaSession as session
from graa_logger import GraaLogger as log
from graa_base import GraaBeat as beat
from graa_base import GraaPlayer as player
from graa_scheduler import GraaScheduler as scheduler
from graa_dispatcher import GraaDispatcher as dispatcher
from graa_dispatcher import DispatcherError
from graa_parser import GraaParser as parser
#again, the dirty old hack ...
import __main__
def start_graa():
"""Initialize the graa> session."""
session.active = True
session.scheduler = scheduler()
session.beat = beat()
session.dispatcher = dispatcher()
os.system('clear')
sys.ps1 = "graa> "
log.shell(
"""
__, ,_ __, __,
/ | / | / | / | \
\_/|/ |_/\_/|_/\_/|_/ /
/|
\| Snapshot 2
Welcome, dear follower of the cult of graa> !
""")
# end start_graa()
def quit_graa():
"""Quit graa> and all it's functions."""
log.action("Quitting graa on next beat ... ")
session.active = False
session.scheduler.active = False
session.scheduler.sched_thread.join()
session.beat.beat_thread.join()
for player_key in session.players:
player = session.players[player_key]
if player.active:
player.active = False
player.graph_thread.join()
log.action("Quitting, bye!")
quit()
# end quit_graa()
def stop(*args, **kwargs):
"""
Stop the specified graphs. Think of 'stop' as an your cd player.
The graphs will be reset, overlays removed.
Graphs should be specified in a string,
as a comma-separated list of identifiers.
"""
for arg in args:
for key in arg.split(","):
key = key.strip()
if key == "all":
for player_key in session.players:
try:
print("\nSTOPPING " + key + " AT " + datetime.now().strftime("%H:%M:%S:%f")[:-3]+"\n")
session.players[player_key].stop()
except Exception as e:
log.action("Couldn't hold graph, probably not played yet!")
log.action(str(e))
# raise e
session.players={}
else:
try:
print("\nSTOPPING " + key + " AT " + datetime.now().strftime("%H:%M:%S:%f")[:-3]+"\n")
session.players[key].stop()
del session.players[key]
except Exception as e:
log.action("Couldn't hold graph '{}', probably not played yet!".format(key))
raise e
# end stop()
def pause(*args, **kwargs):
"""
Pause the specified graphs.
Think of 'pause' as on your cd player. You can resume the graph in
its current state.
Graphs should be specified in a string,
as a comma-separated list of identifiers.
"""
for arg in args:
for key in arg.split(","):
key = key.strip()
if key == "all":
for player_key in session.players:
try:
session.players[player_key].pause()
except:
log.action("Couldn't pause graph, probably not played yet!")
# raise
else:
try:
session.players[key].pause()
except:
log.action("Couldn't pause graph '{}', probably not played yet!".format(key))
# end pause()
def tempo(arg):
"""Change tempo of underlying beat. Should adapt to your desired playing speed. """
try:
session.tempo = int(arg)
log.action("Beat tempo set to {} bpm!".format(session.tempo))
except ValueError:
log.action("Invalid tempo specification! - " + arg)
# end tempo()
def delete(keys):
"""
Delete specified graphs, with all consequences.
Graphs should be specified in a string, as a comma-separated list of identifiers.
Example:
delete("a,b,c") - will delete graphs a, b and c
"""
for key in keys.split(","):
key = key.strip()
# stop and remove player if playing
if key in session.players:
if session.players[key].active:
session.players[key].stop()
del session.players[key]
# remove graph
if key in session.graphs:
del session.graphs[key]
if key in session.overlays:
for player in session.players.keys():
#remove overlay from players
if key in session.players[player].overlays:
del session.players[player].overlays[key]
del session.overlays[key]
# end delete()
def play(*args, **kwargs):
"""
Play graphs. You may specify the graphs as one or more comma-separated list in one
string, or multiple strings, or anything that returns a graph id ...
You may specify an "imd" flag. If True, the graph will be started at once, if False (default),
the graph will be started on next beats (faciliates synchronous start of multiple graphs).
Example:
play("a,b","c", d <<shift>> 256, imd=True) -- will immediately play graphs a,b,c, plus graph d with a timeshift.
"""
session.beat.collect_garbage_players()
for command in args:
for key in command.split(","):
key = key.strip()
if key not in session.graphs:
log.action("{} not found!".format(key))
elif key in session.players and session.players[key].active and not session.players[key].paused:
log.action("{} already playing!".format(key))
else:
immediately = kwargs.get("imd", True)
print("\nSTARTING " + key + " AT " + datetime.now().strftime("%H:%M:%S:%f")[:-3]+"\n")
if immediately:
session.beat.start_graph(key)
else:
session.beat.queue_graph(key)
# end play()
# shift a player by some milliseconds
@infix
def shift(graph_ids, delay):
"""
Shift a graph by a specified amount of milliseconds. Use as infix:
"graph_id" <<shift>> 256
"""
for graph_id in graph_ids.split(","):
graph_id = graph_id.strip()
if graph_id not in session.players:
session.players[graph_id] = player(graph_id)
session.players[graph_id].delay = delay
return graph_ids
# end shift()
def expand(graph_id):
"""
Expand a graph, that is, print its textual representation to the shell.
You may specify a single graph.
If the graph is playing, the player copy will be expanded, if not, the
base graph will be used ...
Mostly important for the emacs mode.
"""
try:
log.shell(session.players[graph_id].player_copy)
except KeyError as e:
log.shell(session.graphs[graph_id])
# end expand()
@infix
def plus(graph_ids, overlay_ids):
"""
Add a non-destructive overlay graph to a graph. Use as infix.
Example:
"foo" <<plus>> "foo_ol" -- adds foo_ol to foo.
"""
for graph_id in graph_ids.split(","):
graph_id = graph_id.strip()
if graph_id is "all":
for key in session.graphs:
for overlay_id in overlay_ids.split(","):
overlay_id = overlay_id.strip()
# if no player present for current graph, create one
if key not in session.players:
session.players[key] = player(key)
session.players[key].add_overlay(overlay_id)
log.action("Added overlay: {} to all graphs'".format(overlay_id))
else:
for overlay_id in overlay_ids.split(","):
overlay_id = overlay_id.strip()
# if no player present for current graph, create one
if graph_id not in session.players:
session.players[graph_id] = player(graph_id)
session.players[graph_id].add_overlay(overlay_id)
log.action("Added overlay: {} to graph: {}'".format(overlay_id, graph_id))
return graph_ids
# end plus()
@infix
def permaplus(graph_ids, permalay_ids):
"""
Add a destructive overlay (permalay) graph to a graph. Use as infix.
Example:
"foo" <<plus>> "foo_ol" -- adds foo_ol to foo.
"""
for graph_id in graph_ids.split(","):
graph_id = graph_id.strip()
if graph_id is "all":
for key in session.graphs:
for permalay_id in permalay_ids.split(","):
permalay_id = permalay_id.strip()
# if no player present for current graph, create one
if key not in session.players:
session.players[key] = player(key)
session.players[key].add_permalay(permalay_id)
log.action("Added permalay: {} to all graphs'".format(permalay_id))
else:
for permalay_id in permalay_ids.split(","):
permalay_id = permalay_id.strip()
# if no player present for current graph, create one
if graph_id not in session.players:
session.players[graph_id] = player(graph_id)
session.players[graph_id].add_permalay(permalay_id)
log.action("Added permalay: {} to graph: {}'".format(permalay_id, graph_id))
return graph_ids
# end permaplus
@infix
def minus(graph_ids, overlay_ids):
"""
Remove an overlay graph from a graph. Use as infix.
Example:
"foo" <<minus>> "foo_ol" -- removes foo_ol from foo.
"""
for graph_id in graph_ids.split(","):
graph_id = graph_id.strip()
if graph_id is "all":
for key in session.graphs:
for overlay_id in overlay_ids.split(","):
overlay_id = overlay_id.strip()
if overlay_id in session.players[key].overlays:
session.players[key].remove_overlay(overlay_id)
if overlay_id in session.players[key].permalays:
session.players[key].remove_permalay(overlay_id)
log.action("Remove over-/permalay: {} to all graphs'".format(overlay_id))
else:
for overlay_id in overlay_ids.split(","):
overlay_id = overlay_id.strip()
if overlay_id in session.players[graph_id].overlays:
session.players[graph_id].remove_overlay(overlay_id)
if overlay_id in session.players[graph_id].permalays:
session.players[graph_id].remove_permalay(overlay_id)
log.action("Remove over-/permalay: {} to graph: {}'".format(overlay_id, graph_id))
return graph_ids
# end minus()
def add(string):
"""
Add graph data. The given data will be parsed and added as Nodes and Edges.
Example:
gaa1|dirt~1:casio:0,
gaa1-500:100->gaa1
This will add a graph with id 'gaa', containing one node and one edge.
"""
for command in string.split(","):
try:
session.dispatcher.dispatch(parser.parse(command))
except DispatcherError as de:
log.action(de.message)
# end add()
def status():
log.shell("Currently playing: ")
for key in session.players:
playline = "'" + str(key) + "' plus "
for ol_key in session.players[key].overlays:
playline += "'" + str(ol_key) + "' "
playline += " permaplus "
for pl_key in session.players[key].permalays:
playline += "'" + str(pl_key) + "' "
log.shell(playline)
# end status()
# change a variable in the main context
#def setvar(var, value):
# #print(var, value)
# setattr(__main__, var, value)
#basically the same, just for the sake of clarity
def inject(function):
setattr(__main__, function.__name__, function)