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)
Example #3
0
def choose_book(index, results, stdscr=None):
    if stdscr:
        song = results[cgui.menu(stdscr, "Select a song", results)]
    else:
        song = results[commandline.menu("Select a song", results)]
    locations = zip(books, index[song])

    bookhits = []
    for book in books:
        if index[song][book]:
            bookhits.append(book)
    if stdscr:
        book = bookhits[cgui.menu(stdscr, "Select a book", bookhits)]
    else:
        book = bookhits[commandline.menu("Select a book", bookhits)]
    return (song, book)
  def graphics(self, stdscr):
    self.stdscr = stdscr
    self.my, self.mx = self.stdscr.getmaxyx()
    self.height = 4
    self.width = self.mx - 30
    self.posy = int(self.my / 2.0 - self.height / 2.0)
    self.posx = int(self.mx / 2.0 - self.width / 2.0)

    self.midipad = curses.newpad(self.height, 1) 
    self.annotationpad = curses.newpad(self.height, 1)
    self.com_buffer = curses.newwin(1, self.width, self.posy, self.posx)

    self.buf = ''
    self.stdscr.refresh()

    if annotationcorpus.exists('autosave', 'autosave'):
      if cgui.menu(self.stdscr, 'Annotator quit unexpectedly. Restore last session?', ['Yes', 'No']) == 0:
        self.load('autosave', 'autosave')

    while True:
      exp = re.compile(r'(?P<repetitions>[0-9]+)?(?P<action>[iqpsx ])$|:(?P<command>set |play|stop|pause|save|strip|subtract|q|load|score|restore)(?P<arg1>resolution|correction|beatsperbar|beatdiv)?(?P<arg2> (-)?[0-9]+)?\n$')
      if self.mode == self.INSERT:
        exp = re.compile(r'(?P<command>[ wsrge]|t(?P<arg>[0-9]+))$') 
      # Check if the buffer contains a command
      m = exp.match(self.buf)
      if m:
        if not self.execute(m):
          break
        self.buf = ''

      self.updateScr(self.stdscr)
      c = self.stdscr.getch()
      if c == curses.ERR: continue
      self.status = ''

      if c == 27: # or c == curses.KEY_BACKSPACE:
        if self.mode == self.INSERT:
          self.mode = self.ANNOTATING
          self.status = 'Leaving insert mode'
        # Empty buffer
        self.buf = ''
      elif c == curses.KEY_BACKSPACE:
        # Empty buffer
        self.buf = ''
      elif c == curses.KEY_LEFT:
        self.curs_left()
      elif c == curses.KEY_RIGHT:
        self.curs_right()
      elif c == curses.KEY_UP and self.mode != self.INSERT:
        if self.mode == self.ANNOTATING:
          self.mode = self.PLAYING
      elif c == curses.KEY_DOWN and self.mode != self.INSERT:
        if self.mode == self.PLAYING:
          self.mode = self.ANNOTATING
      else:
        if c in range(32, 128) + [10]:
          self.buf += chr(c)
  def load(self, collection=None, name=None):
    if not collection:
      collection = annotationcorpus.collections()[\
          cgui.menu(self.stdscr, 'Choose collection', annotationcorpus.collections())]
    results = annotationcorpus.load(collection, name)
    if results:
      self.annotations = []
      self.midifile = annotationcorpus.load_midifile(collection, name)
      for result in results:
        self.annotations += result.annotation

      metadata = results[0].metadata
      self.notelist = results[0].notes
      self.bpm = metadata['bpm']
      self.offset = metadata['offset']
      self.name = metadata['name']
      self.meter = meter.Meter(metadata['beatspb'], metadata['beatdiv'])
      self.refreshAnnotation = True
      self.refreshMidi = True
      return True
    return False
Example #6
0
    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