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
|
import pickle
import time
import pygtk
pygtk.require( '2.0' )
import gtk
import gobject
import math
from Framework.Constants import Constants
from Framework.CSound.CSoundNote import CSoundNote
from Framework.CSound.CSoundClient import CSoundClient
from Framework.CSound.CSoundConstants import CSoundConstants
#------------------------------------------------------------------------------
# A base class used to play a collection of Events at their respective onsets
#------------------------------------------------------------------------------
class EventPlayer:
#-----------------------------------
# initialization
#-----------------------------------
def __init__( self ):
self.time0 = 0
self.horizonDelay = Constants.CSOUND_HORIZON
self.horizonTime = 0
self.horizonOnset = 0
self.clockDelay = Constants.CLOCK_DELAY
self.eventDictionary = {}
self.currentTick = 0
self.playbackTimeout = None
self.tempo = Constants.DEFAULT_TEMPO
self.send_buffer = ""
def getCurrentTick(self):
# used by keyboard
return self.currentTick
def getTempo( self ):
return self.tempo
#-----------------------------------
# playback functions
#-----------------------------------
def playing( self ):
return self.playbackTimeout != None
def startPlayback( self ):
self.time0 = time.time()
self.horizonTime = 0.0
self.horizonOnset = 0
#schedule the handler...
self.playbackTimeout = gobject.timeout_add( int ( 1000 * self.clockDelay) , self.handleClock )
#and call it right away too.
self.handleClock()
def stopPlayback( self ):
if self.playbackTimeout != None:
gobject.source_remove( self.playbackTimeout )
self.playbackTimeout = None
self.shutOff()
# this will happen
def handleClock( self ) :
def onsetCommand( onset, tempo, delay ):
rval = ""
if self.eventDictionary.has_key( onset ):
for event in self.eventDictionary[ onset ]:
rval += event.getText( tempo, delay)
return rval
onsetPerSecond = self.tempo / 60.0 * Constants.TICKS_PER_BEAT
nowTime = time.time() - self.time0
nextTime = self.horizonTime
nextOnset = self.horizonOnset
horizonTime = nowTime + self.horizonDelay
self.horizonOnset = int( horizonTime * onsetPerSecond )
self.horizonTime = self.horizonOnset * onsetPerSecond
self.send_buffer = ""
for i in range( nextOnset, self.horizonOnset ) :
self.delay = i / onsetPerSecond - nowTime
if (self.delay > 0.0 ) :
ev = self.eventDictionary
self.hookTick( ) # may modify currentTick, eventDictionary
self.send_buffer += onsetCommand( self.currentTick, self.tempo, self.delay )
self.currentTick = self.currentTick + 1
else :
print 'WARNING: excessive latency... dropping note with delay %f' % self.delay
if self.send_buffer != "" :
CSoundClient.sendText( self.send_buffer )
#this may invoke GUI crap, which may take a long time
self.hookClock()
return True
#this is meant to handle things that happen once per clock... like the GUI
def hookClock( self ) :
pass
# this is meant to be overridden by things that need to happen on every onset
def hookTick( self ) :
pass
#
# serialization
#
VERSION = '_testing_'
def serialize(self, f):
pickle.dump( self.VERSION, f)
pickle.dump( self.tempo, f )
def unserialize(self, f):
if pickle.load( f ) != self.VERSION :
raise WrongVersionError
self.tempo = pickle.load( f )
# hack for shutOff tied notes when stop playing ( don't work when tracks are selected, probably not for mute...
def shutOff( self ):
for track in range( Constants.NUMBER_OF_TRACKS ):
for i in range( 3 ):
csoundInstrument = i + 101
CSoundClient.sendText( CSoundConstants. PLAY_NOTE_OFF_COMMAND % ( csoundInstrument, track ) )
#-----------------------------------
# add/remove event functions (event(s) must be Event instances)
#-----------------------------------
def add( self, event ):
self.addToDictionary( self.eventDictionary )
def addToDictionary( self, event, eventDictionary ):
if eventDictionary.has_key( event.onset ):
eventDictionary[ event.onset ].add( event )
else:
eventDictionary[ event.onset ] = set( [ event ] )
def addMultiple( self, events ):
self.addMultipleToDictionary( events, self.eventDictionary )
def addMultipleToDictionary( self, events, eventDictionary ):
for event in events:
self.addToDictionary( event, eventDictionary )
def remove( self, event ):
self.removeFromDictionary( event, self.eventDictionary )
def removeFromDictionary( self, event, eventDictionary ):
if eventDictionary.has_key( event.onset ) and event in eventDictionary[ event.onset ]:
eventDictionary[ event.onset ].remove( event )
def removeMultiple( self, events ):
self.removeMultipleFromDictionary( events, self.eventDictionary )
def removeMultipleFromDictionary( self, events, eventDictionary ):
for event in events:
self.removeFromDictionary( event, eventDictionary )
def clear( self ):
self.eventDictionary.clear()
|