def run(stdscr): onsets = [] parses = None mode = BEGIN while True: stdscr.clear() if mode == BEGIN: stdscr.addstr(3, 3, 'Tap space to begin and add an onset, hit b to begin and not add an onset, hit q to stop') elif mode == STARTED: stdscr.addstr(3, 3, 'Running. Tap space to add onsets, q to stop') elif mode == ENDED: stdscr.addstr(3, 3, 'Done. Onsets: {0}'.format(onsets)) stdscr.refresh() c = stdscr.getch() if c == ord('b'): if mode == BEGIN: mode = STARTED start = datetime.now() if c == ord(' '): if mode == BEGIN: mode = STARTED start = datetime.now() onsets.append(0) elif mode == STARTED: diff = datetime.now() - start onsets.append(diff.total_seconds()) if c == ord('r'): mode = BEGIN onsets = [] parses = None if c == ord('q'): if mode == BEGIN or mode == ENDED: break else: diff = datetime.now() - start onsets.append(diff.total_seconds()) mode = ENDED if c == ord('p') and mode == ENDED: if parses == None: cgui.alert(stdscr, 'Parsing', block=False) corpus = annotations.corpus('explicitswing') rhythmmodel = pcfg.train(corpus) expressionmodel = expression.additive_noise(0.1) parser = StochasticParser(corpus, expressionModel=expressionmodel, rhythmModel=rhythmmodel) parses = parser.parse_onsets(onsets) if len(parses) > 0: choice = cgui.menu(stdscr, '{0} parses'.format(len(parses)), ['View analysis', 'View score', 'View all']) if choice == -1: continue elif choice == 0: parse = parses[cgui.menu(stdscr, 'parse?', ['Prior: {0}, likelihood {1}, posterior {2}. Depth {3}'.format(p.prior, p.likelihood, p.posterior, p.depth) for p in parses])] parse.view() elif choice == 1: barlevel = cgui.prompt(stdscr, 'Barlevel?') parse = parses[cgui.menu(stdscr, 'parse?', ['Prior: {0}, likelihood {1}, posterior {2}. Depth {3}'.format(p.prior, p.likelihood, p.posterior, p.depth) for p in parses])] parse.score(barlevel=int(barlevel)) elif choice == 2: latex.view_symbols(parses, scale=False) else: cgui.alert(stdscr, 'No parses')
def gui(self, stdscr): seq = self.seq my, mx = stdscr.getmaxyx() #curses.mousemask(curses.BUTTON1_CLICKED) curses.halfdelay(1) y = x = 0 scale = 10 time = 0.0 tracks = None length = None viewpos = 0 trackview = None viewwidth = mx - 9 - 3 maxscale = 100 speed = 1.0 following = True name = None while True: if not seq.running: pass #break stdscr.clear() curses.curs_set(0) stdscr.addstr(0, 0, '[(p)lay/pause] [(s)top] [choose (f)ile] [choose (t)rack] [choose (o)utput] [((j/k) slower/faster)] [toggle (F)ollowing]') stdscr.addstr(1, 0, '[(e)dit alignment] [e(x)port track]') if seq.midifile: stdscr.addstr(4, 3, 'File: {0}'.format(seq.midifile.name)) stdscr.addstr(5, 3, 'Midi Device: {0}'.format(seq.device_info())) stdscr.addstr(6, 3, 'Midi Track: {0}'.format(seq.currenttrack)) stdscr.addstr(7, 3, 'Player status: {0}'.format(seq.status)) stdscr.refresh() time = self.seq.time # Load tracks once the midifile is loaded if self.seq.midifile and name is not self.seq.midifile.name: name = self.seq.midifile.name tracks = [] for t in self.seq.midifile.values(): if len(t) > 0: tracks.append(t) tracks = sorted(tracks, key=lambda x: x.n) length = max([t.length() for t in tracks]) length /= 1000000.0 trackview = None # Paint the trackview if tracks and not trackview: trackview = \ cgui.trackview(stdscr, tracks, ypos=9, xpos=3, width=viewwidth, scale=scale) viewpos = 0 if tracks and trackview: if seq.mode == seq.PLAYING and following: if time*scale < round(viewwidth/2.0): viewpos = 0 elif time*scale > length*scale - round(viewwidth/2.0): viewpos = length*scale - viewwidth else: viewpos = time*scale - round(viewwidth/2.0) cgui.updatetracks(stdscr, viewpos, time, trackview, ypos=9, xpos=3, width=mx-10, scale=scale, currenttrack=seq.currenttrack) stdscr.addstr(len(tracks)+1+9, 3, 'Time: {0:.2f}\tTime left: {1:.2f}\tTrackview scale: {2}\tSpeed: {3}' .format(time, length-time, scale, speed)) c = stdscr.getch() # if c == curses.KEY_MOUSE: # (id, x, y, z, state) = curses.getmouse() # if state == curses.BUTTON1_CLICKED: # pass # if c == ord('q'): self.seq.control(self.seq.QUIT, None) break elif c == ord('F'): if following: following = False else: following = True elif c == ord('s'): seq.control(seq.STOP, None) elif c == ord('N'): seq.control(seq.NEXTNOTE, None) elif c == ord('p'): if seq.mode == seq.PLAYING: seq.control(seq.PAUSE, None) else: seq.control(seq.PLAY, None) elif c == ord('t'): if seq.midifile: choice = cgui.menu(stdscr, 'Choose a track',\ ['Track #{0}\tName: {1}\tNumber of notes: {2}'.format(\ seq.midifile[t].n, seq.midifile[t].name, len(seq.midifile[t]))\ for t in seq.tracklist()]) if choice < 0: continue seq.control(seq.LOADTRACK, seq.tracklist()[choice]) elif c == ord('j'): if speed > 0: speed -= 0.01 seq.control(seq.SETSPEED, speed) elif c == ord('k'): speed += 0.01 seq.control(seq.SETSPEED, speed) elif c == ord('h'): seq.control(seq.SETTIME, seq.time-1) elif c == ord('l'): seq.control(seq.SETTIME, seq.time+1) elif c == ord('f'): level = 1 midifile = None while level > 0: if level == 1: choice = cgui.menu(stdscr, 'Choose collection', midicorpus.collections()) if choice == -1: level -= 1 continue else: level += 1 collection = midicorpus.collections()[choice] elif level == 2: choice = cgui.menu(stdscr, 'Choose song', midicorpus.songs(collection=collection)) if choice == -1: level -= 1 continue else: level += 1 song = midicorpus.songs(collection=collection)[choice] elif level == 3: choice = cgui.menu(stdscr, 'Choose version', midicorpus.versions(song, collection=collection)) if choice == -1: level -= 1 continue else: level += 1 version = midicorpus.versions(song, collection=collection)[choice] elif level == 4: singletrack = False track = 0 if len(midicorpus.tracks(song, version, collection=collection)) > 0: singletrack = True choice = cgui.menu(stdscr, 'Choose track', midicorpus.tracks(song, version, collection=collection)) if choice == -1: level -= 1 continue track = midicorpus.tracks(song, version, collection=collection)[choice] else: level += 1 midifile = midicorpus.load(song, version, track, singletrack, collection=collection) break if not midifile: continue cgui.alert(stdscr, 'Loading file', block=False) seq.control(seq.LOADFILE, midifile) time = 0 elif c == ord('o'): choice = cgui.menu(stdscr, 'Choose a midi device', seq.devicelist()) if choice < 0: continue seq.control(seq.SETOUTPUT, choice) elif c == curses.KEY_LEFT: if viewpos > 0: viewpos -= 1 elif c == curses.KEY_RIGHT: if viewpos < length*scale - viewwidth: viewpos += 1 elif c == curses.KEY_UP: if scale < maxscale and trackview: scale += 1 trackview = \ cgui.trackview(stdscr, tracks, ypos=9, xpos=3, width=viewwidth, scale=scale) elif c == curses.KEY_DOWN: if scale > 1 and trackview: scale -= 1 trackview = \ cgui.trackview(stdscr, tracks, ypos=9, xpos=3, width=viewwidth, scale=scale) curses.endwin()
def execute(self, match): props = match.groupdict() if self.mode == self.INSERT: self.refreshAnnotation = True if props['command'] == ' ' or props['command'] == 'r': for (quarters, midipos, pitch, type) in self.annotations: if self.cursor == self.quarters2units(quarters) and not type in [Annotation.GRACE, Annotation.ERROR]: index = self.annotations.index((quarters, midipos, pitch, type)) del self.annotations[index] self.midipos = midipos if props['command'] == ' ': return True else: break if props['command'] == ' ': self.addNote() self.midipos += 1 self.seq.control(self.seq.STOP, None) self.seq.control(self.seq.SETEVENTS, self.midifile.nonemptytrack().toEvents(self.midipos-1, self.midipos)) self.seq.control(self.seq.PLAY, True) elif props['command'] == 'r': # Add rest self.addNote(type=Annotation.REST) elif props['command'] == 'g': # Add gracenote self.addNote(type=Annotation.GRACE) self.midipos += 1 elif props['command'] == 'e': # Add end marker self.addNote(type=Annotation.END) elif props['command'] == 'w': # Add end marker self.addNote(type=Annotation.SWUNG) self.midipos += 1 elif props['command'] == 's': # Skip and mark as error self.addNote(type=Annotation.ERROR) self.midipos += 1 elif re.match('t[0-9]+$', props['command']): # Add a triplet division = int(props['arg']) if not division: cgui.alert(self.stdscr, 'Enter a beatdivision: t<beatdivision>', block=True) return True allowed = [math.pow(2, p) for p in range(int(math.log(1/float(self.resolution))/math.log(2)-1))] if not division in allowed: cgui.alert(self.stdscr, 'Beatdivision {0} is invalid.\n'.format(division) +\ 'Either the resolution doesn\'t allow it (try :set resolution <division>)\n' +\ 'or it\'s not a power of two.\n' +\ 'allowed divisions: {0}'.format(allowed), block=True) return True pattern = cgui.prompt(self.stdscr, 'Enter notes for a triplet with duration 1/{0}'.format(division), length=3) exp = re.compile('([ nr])([ nr])([ nr])$') m = exp.match(pattern) if m: self.refreshAnnotation = True for g in range(3): position = self.units2quarters(self.cursor) + self.notelength2quarters(g*(1/float(division))/3.0) if m.group(g+1) == 'n': self.addNote(position=position) self.midipos += 1 elif m.group(g+1) == 'r': self.addNote(type=Annotation.REST, position=position) elif m.group(g+1) == ' ': pass self.cursor += self.notelength2units(1/float(division)) else: cgui.alert(self.stdscr, 'Couldn\'t parse input.', block=True) elif props['action']: if props['action'] == 'q': return False elif props['action'] == 'i': self.mode = self.INSERT self.status = 'Entering insert mode' elif props['action'] == 'r': self.mode = self.INSERT self.status = 'Entering insert mode' elif props['action'] == 'p': if self.mode == self.PLAYING: self.seq.control(self.seq.STOP, None) self.seq.control(self.seq.LOADFILE, self.midifile) self.seq.control(self.seq.SETEVENTS, self.midifile.nonemptytrack().toEvents(self.midipos)) self.seq.control(self.seq.PLAY, True) elif self.mode == self.ANNOTATING: mid = generator.annotations2midi([(quarters, pitch, type) for (quarters, midipos, pitch, type) in self.annotations], meter=self.meter, bpm=self.bpm) if mid.nonemptytrack(): self.seq.control(self.seq.STOP, None) self.seq.control(self.seq.LOADFILE, mid) self.seq.control(self.seq.SETEVENTS, mid.nonemptytrack().toEvents(self.notepos)) self.seq.control(self.seq.PLAY, True) self.status = 'Playing' elif props['action'] == 's': self.seq.control(self.seq.STOP, None) elif props['action'] == 'x' and self.mode == self.ANNOTATING: if len(self.annotations) > 0: del self.annotations[self.notepos] self.refreshAnnotation = True elif props['action'] == 's' and self.mode == self.PLAYING: pass else: if props['command'] == 'set ': if props['arg1'] == 'correction': self.viewcorrection = int(props['arg2']) self.refreshMidi = True self.status = 'Transposing {0} semitone(s)'.format(props['arg2']) elif props['arg1'] == 'beatdiv': self.meter.beatdiv = int(props['arg2']) self.refreshAnnotation = True self.status = 'Changed beatdivision' elif props['arg1'] == 'beatsperbar': self.meter.beatspb = int(props['arg2']) self.refreshAnnotation = True self.status = 'Changed beats per bar' elif props['arg1'] == 'resolution': if not self.setresolution(1/float(props['arg2'])): cgui.alert(self.stdscr, 'Invalid resolution.') self.refreshMidi = True self.refreshAnnotation = True elif props['command'] == 'restore': if cgui.menu(self.stdscr, 'Restore last session?', ['No', 'Yes']) == 1: if not self.load('autosave', 'lastsession'): cgui.alert(self.stdscr, 'No session found') elif props['command'] == 'save': self.save() elif props['command'] == 'strip': self.strip() elif props['command'] == 'subtract': self.subtract() elif props['command'] == 'score': (name, version, track, singletrack) = midi.parsename(self.name) index = rbsearch.load_file() hits = rbsearch.find(index, name.replace('_', ' ')) if len(hits) > 0: (song, book) = rbsearch.choose_book(index, hits, stdscr=self.stdscr) rbsearch.view(song, book) elif props['command'] == 'load': if not self.load(name=self.name): cgui.alert(self.stdscr, 'No annotations found!') elif props['command'] == 'q': return False return True