agrandissement avec maintient du bon point de référence.
[minwii.git] / src / gui / SongPlayingScreen.py
1 '''
2 Created on 23 juil. 2009
3
4 @author: Samuel Benveniste
5 '''
6 from math import floor, ceil
7 import pygame
8 import sys
9 import colorsys
10 import constants
11 from gradients import gradients
12 from logging.PickleableEvent import PickleableEvent
13 from songs.Song import Song
14 from songs.musicxmltosong import Part
15
16
17 class SongPlayingScreen:
18 '''
19 The screen on which the game is played
20
21 wiimotes:
22 The wiimotes used in this session
23 window:
24 The main display window
25 screen:
26 The main display surface
27 clock:
28 The clock used to animate the screen
29 savedScreen:
30 The background that is painted every time
31 playerScreen:
32 The buffer for painting everything before bliting
33 width:
34 The width of the window in pixels
35 height:
36 The height of the window in pixels
37 extendScale :
38 True if the scale is G to C instead of C to C
39 cascade:
40 True if crossing from note to note with a button pressed triggers a new note
41 scaleSize:
42 The size of the scale used
43 cursorPositions:
44 The positions of the cursors on the screen, in pixels
45 '''
46
47
48
49 def __init__(self, instrumentChoice, pguconf):# song, cascade=False, extendedScale=False, easyMode = False, alwaysDown = False, eventLog = None, replay = None, defaultInstrumentChannel = 16, defaultNote = 60):
50 '''
51 Constructor
52 '''
53 song = pguconf.song
54 cascade = pguconf.cascade
55 extendedScale = song.requiresExtendedScale
56 easyMode = pguconf.easyMode
57 alwaysDown = pguconf.alwaysDown
58 eventLog = instrumentChoice.eventLog
59 replay = instrumentChoice.replay
60 defaultInstrumentChannel = 16
61 defaultNote = 60
62
63 if isinstance(song, Song) :
64 self.songDurations = []
65 self.totalDuration = None
66 self.clicks = [0]
67 self.clicksIn = [0]
68 self.clicksPerMinute = [0]
69 self.clicksInPerMinute = [0]
70 self.meanTimeBetweenNotes = []
71 self.firstClick = None
72 self.firstClickIn = None
73
74 self.blinkLength = 200
75 self.minimalVelocity = 90
76 self.shortScaleSize = 8
77 self.longScaleSize = 11
78 if not extendedScale:
79 self.offset = self.longScaleSize - self.shortScaleSize
80 else:
81 self.offset = 0
82 self.borderSize = 5
83 self.highlightedNote = 0
84 self.highlightedNoteNumber = 0
85 self.syllabus = None
86 self.savedHighlightedNote = 0
87 self.alwaysDown = alwaysDown
88 self.nextLevel = None
89
90 self.wiimotes = instrumentChoice.wiimotes
91 self.activeWiimotes = instrumentChoice.activeWiimotes
92 self.window = instrumentChoice.window
93 self.screen = instrumentChoice.screen
94 self.blitOrigin = instrumentChoice.blitOrigin
95 self.clock = instrumentChoice.clock
96 self.width = instrumentChoice.width
97 self.height = instrumentChoice.height
98 self.cursorPositions = instrumentChoice.cursorPositions
99 self.savedScreen = instrumentChoice.savedScreen
100 self.playerScreen = instrumentChoice.playerScreen
101 self.extendedScale = extendedScale
102 self.cascade = cascade
103 self.joys = instrumentChoice.joys
104 self.portOffset = instrumentChoice.portOffset
105 if eventLog == None :
106 self.eventLog = instrumentChoice.eventLog
107 else :
108 self.eventLog = eventLog
109 self.cursorPositions = instrumentChoice.cursorPositions
110 self.song = song
111 self.songIterator = self.song.getSongIterator()
112 self.midiNoteNumbers = self.song.scale
113 if replay == None :
114 self.replay = instrumentChoice.replay
115 else :
116 self.replay = replay
117 self.quarterNoteLength = song.quarterNoteLength
118 self.cascadeLockLengthMultiplier = 1
119 self.nextCascadeLockLengthMultiplier = 1
120 self.cascadeLockLength = self.quarterNoteLength * self.cascadeLockLengthMultiplier
121
122 self.defaultInstrumentChannel = defaultInstrumentChannel
123 self.defaultNote = defaultNote
124
125 self.done = False
126 self.backToInstrumentChoice = False
127 self.easyMode = easyMode
128
129 #Initializes the highlightedNote and highlightedNoteNumber etc...
130 self.moveToNextNote()
131 self.cascadeLockLengthMultiplier = self.nextCascadeLockLengthMultiplier
132
133 self.blinkOn = False
134 self.savedBlinkOn = False
135 ##Will prevent the song to move on if two consecutive notes are identical and the buttons have not been released in between the two
136 ##i.e. it guarantees that there will be an attack between two identical consecutive notes
137 self.highlightIsFree = True
138
139 self.noteRects = []
140 self.boundingRect = None
141 self.notes = []
142
143 self.buttonDown = []
144 self.velocityLock = []
145
146 self._blinkOffset = 0
147 self._cascadeLockTimer = 0
148 self.cascadeIsFree = True
149
150 self.font = pygame.font.Font(None,80)
151 self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers]
152
153 self.drawBackground()
154 self.initializeWiimotes()
155
156 self.songStartTime = self.eventLog.getCurrentTime()
157
158 #The main loop
159 while not self.done :
160
161 #Clear the cursors from the screen
162 if self.hasChanged():
163 self.drawBackground()
164 self.playerScreen.blit(self.savedScreen, (0, 0))
165
166 # Limit frame speed to 50 FPS
167 #
168 timePassed = self.clock.tick(10000)
169
170 self._blinkOffset += timePassed
171 if (self.buttonDown or self.alwaysDown) and not self.cascadeIsFree :
172 self._cascadeLockTimer += timePassed
173 if self._cascadeLockTimer > self.cascadeLockLengthMultiplier*self.quarterNoteLength :
174 self.cascadeIsFree = True
175 self.cascadeLockLengthMultiplier = self.nextCascadeLockLengthMultiplier
176
177
178 if self._blinkOffset > self.blinkLength:
179 self._blinkOffset -= self.blinkLength
180 self.blinkOn = not self.blinkOn
181
182 if self.replay:
183 self.eventLog.update(timePassed)
184 pickledEventsToPost = self.eventLog.getPickledEvents()
185 for pickledEvent in pickledEventsToPost:
186 pygame.event.post(pickledEvent.event)
187
188 events = pygame.event.get()
189
190 if not self.replay:
191 pickledEvents = [PickleableEvent(event.type,event.dict) for event in events]
192 if pickledEvents != [] :
193 self.eventLog.appendEventGroup(pickledEvents)
194
195 for event in events:
196 self.input(event)
197
198 for i in range(len(self.wiimotes)):
199 if self.activeWiimotes[i]:
200 self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i])
201 if self.buttonDown[i] or self.alwaysDown:
202 self.wiimotes[i].cursor.flash()
203 self.wiimotes[i].cursor.blit(self.playerScreen)
204
205 self.screen.blit(self.playerScreen, (0,0))
206
207 pygame.display.flip()
208
209 for i in range(len(self.wiimotes)):
210 if self.activeWiimotes[i]:
211 self.wiimotes[i].stopNoteByNoteNumber(self.midiNoteNumbers[self.notes[i]])
212 if self.replay :
213 self.totalDuration = self.eventLog.getCurrentTime()
214
215 elif isinstance(song, Part) :
216 self.songDurations = []
217 self.totalDuration = None
218 self.clicks = [0]
219 self.clicksIn = [0]
220 self.clicksPerMinute = [0]
221 self.clicksInPerMinute = [0]
222 self.meanTimeBetweenNotes = []
223 self.firstClick = None
224 self.firstClickIn = None
225
226 self.blinkLength = 200
227 self.minimalVelocity = 90
228 self.shortScaleSize = 8
229 self.longScaleSize = 11
230 if not extendedScale:
231 self.offset = self.longScaleSize - self.shortScaleSize
232 else:
233 self.offset = 0
234 self.borderSize = 5
235 self.highlightedNote = 0
236 self.highlightedNoteNumber = 0
237 self.syllabus = None
238 self.savedHighlightedNote = 0
239 self.alwaysDown = alwaysDown
240 self.nextLevel = None
241
242 self.wiimotes = instrumentChoice.wiimotes
243 self.activeWiimotes = instrumentChoice.activeWiimotes
244 self.window = instrumentChoice.window
245 self.screen = instrumentChoice.screen
246 self.blitOrigin = instrumentChoice.blitOrigin
247 self.clock = instrumentChoice.clock
248 self.width = instrumentChoice.width
249 self.height = instrumentChoice.height
250 self.cursorPositions = instrumentChoice.cursorPositions
251 self.savedScreen = instrumentChoice.savedScreen
252 self.playerScreen = instrumentChoice.playerScreen
253 self.extendedScale = extendedScale
254 self.cascade = cascade
255 self.joys = instrumentChoice.joys
256 self.portOffset = instrumentChoice.portOffset
257 if eventLog == None :
258 self.eventLog = instrumentChoice.eventLog
259 else :
260 self.eventLog = eventLog
261 self.cursorPositions = instrumentChoice.cursorPositions
262 self.song = song
263 self.songIterator = self.song.iterNotes()
264 self.midiNoteNumbers = self.song.scale
265 if replay == None :
266 self.replay = instrumentChoice.replay
267 else :
268 self.replay = replay
269 self.quarterNoteLength = song.quarterNoteLength
270 self.cascadeLockLengthMultiplier = 1
271 self.nextCascadeLockLengthMultiplier = 1
272 self.cascadeLockLength = self.quarterNoteLength * self.cascadeLockLengthMultiplier
273
274 self.defaultInstrumentChannel = defaultInstrumentChannel
275 self.defaultNote = defaultNote
276
277 self.done = False
278 self.backToInstrumentChoice = False
279 self.easyMode = easyMode
280
281 #Initializes the highlightedNote and highlightedNoteNumber etc...
282 self.moveToNextNote()
283 self.cascadeLockLengthMultiplier = self.nextCascadeLockLengthMultiplier
284
285 self.blinkOn = False
286 self.savedBlinkOn = False
287 ##Will prevent the song to move on if two consecutive notes are identical and the buttons have not been released in between the two
288 ##i.e. it guarantees that there will be an attack between two identical consecutive notes
289 self.highlightIsFree = True
290
291 self.noteRects = []
292 self.boundingRect = None
293 self.notes = []
294
295 self.buttonDown = []
296 self.velocityLock = []
297
298 self._blinkOffset = 0
299 self._cascadeLockTimer = 0
300 self.cascadeIsFree = True
301
302 self.font = pygame.font.Font(None,80)
303 self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers]
304
305 self.drawBackground()
306 self.initializeWiimotes()
307
308 self.songStartTime = self.eventLog.getCurrentTime()
309
310 #The main loop
311 while not self.done :
312
313 #Clear the cursors from the screen
314 if self.hasChanged():
315 self.drawBackground()
316 self.playerScreen.blit(self.savedScreen, (0, 0))
317
318 # Limit frame speed to 50 FPS
319 #
320 timePassed = self.clock.tick(10000)
321
322 self._blinkOffset += timePassed
323 if (self.buttonDown or self.alwaysDown) and not self.cascadeIsFree :
324 self._cascadeLockTimer += timePassed
325 if self._cascadeLockTimer > self.cascadeLockLengthMultiplier*self.quarterNoteLength :
326 self.cascadeIsFree = True
327 self.cascadeLockLengthMultiplier = self.nextCascadeLockLengthMultiplier
328
329
330 if self._blinkOffset > self.blinkLength:
331 self._blinkOffset -= self.blinkLength
332 self.blinkOn = not self.blinkOn
333
334 if self.replay:
335 self.eventLog.update(timePassed)
336 pickledEventsToPost = self.eventLog.getPickledEvents()
337 for pickledEvent in pickledEventsToPost:
338 pygame.event.post(pickledEvent.event)
339
340 events = pygame.event.get()
341
342 if not self.replay:
343 pickledEvents = [PickleableEvent(event.type,event.dict) for event in events]
344 if pickledEvents != [] :
345 self.eventLog.appendEventGroup(pickledEvents)
346
347 for event in events:
348 self.input(event)
349
350 for i in range(len(self.wiimotes)):
351 if self.activeWiimotes[i]:
352 self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i])
353 if self.buttonDown[i] or self.alwaysDown:
354 self.wiimotes[i].cursor.flash()
355 self.wiimotes[i].cursor.blit(self.playerScreen)
356
357 self.screen.blit(self.playerScreen, (0,0))
358
359 pygame.display.flip()
360
361 for i in range(len(self.wiimotes)):
362 if self.activeWiimotes[i]:
363 self.wiimotes[i].stopNoteByNoteNumber(self.midiNoteNumbers[self.notes[i]])
364 if self.replay :
365 self.totalDuration = self.eventLog.getCurrentTime()
366
367 def drawBackground(self):
368 self.savedScreen.fill((255,255,255))
369
370 if self.extendedScale :
371 self.scaleSize = self.longScaleSize
372 else:
373 self.scaleSize = self.shortScaleSize
374
375 self.noteRects = [pygame.Rect(i * self.width / self.scaleSize+self.blitOrigin[0], self.blitOrigin[1], self.width / self.scaleSize + 1, self.height+1) for i in range(self.scaleSize)]
376 #inflate last noteRect to cover the far right pixels
377 self.noteRects[-1].width = self.noteRects[-1].width + 1
378
379 self.noteRects[self.highlightedNote-self.offset].inflate_ip(self.noteRects[self.highlightedNote-self.offset].width*2,0)
380
381 #create bounding rect
382 self.boundingRect = self.noteRects[0].unionall(self.noteRects)
383
384 self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers]
385
386 #fill the rectangles with a color gradient
387 #We start with blue
388 startingHue = 0.66666666666666663
389
390 for rectNumber in range(self.scaleSize):
391 colorRatio = float(rectNumber) / (self.scaleSize - 1)
392 #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up
393 hue = startingHue * (1 - colorRatio)
394 if rectNumber + self.offset != self.highlightedNote:
395 #The color of the bottom of the rectangle in hls coordinates
396 bottomColorHls = (hue, 0.1, 1)
397 #The color of the top of the rectangle in hls coordinates
398 topColorHls = (hue, 0.1, 1)
399
400 #convert to rgb ranging from 0 to 255
401 bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)]
402 topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)]
403 #add transparency
404 bottomColorRgb.append(255)
405 topColorRgb.append(255)
406 #convert to tuple
407 bottomColorRgb = tuple(bottomColorRgb)
408 topColorRgb = tuple(topColorRgb)
409
410 self.savedScreen.blit(gradients.vertical(self.noteRects[rectNumber].size, topColorRgb, bottomColorRgb), self.noteRects[rectNumber])
411
412 noteNameBlitPoint = (self.noteRects[rectNumber].left+(self.noteRects[rectNumber].width-self.renderedNoteNames[rectNumber+self.offset].get_width())/2,
413 self.noteRects[rectNumber].bottom-self.renderedNoteNames[rectNumber+self.offset].get_height())
414
415 self.savedScreen.blit(self.renderedNoteNames[rectNumber+self.offset], noteNameBlitPoint)
416
417 pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[rectNumber], 2)
418
419 colorRatio = float(self.highlightedNote-self.offset) / (self.scaleSize - 1)
420 #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up
421 hue = startingHue * (1 - colorRatio)
422 #The color of the bottom of the rectangle in hls coordinates
423 bottomColorHls = (hue, 0.6, 1)
424 #The color of the top of the rectangle in hls coordinates
425 topColorHls = (hue, 0.9, 1)
426
427 #convert to rgb ranging from 0 to 255
428 bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)]
429 topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)]
430 #add transparency
431 bottomColorRgb.append(255)
432 topColorRgb.append(255)
433 #convert to tuple
434 bottomColorRgb = tuple(bottomColorRgb)
435 topColorRgb = tuple(topColorRgb)
436
437 self.savedScreen.blit(gradients.vertical(self.noteRects[self.highlightedNote-self.offset].size, topColorRgb, bottomColorRgb), self.noteRects[self.highlightedNote-self.offset])
438
439 noteNameBlitPoint = (self.noteRects[self.highlightedNote-self.offset].left+(self.noteRects[self.highlightedNote-self.offset].width-self.renderedNoteNames[self.highlightedNote].get_width())/2,
440 self.noteRects[self.highlightedNote-self.offset].bottom-self.renderedNoteNames[self.highlightedNote].get_height())
441
442 self.savedScreen.blit(self.renderedNoteNames[self.highlightedNote], noteNameBlitPoint)
443
444 if self.syllabus :
445 renderedSyllabus = self.font.render(self.syllabus,False,(0,0,0))
446
447 syllabusBlitPoint = (self.noteRects[self.highlightedNote-self.offset].left+(self.noteRects[self.highlightedNote-self.offset].width-renderedSyllabus.get_width())/2,
448 self.noteRects[self.highlightedNote-self.offset].centery-renderedSyllabus.get_height()/2)
449
450 self.savedScreen.blit(renderedSyllabus, syllabusBlitPoint)
451
452 pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[self.highlightedNote-self.offset], 2)
453
454 if self.song != None and self.blinkOn:
455 borderSize = self.borderSize
456 pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 0), self.noteRects[self.highlightedNote-self.offset].inflate(borderSize/2,borderSize/2), borderSize)
457
458 def initializeWiimotes(self):
459 for loop in self.wiimotes:
460 if loop.port == None :
461 loop.port = pygame.midi.Output(loop.portNumber)
462 self.notes.append(0)
463 self.buttonDown.append(False)
464 self.velocityLock.append(False)
465
466 def updateCursorPositionFromJoy(self, joyEvent):
467 joyName = pygame.joystick.Joystick(joyEvent.joy).get_name()
468 correctedJoyId = constants.joyNames.index(joyName)
469 if correctedJoyId < len(self.cursorPositions):
470 if joyEvent.axis == 0 :
471 self.cursorPositions[correctedJoyId] = (int((joyEvent.value + 1) / 2 * self.screen.get_width()), self.cursorPositions[correctedJoyId][1])
472 if joyEvent.axis == 1 :
473 self.cursorPositions[correctedJoyId] = (self.cursorPositions[correctedJoyId][0], int((joyEvent.value + 1) / 2 * self.screen.get_height()))
474
475 def heightToVelocity(self, pos, controllerNumber):
476 if self.song != None:
477 if self.boundingRect.collidepoint(pos) and (self.highlightedNote == self.notes[controllerNumber] or self.velocityLock[controllerNumber]):
478 velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity)
479 else :
480 if self.easyMode:
481 velocity = None
482 else:
483 velocity = 60
484 else:
485 if self.boundingRect.collidepoint(pos):
486 velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity)
487 else :
488 velocity = self.minimalVelocity
489 return(velocity)
490
491 def widthToNote(self, pos):
492 nn = 0
493 try :
494 if self.noteRects[self.highlightedNote-self.offset].collidepoint(pos) :
495 return self.highlightedNote
496 else :
497 while self.noteRects[nn].collidepoint(pos) == False:
498 nn = nn + 1
499 return(nn + self.offset)
500 except(IndexError):
501 return(None)
502
503 def logClick(self):
504 self.clicks[-1] += 1
505 if self.firstClick == None :
506 self.firstClick = self.eventLog.getCurrentTime()
507 minute = int(floor((self.eventLog.getCurrentTime()-self.songStartTime)/60000))
508 if minute > len(self.clicksPerMinute)-1:
509 self.clicksPerMinute.append(0)
510 self.clicksPerMinute[-1] += 1
511
512 def logClickIn(self):
513 self.clicksIn[-1] += 1
514 if self.clicksIn[-1] > len(self.song.notes)-1 :
515 self.clicksIn.append(0)
516 self.clicks.append(0)
517 self.songDurations.append(self.eventLog.getCurrentTime())
518 if self.firstClickIn == None :
519 self.firstClickIn = self.eventLog.getCurrentTime()
520 minute = int(floor((self.eventLog.getCurrentTime()-self.songStartTime)/60000))
521 if minute > len(self.clicksInPerMinute)-1:
522 self.clicksInPerMinute.append(0)
523 self.clicksInPerMinute[-1]+=1
524
525 def input(self, event):
526
527 if event.type == pygame.QUIT:
528 for loop in self.wiimotes:
529 del loop.port
530 pygame.midi.quit()
531 sys.exit(0)
532
533 if event.type == pygame.KEYDOWN:
534 if event.key == pygame.K_q:
535 self.nextLevel = None
536 self.done = True
537
538 if event.key == pygame.K_i:
539 self.backToInstrumentChoice = True
540 self.done = True
541
542 if event.key == pygame.K_w:
543 self.nextLevel = 0
544 self.done = True
545
546 if event.key == pygame.K_e:
547 self.nextLevel = 1
548 self.done = True
549
550 if event.key == pygame.K_r:
551 self.nextLevel = 2
552 self.done = True
553
554 if event.key == pygame.K_t:
555 self.nextLevel = 3
556 self.done = True
557
558 if event.type == pygame.JOYAXISMOTION:
559
560 joyName = pygame.joystick.Joystick(event.joy).get_name()
561 correctedJoyId = constants.joyNames.index(joyName)
562 if self.activeWiimotes[correctedJoyId]:
563 self.updateCursorPositionFromJoy(event)
564 wiimote = self.wiimotes[correctedJoyId]
565 pos = self.cursorPositions[correctedJoyId]
566
567 if (self.buttonDown[correctedJoyId] or self.alwaysDown):
568 if self.notes[correctedJoyId] != None:
569 velocity = self.heightToVelocity(pos, correctedJoyId)
570 if velocity != None :
571 CCHexCode = wiimote.getCCHexCode()
572 wiimote.port.write_short(CCHexCode, 07, velocity)
573 if self.cascade and self.cascadeIsFree :
574 n = self.widthToNote(pos)
575 if self.highlightedNote == n:
576 wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]])
577 self.notes[correctedJoyId] = n
578 velocity = self.heightToVelocity(pos, correctedJoyId)
579 self.velocityLock[correctedJoyId] = True
580 wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity)
581 self.moveToNextNote()
582 self._cascadeLockTimer = 0
583 self.cascadeIsFree = False
584
585 if event.type == pygame.JOYBUTTONDOWN :
586
587 joyName = pygame.joystick.Joystick(event.joy).get_name()
588 correctedJoyId = constants.joyNames.index(joyName)
589 if self.activeWiimotes[correctedJoyId]:
590 wiimote = self.wiimotes[correctedJoyId]
591 pos = self.cursorPositions[correctedJoyId]
592 self.wiimotes[correctedJoyId].cursor.flash()
593 if self.replay:
594 self.logClick()
595
596 if not (self.buttonDown[correctedJoyId] or self.alwaysDown):
597 n = self.widthToNote(pos)
598 if self.highlightedNote == n:
599 self._cascadeLockTimer = 0
600 self.cascadeIsFree = False
601 if self.easyMode:
602 wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]])
603 self.notes[correctedJoyId] = n
604 velocity = self.heightToVelocity(pos, correctedJoyId)
605 self.velocityLock[correctedJoyId] = True
606 wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity)
607 if self.replay :
608 self.logClickIn()
609 self.moveToNextNote()
610 else :
611 if not self.easyMode :
612 self._cascadeLockTimer = 0
613 self.cascadeIsFree = False
614 self.notes[correctedJoyId] = n
615 velocity = self.heightToVelocity(pos, correctedJoyId)
616 if velocity != None and self.notes[correctedJoyId] != None :
617 wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity)
618 self.buttonDown[correctedJoyId] = True
619
620 if event.type == pygame.JOYBUTTONUP:
621 joyName = pygame.joystick.Joystick(event.joy).get_name()
622 correctedJoyId = constants.joyNames.index(joyName)
623 if self.activeWiimotes[correctedJoyId]:
624 self.buttonDown[correctedJoyId] = False
625 wiimote = self.wiimotes[correctedJoyId]
626 if not self.easyMode:
627 wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]])
628 self.velocityLock[correctedJoyId] = False
629
630 if event.type == pygame.MOUSEMOTION:
631
632 self.updateCursorPositionFromMouse(event)
633
634 correctedJoyId = 0
635 while not self.activeWiimotes[correctedJoyId] :
636 correctedJoyId += 1
637 wiimote = self.wiimotes[correctedJoyId]
638 pos = self.cursorPositions[correctedJoyId]
639
640 if (self.buttonDown[correctedJoyId] or self.alwaysDown):
641 self.wiimotes[correctedJoyId].cursor.flash()
642 if self.notes[correctedJoyId] != None:
643 velocity = self.heightToVelocity(pos, correctedJoyId)
644 if velocity != None :
645 CCHexCode = wiimote.getCCHexCode()
646 wiimote.port.write_short(CCHexCode, 07, velocity)
647 if self.cascade and self.cascadeIsFree :
648 n = self.widthToNote(pos)
649 if self.highlightedNote == n:
650 wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]])
651 self.notes[correctedJoyId] = n
652 velocity = self.heightToVelocity(pos, correctedJoyId)
653 self.velocityLock[correctedJoyId] = True
654 wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity)
655 self.moveToNextNote()
656 self._cascadeLockTimer = 0
657 self.cascadeIsFree = False
658
659 if event.type == pygame.MOUSEBUTTONDOWN:
660
661 if event.button == 1:
662 correctedJoyId = 0
663 while not self.activeWiimotes[correctedJoyId] :
664 correctedJoyId += 1
665 wiimote = self.wiimotes[correctedJoyId]
666 pos = self.cursorPositions[correctedJoyId]
667 self.wiimotes[correctedJoyId].cursor.flash()
668 if self.replay:
669 self.logClick()
670
671 if not (self.buttonDown[correctedJoyId] or self.alwaysDown):
672 n = self.widthToNote(pos)
673 if self.highlightedNote == n:
674 self._cascadeLockTimer = 0
675 self.cascadeIsFree = False
676 if self.easyMode:
677 wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]])
678 self.notes[correctedJoyId] = n
679 velocity = self.heightToVelocity(pos, correctedJoyId)
680 self.velocityLock[correctedJoyId] = True
681 wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity)
682 if self.replay :
683 self.logClickIn()
684 self.moveToNextNote()
685 else :
686 if not self.easyMode :
687 self._cascadeLockTimer = 0
688 self.cascadeIsFree = False
689 self.notes[correctedJoyId] = n
690 velocity = self.heightToVelocity(pos, correctedJoyId)
691 if velocity != None and self.notes[correctedJoyId] != None :
692 wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity)
693 self.buttonDown[correctedJoyId] = True
694
695 if event.button == 2:
696
697 self.done = True
698
699 if event.type == pygame.MOUSEBUTTONUP:
700 if event.button == 1 :
701 correctedJoyId = 0
702 while not self.activeWiimotes[correctedJoyId] :
703 correctedJoyId += 1
704 wiimote = self.wiimotes[correctedJoyId]
705 self.buttonDown[correctedJoyId] = False
706 if not self.easyMode:
707 if self.notes[correctedJoyId] != None :
708 wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]])
709 self.velocityLock[correctedJoyId] = False
710
711 def hasChanged(self):
712 changed = False
713 if self.song != None:
714 if self.blinkOn != self.savedBlinkOn or self.highlightedNote != self.savedHighlightedNote:
715 self.savedBlinkOn = self.blinkOn
716 self.savedHighlightedNote = self.highlightedNote
717 changed = True
718 return(changed)
719
720 def updateCursorPositionFromMouse(self, mouseEvent):
721 correctedJoyId = 0
722 while not self.activeWiimotes[correctedJoyId] :
723 correctedJoyId += 1
724 self.cursorPositions[correctedJoyId] = mouseEvent.pos
725
726 def moveToNextNote(self):
727 self.savedMidiNoteNumbers = self.midiNoteNumbers[:]
728 note, lyricIndex = self.songIterator.next()
729 self.highlightedNote = note.column
730 self.highlightedNoteNumber = note.midi
731 self.syllabus = note.lyrics[lyricIndex].syllabus('iso-8859-1')
732 self.nextCascadeLockLengthMultiplier = note.duration
733 self.midiNoteNumbers[self.highlightedNote] = self.highlightedNoteNumber
734
735 #self.highlightedNote, self.highlightedNoteNumber, self.syllabus, self.nextCascadeLockLengthMultiplier = self.songIterator.next()
736 #self.midiNoteNumbers[self.highlightedNote] = self.highlightedNoteNumber