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 save(self, collection=None, name=None, force=False): """Save the annotation to the corpus""" if not collection: choice = cgui.menu(self.stdscr, 'Collection', annotationcorpus.collections() + ['Add new collection']) if choice == -1: return elif choice == len(annotationcorpus.collections()): collection = cgui.prompt(self.stdscr, 'Collection?') else: collection = annotationcorpus.collections()[choice] if not name: name = self.name metadata = {'beatdiv':self.meter.beatdiv, 'beatspb':self.meter.beatspb, 'offset':self.offset, 'bpm':self.bpm, 'name':self.name} if annotationcorpus.exists(collection, name) and not force: if cgui.menu(self.stdscr, 'Item exists, overwrite?', ['No', 'Yes']) != 1: return annotationcorpus.save(collection, name, metadata, sorted(self.annotations, key=lambda x: x[0]), self.notelist, self.midifile)
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