christopher@45: ''' christopher@45: Author: Chunyang Song christopher@45: Institution: Centre for Digital Music, Queen Mary University of London christopher@45: christopher@45: ''' christopher@45: from rhythm_parser import * christopher@45: from music_objects import * christopher@45: christopher@45: christopher@45: def sync_perbar_permodel (model, bar, parameters=None): christopher@45: return model.get_syncopation(bar, parameters) christopher@45: christopher@75: def calculate_syncopation(model, source, parameters=None, outfile=None, barRange=None): christopher@45: total = 0.0 christopher@45: barResults = [] christopher@45: numberOfNotes = 0 christopher@45: christopher@45: barlist = None christopher@45: christopher@45: if isinstance(source, BarList): christopher@45: barlist = source christopher@45: sourceType = "bar list" christopher@45: elif isinstance(source, Bar): christopher@50: barlist = BarList() christopher@50: barlist.append(source) christopher@50: print barlist christopher@45: sourceType = "single bar" christopher@45: elif isinstance(source, basestring): christopher@45: #treat source as a filename christopher@45: sourceType = source christopher@45: if source[-4:]==".mid": christopher@45: import readmidi christopher@45: midiFile = readmidi.read_midi_file(source) christopher@45: barlist = readmidi.get_bars_from_midi(midiFile) christopher@45: christopher@45: elif source[-4:]==".rhy": christopher@45: #import rhythm_parser christopher@45: barlist = read_rhythm(source) christopher@45: else: christopher@45: print "Error in syncopation_barlist_permodel(): Unrecognised file type." christopher@45: else: christopher@45: print "Error in syncopation_barlist_permodel(): unrecognised source type." christopher@45: christopher@45: barsDiscarded=0 christopher@45: discardedlist = [] christopher@45: includedlist = [] christopher@45: christopher@50: christopher@45: if barlist!=None: christopher@75: christopher@75: if barRange==None: christopher@75: barstart=0 christopher@75: barend=len(barlist) christopher@75: else: christopher@75: barstart = barRange[0] christopher@75: barend = barRange[1] christopher@75: christopher@75: christopher@75: for bar in barlist[barstart:barend]: christopher@50: print 'processing bar %d' % (barlist.index(bar)+1) christopher@50: christopher@50: barSyncopation = sync_perbar_permodel(model, bar, parameters) christopher@50: christopher@50: christopher@50: # if not bar.is_empty(): christopher@50: # barSyncopation = sync_perbar_permodel(model, bar, parameters) christopher@50: # else: christopher@50: # barSyncopation = None christopher@50: # print 'Bar %d cannot be measured because it is empty, returning None.' % barlist.index(bar) christopher@45: christopher@45: barResults.append(barSyncopation) christopher@45: if barSyncopation != None: christopher@45: total += barSyncopation christopher@45: numberOfNotes += sum(bar.get_binary_sequence()) christopher@45: includedlist.append(barlist.index(bar)) christopher@45: else: christopher@45: barsDiscarded += 1 christopher@45: discardedlist.append(barlist.index(bar)) christopher@50: print 'Model could not measure bar %d, returning None.' % (barlist.index(bar)+1) christopher@45: christopher@45: import WNBD christopher@45: if model is WNBD: christopher@45: total = total / numberOfNotes christopher@75: christopher@50: if len(barResults)>barsDiscarded: christopher@50: average = total / (len(barResults)-barsDiscarded) christopher@50: else: christopher@50: average = total christopher@45: christopher@45: output = { christopher@45: "model_name":model.__name__ , christopher@45: "summed_syncopation":total, christopher@45: "mean_syncopation_per_bar":average, christopher@45: "source":sourceType, christopher@45: "number_of_bars":len(barResults), christopher@45: "number_of_bars_not_measured":barsDiscarded, christopher@45: "bars_with_valid_output":includedlist, christopher@50: "bars_without_valid_output":discardedlist, christopher@45: "syncopation_by_bar":barResults christopher@45: } christopher@45: christopher@45: if outfile!=None: christopher@45: christopher@45: if ".xml" in outfile: christopher@45: results_to_xml(output,outfile) christopher@45: elif ".json" in outfile: christopher@45: results_to_json(output,outfile) christopher@45: else: christopher@45: print "Error in syncopation.py: Unrecognised output file type: ", outfile christopher@45: christopher@45: return output christopher@45: christopher@45: christopher@45: christopher@45: def results_to_xml(results, outputFilename): christopher@45: from xml.etree.ElementTree import Element, ElementTree christopher@45: christopher@45: elem = Element("syncopation_results") christopher@45: christopher@45: for key, val in results.items(): christopher@45: child = Element(key) christopher@45: child.text = str(val) christopher@45: elem.append(child) christopher@45: christopher@45: ElementTree(elem).write(outputFilename) christopher@45: christopher@45: def results_to_json(results, outputFilename): christopher@45: import json christopher@45: christopher@45: fileHandle = open(outputFilename, 'w') christopher@45: json.dump(results, fileHandle, sort_keys=True, indent=4, separators=(',', ': ')) christopher@45: fileHandle.flush() christopher@45: