Implémentation de l'ajustement « en live » du tempo d'exécution de la chanson sur...
[minwii.git] / src / minwii / app.py
1 # -*- coding: utf-8 -*-
2 """
3 l'application winwii
4
5 $Id$
6 $URL$
7 """
8
9 import pygame
10 from pgu.gui import Theme
11 from pgu.gui import Desktop
12 from pgu.gui import QUIT
13 from minwii.widgets.launch import LaunchScreen
14 from minwii.widgets.home import Home
15 from minwii.widgets.playingscreen import SongPlayingScreen, PlayingScreen
16 from minwii.widgets.instrumentselector import InstrumentSelector
17 from minwii.synth import Synth
18 from minwii.eventutils import EventDispatcher
19 from minwii.musicxml import musicXml2Song
20 from minwii.config import SONG_FILE_PATH
21 from minwii.config import SCREEN_RESOLUTION
22 from minwii.globals import PLAYING_MODES_DICT
23 from minwii.log import console, LOG_FORMAT_VERSION, envLogger
24 import os.path
25
26 wiiuse = None
27 pygame_wiimouse = None
28
29 SCREEN_HOME = 0
30 SCREEN_INSTRUMENTS = 1
31 SCREEN_PLAY = 2
32
33
34
35 class MinWii(object):
36
37 def __init__(self, wiimoteSupport=True, fullscreen=False) :
38 envLogger.info('winwii log format version : %s', LOG_FORMAT_VERSION)
39 self.wiimoteSupport = wiimoteSupport
40 self.fullscreen = fullscreen
41 LaunchScreen()
42 themedir = __file__.split(os.path.sep)[:-1] + ['widgets', 'data', 'minwii_theme']
43 themedir = os.path.sep.join(themedir)
44 theme = Theme(themedir)
45 self.app = Desktop(theme=theme)
46 self.synth = Synth()
47 self.screenResolution = SCREEN_RESOLUTION
48 envLogger.info('résolution écran : %s', self.screenResolution)
49 self.nwiimotes = 0
50 self.initWiimotes()
51 self.firstSong = True
52 self.screen = SCREEN_HOME
53 self.playingScreen = None
54
55 def initWiimotes(self) :
56 if self.wiimoteSupport :
57 global wiiuse
58 from pywiiuse import PyWiiUse as wiiuse
59 global pygame_wiimouse
60 from pywiiuse import pygame_wiimouse
61 from minwii.config import IR_POSITION
62 pygame_wiimouse.init(5, 5, self.screenResolution, IR_POSITION) # look for 5, wait 5 seconds
63 self.nwiimotes = nwiimotes = pygame_wiimouse.get_count()
64 console.debug('wiimotes found : %d', nwiimotes)
65 self.WT = WT = pygame_wiimouse.WT
66 WT.setEventCallBack(self._wiimotesEventCallBack)
67 WT.pause()
68 else :
69 self.WT = _WTFacade()
70
71 def _wiimotesEventCallBack(self, wt, id, wmp) :
72 if self.screen == SCREEN_PLAY :
73 pygame_wiimouse._default_event_cb(wt, id, wmp)
74
75 wm = wmp[0]
76 if id == self.nwiimotes - 1 :
77 # le bouton Home de la télécommande permet de sortir
78 # (envoi d'un événement clavier « q »)
79 if wiiuse.is_just_pressed(wm, wiiuse.button['Home']) :
80 event = pygame.event.Event(pygame.KEYDOWN,
81 key = pygame.K_q,
82 unicode = u'q')
83 pygame.event.post(event)
84 elif wiiuse.is_just_pressed(wm, wiiuse.button['+']) :
85 self.synth.inc_gain()
86 elif wiiuse.is_just_pressed(wm, wiiuse.button['-']) :
87 self.synth.dec_gain()
88 elif wiiuse.is_just_pressed(wm, wiiuse.button['1']) and self.playingScreen :
89 self.playingScreen.tempoTrimUp()
90 elif wiiuse.is_just_pressed(wm, wiiuse.button['2']) and self.playingScreen :
91 self.playingScreen.tempoTrimDown()
92
93 elif self.screen in (SCREEN_HOME, SCREEN_INSTRUMENTS) :
94 pygame_wiimouse._full_mouse_event_cb(wt, id, wmp)
95
96 def run(self) :
97 "séquençage de l'affichage des écrans"
98 displayFlags = 0
99 if self.fullscreen :
100 displayFlags = displayFlags | pygame.FULLSCREEN
101 pygame.display.set_mode(self.screenResolution, displayFlags)
102 pygame.display.set_caption('MINWii')
103 WT = self.WT
104
105 songFile, playMode, wiimoteIndex = '', 'NORMAL', 0
106
107 while True :
108 WT.resume()
109 WT.selectWiimote(self.nwiimotes - 1) # la télécommande est la souris
110 self.screen = SCREEN_HOME
111 exit, songFile, playMode, wiimoteIndex = \
112 self.selectSongAndOptions(songFile, playMode, wiimoteIndex)
113 if exit : break
114
115
116 self.screen = SCREEN_INSTRUMENTS
117 instrumentDescription = self.selectInstrument()
118 if not instrumentDescription :
119 continue
120
121 self.screen = SCREEN_PLAY
122 WT.selectWiimote(wiimoteIndex)
123 self.runPlayingScreen(songFile, playMode, instrumentDescription)
124 WT.pause()
125
126
127 def selectSongAndOptions(self, songFile, playMode, wiimoteIndex) :
128 """ lance l'écran de paramétrage et retourne un tuple comportant :
129 - drapeau de sortie de l'application (booléen)
130 - chemin du fichier de la chanson
131 - mode (entier)
132 - wiimote sélectionnée (entier)
133 """
134 home = Home(songPath=SONG_FILE_PATH,
135 songFile=songFile,
136 playMode=playMode,
137 wiimoteIndex=wiimoteIndex,
138 nwiimotes=self.nwiimotes)
139 app = self.app
140 home.connect(QUIT, app.quit)
141 app.run(home)
142 app.close(home)
143
144 #logging
145 if home.exitApp :
146 console.debug("sortie de l'application")
147 else :
148 actual_wiimotes = self.WT.get_count()
149 if self.firstSong :
150 self.firstSong = False
151 else :
152 envLogger.info('NEW_LOG_FILE')
153 console.info('chanson : %s', home.songFile)
154 console.info('mode : %s', home.modeSelect.value)
155 if actual_wiimotes is None :
156 console.info('HID : souris')
157 elif actual_wiimotes == 0 :
158 console.info('HID : souris (pas de wiimote trouvée)')
159 else :
160 console.info('HID : wiimote %d', home.selectedWiimote.value + 1)
161 #---
162
163 return (home.exitApp,
164 home.songFile,
165 home.selectedPlayMode,
166 home.selectedWiimoteIndex)
167
168 def selectInstrument(self) :
169 """ lance l'écran de sélection de l'instrument et retourne
170 un dictionnaire comportant la description de l'instrument
171 """
172 selector = InstrumentSelector()
173 selector.run()
174 selector.stop()
175 pygame.event.clear()
176 EventDispatcher.reset()
177 instru = selector.selectedInstrument
178 if instru :
179 console.info('instrument : %s', instru['name'])
180 console.info('preset : %d', instru['preset'])
181 console.info('bank : %d', instru['bank'])
182 console.info('ajustement octave : %d', instru['octave'])
183 return instru
184
185 def runPlayingScreen(self, songFile, playMode, instrumentDescription) :
186 """ Lance l'écran de jeu principal avec la chanson 'songFile' dans le mode 'playMode'
187 avec l'instrument midi 'instrumentDescription'.
188 """
189 playMode = PLAYING_MODES_DICT[playMode]
190 bank, preset = instrumentDescription['bank'], instrumentDescription['preset']
191 octave = instrumentDescription['octave']
192 self.synth.adjust_octave(0, octave)
193 self.synth.program_select(0, bank, preset)
194 if playMode == PLAYING_MODES_DICT['IMPRO'] :
195 playingScreen = PlayingScreen(self.synth)
196 else :
197 song = musicXml2Song(songFile)
198 self.playingScreen = playingScreen = SongPlayingScreen(self.synth, song, mode=playMode)
199 playingScreen.run()
200 pygame.event.clear()
201 EventDispatcher.reset()
202 self.playingScreen = None
203
204
205 class _WTFacade :
206 """ Classe utilitaire pour singer l'api
207 de pygame_wiimouse en cas d'abscence de wiimote.
208 """
209 selectWimoteIndex = 0
210 def pause(self):
211 pass
212 def resume(self):
213 pass
214 def selectWiimote(self, i):
215 pass
216 def get_count(self) :
217 return None