def recordAll(score, args, splitRecord = [], counter = 1): #score needs to be flat #splitRecord is used to split the original score into pieces #because it is possible that the splitRecord is generated by structural #analysis in the future, so we seperate the score splitting code after all #recording are finished #record perfs and generate split file if len(score) == 0: #splitRecFilename= args.outputDir #splitRecFilename+= settings.getScoreName(args.scoreFilename)+'.split.json' splitRecFilename = settings.getSplitRecFilename(args.scoreFilename, args.outputDir) with open(splitRecFilename, 'w') as f: simplejson.dump(splitRecord, f, indent = 3) print('[INFO] splitting record saved to ' + splitRecFilename) return else: try: print("[INFO] Now playing score."), print("You can start to record anytime by pressing Ctrl+c") record.playStream(score); #provide stop button except KeyboardInterrupt: pass print("[INFO] =====Now recording phrase no." + str(counter) + "=====") #recLogFilename = settings.getRecLogFilename(args.scoreFilename +'.'+ str(counter)) #recLogFilename = args.outputDir + settings.getScoreName(args.scoreFilename) #recLogFilename += '.'+ str(counter) + '.log' recLogFilename = settings.getRecLogFilename(counter, args.scoreFilename, args.outputDir) settings.printDebug(recLogFilename) record.record(score, recLogFilename) perf = musicGenerator.generatePerf(score, recLogFilename) #outFilename= args.outputDir + settings.getScoreName(args.scoreFilename) #outFilename+= '.'+ str(counter) + '.perf' + settings.defaultOutputFormat outFilename = settings.getOutFilename(counter, args.scoreFilename, args.outputDir) musicGenerator.savePerf2File(perf, outFilename) scoreHead= score[:len(perf)] #if settings.DEBUG: # settings.printDebug('') # scoreHead.show('text') scoreTail= score[len(perf):] #if settings.DEBUG: #settings.printDebug('') #scoreTail.show('text') scoreHeadOffsets = [n.offset for n in scoreHead] splitRecord.append(scoreHeadOffsets) settings.printDebug(splitRecord) #splitRecord.extend(scoreHead) #capture mouse #pos = pygame.mouse.get_pos() #print("mouse position: "+pos) recordAll(scoreTail, args, splitRecord, counter+1)
def record(recLogFilename): period = 1; # in ms cmd = ['synclient', '-m' , str(period)]; settings.printDebug(cmd) key = 'r'; while (key != ''): with open(recLogFilename, 'w') as outfile: p = subprocess.Popen(cmd, stdout = outfile); key = raw_input('Press ENTER to continue, "r"-Enter to restart.'); settings.printDebug(key) p.kill();
def split(splitRecFilename, origScoreFilename, outputDir): with open(splitRecFilename, 'r') as f: splitRec = simplejson.load(f) origScore = music21.converter.parse(origScoreFilename) timeSigList = computeTimeSigList(origScore) settings.printDebug(timeSigList) #scoreElemsAll is all notational elements for each segments #e.g. [[timeSig1, key1], [timeSig2, key2]...] scoreElemsAll= zip(timeSigList) #may have key etc #for offsetSegment, scoreElems in zip(splitRec, scoreElemsAll): writeSegments(splitRec, scoreElemsAll, origScore, outputDir, origScoreFilename)
def savePerf2File(perf, outFilename): tempo = music21.tempo.MetronomeMark(number=120) onsetDuraObjs= [tempo.secondsToDuration(n['onset']) for n in perf] #for d in onsetDuraObjs: # settings.printDebug(d) onsets = [d.quarterLength for d in onsetDuraObjs ] durations= [tempo.secondsToDuration(n['duration']) for n in perf] velocities= [n['velocity'] for n in perf] pitches = [n['pitch'] for n in perf] outStream = music21.stream.Stream() for onset, duration, vel, pitch in zip(onsets, durations, velocities, pitches): note = music21.note.Note() note.duration = duration note.volume.velocity = vel note.pitch = pitch settings.printDebug(onset) settings.printDebug(note) outStream.insert(onset, note) settings.printDebug('') if settings.DEBUG: outStream.show('text') midifile = music21.midi.translate.streamToMidiFile(outStream) midifile.open(outFilename, 'wb') midifile.write() midifile.close() print('[INFO] Expressive performance wrote to ' + outFilename)
def record(score, recLogFilename): period = 1; # in ms print("[INFO] Remember to turn on SHMConfig for the touchpad. See README for detail.") cmd = ['synclient', '-m' , str(period)] settings.printDebug(cmd) p = subprocess.Popen(cmd, stdout = subprocess.PIPE) print('[INFO] Press Ctrl+c to cut off the current phrase.') noteIter = iter(score) recLogLines = ['time\t y\t z\t f\t w\t l\t r\t u\t d\t m\t multi\n'] prevFingerCount= 0 while True: try: line = p.stdout.readline() settings.printDebug(line), sys.stdout.flush() if len(line.split()) != 12: settings.printDebug('Not a data line format. Skipped.'), continue; (time, x, y, z, f, w, l, r, u, d, m, multi) = line.split(); fingerCount = int(f) if fingerCount > prevFingerCount: #Note on event settings.printDebug("Note ON") try: note = noteIter.next() except StopIteration: print('[ERROR]: Your recording is longer than the score. Force cut.') break #raise Exception('[ERROR]: Your recording is longer than the score. Stopped') t = threading.Thread(target=playNote, args=(note,)) t.start() #playNote(note) recLogLines.append(line) prevFingerCount = fingerCount except KeyboardInterrupt: print('[INFO] Current phrase is cut by user') break p.kill() with open(recLogFilename, 'w') as f: f.writelines(recLogLines)
def parseRecLog(filename): recLog = [] settings.printDebug(filename) with open(filename, 'r') as recLogFile: for line in recLogFile: #settings.printDebug(line.split()) #if len(line.split()) == 17: # (time, x, y, z, f, w, l, r, u, d, m, multi, gl, gm, gr, gdx, gdy) = line.split(); if len(line.split()) == 12: (time, x, y, z, f, w, l, r, u, d, m, multi) = line.split(); try: recLog.append({'time': float(time), 'pressure': int(z), 'fingerCount': int(f)}) except ValueError: settings.printDebug('Title line, skipped') pass else: settings.printDebug('Not a data line format in ' + filename + ". Skipped."); continue; return recLog
def generatePerf(score, recLogFilename): recLog = parseRecLog(recLogFilename) queue = deque() #enqueue from right, dequeue from left perf = [] noteIter = iter(score) for prevLine, thisLine in zip(recLog, recLog[1:]): if thisLine['fingerCount'] > prevLine['fingerCount']: try: note = noteIter.next() except StopIteration: raise Exception('[ERROR]: Your recording is longer than the score. Stopped') queue.append({'onset':thisLine['time'], 'velocity': thisLine['pressure'], 'pitch': note.pitch, 'duration': None }) settings.printDebug(queue) elif thisLine['fingerCount'] < prevLine['fingerCount']: note = queue.popleft() settings.printDebug(queue) note['duration'] = thisLine['time'] - note['onset'] perf.append(note) settings.printDebug(perf) return perf
def writeSegments(splitRec, scoreElemsAll, origScore, outputDir, scoreFilename, counter = 1): #score needs to be flat #see split for def of scoreElemsAll if len(splitRec) == 0: return splitRecHead = splitRec[0] splitRecTail = splitRec[1:] scoreElemsAllHead = scoreElemsAll[0] scoreElemsAllTail = scoreElemsAll[1:] minOffset = min(splitRecHead) maxOffset = max(splitRecHead) settings.printDebug(origScore) scoreSegment = (origScore.flat.getElementsByOffset(minOffset, maxOffset)) if settings.DEBUG: settings.printDebug('') scoreSegment.show('text') settings.printDebug(scoreSegment[0].offset) for scoreElem in scoreElemsAllHead: scoreSegment.insert(scoreSegment[0].offset, scoreElem) if settings.DEBUG: settings.printDebug('') scoreSegment.show('text') #settings.printDebug(scoreSegment.notes[0]) #settings.printDebug(scoreSegment.notes[0].beat) scoreSegment.shiftElements(-(scoreSegment.lowestOffset)) # segment no >2 need shift, or will have heading rests # If not start at first beat, insert rests # However, the "beat" is right but "offset" is not. # Inserting rest will increase readability. But may screw up beat startBeat = scoreSegment.notes[0].beat if startBeat > 1: # If not start at first beat, insert rests r = music21.note.Rest(quarterLength=(startBeat-1)) settings.printDebug(r.quarterLength) scoreSegment.insertAndShift(scoreSegment.notes[0].offset, r) if settings.DEBUG: settings.printDebug('') scoreSegment.show('text') scoreMeasures = scoreSegment.makeMeasures() #splittedScoreFilename = outputDir + scoreName #splittedScoreFilename += '.'+ str(counter) + '.score.xml' splittedScoreFilename = settings.getSplittedScoreFilename(counter, scoreFilename, outputDir) scoreMeasures.write(settings.defaultScoreFormatName, splittedScoreFilename) print('[INFO] Splitted score saved to ' + splittedScoreFilename) writeSegments(splitRecTail, scoreElemsAllTail, origScore, outputDir, scoreFilename, counter+1) return
for elem in sop.flat: if elem.isChord: tmpElem = elem[0] else: tmpElem = elem output.append(tmpElem) #settings.printDebug(os.path.dirname(scoreName)) #settings.printDebug(os.path.basename(scoreName)) #settings.printDebug(os.path.splitext(scoreName)) #settings.printDebug(os.path.split(scoreName)) #pathElems = os.path.split(scoreName)[:-1] if useCorpus: pieceName = scoreName else: pieceName = os.path.basename(scoreName) settings.printDebug(pieceName) pathWOtitle= os.path.splitext(pieceName)[0] workTitle = '.'.join(pathWOtitle.split('/')) #workTitle = os.path.splitext(os.path.basename(scoreName))[0] outFilename = outputDir + workTitle+ '.score.xml' output.write('musicxml', outFilename) print('[INFO] '+ outFilename + ' created.') #outFilename = outputDir + workTitle+ '.score.mid' #sop.write('midi', outFilename) #print('[INFO] '+ outFilename + ' created.') except (ValueError, AttributeError): print('[ERROR] '+ scoreName+ ' conversion FAILED.') pass