X-Git-Url: https://scm.cri.ensmp.fr/git/minwii.git/blobdiff_plain/79aca379ed6dffa4d71d66f513a973d2e3470c5a..1b71e2e6e4439f8e753ceca8ccbf4abf18be4d29:/src/minwii/widgets/playingscreen.py diff --git a/src/minwii/widgets/playingscreen.py b/src/minwii/widgets/playingscreen.py index 0591929..6d66ace 100755 --- a/src/minwii/widgets/playingscreen.py +++ b/src/minwii/widgets/playingscreen.py @@ -10,6 +10,7 @@ import pygame import types import minwii.events as events +from minwii.log import eventLogger from minwii.eventutils import event_handler, EventDispatcher, EventHandlerMixin from minwii.musicxml import Tone from minwii.config import FRAMERATE @@ -26,7 +27,7 @@ from column import Column class PlayingScreenBase(pygame.sprite.LayeredDirty, EventHandlerMixin) : - def __init__(self, synth, distinctNotes=[]) : + def __init__(self, synth, distinctNotes=[], displayNotes=True) : """ distinctNotes : notes disctinctes présentes dans la chanson triées du plus grave au plus aigu. @@ -34,6 +35,7 @@ class PlayingScreenBase(pygame.sprite.LayeredDirty, EventHandlerMixin) : super(PlayingScreenBase, self).__init__() self.synth = synth self.distinctNotes = distinctNotes + self.displayNotes = displayNotes self.keyboardLength = 0 self.keyboardRects = [] self.cursor = None @@ -58,11 +60,16 @@ class PlayingScreenBase(pygame.sprite.LayeredDirty, EventHandlerMixin) : columnWidth = int(round(float(dispWidth) / self.keyboardLength)) rects = [] - for i in range(self.keyboardLength) : + for i in range(self.keyboardLength - 1) : upperLeftCorner = (i*columnWidth, 0) rect = pygame.Rect(upperLeftCorner, (columnWidth, dispHeight)) rects.append(rect) + # la dernière colonne à la largeur du reste + upperLeftCorner = ((i+1) * columnWidth, 0) + rect = pygame.Rect(upperLeftCorner, (dispWidth - (self.keyboardLength - 1) * columnWidth , dispHeight)) + rects.append(rect) + self.keyboardRects = rects def _initColumns(self) : @@ -71,7 +78,7 @@ class PlayingScreenBase(pygame.sprite.LayeredDirty, EventHandlerMixin) : for i, rect in enumerate(self.keyboardRects) : hue = FIRST_HUE - hueStep * i tone = self.distinctNotes[i] - c = Column(self, i, hue, rect, tone) + c = Column(self, i, hue, rect, tone, displayNote=self.displayNotes) self.add(c, layer=BACKGROUND_LAYER) self.columns[tone.midi] = c @@ -99,7 +106,9 @@ class PlayingScreenBase(pygame.sprite.LayeredDirty, EventHandlerMixin) : @event_handler(pygame.KEYDOWN) def handleKeyDown(self, event) : - if event.key == pygame.K_q or event.unicode == u'q': + if event.key == pygame.K_q or \ + event.unicode == u'q' or \ + pygame.K_ESCAPE: self.stop() @event_handler(pygame.MOUSEBUTTONDOWN) @@ -158,31 +167,36 @@ class PlayingScreen(PlayingScreenBase) : scale = [55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72] - def __init__(self, synth) : + def __init__(self, synth, displayNotes=True) : distinctNotes = [] + self.currentColumn = None for midi in self.scale : tone = Tone(midi) distinctNotes.append(tone) - super(PlayingScreen, self).__init__(synth, distinctNotes) + super(PlayingScreen, self).__init__(synth, distinctNotes, displayNotes=displayNotes) - @event_handler(events.NOTEON) - def noteon(self, evt) : - tone = evt.tone - self.synth.noteon(0, tone.midi, 96) - - @event_handler(events.NOTEOFF) - def noteoff(self, evt) : - tone = evt.tone - self.synth.noteoff(0, tone.midi) + @event_handler(events.COLDOWN) + def noteon(self, event) : + col = event.column + col.update(True) + self.currentColumn = col + self.playnote(col, event.pos) + @event_handler(events.COLUP) + def noteoff(self, event) : + if self.currentColumn : + self.currentColumn.update(False) + self.synth.noteoff(0, self.currentColumn.tone.midi) + class SongPlayingScreen(PlayingScreenBase) : - def __init__(self, synth, song, mode=PLAYING_MODES_DICT['NORMAL']) : - super(SongPlayingScreen, self).__init__(synth, song.distinctNotes) + def __init__(self, synth, song, mode=PLAYING_MODES_DICT['NORMAL'], displayNotes=True, tempoTrim=0) : + super(SongPlayingScreen, self).__init__(synth, song.distinctNotes, displayNotes=displayNotes) self.song = song self.quarterNoteDuration = song.quarterNoteDuration + self.tempoTrim = tempoTrim self.currentColumn = None self.noteIterator = self.song.iterNotes() self.displayNext() @@ -217,29 +231,23 @@ class SongPlayingScreen(PlayingScreenBase) : col = event.column if col.state and not self.currentNotePlayed : self.playnote(col, event.pos) - SongPlayingScreen.setNoteTimeout( - int(self.currentNote.duration * \ - self.quarterNoteDuration) - ) + self.setNoteTimeout() self.currentNotePlayed = True def handleEasyColumnOver(self, event) : col = event.column if col.state and \ - any(event.mouseEvent.buttons) and \ + self.cursor.pressed and \ not self.currentNotePlayed : self.playnote(col, event.pos) - SongPlayingScreen.setNoteTimeout( - int(self.currentNote.duration * \ - self.quarterNoteDuration) - ) + self.setNoteTimeout() self.currentNotePlayed = True def handleNormalColumnOver(self, event) : col = event.column if col.state and \ - any(event.mouseEvent.buttons) and \ + self.cursor.pressed and \ not self.currentNotePlayed : self.playnote(col, event.pos) self.currentNotePlayed = True @@ -255,10 +263,7 @@ class SongPlayingScreen(PlayingScreenBase) : if col.state and \ not self.currentNotePlayed : self.playnote(col, event.pos) - SongPlayingScreen.setNoteTimeout( - int(self.currentNote.duration * \ - self.quarterNoteDuration) - ) + self.setNoteTimeout() self.currentNotePlayed = True @@ -292,8 +297,17 @@ class SongPlayingScreen(PlayingScreenBase) : def displayNext(self, event=None) : if self.currentColumn: self.currentColumn.update(False) - note, verseIndex = self.noteIterator.next() - syllabus = note.lyrics[verseIndex].syllabus() + try : + note, verseIndex = self.noteIterator.next() + except StopIteration : + self.noteIterator = self.song.iterNotes() + note, verseIndex = self.noteIterator.next() + eventLogger.info(pygame.event.Event(events.SONGEND)) + try : + syllabus = note.lyrics[verseIndex].syllabus() + except IndexError : + syllabus = u'…' + column = self.columns[note.midi] column.update(True, syllabus) self.currentColumn = column @@ -306,10 +320,18 @@ class SongPlayingScreen(PlayingScreenBase) : self.synth.noteoff(0, self.currentNote.midi) self.displayNext() - @staticmethod - def setNoteTimeout(delay) : + def setNoteTimeout(self) : + delay = self.currentNote.duration * self.quarterNoteDuration + delay = delay + delay * self.tempoTrim + delay = int(delay) pygame.time.set_timer(events.NOTEEND, delay) + def tempoTrimUp(self, step=0.1) : + self.tempoTrim = round(self.tempoTrim - step, 1) + + def tempoTrimDown(self, step=0.1) : + self.tempoTrim = round(self.tempoTrim + step, 1) + def stop(self) : pygame.time.set_timer(events.NOTEEND, 0) super(SongPlayingScreen, self).stop()