# HG changeset patch # User csong # Date 1428078396 -3600 # Node ID 4fb9c00e4ef005a54315186e437cf7a6c2ea0cc3 # Parent 6b6f8e3d72621e828902fbfe94328c2f72b5d560# Parent bc3b9022ebc4e02ee988736c9c5bc01770e7bdaf fixing merge problem diff -r bc3b9022ebc4 -r 4fb9c00e4ef0 Syncopation models/basic_functions.py.orig --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Syncopation models/basic_functions.py.orig Fri Apr 03 17:26:36 2015 +0100 @@ -0,0 +1,182 @@ +# This python file is a collection of basic functions that are used in the syncopation models. + +import math + +# The concatenation function is used to concatenate two sequences. +def concatenate(seq1,seq2): + return seq1+seq2 + +# The repetition function is to concatenate a sequence to itself for 'times' number of times. +def repeat(seq,times): + new_seq = list(seq) + if times >= 1: + for i in range(times-1): + new_seq = concatenate(new_seq,seq) + else: + #print 'Error: repetition times needs to be no less than 1.' + new_seq = [] + return new_seq + +# The subdivision function is to equally subdivide a sequence into 'divisor' number of segments. +def subdivide(seq,divisor): + subSeq = [] + if len(seq) % divisor != 0: + print 'Error: rhythmic sequence cannot be equally subdivided.' + else: + n = len(seq) / divisor + start , end = 0, n + for i in range(divisor): + subSeq.append(seq[start : end]) + start = end + end = end + n + return subSeq + + +# The ceiling function is to round each number inside a sequence up to its nearest integer. +def ceiling(seq): + seq_ceil = [] + for s in seq: + seq_ceil.append(int(math.ceil(s))) + return seq_ceil + +# The find_divisor function returns a list of all possible divisors for a length of sequence. +def find_divisor(number): + divisors = [1] + for i in range(2,number+1): + if number%i ==0: + divisors.append(i) + return divisors + +# The find_divisor function returns a list of all possible divisors for a length of sequence. +def find_prime_factors(number): + prime_factors = find_divisor(number) + + def is_prime(num): + if num < 2: + return False + if num == 2: + return True + else: + for div in range(2,num): + if num % div == 0: + return False + return True + + for i in range(len(prime_factors)-1,0,-1): + if is_prime(prime_factors[i]) == False: + del prime_factors[i] + + return prime_factors + +# The min_timeSpan function searches for the shortest possible time-span representation for a sequence. +def get_min_timeSpan(seq): + min_ts = [1] + for d in find_divisor(len(seq)): + segments = subdivide(seq,d) + if len(segments)!=0: + del min_ts[:] + for s in segments: + min_ts.append(s[0]) + if sum(min_ts) == sum(seq): + break + return min_ts + +# get_note_indices returns all the indices of all the notes in this sequence +def get_note_indices(seq): + note_indices = [] + + for index in range(len(seq)): + if seq[index] != 0: + note_indices.append(index) + + return note_indices + +# The get_H returns a sequence of metrical weight for a certain metrical level (horizontal), +# given the sequence of metrical weights in a hierarchy (vertical) and a sequence of subdivisions. +def get_H(weight_seq,subdivision_seq, level): + H = [] + #print len(weight_seq), len(subdivision_seq), level + if (level <= len(subdivision_seq)-1) & (level <= len(weight_seq)-1): + if level == 0: + H = repeat([weight_seq[0]],subdivision_seq[0]) + else: + H_pre = get_H(weight_seq,subdivision_seq,level-1) + for h in H_pre: + H = concatenate(H, concatenate([h], repeat([weight_seq[level]],subdivision_seq[level]-1))) + else: + print 'Error: a subdivision factor or metrical weight is not defined for the request metrical level.' + return H + +# The get_subdivision_seq function returns the subdivision sequence of several common time-signatures defined by GTTM, +# or ask for the top three level of subdivision_seq manually set by the user. +def get_subdivision_seq(timesig, L_max): + subdivision_seq = [] + + if timesig == '2/4' or timesig == '4/4': + subdivision_seq = [1,2,2] + elif timesig == '3/4' or timesig == '3/8': + subdivision_seq = [1,3,2] + elif timesig == '6/8': + subdivision_seq = [1,2,3] + elif timesig == '9/8': + subdivision_seq = [1,3,3] + elif timesig == '12/8': + subdivision_seq = [1,4,3] + elif timesig == '5/4' or timesig == '5/8': + subdivision_seq = [1,5,2] + elif timesig == '7/4' or timesig == '7/8': + subdivision_seq = [1,7,2] + elif timesig == '11/4' or timesig == '11/8': + subdivision_seq = [1,11,2] + else: + print 'Time-signature',timesig,'is undefined. Please indicate subdivision sequence for this requested time-signature, e.g. [1,2,2] for 4/4 meter.' + for i in range(3): + s = int(input('Enter the subdivision factor at metrical level '+str(i)+':')) + subdivision_seq.append(s) + + if L_max > 2: + subdivision_seq = subdivision_seq + [2]*(L_max-2) + else: + subdivision_seq = subdivision_seq[0:L_max+1] + + return subdivision_seq + + +def get_rhythm_category(velocitySequence, subdivisionSequence): + ''' + The get_rhythm_category function is used to detect rhythm category: monorhythm or polyrhythm. + For monorhythms, all prime factors of the length of minimum time-span representation of this sequence are + elements of its subdivision_seq, otherwise it is polyrhythm; + e.g. prime_factors of polyrhythm 100100101010 in 4/4 is [2,3] but subdivision_seq = [1,2,2] for 4/4 + ''' + rhythmCategory = 'mono' + for f in find_prime_factors(len(get_min_timeSpan(velocitySequence))): + if not (f in subdivisionSequence): + rhythmCategory = 'poly' + break + return rhythmCategory + +def string_to_sequence(inputString): + return map(int, inputString.split(',')) + + + # The split_by_bar function seperates the score representation of rhythm by bar lines, + # resulting in a list representingbar-by-bar rhythm sequence, + # e.g. rhythm = ['|',[ts1,td1,v1], [ts2,td2,v2], '|',[ts3,td3,v3],'|'...] + # rhythm_bybar = [ [ [ts1,td1,v1], [ts2,td2,v2] ], [ [ts3,td3,v3] ], [...]] +# def split_by_bar(rhythm): +# rhythm_bybar = [] +# bar_index = [] +# for index in range(len(rhythm)): +# if rhythm[index] == '|': + +# return rhythm_bybar + +# def yseq_to_vseq(yseq): +# vseq = [] + +# return vseq + + +# # testing +# print find_prime_factors(10) \ No newline at end of file diff -r bc3b9022ebc4 -r 4fb9c00e4ef0 Syncopation models/music_objects.py.orig --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Syncopation models/music_objects.py.orig Fri Apr 03 17:26:36 2015 +0100 @@ -0,0 +1,107 @@ + +from basic_functions import ceiling, string_to_sequence + +import parameter_setter +import rhythm_parser + +class Note(): + def __init__(self, argstring): + intlist = string_to_sequence(argstring) + self.startTime = intlist[0] + self.duration = intlist[1] + self.velocity = intlist[2] + + # toString() + +# NoteSequence is a list of Note +class NoteSequence(list): + def __init__(self, noteSequenceString=None): + if noteSequenceString!=None: + self.string_to_note_sequence(noteSequenceString) + + def string_to_note_sequence(self, noteSequenceString): + noteSequenceString = rhythm_parser.discardSpaces(noteSequenceString) + # try: + # Turning "(1,2,3),(4,5,6),(7,8,9)" into ["1,2,3","4,5,6,","7,8,9"] + listStrings = noteSequenceString[1:-1].split("),(") + for localString in listStrings: + self.append(Note(localString)) + + # toString() + + +#print NoteSequence("(1,2,3),(4,5,6),(7,8,9)") +class VelocitySequence(list): + def __init__(self, noteSequenceString=None): + if noteSequenceString!=None: + self.string_to_note_sequence(noteSequenceString) + + def string_to_note_sequence(self,inputString): + self.extend(string_to_sequence(inputString)) + + +class BarList(list): + def append(self,bar): + if(len(self)>0): + bar.set_previous_bar(self[-1]) + self[-1].set_next_bar(bar) + super(BarList, self).append(bar) + + + + + +class Bar: + + def __init__(self, rhythmSequence, timeSignature, ticksPerQuarter=None, qpmTempo=None, nextBar=None, prevBar=None): + if isinstance(rhythmSequence, NoteSequence): + self.noteSequence = rhythmSequence + self.velocitySequence = None + elif isinstance(rhythmSequence, VelocitySequence): + self.velocitySequence = rhythmSequence + self.noteSequence = None + + self.tpq = ticksPerQuarter + self.qpm = qpmTempo + self.timeSignature = timeSignature + self.nextBar = nextBar + self.prevBar = prevBar + + def get_note_sequence(self): + #if self.noteSequence==None: + # self.noteSequence = velocity_sequence_to_notes(self.velocitySequence) + return self.noteSequence + + def get_velocity_sequence(self): + if self.velocitySequence==None: + self.velocitySequence = note_sequence_to_velocities(self.velocitySequence) + return self.velocitySequence + + def get_binary_sequence(self): + return ceiling(self.get_velocity_sequence()) + + def get_next_bar(self): + return self.nextBar + + def get_previous_bar(self): + return self.prevBar + + def set_next_bar(self, bar): + self.nextBar = bar + + def set_previous_bar(self, bar): + self.prevBar = bar + + def get_subdivision_sequence(self): + return ParameterSetter.get_subdivision_seq(self.timeSignature) + + def get_beat_level(self): + return ParameterSetter.get_beat_level(self.timeSignature) + + def get_time_signature(self): + return self.timeSignature + + def get_t_span(self): + # return the length of a bar in time units + return None # NEED TO IMPLEMENT + diff -r bc3b9022ebc4 -r 4fb9c00e4ef0 Syncopation models/readmidi.py --- a/Syncopation models/readmidi.py Fri Apr 03 17:05:31 2015 +0100 +++ b/Syncopation models/readmidi.py Fri Apr 03 17:26:36 2015 +0100 @@ -8,13 +8,13 @@ from midiparser import MidiFile, MidiTrack, DeltaTime, MidiEvent #from RhythmParser import Bar -from MusicObjects import * +from music_objects import * -def readMidiFile(filename): +def read_midi_file(filename): """ open and read a MIDI file, return a MidiFile object """ #create a midifile object, open and read a midi file @@ -25,26 +25,28 @@ return midiFile -def getBars(midiFile, trackindex=1): +# def get_bars(midiFile, trackindex=1): +# """ returns a list of bar objects from a MidiFile object """ - track = midiFile.tracks[trackindex] # ignore dummy track 0 - eventIdx = 0 - numNotes = 0 +# # select a track to extract (default = 1, ignoring dummy track 0) +# track = midiFile.tracks[trackindex] +# eventIndex = 0 +# numNotes = 0 - noteonlist = [] - noteOnFound==True +# noteonlist = [] +# noteOnFound==True - while noteOnFound==True: - (noteOnIdx, noteOnDelta, noteOnFound) = self.findEvent(track, eventIdx, lambda e: e.type == 'NOTE_ON') - noteEvent = track.events[noteOnIdx] - eventIdx = noteOnIdx + 1 +# while noteOnFound==True: +# (noteOnIndex, noteOnDelta, noteOnFound) = self.find_event(track, eventIndex, lambda e: e.type == 'NOTE_ON') +# noteEvent = track.events[noteOnIndex] +# eventIndex = noteOnIndex + 1 -def findEvent(track, eventStartIdx, lambdaExpr): +def find_event(track, eventStartIndex, lambdaExpr): ''' From code by Csaba Sulyok: Finds MIDI event based on lambda expression, starting from a given index. @@ -54,14 +56,14 @@ 3. flag whether or not any value was found, or we've reached the end of the event queue ''' - eventIdx = eventStartIdx + eventIndex = eventStartIndex deltaTime = 0 - while eventIdx < len(track.events) and not lambdaExpr(track.events[eventIdx]): - if track.events[eventIdx].type == 'DeltaTime': - deltaTime += track.events[eventIdx].time - eventIdx += 1 + while eventIndex < len(track.events) and not lambdaExpr(track.events[eventIndex]): + if track.events[eventIndex].type == 'DeltaTime': + deltaTime += track.events[eventIndex].time + eventIndex += 1 - success = eventIdx < len(track.events) - return (eventIdx, deltaTime, success) + success = eventIndex < len(track.events) + return (eventIndex, deltaTime, success) diff -r bc3b9022ebc4 -r 4fb9c00e4ef0 Syncopation models/syncopation.py --- a/Syncopation models/syncopation.py Fri Apr 03 17:05:31 2015 +0100 +++ b/Syncopation models/syncopation.py Fri Apr 03 17:26:36 2015 +0100 @@ -16,19 +16,23 @@ else: while subdivision_seq == None: - from BasicFuncs import get_subdivision_seq + from basic_functions import get_subdivision_seq subdivision_seq = get_subdivision_seq(timesig, L_max) - # def get_rhythm_category(): - # rhythm_category = 'mono' - # from BasicFuncs import get_min_timeSpan, find_prime_factors - # for f in find_prime_factors(len(get_min_timeSpan(seq))): - # if not (f in subdivision_seq): - # rhythm_category = 'poly' - # break - # return rhythm_category + # The get_rhythm_category function is used to detect rhythm category: monorhythm or polyrhythm. + # For monorhythms, all prime factors of the length of minimum time-span representation of this sequence are + # elements of its subdivision_seq, otherwise it is polyrhythm; + # e.g. prime_factors of polyrhythm 100100101010 in 4/4 is [2,3] but subdivision_seq = [1,2,2] for 4/4 + def get_rhythm_category(): + rhythm_category = 'mono' + from basic_functions import get_min_timeSpan, find_prime_factors + for f in find_prime_factors(len(get_min_timeSpan(seq))): + if not (f in subdivision_seq): + rhythm_category = 'poly' + break + return rhythm_category - # rhythm_category = get_rhythm_category() + rhythm_category = get_rhythm_category() if model == 'LHL': import LHL diff -r bc3b9022ebc4 -r 4fb9c00e4ef0 Syncopation models/syncopation.py.orig --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Syncopation models/syncopation.py.orig Fri Apr 03 17:26:36 2015 +0100 @@ -0,0 +1,103 @@ +''' +Author: Chunyang Song +Institution: Centre for Digital Music, Queen Mary University of London + +''' + + +def sync_perbar_permodel(seq, model, timesig = None, subdivision_seq = None, weight_seq = None, L_max = 5, prebar_seq = None, postbar_seq = None, strong_beat_level = None): + syncopation = None + + if seq == None or model == None: + print 'Error: please indicate rhythm sequence and syncopation model.' + + elif timesig == None and subdivision_seq == None: + print 'Error: please indicate either time signature or subdivision sequence.' + + else: + while subdivision_seq == None: + from basic_functions import get_subdivision_seq + subdivision_seq = get_subdivision_seq(timesig, L_max) + + # The get_rhythm_category function is used to detect rhythm category: monorhythm or polyrhythm. + # For monorhythms, all prime factors of the length of minimum time-span representation of this sequence are + # elements of its subdivision_seq, otherwise it is polyrhythm; + # e.g. prime_factors of polyrhythm 100100101010 in 4/4 is [2,3] but subdivision_seq = [1,2,2] for 4/4 + def get_rhythm_category(): + rhythm_category = 'mono' + from basic_functions import get_min_timeSpan, find_prime_factors + for f in find_prime_factors(len(get_min_timeSpan(seq))): + if not (f in subdivision_seq): + rhythm_category = 'poly' + break + return rhythm_category + + rhythm_category = get_rhythm_category() + + if model == 'LHL': + import LHL + if weight_seq == None: + weight_seq = range(0,-L_max,-1) + syncopation = LHL.get_syncopation(seq, subdivision_seq, weight_seq, prebar_seq, rhythm_category) + elif model == 'PRS': + import PRS + syncopation = PRS.get_syncopation(seq, subdivision_seq, postbar_seq, rhythm_category) + elif model == 'TMC': + import TMC + if weight_seq == None: + weight_seq = range(L_max+1,0,-1) + syncopation = TMC.get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category) + elif model == 'SG': + import SG + if weight_seq == None: + weight_seq = range(L_max+1) + syncopation = SG.get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category) + elif model == 'KTH': + import KTH + syncopation = KTH.get_syncopation(seq, timesig, postbar_seq) + elif model == 'TOB': + import TOB + syncopation = TOB.get_syncopation(seq) + elif model == 'WNBD': + import WNBD + if strong_beat_level == None: + if timesig == '4/4': + strong_beat_level = 2 + else: + strong_beat_level = 1 + syncopation = WNBD.get_syncopation(seq, subdivision_seq, strong_beat_level, postbar_seq) + + else: + print 'Error: undefined syncopation model.' + + return syncopation + +# def syncopation_all(rhythm, model, timesig, subdivision_seq = None, weight_seq = None, L_max = 5, strong_beat_level = None): +# syncopation = 0 +# # Chope rhythm into seq +# # ... + +# for (seq_perbar in seq): +# sync_perbar = syncopation_perbar(seq_perbar,model, timesig, subdivision_seq, weight_seq, L_max, strong_beat_level) +# if sync_perbar != None: +# syncopation = syncopation + sync_perbar + +# return syncopation + + +### TESTING +# clave = [1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0] +# bf = [0,0,0,1,0,0,0,0,0,0,1,0] +# rhythm = [0,1,0,1,0,1,0,1] +# classic1 = [1,0,1,1]*3 + [1,0,0,0] +# classic2 = [1,0,0,1]*3 + [1,0,0,0] +# shiko = [1,0,1,1,0,1,1,0] +# rumba = [1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0] +# soukous = [1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0] +# gahu = [1,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0] +# bossanova = [1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0] + +# classic12 = [1,0,0,1,1,1,1,0,0,1,1,1] +# soli = [1,0,1,0,1,0,1,0,1,1,0,1] + +# print sync_perbar(seq = clave, model = 'WNBD', timesig = '4/4') diff -r bc3b9022ebc4 -r 4fb9c00e4ef0 Syncopation models/syncopation.py.resolve --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Syncopation models/syncopation.py.resolve Fri Apr 03 17:26:36 2015 +0100 @@ -0,0 +1,103 @@ +''' +Author: Chunyang Song +Institution: Centre for Digital Music, Queen Mary University of London + +''' + + +def sync_perbar_permodel(seq, model, timesig = None, subdivision_seq = None, weight_seq = None, L_max = 5, prebar_seq = None, postbar_seq = None, strong_beat_level = None): + syncopation = None + + if seq == None or model == None: + print 'Error: please indicate rhythm sequence and syncopation model.' + + elif timesig == None and subdivision_seq == None: + print 'Error: please indicate either time signature or subdivision sequence.' + + else: + while subdivision_seq == None: + from basic_functions import get_subdivision_seq + subdivision_seq = get_subdivision_seq(timesig, L_max) + + # The get_rhythm_category function is used to detect rhythm category: monorhythm or polyrhythm. + # For monorhythms, all prime factors of the length of minimum time-span representation of this sequence are + # elements of its subdivision_seq, otherwise it is polyrhythm; + # e.g. prime_factors of polyrhythm 100100101010 in 4/4 is [2,3] but subdivision_seq = [1,2,2] for 4/4 + def get_rhythm_category(): + rhythm_category = 'mono' + from basic_functions import get_min_timeSpan, find_prime_factors + for f in find_prime_factors(len(get_min_timeSpan(seq))): + if not (f in subdivision_seq): + rhythm_category = 'poly' + break + return rhythm_category + + rhythm_category = get_rhythm_category() + + if model == 'LHL': + import LHL + if weight_seq == None: + weight_seq = range(0,-L_max,-1) + syncopation = LHL.get_syncopation(seq, subdivision_seq, weight_seq, prebar_seq, rhythm_category) + elif model == 'PRS': + import PRS + syncopation = PRS.get_syncopation(seq, subdivision_seq, postbar_seq, rhythm_category) + elif model == 'TMC': + import TMC + if weight_seq == None: + weight_seq = range(L_max+1,0,-1) + syncopation = TMC.get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category) + elif model == 'SG': + import SG + if weight_seq == None: + weight_seq = range(L_max+1) + syncopation = SG.get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category) + elif model == 'KTH': + import KTH + syncopation = KTH.get_syncopation(seq, timesig, postbar_seq) + elif model == 'TOB': + import TOB + syncopation = TOB.get_syncopation(seq) + elif model == 'WNBD': + import WNBD + if strong_beat_level == None: + if timesig == '4/4': + strong_beat_level = 2 + else: + strong_beat_level = 1 + syncopation = WNBD.get_syncopation(seq, subdivision_seq, strong_beat_level, postbar_seq) + + else: + print 'Error: undefined syncopation model.' + + return syncopation + +# def syncopation_all(rhythm, model, timesig, subdivision_seq = None, weight_seq = None, L_max = 5, strong_beat_level = None): +# syncopation = 0 +# # Chope rhythm into seq +# # ... + +# for (seq_perbar in seq): +# sync_perbar = syncopation_perbar(seq_perbar,model, timesig, subdivision_seq, weight_seq, L_max, strong_beat_level) +# if sync_perbar != None: +# syncopation = syncopation + sync_perbar + +# return syncopation + + +### TESTING +# clave = [1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0] +# bf = [0,0,0,1,0,0,0,0,0,0,1,0] +# rhythm = [0,1,0,1,0,1,0,1] +# classic1 = [1,0,1,1]*3 + [1,0,0,0] +# classic2 = [1,0,0,1]*3 + [1,0,0,0] +# shiko = [1,0,1,1,0,1,1,0] +# rumba = [1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0] +# soukous = [1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0] +# gahu = [1,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0] +# bossanova = [1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0] + +# classic12 = [1,0,0,1,1,1,1,0,0,1,1,1] +# soli = [1,0,1,0,1,0,1,0,1,1,0,1] + +# print sync_perbar(seq = clave, model = 'WNBD', timesig = '4/4') diff -r bc3b9022ebc4 -r 4fb9c00e4ef0 Syncopation models/test.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Syncopation models/test.py Fri Apr 03 17:26:36 2015 +0100 @@ -0,0 +1,1 @@ +