+++ /dev/null
-'''\r
-Created on 23 juil. 2009\r
-\r
-@author: Samuel Benveniste\r
-'''\r
-from math import floor, ceil\r
-import pygame\r
-import sys\r
-import colorsys\r
-import constants\r
-from gradients import gradients\r
-from logging.PickleableEvent import PickleableEvent\r
-\r
-\r
-class PlayingScreen:\r
- '''\r
- The screen on which the game is played\r
- \r
- wiimotes: \r
- The wiimotes used in this session\r
- window:\r
- The main display window\r
- screen:\r
- The main display surface\r
- clock:\r
- The clock used to animate the screen\r
- savedScreen:\r
- The background that is painted every time\r
- playerScreen:\r
- The buffer for painting everything before bliting\r
- width:\r
- The width of the window in pixels\r
- height:\r
- The height of the window in pixels\r
- extendScale :\r
- True if the scale is G to C instead of C to C\r
- cascade:\r
- True if crossing from note to note with a button pressed triggers a new note\r
- scaleSize:\r
- The size of the scale used\r
- cursorPositions:\r
- The positions of the cursors on the screen, in pixels\r
- '''\r
- \r
- \r
- \r
- def __init__(self, instrumentChoice=None, song = None, cascade=False, extendedScale=False, defaultInstrumentChannel = 16, defaultNote = 60):\r
- '''\r
- Constructor\r
- ''' \r
- self.blinkLength = 200\r
- self.minimalVelocity = 64\r
- self.shortScaleSize = 8\r
- self.longScaleSize = 11\r
- if not extendedScale:\r
- self.offset = self.longScaleSize - self.shortScaleSize\r
- else:\r
- self.offset = 0\r
- self.borderSize = 5\r
- self.savedHighlightedNote = 0\r
- \r
- self.wiimotes = instrumentChoice.wiimotes\r
- self.activeWiimotes = instrumentChoice.activeWiimotes\r
- self.window = instrumentChoice.window\r
- self.screen = instrumentChoice.screen\r
- self.blitOrigin = instrumentChoice.blitOrigin\r
- self.clock = instrumentChoice.clock\r
- self.width = instrumentChoice.width\r
- self.height = instrumentChoice.height\r
- self.cursorPositions = instrumentChoice.cursorPositions\r
- self.savedScreen = instrumentChoice.savedScreen\r
- self.playerScreen = instrumentChoice.playerScreen\r
- self.extendedScale = extendedScale\r
- self.cascade = cascade\r
- self.joys = instrumentChoice.joys\r
- self.portOffset = instrumentChoice.portOffset\r
- self.eventLog = instrumentChoice.eventLog\r
- self.cursorPositions = instrumentChoice.cursorPositions\r
- self.song = song\r
- self.songIterator = self.moveToNextNote()\r
- self.replay = instrumentChoice.replay\r
- \r
- self.defaultInstrumentChannel = defaultInstrumentChannel\r
- self.defaultNote = defaultNote\r
- \r
- self.done = False\r
- self.backToInstrumentChoice = False\r
- self.easyMode = False\r
- \r
- self.highlightedNote = self.songIterator.next()\r
- \r
- self.blinkOn = False\r
- self.savedBlinkOn = False\r
- ##Will prevent the song to move on if two consecutive notes are identical and the buttons have not been released in between the two\r
- ##i.e. it guarantees that there will be an attack between two identical consecutive notes\r
- self.highlightIsFree = True\r
- \r
- self.noteRects = []\r
- self.boundingRect = None\r
- self.notes = []\r
- self.buttonDown = []\r
- self.velocityLock = []\r
- \r
- self._blinkOffset = 0\r
- \r
- self.font = pygame.font.Font(None,50)\r
- self.firstWiimote = 0\r
- while not self.activeWiimotes[self.firstWiimote] :\r
- self.firstWiimote += 1\r
- self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.wiimotes[self.firstWiimote].instrument.notes[self.offset:]]\r
- \r
- self.drawBackground()\r
- self.initializeWiimotes()\r
- \r
- #The main loop\r
- while not self.done :\r
- \r
- #Clear the cursors from the screen\r
- if self.hasChanged():\r
- self.drawBackground()\r
- self.playerScreen.blit(self.savedScreen, (0, 0))\r
- \r
- # Limit frame speed to 50 FPS\r
- #\r
- timePassed = self.clock.tick(50)\r
- \r
- self._blinkOffset += timePassed\r
- if self._blinkOffset > self.blinkLength:\r
- self._blinkOffset -= self.blinkLength\r
- self.blinkOn = not self.blinkOn\r
- \r
- if self.replay:\r
- self.eventLog.update(timePassed)\r
- pickledEventsToPost = self.eventLog.getPickledEvents() \r
- for pickledEvent in pickledEventsToPost:\r
- pygame.event.post(pickledEvent.event)\r
- \r
- events = pygame.event.get()\r
- \r
- if not self.replay:\r
- pickledEvents = [PickleableEvent(event.type,event.dict) for event in events]\r
- if pickledEvents != [] :\r
- self.eventLog.appendEventGroup(pickledEvents)\r
- \r
- for event in events:\r
- self.input(event)\r
- \r
- for i in range(len(self.wiimotes)):\r
- if self.activeWiimotes[i]:\r
- self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i])\r
- if self.buttonDown[i] :\r
- self.wiimotes[i].cursor.flash()\r
- self.wiimotes[i].cursor.blit(self.playerScreen)\r
- \r
- self.screen.blit(self.playerScreen, (0,0))\r
- \r
- pygame.display.flip()\r
- \r
- for i in range(len(self.wiimotes)):\r
- if self.activeWiimotes[i]:\r
- self.wiimotes[i].stopNote(self.notes[i]) \r
- \r
- def drawBackground(self):\r
- self.savedScreen.fill((255,255,255))\r
- \r
- if self.extendedScale :\r
- self.scaleSize = self.longScaleSize\r
- else:\r
- self.scaleSize = self.shortScaleSize\r
- \r
- 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)]\r
- #inflate last noteRect to cover the far right pixels\r
- self.noteRects[-1].width = self.noteRects[-1].width + 1\r
- \r
- #create bounding rect\r
- self.boundingRect = self.noteRects[0].unionall(self.noteRects)\r
- \r
- #fill the rectangles with a color gradient\r
- #We start with blue\r
- startingHue = 0.66666666666666663\r
- \r
- for rectNumber in range(self.scaleSize):\r
- colorRatio = float(rectNumber) / (self.scaleSize - 1)\r
- #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up\r
- hue = startingHue * (1 - colorRatio)\r
- if self.song != None:\r
- if rectNumber + self.offset == self.highlightedNote:\r
- #The color of the bottom of the rectangle in hls coordinates\r
- bottomColorHls = (hue, 0.6, 1)\r
- #The color of the top of the rectangle in hls coordinates\r
- topColorHls = (hue, 0.9, 1)\r
- else:\r
- #The color of the bottom of the rectangle in hls coordinates\r
- bottomColorHls = (hue, 0.2, 1)\r
- #The color of the top of the rectangle in hls coordinates\r
- topColorHls = (hue, 0.4, 1)\r
- else:\r
- #The color of the bottom of the rectangle in hls coordinates\r
- bottomColorHls = (hue, 0.6, 1)\r
- #The color of the top of the rectangle in hls coordinates\r
- topColorHls = (hue, 0.9, 1)\r
- \r
- #convert to rgb ranging from 0 to 255\r
- bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)]\r
- topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)]\r
- #add transparency\r
- bottomColorRgb.append(255)\r
- topColorRgb.append(255)\r
- #convert to tuple\r
- bottomColorRgb = tuple(bottomColorRgb)\r
- topColorRgb = tuple(topColorRgb) \r
- \r
- self.savedScreen.blit(gradients.vertical(self.noteRects[rectNumber].size, topColorRgb, bottomColorRgb), self.noteRects[rectNumber])\r
- \r
- textBlitPoint = (self.noteRects[rectNumber].left+(self.noteRects[rectNumber].width-self.renderedNoteNames[rectNumber].get_width())/2,\r
- self.noteRects[rectNumber].bottom-self.renderedNoteNames[rectNumber].get_height())\r
- \r
- self.savedScreen.blit(self.renderedNoteNames[rectNumber], textBlitPoint)\r
- \r
- pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[rectNumber], 2)\r
- \r
- \r
- if self.song != None and self.blinkOn:\r
- borderSize = self.borderSize\r
- pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 0), self.noteRects[self.highlightedNote-self.offset].inflate(borderSize/2,borderSize/2), borderSize)\r
- \r
- def initializeWiimotes(self):\r
- for loop in self.wiimotes:\r
- if loop.port == None :\r
- loop.port = pygame.midi.Output(loop.portNumber)\r
- self.notes.append(0)\r
- self.buttonDown.append(False)\r
- self.velocityLock.append(False)\r
- \r
- def updateCursorPositionFromJoy(self, joyEvent):\r
- joyName = pygame.joystick.Joystick(joyEvent.joy).get_name()\r
- correctedJoyId = constants.joyNames.index(joyName)\r
- if correctedJoyId < len(self.cursorPositions):\r
- if joyEvent.axis == 0 :\r
- self.cursorPositions[correctedJoyId] = (int((joyEvent.value + 1) / 2 * self.screen.get_width()), self.cursorPositions[correctedJoyId][1])\r
- if joyEvent.axis == 1 :\r
- self.cursorPositions[correctedJoyId] = (self.cursorPositions[correctedJoyId][0], int((joyEvent.value + 1) / 2 * self.screen.get_height()))\r
- \r
- def heightToVelocity(self, pos, controllerNumber):\r
- if self.song != None:\r
- if self.boundingRect.collidepoint(pos) and (self.highlightedNote == self.notes[controllerNumber] or self.velocityLock[controllerNumber]):\r
- velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity)\r
- else :\r
- if self.easyMode:\r
- velocity = None\r
- else:\r
- velocity = self.minimalVelocity/3\r
- else:\r
- if self.boundingRect.collidepoint(pos):\r
- velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity)\r
- else :\r
- velocity = self.minimalVelocity\r
- return(velocity)\r
- \r
- def widthToNote(self, pos):\r
- nn = 0\r
- try :\r
- while self.noteRects[nn].collidepoint(pos) == False:\r
- nn = nn + 1\r
- return(nn + self.offset)\r
- except(IndexError):\r
- return(None)\r
- \r
- def input(self, event): \r
- \r
- if event.type == pygame.QUIT:\r
- for loop in self.wiimotes:\r
- del loop.port\r
- pygame.midi.quit()\r
- sys.exit(0) \r
- \r
- if event.type == pygame.KEYDOWN:\r
- if event.key == pygame.K_q:\r
- self.done = True\r
- \r
- if event.key == pygame.K_i:\r
- self.backToInstrumentChoice = True\r
- self.done = True \r
- \r
- if event.type == pygame.JOYAXISMOTION:\r
- joyName = pygame.joystick.Joystick(event.joy).get_name()\r
- correctedJoyId = constants.joyNames.index(joyName)\r
- if self.activeWiimotes[correctedJoyId]:\r
- self.updateCursorPositionFromJoy(event) \r
- wiimote = self.wiimotes[correctedJoyId]\r
- pos = self.cursorPositions[correctedJoyId]\r
- \r
- if self.buttonDown[correctedJoyId]:\r
- if self.notes[correctedJoyId] != None:\r
- velocity = self.heightToVelocity(pos, correctedJoyId)\r
- CCHexCode = wiimote.getCCHexCode()\r
- wiimote.port.write_short(CCHexCode, 07, velocity)\r
- if self.cascade:\r
- n = self.widthToNote(pos)\r
- if n != self.notes[correctedJoyId]:\r
- wiimote.stopNote(self.notes[correctedJoyId])\r
- self.notes[correctedJoyId] = n\r
- \r
- if self.song != None :\r
- if self.highlightedNote == self.notes[correctedJoyId]:\r
- self.highlightedNote = self.songIterator.next()\r
- self.velocityLock[correctedJoyId] = True\r
- else:\r
- self.velocityLock[correctedJoyId] = False\r
- \r
- velocity = self.heightToVelocity(pos, correctedJoyId)\r
- \r
- wiimote.playNote(self.notes[correctedJoyId],velocity)\r
- \r
- if event.type == pygame.JOYBUTTONDOWN :\r
- \r
- joyName = pygame.joystick.Joystick(event.joy).get_name()\r
- correctedJoyId = constants.joyNames.index(joyName)\r
- if self.activeWiimotes[correctedJoyId]:\r
- wiimote = self.wiimotes[correctedJoyId]\r
- pos = self.cursorPositions[correctedJoyId]\r
- \r
- if not self.buttonDown[correctedJoyId]:\r
- savedNote = self.notes[correctedJoyId]\r
- self.notes[correctedJoyId] = self.widthToNote(pos)\r
- \r
- if self.song != None :\r
- if self.highlightedNote == self.notes[correctedJoyId]:\r
- self.highlightedNote = self.songIterator.next()\r
- self.velocityLock[correctedJoyId] = True\r
- \r
- velocity = self.heightToVelocity(pos, correctedJoyId)\r
- \r
- if velocity != None : \r
- if self.easyMode :\r
- wiimote.stopNote(savedNote)\r
- wiimote.playNote(self.notes[correctedJoyId],velocity)\r
- self.buttonDown[correctedJoyId] = True\r
- \r
- if event.type == pygame.JOYBUTTONUP:\r
- joyName = pygame.joystick.Joystick(event.joy).get_name()\r
- correctedJoyId = constants.joyNames.index(joyName)\r
- if self.activeWiimotes[correctedJoyId]:\r
- self.buttonDown[correctedJoyId] = False\r
- wiimote = self.wiimotes[correctedJoyId]\r
- if not self.easyMode:\r
- wiimote.stopNote(self.notes[correctedJoyId])\r
- self.velocityLock[correctedJoyId] = False\r
- \r
- if event.type == pygame.MOUSEMOTION:\r
- \r
- self.updateCursorPositionFromMouse(event)\r
-\r
- correctedJoyId = 0\r
- while not self.activeWiimotes[correctedJoyId] :\r
- correctedJoyId += 1\r
- wiimote = self.wiimotes[correctedJoyId]\r
- pos = self.cursorPositions[correctedJoyId]\r
-\r
- if self.buttonDown[correctedJoyId]:\r
- if self.notes[correctedJoyId] != None:\r
- velocity = self.heightToVelocity(pos, correctedJoyId)\r
- CCHexCode = wiimote.getCCHexCode()\r
- wiimote.port.write_short(CCHexCode, 07, velocity)\r
- if self.cascade:\r
- n = self.widthToNote(pos)\r
- if n != self.notes[correctedJoyId]:\r
- wiimote.stopNote(self.notes[correctedJoyId])\r
- self.notes[correctedJoyId] = n\r
- \r
- if self.song != None :\r
- if self.highlightedNote == self.notes[correctedJoyId]:\r
- self.highlightedNote = self.songIterator.next()\r
- self.velocityLock[correctedJoyId] = True\r
- else:\r
- self.velocityLock[correctedJoyId] = False\r
- \r
- velocity = self.heightToVelocity(pos, correctedJoyId)\r
- \r
- wiimote.playNote(self.notes[correctedJoyId],velocity) \r
- \r
- if event.type == pygame.MOUSEBUTTONDOWN:\r
- \r
- if event.button == 1:\r
- correctedJoyId = 0\r
- while not self.activeWiimotes[correctedJoyId] :\r
- correctedJoyId += 1\r
- wiimote = self.wiimotes[correctedJoyId]\r
- pos = self.cursorPositions[correctedJoyId]\r
- \r
- if not self.buttonDown[correctedJoyId]:\r
- self.notes[correctedJoyId] = self.widthToNote(pos)\r
- \r
- if self.song != None :\r
- if self.highlightedNote == self.notes[correctedJoyId]:\r
- self.highlightedNote = self.songIterator.next()\r
- self.velocityLock[correctedJoyId] = True\r
- \r
- velocity = self.heightToVelocity(pos, correctedJoyId)\r
- \r
- wiimote.playNote(self.notes[correctedJoyId],velocity)\r
- self.buttonDown[correctedJoyId] = True\r
- \r
- if event.button == 2:\r
- \r
- self.done = True\r
- \r
- if event.type == pygame.MOUSEBUTTONUP:\r
- \r
- correctedJoyId = 0\r
- while not self.activeWiimotes[correctedJoyId] :\r
- correctedJoyId += 1\r
- wiimote = self.wiimotes[correctedJoyId]\r
- wiimote.stopNote(self.notes[correctedJoyId])\r
- self.buttonDown[correctedJoyId] = False\r
- self.velocityLock[correctedJoyId] = False\r
- \r
- def hasChanged(self):\r
- changed = False\r
- if self.song != None:\r
- if self.blinkOn != self.savedBlinkOn or self.highlightedNote != self.savedHighlightedNote:\r
- self.savedBlinkOn = self.blinkOn\r
- self.savedHighlightedNote = self.highlightedNote\r
- changed = True\r
- return(changed)\r
- \r
- def updateCursorPositionFromMouse(self, mouseEvent):\r
- correctedJoyId = 0\r
- while not self.activeWiimotes[correctedJoyId] :\r
- correctedJoyId += 1\r
- self.cursorPositions[correctedJoyId] = mouseEvent.pos\r
- \r
- def moveToNextNote(self):\r
- while True:\r
- if self.song == None:\r
- yield(None)\r
- else:\r
- for note in self.song:\r
- yield note\r