X-Git-Url: https://scm.cri.ensmp.fr/git/minwii.git/blobdiff_plain/346a9b8e1fcfe30629f0d1ee4675e9e8f89890cf..4c4732c6ed8cb0aaa70fb2d4c6e5a958868c5349:/src/gui/SongFamiliarizer.py diff --git a/src/gui/SongFamiliarizer.py b/src/gui/SongFamiliarizer.py deleted file mode 100644 index 69ab03c..0000000 --- a/src/gui/SongFamiliarizer.py +++ /dev/null @@ -1,583 +0,0 @@ -''' -Created on 23 juil. 2009 - -@author: Samuel Benveniste -''' -from math import floor, ceil -import pygame -import sys -import colorsys -import constants -from gradients import gradients -from logging.PickleableEvent import PickleableEvent -from logging.EventLog import EventLog - - -class SongFamiliarizer: - ''' - The screen on which the game is played - - wiimotes: - The wiimotes used in this session - window: - The main display window - screen: - The main display surface - clock: - The clock used to animate the screen - savedScreen: - The background that is painted every time - playerScreen: - The buffer for painting everything before bliting - width: - The width of the window in pixels - height: - The height of the window in pixels - extendScale : - True if the scale is G to C instead of C to C - cascade: - True if crossing from note to note with a button pressed triggers a new note - scaleSize: - The size of the scale used - cursorPositions: - The positions of the cursors on the screen, in pixels - ''' - - - - def __init__(self, wiimotes, window, screen, clock, joys, portOffset, song, activeWiimotes, cascade=False, extendedScale=False, easyMode = False, replay = False, eventLog = None, defaultInstrumentChannel = 16, defaultNote = 60): - ''' - Constructor - ''' - self.firstClickTime = None - self.firstClickInTime = None - self.duration = None - self.clicks = 0 - self.clicksIn = 0 - - pygame.font.init() - self.font = pygame.font.Font(None,60) - self.congratulations = ["Bien !","Tres Bien !","Bravo !","Excellent !","Felicitations !"] - self.renderedCongratulations = [self.font.render(congratulation,False,(0,0,0)) for congratulation in self.congratulations] - self.congratulationCount = None - self.isCongratulating = False - self.congratulationTimer = 0 - self.congratulationLength = 2000 - self.congratulationPos = None - - self.blinkLength = 200 - self.minimalVelocity = 90 - self.shortScaleSize = 8 - self.longScaleSize = 11 - if not extendedScale: - self.offset = self.longScaleSize - self.shortScaleSize - else: - self.offset = 0 - self.borderSize = 5 - self.highlightedNote = 0 - self.highlightedNoteNumber = 0 - self.syllabus = None - self.savedHighlightedNote = 0 - self.scaleFactor = 1 - self.level = 3 - - self.wiimotes = wiimotes - self.activeWiimotes = activeWiimotes - self.window = window - self.screen = screen - self.width = int(floor(screen.get_width()*self.scaleFactor)) - self.height = int(floor(screen.get_height()*self.scaleFactor)) - self.blitOrigin = ((self.screen.get_width()-self.width)/2,(self.screen.get_height()-self.height)/2) - self.joys = joys - self.clock = clock - self.cursorPositions = [] - self.savedScreen = pygame.Surface(self.screen.get_size()) - self.savedScreen.fill((255,255,255)) - self.playerScreen = pygame.Surface(self.savedScreen.get_size()) - self.playerScreen.blit(self.savedScreen, (0, 0)) - self.extendedScale = extendedScale - self.cascade = cascade - self.portOffset =portOffset - self.eventLog = eventLog - self.song = song - self.songIterator = self.song.getSongIterator() - self.midiNoteNumbers = self.song.scale - self.replay = replay - self.quarterNoteLength = 800 - self.cascadeLockLengthMultiplier = 1 - self.cascadeLockLength = self.quarterNoteLength * self.cascadeLockLengthMultiplier - - self.defaultInstrumentChannel = defaultInstrumentChannel - self.defaultNote = defaultNote - - self.done = False - self.backToInstrumentChoice = False - self.easyMode = easyMode - - if eventLog == None: - self.eventLog = EventLog() - self.replay = False - else: - self.eventLog = eventLog - self.replay = replay - - #Initializes the highlightedNote and highlightedNoteNumber etc... - self.moveToNextNote() - - self.blinkOn = False - self.savedBlinkOn = False - ##Will prevent the song to move on if two consecutive notes are identical and the buttons have not been released in between the two - ##i.e. it guarantees that there will be an attack between two identical consecutive notes - self.highlightIsFree = True - - self.noteRects = [] - self.boundingRect = None - self.notes = [] - - self.buttonDown = [] - self.velocityLock = [] - - self._blinkOffset = 0 - self._cascadeLockTimer = 0 - self.cascadeIsFree = True - - self.font = pygame.font.Font(None,50) - self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers] - - self.drawBackground() - self.initializeWiimotes() - - events = pygame.event.get() - - #The main loop - while not self.done : - - #Clear the cursors from the screen - if self.hasChanged(): - self.drawBackground() - self.playerScreen.blit(self.savedScreen, (0, 0)) - - # Limit frame speed to 50 FPS - # - timePassed = self.clock.tick(10000) - - self._blinkOffset += timePassed - if self.buttonDown and not self.cascadeIsFree : - self._cascadeLockTimer += timePassed - if self._cascadeLockTimer > self.cascadeLockLength : - self.cascadeIsFree = True - - - if self._blinkOffset > self.blinkLength: - self._blinkOffset -= self.blinkLength - self.blinkOn = not self.blinkOn - - if self.replay: - self.eventLog.update(timePassed) - pickledEventsToPost = self.eventLog.getPickledEvents() - for pickledEvent in pickledEventsToPost: - pygame.event.post(pickledEvent.event) - - events = pygame.event.get() - - if not self.replay: - pickledEvents = [PickleableEvent(event.type,event.dict) for event in events] - if pickledEvents != [] : - self.eventLog.appendEventGroup(pickledEvents) - - for event in events: - self.input(event) - - if self.isCongratulating : - self.congratulationTimer += timePassed - if self.congratulationTimer < self.congratulationLength : - self.blitCongratulation() - else : - self.isCongratulating = False - - for i in range(len(self.wiimotes)): - if self.activeWiimotes[i]: - self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i]) - if self.buttonDown[i] : - self.wiimotes[i].cursor.flash() - self.wiimotes[i].cursor.blit(self.playerScreen) - - self.screen.blit(self.playerScreen, (0,0)) - - pygame.display.flip() - - for i in range(len(self.wiimotes)): - if self.activeWiimotes[i]: - self.wiimotes[i].stopNoteByNoteNumber(self.midiNoteNumbers[self.notes[i]]) - if self.replay : - self.duration = self.eventLog.getCurrentTime() - - def drawBackground(self): - self.savedScreen.fill((255,255,255)) - - if self.extendedScale : - self.scaleSize = self.longScaleSize - else: - self.scaleSize = self.shortScaleSize - - 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)] - #inflate last noteRect to cover the far right pixels - self.noteRects[-1].width = self.noteRects[-1].width + 1 - - self.noteRects[self.highlightedNote-self.offset].inflate_ip(self.noteRects[self.highlightedNote-self.offset].width*2,0) - - #create bounding rect - self.boundingRect = self.noteRects[0].unionall(self.noteRects) - - self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers] - - #fill the rectangles with a color gradient - #We start with blue - startingHue = 0.66666666666666663 - -# for rectNumber in range(self.scaleSize): -# colorRatio = float(rectNumber) / (self.scaleSize - 1) -# #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up -# hue = startingHue * (1 - colorRatio) -# if rectNumber + self.offset != self.highlightedNote: -# #The color of the bottom of the rectangle in hls coordinates -# bottomColorHls = (hue, 0.1, 1) -# #The color of the top of the rectangle in hls coordinates -# topColorHls = (hue, 0.1, 1) -# -# #convert to rgb ranging from 0 to 255 -# bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)] -# topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)] -# #add transparency -# bottomColorRgb.append(255) -# topColorRgb.append(255) -# #convert to tuple -# bottomColorRgb = tuple(bottomColorRgb) -# topColorRgb = tuple(topColorRgb) -# -# self.savedScreen.blit(gradients.vertical(self.noteRects[rectNumber].size, topColorRgb, bottomColorRgb), self.noteRects[rectNumber]) -# -# noteNameBlitPoint = (self.noteRects[rectNumber].left+(self.noteRects[rectNumber].width-self.renderedNoteNames[rectNumber].get_width())/2, -# self.noteRects[rectNumber].bottom-self.renderedNoteNames[rectNumber].get_height()) -# -# self.savedScreen.blit(self.renderedNoteNames[rectNumber], noteNameBlitPoint) -# -# pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[rectNumber], 2) - - colorRatio = float(self.highlightedNote-self.offset) / (self.scaleSize - 1) - #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up - hue = startingHue * (1 - colorRatio) - #The color of the bottom of the rectangle in hls coordinates - bottomColorHls = (hue, 0.6, 1) - #The color of the top of the rectangle in hls coordinates - topColorHls = (hue, 0.9, 1) - - #convert to rgb ranging from 0 to 255 - bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)] - topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)] - #add transparency - bottomColorRgb.append(255) - topColorRgb.append(255) - #convert to tuple - bottomColorRgb = tuple(bottomColorRgb) - topColorRgb = tuple(topColorRgb) - - self.savedScreen.blit(gradients.vertical(self.noteRects[self.highlightedNote-self.offset].size, topColorRgb, bottomColorRgb), self.noteRects[self.highlightedNote-self.offset]) - -# noteNameBlitPoint = (self.noteRects[self.highlightedNote-self.offset].left+(self.noteRects[self.highlightedNote-self.offset].width-self.renderedNoteNames[self.highlightedNote-self.offset].get_width())/2, -# self.noteRects[self.highlightedNote-self.offset].bottom-self.renderedNoteNames[self.highlightedNote-self.offset].get_height()) -# -# self.savedScreen.blit(self.renderedNoteNames[self.highlightedNote-self.offset], noteNameBlitPoint) -# -# if self.syllabus : -# renderedSyllabus = self.font.render(self.syllabus,False,(0,0,0)) -# -# syllabusBlitPoint = (self.noteRects[self.highlightedNote-self.offset].left+(self.noteRects[self.highlightedNote-self.offset].width-renderedSyllabus.get_width())/2, -# self.noteRects[self.highlightedNote-self.offset].centery-renderedSyllabus.get_height()/2) -# -# self.savedScreen.blit(renderedSyllabus, syllabusBlitPoint) - - pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[self.highlightedNote-self.offset], 2) - -# if self.song != None and self.blinkOn: -# borderSize = self.borderSize -# pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 0), self.noteRects[self.highlightedNote-self.offset].inflate(borderSize/2,borderSize/2), borderSize) - - def initializeWiimotes(self): - for loop in self.wiimotes: - if loop.port == None : - loop.port = pygame.midi.Output(loop.portNumber) - self.notes.append(0) - self.cursorPositions.append(loop.cursor.centerPosition) - self.buttonDown.append(False) - self.velocityLock.append(False) - - def updateCursorPositionFromJoy(self, joyEvent): - joyName = pygame.joystick.Joystick(joyEvent.joy).get_name() - correctedJoyId = constants.joyNames.index(joyName) - if correctedJoyId < len(self.cursorPositions): - if joyEvent.axis == 0 : - self.cursorPositions[correctedJoyId] = (int((joyEvent.value + 1) / 2 * self.screen.get_width()), self.cursorPositions[correctedJoyId][1]) - if joyEvent.axis == 1 : - self.cursorPositions[correctedJoyId] = (self.cursorPositions[correctedJoyId][0], int((joyEvent.value + 1) / 2 * self.screen.get_height())) - - def heightToVelocity(self, pos, controllerNumber): - if self.song != None: - if self.boundingRect.collidepoint(pos) and (self.highlightedNote == self.notes[controllerNumber] or self.velocityLock[controllerNumber]): - velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity) - else : - if self.easyMode: - velocity = None - else: - velocity = 60 - else: - if self.boundingRect.collidepoint(pos): - velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity) - else : - velocity = self.minimalVelocity - return(velocity) - - def widthToNote(self, pos): - nn = 0 - try : - if self.noteRects[self.highlightedNote-self.offset].collidepoint(pos) : - return self.highlightedNote - else : - while self.noteRects[nn].collidepoint(pos) == False: - nn = nn + 1 - return(nn + self.offset) - except(IndexError): - return(None) - - def congratulate(self,targetRect,posy): - if self.congratulationCount != None : - if self.congratulationCount < len(self.congratulations)-1: - self.congratulationCount += 1 - else : - self.congratulationCount = 0 - self.congratulationTimer = 0 - self.congratulationPos = (targetRect.left+(targetRect.width-self.renderedCongratulations[self.congratulationCount].get_width())/2,posy) - self.isCongratulating = True - - def resetCongratulation(self): - self.congratulationCount = None - self.congratulationPos = None - self.isCongratulating = False - - def blitCongratulation(self): - self.playerScreen.blit(self.renderedCongratulations[self.congratulationCount],self.congratulationPos) - - def input(self, event): - - if event.type == pygame.QUIT: - for loop in self.wiimotes: - del loop.port - pygame.midi.quit() - sys.exit(0) - - if event.type == pygame.KEYDOWN: - if event.key == pygame.K_q: - self.nextLevel = None - self.done = True - - if event.key == pygame.K_w: - self.nextLevel = 0 - self.done = True - - if event.key == pygame.K_e: - self.nextLevel = 1 - self.done = True - - if event.key == pygame.K_r: - self.nextLevel = 2 - self.done = True - - if event.key == pygame.K_t: - self.nextLevel = 3 - self.done = True - - if event.type == pygame.JOYAXISMOTION: - - joyName = pygame.joystick.Joystick(event.joy).get_name() - correctedJoyId = constants.joyNames.index(joyName) - if self.activeWiimotes[correctedJoyId]: - self.updateCursorPositionFromJoy(event) - wiimote = self.wiimotes[correctedJoyId] - pos = self.cursorPositions[correctedJoyId] - - if self.buttonDown[correctedJoyId]: - if self.notes[correctedJoyId] != None: - velocity = self.heightToVelocity(pos, correctedJoyId) - if velocity != None : - CCHexCode = wiimote.getCCHexCode() - wiimote.port.write_short(CCHexCode, 07, velocity) - if self.cascade and self.cascadeIsFree : - n = self.widthToNote(pos) - if self.highlightedNote == n: - wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) - self.notes[correctedJoyId] = n - velocity = self.heightToVelocity(pos, correctedJoyId) - self.velocityLock[correctedJoyId] = True - wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) - self.moveToNextNote() - self._cascadeLockTimer = 0 - self.cascadeIsFree = False - - if event.type == pygame.JOYBUTTONDOWN : - - joyName = pygame.joystick.Joystick(event.joy).get_name() - correctedJoyId = constants.joyNames.index(joyName) - if self.activeWiimotes[correctedJoyId]: - wiimote = self.wiimotes[correctedJoyId] - pos = self.cursorPositions[correctedJoyId] - self.wiimotes[correctedJoyId].cursor.flash() - if self.replay: - self.clicks += 1 - if self.firstClickTime == None : - self.firstClickTime = self.eventLog.getCurrentTime() - - if not self.buttonDown[correctedJoyId]: - n = self.widthToNote(pos) - if self.highlightedNote == n: - self._cascadeLockTimer = 0 - self.cascadeIsFree = False - if self.easyMode: - wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) - self.notes[correctedJoyId] = n - velocity = self.heightToVelocity(pos, correctedJoyId) - self.velocityLock[correctedJoyId] = True - wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) - self.congratulate(self.noteRects[self.notes[correctedJoyId]],pos[1]) - if self.replay: - self.clicksIn += 1 - if self.firstClickInTime == None : - self.firstClickInTime = self.eventLog.getCurrentTime() - - self.moveToNextNote() - else : - self.resetCongratulation() - if not self.easyMode : - self._cascadeLockTimer = 0 - self.cascadeIsFree = False - self.notes[correctedJoyId] = n - velocity = self.heightToVelocity(pos, correctedJoyId) - if velocity != None : - wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) - self.buttonDown[correctedJoyId] = True - - if event.type == pygame.JOYBUTTONUP: - joyName = pygame.joystick.Joystick(event.joy).get_name() - correctedJoyId = constants.joyNames.index(joyName) - if self.activeWiimotes[correctedJoyId]: - self.buttonDown[correctedJoyId] = False - wiimote = self.wiimotes[correctedJoyId] - if not self.easyMode: - wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) - self.velocityLock[correctedJoyId] = False - - if event.type == pygame.MOUSEMOTION: - - self.updateCursorPositionFromMouse(event) - - correctedJoyId = 0 - while not self.activeWiimotes[correctedJoyId] : - correctedJoyId += 1 - wiimote = self.wiimotes[correctedJoyId] - pos = self.cursorPositions[correctedJoyId] - - if self.buttonDown[correctedJoyId]: - self.wiimotes[correctedJoyId].cursor.flash() - if self.notes[correctedJoyId] != None: - velocity = self.heightToVelocity(pos, correctedJoyId) - if velocity != None : - CCHexCode = wiimote.getCCHexCode() - wiimote.port.write_short(CCHexCode, 07, velocity) - if self.cascade and self.cascadeIsFree : - n = self.widthToNote(pos) - if self.highlightedNote == n: - wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) - self.notes[correctedJoyId] = n - velocity = self.heightToVelocity(pos, correctedJoyId) - self.velocityLock[correctedJoyId] = True - wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) - self.moveToNextNote() - self._cascadeLockTimer = 0 - self.cascadeIsFree = False - - if event.type == pygame.MOUSEBUTTONDOWN: - - if event.button == 1: - correctedJoyId = 0 - while not self.activeWiimotes[correctedJoyId] : - correctedJoyId += 1 - wiimote = self.wiimotes[correctedJoyId] - pos = self.cursorPositions[correctedJoyId] - self.wiimotes[correctedJoyId].cursor.flash() - if self.replay: - self.clicks += 1 - if self.firstClickTime == None : - self.firstClickTime = self.eventLog.getCurrentTime() - - if not self.buttonDown[correctedJoyId]: - n = self.widthToNote(pos) - if self.highlightedNote == n: - self._cascadeLockTimer = 0 - self.cascadeIsFree = False - if self.easyMode: - wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) - self.notes[correctedJoyId] = n - velocity = self.heightToVelocity(pos, correctedJoyId) - self.velocityLock[correctedJoyId] = True - wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) - self.congratulate(self.noteRects[self.notes[correctedJoyId]],pos[1]) - if self.replay: - self.clicksIn += 1 - if self.firstClickInTime == None : - self.firstClickInTime = self.eventLog.getCurrentTime() - - self.moveToNextNote() - else : - self.resetCongratulation() - if not self.easyMode : - self._cascadeLockTimer = 0 - self.cascadeIsFree = False - self.notes[correctedJoyId] = n - velocity = self.heightToVelocity(pos, correctedJoyId) - if velocity != None : - wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) - self.buttonDown[correctedJoyId] = True - - if event.button == 2: - - self.done = True - - if event.type == pygame.MOUSEBUTTONUP: - if event.button == 1 : - correctedJoyId = 0 - while not self.activeWiimotes[correctedJoyId] : - correctedJoyId += 1 - wiimote = self.wiimotes[correctedJoyId] - self.buttonDown[correctedJoyId] = False - if not self.easyMode: - wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) - self.velocityLock[correctedJoyId] = False - - def hasChanged(self): - changed = False - if self.song != None: - if self.blinkOn != self.savedBlinkOn or self.highlightedNote != self.savedHighlightedNote: - self.savedBlinkOn = self.blinkOn - self.savedHighlightedNote = self.highlightedNote - changed = True - return(changed) - - def updateCursorPositionFromMouse(self, mouseEvent): - correctedJoyId = 0 - while not self.activeWiimotes[correctedJoyId] : - correctedJoyId += 1 - self.cursorPositions[correctedJoyId] = mouseEvent.pos - - def moveToNextNote(self): - self.savedMidiNoteNumbers = self.midiNoteNumbers[:] - self.highlightedNote, self.highlightedNoteNumber, self.syllabus, self.cascadeLockLengthMultiplier = self.songIterator.next() - self.midiNoteNumbers[self.highlightedNote] = self.highlightedNoteNumber