8e62b5e7d37dd7440c031834218ea832d8125353
[minwii.git] / src / gui / Familiarizer.py
1 '''
2 Created on 15 juil. 2009
3
4 @author: Samuel Benveniste
5 '''
6
7 import pygame
8 import pygame.midi
9 import sys
10 import time
11 import pickle
12 import random
13
14 from numpy import array
15 from numpy.linalg import norm
16
17 from math import floor
18
19 from gui.constants import *
20 from PlayingScreen import PlayingScreen
21 from instruments.Instrument import Instrument
22 from cursor.WarpingCursor import *
23 from controllers.Wiimote import Wiimote
24 from logging.EventLog import EventLog
25 from logging.PickleableEvent import PickleableEvent
26
27 joyNames = ["PPJoy Virtual joystick 1", "PPJoy Virtual joystick 2", "PPJoy Virtual joystick 3"]
28 portNames = ["Out To MIDI Yoke: 1"]
29 majorScale = [55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72]
30 minorScale = [55, 56, 58, 60, 62, 63, 65, 67, 68, 70, 72]
31 myxolydianScale = [55, 57, 58, 60, 62, 64, 65, 67, 69, 70, 72]
32 dorianScale = [55, 57, 58, 60, 62, 63, 65, 67, 69, 70, 72]
33 instrumentImagePathList = ["piano", "guitare", "accordeon", "violon", "flute", "tuba", "orgue", "violoncelle", "celesta"]
34 octaves = [0, -1, 0, 1, 1, -2, 0, -1, 0]
35
36 class Familiarizer:
37 '''
38 The screen for choosing instruments
39
40 instruments:
41 The available instruments
42 wiimotes:
43 The wiimotes used in this session
44 window:
45 The main display window
46 screen:
47 The main display surface
48 clock:
49 The clock used to animate the screen
50 savedScreen:
51 The background that is painted every time
52 playerScreen:
53 The buffer for painting everything before bliting
54 width:
55 The width of the window in pixels
56 height:
57 The height of the window in pixels
58 done:
59 Goes to True when all instruments have been selected
60 cursorPositions:
61 The positions of the cursors on the screen, in pixels
62 imageRects:
63 The rectangles where the images of the instruments are located
64 focus:
65 The numbers of the instruments currently in focus
66 '''
67
68 def __init__(self, instruments, wiimotes, window, screen, clock, joys, portOffset, eventLog=None, replay = False, logFilePath = None, scaleFactor = 1, level = 1):
69 '''
70 Constructor
71
72 instruments:
73 The instruments for this session
74 wiimotes:
75 The wiimotes used in this session
76 '''
77
78
79 self.scaleFactor = scaleFactor
80
81 self.instruments = instruments
82 self.wiimotes = wiimotes
83 self.window = window
84 self.screen = screen
85 self.clock = clock
86 self.width = int(floor(screen.get_width()*self.scaleFactor))
87 self.height = int(floor(screen.get_height()*self.scaleFactor))
88 self.blitOrigin = ((self.screen.get_width()-self.width)/2,(self.screen.get_height()-self.height)/2)
89 self.joys = joys
90 self.portOffset = portOffset
91
92 self.currentWiimote = 0
93 self.done = False
94
95 self.cursorPositions = []
96 self.imageRects = []
97 self.displayedInstruments = []
98 self.savedImageRects = []
99 self.focus = []
100 self.level = level
101
102 if eventLog == None:
103 self.eventLog = EventLog()
104 self.replay = False
105 else:
106 self.eventLog = eventLog
107 self.replay = replay
108
109 self.savedScreen = pygame.Surface(self.screen.get_size())
110
111 self.displayedInstruments.append(0)
112 if level == 1 :
113 self.displayedInstruments.append(2)
114
115 self.savedScreen.fill((255, 255, 255))
116 for i in range(len(self.displayedInstruments)):
117 self.imageRects.append(self.drawInstrument(self.displayedInstruments[i]))
118
119 self.savedImageRects = self.imageRects[:]
120
121 #Draw the initial cursor on the buffer
122 self.playerScreen = pygame.Surface(self.savedScreen.get_size())
123 self.playerScreen.blit(self.savedScreen, (0, 0))
124
125 for i in range(len(self.wiimotes)):
126 #Create the list of instrument focus (one focus per wiimote)
127 self.focus.append(None)
128 #Set the screen for the cursors (it can't be set before)
129 self.wiimotes[i].cursor.screen = self.playerScreen
130 self.cursorPositions.append(self.wiimotes[i].cursor.centerPosition)
131
132 self.wiimotes[self.currentWiimote].cursor.blit(self.playerScreen)
133
134 #The main loop
135 while self.done == False :
136
137 #Clear the cursors from the screen
138 self.drawBackground()
139 self.playerScreen.blit(self.savedScreen, (0, 0))
140
141 # Limit frame speed to 50 FPS
142 #
143 timePassed = self.clock.tick(50)
144
145 if self.replay:
146 self.eventLog.update(timePassed)
147 pickledEventsToPost = self.eventLog.getPickledEvents()
148 for pickledEvent in pickledEventsToPost:
149 pygame.event.post(pickledEvent.event)
150
151 events = pygame.event.get()
152
153 if not self.replay:
154 pickledEvents = [PickleableEvent(event.type,event.dict) for event in events if self.eventFilter(event)]
155 if pickledEvents != [] :
156 self.eventLog.appendEventGroup(pickledEvents)
157
158 for event in events:
159 self.input(event)
160
161 for i in range(len(self.wiimotes)):
162 self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i])
163
164 self.wiimotes[self.currentWiimote].cursor.blit(self.playerScreen)
165
166 self.focus[self.currentWiimote] = None
167
168 for i in range(len(self.imageRects)) :
169 if self.imageRects[i].collidepoint(self.cursorPositions[self.currentWiimote]):
170 self.focus[self.currentWiimote] = i
171
172 self.screen.blit(self.playerScreen, (0, 0))
173
174 pygame.display.flip()
175
176 def input(self, event):
177 if event.type == pygame.QUIT:
178 pygame.midi.quit()
179 sys.exit()
180 if event.type == pygame.JOYAXISMOTION:
181 self.updateCursorPositionFromJoy(event)
182 if event.type == pygame.JOYBUTTONDOWN :
183 self.joyClicked(event)
184 if event.type == pygame.MOUSEBUTTONDOWN:
185 self.mouseClicked(event)
186 if event.type == pygame.MOUSEMOTION:
187 self.updateCursorPositionFromMouse(event)
188 if event.type == pygame.KEYDOWN:
189 if event.key == pygame.K_q:
190 self.done = True
191
192 def updateCursorPositionFromJoy(self, joyEvent):
193 joyName = pygame.joystick.Joystick(joyEvent.joy).get_name()
194 correctedJoyId = joyNames.index(joyName)
195 if correctedJoyId < len(self.cursorPositions):
196 if joyEvent.axis == 0 :
197 self.cursorPositions[correctedJoyId] = (int((joyEvent.value + 1) / 2 * self.screen.get_width()), self.cursorPositions[correctedJoyId][1])
198 if joyEvent.axis == 1 :
199 self.cursorPositions[correctedJoyId] = (self.cursorPositions[correctedJoyId][0], int((joyEvent.value + 1) / 2 * self.screen.get_height()))
200
201 def assignInstrumentToWiimote(self, joyEvent):
202 joyName = pygame.joystick.Joystick(joyEvent.joy).get_name()
203 correctedJoyId = joyNames.index(joyName)
204 if self.zoomed[correctedJoyId] == self.focus[correctedJoyId]:
205 self.wiimotes[correctedJoyId].instrument = self.instruments[self.focus[correctedJoyId]]
206 self.zoomed[correctedJoyId] = None
207 self.imageRects = self.savedImageRects[:]
208 if self.currentWiimote<len(self.wiimotes)-1:
209 self.currentWiimote = self.currentWiimote+1
210 else:
211 self.zoomed[correctedJoyId] = self.focus[correctedJoyId]
212 if self.hasFinished():
213 self.done = True
214
215 def updateCursorPositionFromMouse(self, mouseEvent):
216 self.cursorPositions[0] = mouseEvent.pos
217
218 def assignInstrumentToMouse(self, mouseEvent):
219 self.wiimotes[0].instrument = self.instruments[self.focus[0]]
220 if self.hasFinished():
221 self.done = True
222
223 def hasFinished(self):
224 finished = True
225 for wiimote in self.wiimotes:
226 if wiimote.instrument == None:
227 finished = False
228 return(finished)
229
230 def eventFilter(self, event):
231 c = event.type
232 if c == 17:
233 return False
234 elif c == pygame.MOUSEMOTION or pygame.MOUSEBUTTONDOWN or pygame.MOUSEBUTTONUP or pygame.JOYAXISMOTION or pygame.JOYBUTTONDOWN or pygame.JOYBUTTONUP or pygame.KEYDOWN:
235 return True
236 else:
237 return False
238
239 def drawInstrument(self,instrumentNumber,drawPos = None):
240 if not drawPos :
241 drawPos = array([random.randint(0,self.width/2),random.randint(0,self.height/2)])
242 curImage = pygame.image.load(self.instruments[instrumentNumber].image).convert_alpha()
243 scaledImage = pygame.transform.smoothscale(curImage, (self.width / 2, self.height / 2))
244 imageRect = self.savedScreen.blit(scaledImage, drawPos + self.blitOrigin)
245 pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), imageRect, 5)
246 return imageRect
247
248 def drawBackground(self):
249 self.savedScreen.fill((255, 255, 255))
250 for i in range(len(self.displayedInstruments)):
251 self.drawInstrument(self.displayedInstruments[i], self.imageRects[i].topleft)
252 if i in self.focus:
253 pygame.draw.rect(self.savedScreen, pygame.Color(0, 255, 0, 255), self.imageRects[i], 10)
254
255 def mouseClicked(self,mouseEvent):
256 correctedJoyId = 0
257 self.wiimotes[correctedJoyId].cursor.flash(400)
258 if self.focus[correctedJoyId] != None :
259 self.imageRects.pop(self.focus[correctedJoyId])
260 instrumentNumber = self.displayedInstruments.pop(self.focus[correctedJoyId])
261 self.drawBackground()
262 self.imageRects.append(self.drawInstrument(instrumentNumber))
263 self.displayedInstruments.append(instrumentNumber)
264 self.wiimotes[correctedJoyId].instrument = self.instruments[instrumentNumber]
265 octave = self.wiimotes[correctedJoyId].instrument.octave
266 noteOnHexCode = self.wiimotes[correctedJoyId].getNoteOnHexCode()
267 baseTime = pygame.midi.time()
268 self.wiimotes[correctedJoyId].port.write([[[noteOnHexCode,60+12*octave,127],baseTime],[[noteOnHexCode,60+12*octave,0],baseTime+500],[[noteOnHexCode,65+12*octave,100],baseTime+510],[[noteOnHexCode,65+12*octave,0],baseTime+1000]])
269 self.wiimotes[correctedJoyId].instrument = None
270
271 def joyClicked(self,joyEvent):
272 joyName = pygame.joystick.Joystick(joyEvent.joy).get_name()
273 correctedJoyId = joyNames.index(joyName)
274 self.wiimotes[correctedJoyId].cursor.flash(400)
275 if self.focus[correctedJoyId] != None :
276 self.imageRects.pop(self.focus[correctedJoyId])
277 instrumentNumber = self.displayedInstruments.pop(self.focus[correctedJoyId])
278 self.drawBackground()
279 self.imageRects.append(self.drawInstrument(instrumentNumber))
280 self.displayedInstruments.append(instrumentNumber)
281 self.wiimotes[correctedJoyId].instrument = self.instruments[instrumentNumber]
282 octave = self.wiimotes[correctedJoyId].instrument.octave
283 noteOnHexCode = self.wiimotes[correctedJoyId].getNoteOnHexCode()
284 baseTime = pygame.midi.time()
285 self.wiimotes[correctedJoyId].port.write([[[noteOnHexCode,60+12*octave,127],baseTime],[[noteOnHexCode,60+12*octave,0],baseTime+500],[[noteOnHexCode,65+12*octave,100],baseTime+510],[[noteOnHexCode,65+12*octave,0],baseTime+1000]])
286 self.wiimotes[correctedJoyId].instrument = None
287
288
289 def zoomRect(rect, ratio):
290 zoomedRect = rect.inflate(int(floor((ratio - 1) * rect.width)), int(floor((ratio - 1) * rect.height)))
291 return(zoomedRect)
292
293 if __name__ == "__main__":
294 pygame.init()
295 #pygame.event.set_blocked([pygame.MOUSEBUTTONDOWN,pygame.MOUSEBUTTONUP,pygame.MOUSEMOTION])
296
297 pygame.midi.init()
298 instruments = [Instrument(majorScale, i + 1, "".join(["../instruments/instrumentImages/", instrumentImagePathList[i], ".jpg"]), octaves[i]) for i in range(9)]
299
300 joys = [pygame.joystick.Joystick(id).get_name() for id in range(pygame.joystick.get_count())]
301 joyOffset = joys.index(joyNames[0])
302 pygame.joystick.Joystick(joyOffset).init()
303 print(joyOffset)
304
305 ports = [pygame.midi.get_device_info(id)[1] for id in range(pygame.midi.get_count())]
306 portOffset = ports.index(portNames[0])
307 print(portOffset)
308
309 window = pygame.display.set_mode((1280, 1024),pygame.FULLSCREEN)
310 screen = pygame.display.get_surface()
311 clock = pygame.time.Clock()
312 cursorImages = createImageListFromPath('../cursor/cursorImages/black', 11)
313 durations = [75 for i in range(len(cursorImages))]
314
315 extsc = False
316 casc = False
317
318 jadbt = [3, 4, 5, 3, 4, 4, 5, 6, 6, 5, 3, 3, 4, 5, 3, 4, 4, 5, 6, 7, 3]
319 song = None
320
321 cursors = [WarpingCursor(None, cursorImages, durations, (300 * i, 300 * i),'../cursor/cursorImages/black/flash.png') for i in range(1)]
322 wiimotes = [Wiimote(i, i + portOffset, pygame.midi.Output(i+portOffset,latency = 20), None, cursors[i]) for i in range(1)]
323 familiarize = Familiarizer(instruments, wiimotes, window, screen, clock, joyOffset, portOffset)
324 for wiimote in wiimotes:
325 del wiimote.port
326
327 pygame.midi.quit()
328 sys.exit()