X-Git-Url: https://scm.cri.ensmp.fr/git/minwii.git/blobdiff_plain/928c4fcf26174df9b8cf62d67e0061ad703481e9..4c4732c6ed8cb0aaa70fb2d4c6e5a958868c5349:/src/gui/SongPlayingScreen.py?ds=sidebyside diff --git a/src/gui/SongPlayingScreen.py b/src/gui/SongPlayingScreen.py deleted file mode 100644 index a06e831..0000000 --- a/src/gui/SongPlayingScreen.py +++ /dev/null @@ -1,564 +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 - - -class SongPlayingScreen: - ''' - 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, instrumentChoice, song, cascade=False, extendedScale=False, easyMode = False, alwaysDown = False, eventLog = None, replay = None, defaultInstrumentChannel = 16, defaultNote = 60): - ''' - Constructor - ''' - self.songDurations = [] - self.totalDuration = None - self.clicks = [0] - self.clicksIn = [0] - self.clicksPerMinute = [0] - self.clicksInPerMinute = [0] - self.meanTimeBetweenNotes = [] - self.firstClick = None - self.firstClickIn = 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.alwaysDown = alwaysDown - self.nextLevel = None - - self.wiimotes = instrumentChoice.wiimotes - self.activeWiimotes = instrumentChoice.activeWiimotes - self.window = instrumentChoice.window - self.screen = instrumentChoice.screen - self.blitOrigin = instrumentChoice.blitOrigin - self.clock = instrumentChoice.clock - self.width = instrumentChoice.width - self.height = instrumentChoice.height - self.cursorPositions = instrumentChoice.cursorPositions - self.savedScreen = instrumentChoice.savedScreen - self.playerScreen = instrumentChoice.playerScreen - self.extendedScale = extendedScale - self.cascade = cascade - self.joys = instrumentChoice.joys - self.portOffset = instrumentChoice.portOffset - if eventLog == None : - self.eventLog = instrumentChoice.eventLog - else : - self.eventLog = eventLog - self.cursorPositions = instrumentChoice.cursorPositions - self.song = song - self.songIterator = self.song.getSongIterator() - self.midiNoteNumbers = self.song.scale - if replay == None : - self.replay = instrumentChoice.replay - else : - self.replay = replay - self.quarterNoteLength = song.quarterNoteLength - self.cascadeLockLengthMultiplier = 1 - self.nextCascadeLockLengthMultiplier = 1 - self.cascadeLockLength = self.quarterNoteLength * self.cascadeLockLengthMultiplier - - self.defaultInstrumentChannel = defaultInstrumentChannel - self.defaultNote = defaultNote - - self.done = False - self.backToInstrumentChoice = False - self.easyMode = easyMode - - #Initializes the highlightedNote and highlightedNoteNumber etc... - self.moveToNextNote() - self.cascadeLockLengthMultiplier = self.nextCascadeLockLengthMultiplier - - 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,80) - self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers] - - self.drawBackground() - self.initializeWiimotes() - - self.songStartTime = self.eventLog.getCurrentTime() - - #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 or self.alwaysDown) and not self.cascadeIsFree : - self._cascadeLockTimer += timePassed - if self._cascadeLockTimer > self.cascadeLockLengthMultiplier*self.quarterNoteLength : - self.cascadeIsFree = True - self.cascadeLockLengthMultiplier = self.nextCascadeLockLengthMultiplier - - - 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) - - for i in range(len(self.wiimotes)): - if self.activeWiimotes[i]: - self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i]) - if self.buttonDown[i] or self.alwaysDown: - 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.totalDuration = 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+self.offset].get_width())/2, - self.noteRects[rectNumber].bottom-self.renderedNoteNames[rectNumber+self.offset].get_height()) - - self.savedScreen.blit(self.renderedNoteNames[rectNumber+self.offset], 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].get_width())/2, - self.noteRects[self.highlightedNote-self.offset].bottom-self.renderedNoteNames[self.highlightedNote].get_height()) - - self.savedScreen.blit(self.renderedNoteNames[self.highlightedNote], 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.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 logClick(self): - self.clicks[-1] += 1 - if self.firstClick == None : - self.firstClick = self.eventLog.getCurrentTime() - minute = int(floor((self.eventLog.getCurrentTime()-self.songStartTime)/60000)) - if minute > len(self.clicksPerMinute)-1: - self.clicksPerMinute.append(0) - self.clicksPerMinute[-1] += 1 - - def logClickIn(self): - self.clicksIn[-1] += 1 - if self.clicksIn[-1] > len(self.song.notes)-1 : - self.clicksIn.append(0) - self.clicks.append(0) - self.songDurations.append(self.eventLog.getCurrentTime()) - if self.firstClickIn == None : - self.firstClickIn = self.eventLog.getCurrentTime() - minute = int(floor((self.eventLog.getCurrentTime()-self.songStartTime)/60000)) - if minute > len(self.clicksInPerMinute)-1: - self.clicksInPerMinute.append(0) - self.clicksInPerMinute[-1]+=1 - - 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_i: - self.backToInstrumentChoice = True - 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] or self.alwaysDown): - 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.logClick() - - if not (self.buttonDown[correctedJoyId] or self.alwaysDown): - 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) - if self.replay : - self.logClickIn() - self.moveToNextNote() - else : - if not self.easyMode : - self._cascadeLockTimer = 0 - self.cascadeIsFree = False - self.notes[correctedJoyId] = n - velocity = self.heightToVelocity(pos, correctedJoyId) - if velocity != None and self.notes[correctedJoyId] != 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] or self.alwaysDown): - 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.logClick() - - if not (self.buttonDown[correctedJoyId] or self.alwaysDown): - 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) - if self.replay : - self.logClickIn() - self.moveToNextNote() - else : - if not self.easyMode : - self._cascadeLockTimer = 0 - self.cascadeIsFree = False - self.notes[correctedJoyId] = n - velocity = self.heightToVelocity(pos, correctedJoyId) - if velocity != None and self.notes[correctedJoyId] != 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: - if self.notes[correctedJoyId] != None : - 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.nextCascadeLockLengthMultiplier = self.songIterator.next() - self.midiNoteNumbers[self.highlightedNote] = self.highlightedNoteNumber