2 Created on 23 juil. 2009
4 @author: Samuel Benveniste
6 from math
import floor
, ceil
12 from gradients
import gradients
13 from logging
.PickleableEvent
import PickleableEvent
14 from instruments
.Instrument
import Instrument
15 from cursor
.WarpingCursor
import *
16 from controllers
.Wiimote
import Wiimote
17 from logging
.EventLog
import EventLog
20 class StaticFamiliarizer
:
22 The screen on which the game is played
25 The wiimotes used in this session
27 The main display window
29 The main display surface
31 The clock used to animate the screen
33 The background that is painted every time
35 The buffer for painting everything before bliting
37 The width of the window in pixels
39 The height of the window in pixels
41 True if the scale is G to C instead of C to C
43 True if crossing from note to note with a button pressed triggers a new note
45 The size of the scale used
47 The positions of the cursors on the screen, in pixels
52 def __init__(self
, wiimotes
, window
, screen
, clock
, joys
, portOffset
,activeWiimotes
,replay
= False, level
= 0, defaultInstrumentChannel
= 16, defaultNote
= 60, eventLog
= None):
56 self
.firstClickTime
= None
57 self
.firstClickInTime
= None
63 self
.font
= pygame
.font
.Font(None,60)
64 self
.congratulations
= ["Bien !","Tres Bien !","Bravo !","Excellent !","Felicitations !"]
65 self
.renderedCongratulations
= [self
.font
.render(congratulation
,False,(0,0,0)) for congratulation
in self
.congratulations
]
66 self
.congratulationCount
= None
67 self
.isCongratulating
= False
68 self
.congratulationTimer
= 0
69 self
.congratulationLength
= 2000
70 self
.congratulationPos
= None
72 self
.blinkLength
= 200
73 self
.minimalVelocity
= 64
74 self
.shortScaleSize
= 8
75 self
.longScaleSize
= 11
77 self
.savedHighlightedNote
= 0
79 self
.wiimotes
= wiimotes
83 self
.width
= int(floor(screen
.get_width()*self
.scaleFactor
))
84 self
.height
= int(floor(screen
.get_height()*self
.scaleFactor
))
85 self
.blitOrigin
= ((self
.screen
.get_width()-self
.width
)/2,(self
.screen
.get_height()-self
.height
)/2)
87 self
.portOffset
= portOffset
88 self
.savedScreen
= pygame
.Surface(self
.screen
.get_size())
89 self
.savedScreen
.fill((255,255,255))
90 self
.playerScreen
= pygame
.Surface(self
.savedScreen
.get_size())
91 self
.playerScreen
.blit(self
.savedScreen
, (0, 0))
92 self
.cursorPositions
= []
95 self
.activeWiimotes
= activeWiimotes
97 for i
in range(len(self
.wiimotes
)):
98 #Set the screen for the cursors (it can't be set before)
99 self
.wiimotes
[i
].cursor
.screen
= self
.playerScreen
100 self
.cursorPositions
.append(self
.wiimotes
[i
].cursor
.centerPosition
)
103 self
.eventLog
= EventLog()
106 self
.eventLog
= eventLog
109 self
.defaultInstrumentChannel
= defaultInstrumentChannel
110 self
.defaultNote
= defaultNote
113 self
.backToInstrumentChoice
= False
114 self
.easyMode
= False
117 self
.boundingRect
= None
120 self
.velocityLock
= []
122 self
.drawBackground()
123 self
.initializeWiimotes()
124 events
= pygame
.event
.get()
127 while not self
.done
:
129 self
.playerScreen
.blit(self
.savedScreen
, (0, 0))
131 # Limit frame speed to 50 FPS
133 timePassed
= self
.clock
.tick(10000)
136 self
.eventLog
.update(timePassed
)
137 pickledEventsToPost
= self
.eventLog
.getPickledEvents()
138 for pickledEvent
in pickledEventsToPost
:
139 pygame
.event
.post(pickledEvent
.event
)
141 events
= pygame
.event
.get()
144 pickledEvents
= [PickleableEvent(event
.type,event
.dict) for event
in events
]
145 if pickledEvents
!= [] :
146 self
.eventLog
.appendEventGroup(pickledEvents
)
151 if self
.isCongratulating
:
152 self
.congratulationTimer
+= timePassed
153 if self
.congratulationTimer
< self
.congratulationLength
:
154 self
.blitCongratulation()
156 self
.isCongratulating
= False
158 for i
in range(len(self
.wiimotes
)):
159 if self
.activeWiimotes
[i
]:
160 self
.wiimotes
[i
].cursor
.update(timePassed
, self
.cursorPositions
[i
])
161 if self
.buttonDown
[i
] :
162 self
.wiimotes
[i
].cursor
.flash()
163 self
.wiimotes
[i
].cursor
.blit(self
.playerScreen
)
165 self
.screen
.blit(self
.playerScreen
, (0,0))
167 pygame
.display
.flip()
169 for i
in range(len(self
.wiimotes
)):
170 if self
.activeWiimotes
[i
]:
171 if self
.notes
[i
] != None :
172 self
.wiimotes
[i
].stopNote(self
.notes
[i
])
174 self
.duration
= self
.eventLog
.getCurrentTime()
176 def drawBackground(self
):
177 self
.savedScreen
.fill((255,255,255))
183 self
.noteRects
= [pygame
.Rect(i
* self
.width
/ 11+self
.blitOrigin
[0], self
.blitOrigin
[1], (self
.width
/ 11 + 1)*3, self
.height
+1) for i
in A
]
185 #create bounding rect
186 self
.boundingRect
= self
.noteRects
[0].unionall(self
.noteRects
)
188 #fill the rectangles with a color gradient
190 startingHue
= 0.66666666666666663
192 for rectNumber
in range(len(self
.noteRects
)) :
193 colorRatio
= float(A
[rectNumber
]) / (11 - 1)
194 #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up
195 hue
= startingHue
* (1 - colorRatio
)
196 #The color of the bottom of the rectangle in hls coordinates
197 bottomColorHls
= (hue
, 0.6, 1)
198 #The color of the top of the rectangle in hls coordinates
199 topColorHls
= (hue
, 0.9, 1)
201 #convert to rgb ranging from 0 to 255
202 bottomColorRgb
= [floor(255 * i
) for i
in colorsys
.hls_to_rgb(*bottomColorHls
)]
203 topColorRgb
= [floor(255 * i
) for i
in colorsys
.hls_to_rgb(*topColorHls
)]
205 bottomColorRgb
.append(255)
206 topColorRgb
.append(255)
208 bottomColorRgb
= tuple(bottomColorRgb
)
209 topColorRgb
= tuple(topColorRgb
)
211 self
.savedScreen
.blit(gradients
.vertical(self
.noteRects
[rectNumber
].size
, topColorRgb
, bottomColorRgb
), self
.noteRects
[rectNumber
])
213 pygame
.draw
.rect(self
.savedScreen
, pygame
.Color(0, 0, 0, 255), self
.noteRects
[rectNumber
], 2)
215 def initializeWiimotes(self
):
216 for loop
in self
.wiimotes
:
217 if loop
.port
== None :
218 loop
.port
= pygame
.midi
.Output(loop
.portNumber
)
220 self
.buttonDown
.append(False)
221 self
.velocityLock
.append(False)
223 def updateCursorPositionFromJoy(self
, joyEvent
):
224 joyName
= pygame
.joystick
.Joystick(joyEvent
.joy
).get_name()
225 correctedJoyId
= constants
.joyNames
.index(joyName
)
226 if correctedJoyId
< len(self
.cursorPositions
):
227 if joyEvent
.axis
== 0 :
228 self
.cursorPositions
[correctedJoyId
] = (int((joyEvent
.value
+ 1) / 2 * self
.screen
.get_width()), self
.cursorPositions
[correctedJoyId
][1])
229 if joyEvent
.axis
== 1 :
230 self
.cursorPositions
[correctedJoyId
] = (self
.cursorPositions
[correctedJoyId
][0], int((joyEvent
.value
+ 1) / 2 * self
.screen
.get_height()))
232 def heightToVelocity(self
, pos
, controllerNumber
):
233 velocity
= int(floor((1 - (float(pos
[1])-self
.blitOrigin
[1]) / self
.height
) * (127-self
.minimalVelocity
))+self
.minimalVelocity
)
236 def widthToNote(self
, pos
):
239 while self
.noteRects
[nn
].collidepoint(pos
) == False:
245 def congratulate(self
,targetRect
,posy
):
246 if self
.congratulationCount
!= None :
247 if self
.congratulationCount
< len(self
.congratulations
)-1:
248 self
.congratulationCount
+= 1
250 self
.congratulationCount
= 0
251 self
.congratulationTimer
= 0
252 self
.congratulationPos
= (targetRect
.left
+(targetRect
.width
-self
.renderedCongratulations
[self
.congratulationCount
].get_width())/2,posy
)
253 self
.isCongratulating
= True
255 def resetCongratulation(self
):
256 self
.congratulationCount
= None
257 self
.congratulationPos
= None
258 self
.isCongratulating
= False
260 def blitCongratulation(self
):
261 self
.playerScreen
.blit(self
.renderedCongratulations
[self
.congratulationCount
],self
.congratulationPos
)
263 def input(self
, event
):
267 if event
.type == pygame
.QUIT
:
268 for loop
in self
.wiimotes
:
273 if event
.type == pygame
.KEYDOWN
:
274 if event
.key
== pygame
.K_q
:
275 self
.nextLevel
= None
278 if event
.key
== pygame
.K_w
:
282 if event
.key
== pygame
.K_e
:
286 if event
.key
== pygame
.K_r
:
290 if event
.key
== pygame
.K_t
:
294 if event
.type == pygame
.JOYAXISMOTION
:
297 joyName
= pygame
.joystick
.Joystick(event
.joy
).get_name()
298 correctedJoyId
= constants
.joyNames
.index(joyName
)
299 if self
.activeWiimotes
[correctedJoyId
]:
300 self
.updateCursorPositionFromJoy(event
)
301 wiimote
= self
.wiimotes
[correctedJoyId
]
302 pos
= self
.cursorPositions
[correctedJoyId
]
304 if self
.buttonDown
[correctedJoyId
]:
305 wiimote
.cursor
.flash()
306 if self
.notes
[correctedJoyId
] != None:
307 velocity
= self
.heightToVelocity(pos
, correctedJoyId
)
308 CCHexCode
= wiimote
.getCCHexCode()
309 wiimote
.port
.write_short(CCHexCode
, 07, velocity
)
311 if event
.type == pygame
.JOYBUTTONDOWN
:
313 joyName
= pygame
.joystick
.Joystick(event
.joy
).get_name()
314 correctedJoyId
= constants
.joyNames
.index(joyName
)
315 if self
.activeWiimotes
[correctedJoyId
]:
316 wiimote
= self
.wiimotes
[correctedJoyId
]
317 pos
= self
.cursorPositions
[correctedJoyId
]
318 wiimote
.cursor
.flash()
321 if self
.firstClickTime
== None :
322 self
.firstClickTime
= self
.eventLog
.getCurrentTime()
324 if not self
.buttonDown
[correctedJoyId
]:
325 self
.notes
[correctedJoyId
] = self
.widthToNote(pos
)
327 velocity
= self
.heightToVelocity(pos
, correctedJoyId
)
329 if self
.notes
[correctedJoyId
] != None :
330 wiimote
.playNote(self
.notes
[correctedJoyId
],velocity
)
331 self
.congratulate(self
.noteRects
[self
.notes
[correctedJoyId
]],pos
[1])
334 if self
.firstClickInTime
== None :
335 self
.firstClickInTime
= self
.eventLog
.getCurrentTime()
337 self
.resetCongratulation()
339 self
.buttonDown
[correctedJoyId
] = True
341 if event
.type == pygame
.JOYBUTTONUP
:
342 joyName
= pygame
.joystick
.Joystick(event
.joy
).get_name()
343 correctedJoyId
= constants
.joyNames
.index(joyName
)
344 if self
.activeWiimotes
[correctedJoyId
]:
345 wiimote
= self
.wiimotes
[correctedJoyId
]
346 wiimote
.stopNote(self
.notes
[correctedJoyId
])
347 self
.buttonDown
[correctedJoyId
] = False
348 self
.velocityLock
[correctedJoyId
] = False
350 if event
.type == pygame
.MOUSEMOTION
:
352 self
.updateCursorPositionFromMouse(event
)
355 while not self
.activeWiimotes
[correctedJoyId
] :
357 wiimote
= self
.wiimotes
[correctedJoyId
]
358 pos
= self
.cursorPositions
[correctedJoyId
]
360 if self
.buttonDown
[correctedJoyId
]:
361 wiimote
.cursor
.flash()
362 if self
.notes
[correctedJoyId
] != None:
363 velocity
= self
.heightToVelocity(pos
, correctedJoyId
)
364 CCHexCode
= wiimote
.getCCHexCode()
365 wiimote
.port
.write_short(CCHexCode
, 07, velocity
)
367 if event
.type == pygame
.MOUSEBUTTONDOWN
:
369 if event
.button
== 1:
371 while not self
.activeWiimotes
[correctedJoyId
] :
373 wiimote
= self
.wiimotes
[correctedJoyId
]
374 pos
= self
.cursorPositions
[correctedJoyId
]
375 wiimote
.cursor
.flash()
378 if self
.firstClickTime
== None :
379 self
.firstClickTime
= self
.eventLog
.getCurrentTime()
381 if not self
.buttonDown
[correctedJoyId
]:
382 self
.notes
[correctedJoyId
] = self
.widthToNote(pos
)
384 velocity
= self
.heightToVelocity(pos
, correctedJoyId
)
386 if self
.notes
[correctedJoyId
] != None :
387 wiimote
.playNote(self
.notes
[correctedJoyId
],velocity
)
388 self
.congratulate(self
.noteRects
[self
.notes
[correctedJoyId
]],pos
[1])
391 if self
.firstClickInTime
== None :
392 self
.firstClickInTime
= self
.eventLog
.getCurrentTime()
394 self
.resetCongratulation()
396 self
.buttonDown
[correctedJoyId
] = True
398 if event
.button
== 2:
402 if event
.type == pygame
.MOUSEBUTTONUP
:
405 while not self
.activeWiimotes
[correctedJoyId
] :
407 wiimote
= self
.wiimotes
[correctedJoyId
]
408 wiimote
.stopNote(self
.notes
[correctedJoyId
])
409 self
.buttonDown
[correctedJoyId
] = False
410 self
.velocityLock
[correctedJoyId
] = False
412 def hasChanged(self
):
415 def updateCursorPositionFromMouse(self
, mouseEvent
):
417 while not self
.activeWiimotes
[correctedJoyId
] :
419 self
.cursorPositions
[correctedJoyId
] = mouseEvent
.pos
421 if __name__
== "__main__" :
423 modeResolution
= (1024,768)
424 window
= pygame
.display
.set_mode(modeResolution
,pygame
.FULLSCREEN
)
428 instruments
= [Instrument(constants
.scaleDict
["majorScale"], i
+ 1, "".join(["../instruments/instrumentImages/", constants
.instrumentImagePathList
[i
], ".jpg"]), constants
.octaves
[i
]) for i
in range(9)]
430 joys
= [[id,pygame
.joystick
.Joystick(id).get_name()] for id in range(pygame
.joystick
.get_count())]
432 if joy
[1] in constants
.joyNames
:
433 pygame
.joystick
.Joystick(joy
[0]).init()
435 ports
= [pygame
.midi
.get_device_info(id)[1] for id in range(pygame
.midi
.get_count())]
436 portOffset
= ports
.index(constants
.portNames
[0])
439 events
= pygame
.event
.get()
441 screen
= pygame
.display
.get_surface()
442 clock
= pygame
.time
.Clock()
443 cursorImages
= [createImageListFromPath('../cursor/cursorImages/black', 11),createImageListFromPath('../cursor/cursorImages/red', 11)]
444 durations
= [75 for i
in range(len(cursorImages
[0]))]
447 cursors
= [WarpingCursor(None, cursorImages
[i
], durations
, (300 * i
, 300 * i
),flashImage
= '../cursor/cursorImages/black/flash.png' ) for i
in range(wiimoteCount
)]
448 wiimotes
= [Wiimote(i
, i
+ portOffset
, None, instruments
[i
], cursors
[i
]) for i
in range(wiimoteCount
)]
450 fam
= StaticFamiliarizer(instruments
, wiimotes
, window
, screen
, clock
, joys
, portOffset
)
452 for loop
in fam
.wiimotes
: