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