Mercurial > hg > syncopation-dataset
changeset 9:c2843ef4de2c
changing filenames to Python conventions
author | csong |
---|---|
date | Fri, 03 Apr 2015 11:41:01 +0100 |
parents | 2c5df6a4a22f |
children | a3ed7d2b57d8 4acddc008048 |
files | Syncopation models/BasicFuncs.py Syncopation models/MusicObjects.py Syncopation models/ParameterSetter.py Syncopation models/RhythmParser.py Syncopation models/basic_functions.py Syncopation models/main.py Syncopation models/music_objects.py Syncopation models/parameter_setter.py Syncopation models/rhythm_parser.py Syncopation models/syncopation.py |
diffstat | 10 files changed, 576 insertions(+), 566 deletions(-) [+] |
line wrap: on
line diff
--- a/Syncopation models/BasicFuncs.py Thu Apr 02 00:06:57 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -# 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 - - # 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
--- a/Syncopation models/MusicObjects.py Thu Apr 02 00:06:57 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ - -from BasicFuncs import ceiling - -import ParameterSetter -import RhythmParser - -class Note(): - def __init__(self, argstring): - intlist = map(int,argstring.split(',')) - 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 = RhythmParser.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(string): - - -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 = velocitySequenceToNotes(self.velocitySequence) - return self.noteSequence - - def get_velocity_sequence(self): - if self.velocitySequence==None: - self.velocitySequence = noteSequenceToVelocities(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 -
--- a/Syncopation models/ParameterSetter.py Thu Apr 02 00:06:57 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -''' -Author: Chunyang Song -Institution: Centre for Digital Music, Queen Mary University of London -''' - -# Set the parameters: subdivision_seq, weight_seq, L_max, strong_beat_level - -L_max = 5 - -# {'key': time-signature} : -# {'value': [subdivision_seq, theoretical beat-level represented by index in the subdivision_seq list]} -timesigBase = { - '2/2': [[1,2,2,2,2],1], - '3/2': [[1,3,2,2,2],1], - '4/2': [[1,2,2,2,2],1], - '2/4': [[1,2,2,2,2],1], - '3/4': [[1,3,2,2,2],1], - '4/4': [[1,2,2,2,2],2], - '5/4': [[1,5,2,2,2],1], - '7/4': [[1,7,2,2,2],1], - '3/8': [[1,3,2,2,2],1], - '5/8': [[1,5,2,2,2],1], - '6/8': [[1,2,3,2,2],1], - '9/8': [[1,3,3,2,2],1], - '12/8':[[1,2,2,3,2],2], -} - - -def addTimesig(timesig, subdivision_seq, beat_level): - if isTSValid(timesig,subdivision_seq,beat_level): - if timesig in timesigBase: - print 'This time-signature is existed already.' - else: - timesigBase[timesig] = [subdivision_seq, beat_level] - writeTimesig() - -def updateTimesig(timesig, subdivision_seq, beat_level): - if isTSValid(timesig,subdivision_seq,beat_level): - if timesig in timesigBase: - print 'Original settings for', timesig, ':',timesigBase[timesig] - timesigBase[timesig] = [subdivision_seq, beat_level] - print 'Changed into:',timesigBase[timesig] - writeTimesig() - -def isTSValid(timesig, subdivision_seq, beat_level): - isValid = False - if ('/' not in timesig) or (not timesig.split('/')[0].isdigit()) or (not timesig.split('/')[1].isdigit()): - print 'Error: invalid time-signature. Please indicate in the form of fraction, e.g. 4/4, 6/8 or 3/4.' - elif subdivision_seq != [s for s in subdivision_seq if isinstance(s,int)]: - print 'Error: invalid subdivision sequence. Please indicate in the form of list of numbers, e.g [1,2,2,2,2].' - elif beat_level >= len(subdivision_seq): - print 'Error: beat-level exceeds the range of subdivision sequence list.' - else: - isValid = True - return isValid - -def writeTimesig(): - import cPickle as pickle - timesigFile = open('TimeSignature.pkl', 'wb') - pickle.dump(timesigBase, timesigFile) - timesigFile.close() - -def readTimesig(): - import cPickle as pickle - timesigFile = open('TimeSignature.pkl','rb') - data = pickle.load(timesigFile) - return data - timesigFile.close() - -def viewTimesigBase(): - data = readTimesig() - for timesig, settings in data.items(): - print timesig, settings - -def set_L_max(number): - L_max = number - -def get_subdivision_seq(timesig): - if timesig in readTimesig(): - return timesigBase[timesig][0] - else: - print 'Error: the subdivision sequence for this time-signature is not defined.' - return None - -def get_beat_level(timesig): - if timesig in readTimesig(): - return timesigBase[timesig][1] - else: - print 'Error: the subdivision sequence for this time-signature is not defined.' - return None
--- a/Syncopation models/RhythmParser.py Thu Apr 02 00:06:57 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -''' -Author: Chunyang Song -Institution: Centre for Digital Music, Queen Mary University of London -''' - -# Parse the rhythm file and return a list of Bar objects -Piece = [] - -from ParameterSetter import timesigBase - - -comment_sign = '#' -def discardComments(line): - if comment_sign in line: - line = line[0:line.find(comment_sign)] - return line - -def discardSpaces(line): - line = line.replace(" ", '').replace("\t", '') - return line - -def extractInfo(line): - try: - if '{' not in line and '}' not in line: - raise RhythmSyntaxError(line) - else: - return line[line.find('{')+1 : line.find('}')] - except RhythmSyntaxError: - print 'Rhythmic information needs to be enclosed by "{" and "}"' - - -current_timesig = '' -current_timesigValue = [] -def process(line): - try: - if 't' in line: - current_timesig = extractInfo(line) - if current_timesig in timesigBase: - current_timesigValue = timesigBase[current_timesig] - else: - raise NoTimesigError(current_timesig) - - elif 'v' in line: - if current_timesig == '': - raise InitialTimesigError(line) - else: - rhythmString = extractInfo(line) - rhythm_seq = map(int,rhythmString.split(',')) - Piece.append(Bar(rhythm_seq, current_timesigValue[0], current_timesigValue[1])) - - else: - raise SymbolError(line) - - except InitialTimesigError: - print 'The initial time-signature is not given.' - except NoTimesigError: - print 'The time-signature is not recognised.' - except SymbolError: - print 'Unrecognised symbol.' - - -def readRhythm(fileName): - try: - f = file(fileName) - - # Clean up each line by discarding comments and spaces; extract time-signature or sequence information - isfinished = False - while(not isfinished): - line = f.readline() - if len(line) == 0: - isfinished = True - else: - cleanline = discardSpaces(discardComments(line)) - process(cleanline) - - # Extract time-signature and rhythm sequence information - - except IOError as e: - print "I/O error({0}): {1}".format(e.errno, e.strerror) - except: - print 'Unexpected error.'#, sys.exc_info()[0] - -# To check the -def isInfoValid(info): - # If two parts of information is not seperated by ; - # if 't' in info and 'q' in info: - # print 'Error: time-signature and rhythm sequence needs ";" to seperate. Please check this rhythm file: %s.' %fileName - # Piece = None - # break - # elif '{' not in info and '}' not in info: - # print 'Error: information needs to be enclosed by "{ }". Please check this rhythm file: %s.' %fileName - # Piece = None - # break - # else: - return True - -# To check whether the given time-signature is existed; if not then requires user to add in the new time-signature -#def checkTimesig(input): - - -# TESTING -line = 't{4/4} q{1,0,0,1,0,0,1,0,0,0,1,0,0.8,0,0,0} t{2/4} # This is a comment' -# print discardSpaces(discardComments(line)) -print line[line.find('{')+1:line.find('}')] -#print readRhythm("rhythmbase/testrhythm.txt") -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Syncopation models/basic_functions.py Fri Apr 03 11:41:01 2015 +0100 @@ -0,0 +1,173 @@ +# 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(sequence, subdivision_seq): + rhythm_category = 'mono' + for f in find_prime_factors(len(get_min_timeSpan(sequence))): + if not (f in subdivision_seq): + rhythm_category = 'poly' + break + return rhythm_category + + + # 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
--- a/Syncopation models/main.py Thu Apr 02 00:06:57 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -''' -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 BasicFuncs 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 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 - - 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')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Syncopation models/music_objects.py Fri Apr 03 11:41:01 2015 +0100 @@ -0,0 +1,104 @@ + +from BasicFuncs import ceiling + +import ParameterSetter +import RhythmParser + +class Note(): + def __init__(self, argstring): + intlist = map(int,argstring.split(',')) + 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 = RhythmParser.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(string): + + +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 = velocitySequenceToNotes(self.velocitySequence) + return self.noteSequence + + def get_velocity_sequence(self): + if self.velocitySequence==None: + self.velocitySequence = noteSequenceToVelocities(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 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Syncopation models/parameter_setter.py Fri Apr 03 11:41:01 2015 +0100 @@ -0,0 +1,90 @@ +''' +Author: Chunyang Song +Institution: Centre for Digital Music, Queen Mary University of London +''' + +# Set the parameters: subdivision_seq, weight_seq, L_max, strong_beat_level + +L_max = 5 + +# {'key': time-signature} : +# {'value': [subdivision_seq, theoretical beat-level represented by index in the subdivision_seq list]} +timesigBase = { + '2/2': [[1,2,2,2,2],1], + '3/2': [[1,3,2,2,2],1], + '4/2': [[1,2,2,2,2],1], + '2/4': [[1,2,2,2,2],1], + '3/4': [[1,3,2,2,2],1], + '4/4': [[1,2,2,2,2],2], + '5/4': [[1,5,2,2,2],1], + '7/4': [[1,7,2,2,2],1], + '3/8': [[1,3,2,2,2],1], + '5/8': [[1,5,2,2,2],1], + '6/8': [[1,2,3,2,2],1], + '9/8': [[1,3,3,2,2],1], + '12/8':[[1,2,2,3,2],2], +} + + +def addTimesig(timesig, subdivision_seq, beat_level): + if isTSValid(timesig,subdivision_seq,beat_level): + if timesig in timesigBase: + print 'This time-signature is existed already.' + else: + timesigBase[timesig] = [subdivision_seq, beat_level] + writeTimesig() + +def updateTimesig(timesig, subdivision_seq, beat_level): + if isTSValid(timesig,subdivision_seq,beat_level): + if timesig in timesigBase: + print 'Original settings for', timesig, ':',timesigBase[timesig] + timesigBase[timesig] = [subdivision_seq, beat_level] + print 'Changed into:',timesigBase[timesig] + writeTimesig() + +def isTSValid(timesig, subdivision_seq, beat_level): + isValid = False + if ('/' not in timesig) or (not timesig.split('/')[0].isdigit()) or (not timesig.split('/')[1].isdigit()): + print 'Error: invalid time-signature. Please indicate in the form of fraction, e.g. 4/4, 6/8 or 3/4.' + elif subdivision_seq != [s for s in subdivision_seq if isinstance(s,int)]: + print 'Error: invalid subdivision sequence. Please indicate in the form of list of numbers, e.g [1,2,2,2,2].' + elif beat_level >= len(subdivision_seq): + print 'Error: beat-level exceeds the range of subdivision sequence list.' + else: + isValid = True + return isValid + +def writeTimesig(): + import cPickle as pickle + timesigFile = open('TimeSignature.pkl', 'wb') + pickle.dump(timesigBase, timesigFile) + timesigFile.close() + +def readTimesig(): + import cPickle as pickle + timesigFile = open('TimeSignature.pkl','rb') + data = pickle.load(timesigFile) + return data + timesigFile.close() + +def viewTimesigBase(): + data = readTimesig() + for timesig, settings in data.items(): + print timesig, settings + +def set_L_max(number): + L_max = number + +def get_subdivision_seq(timesig): + if timesig in readTimesig(): + return timesigBase[timesig][0] + else: + print 'Error: the subdivision sequence for this time-signature is not defined.' + return None + +def get_beat_level(timesig): + if timesig in readTimesig(): + return timesigBase[timesig][1] + else: + print 'Error: the subdivision sequence for this time-signature is not defined.' + return None
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Syncopation models/rhythm_parser.py Fri Apr 03 11:41:01 2015 +0100 @@ -0,0 +1,106 @@ +''' +Author: Chunyang Song +Institution: Centre for Digital Music, Queen Mary University of London +''' + +# Parse the rhythm file and return a list of Bar objects +Piece = [] + +from ParameterSetter import timesigBase + + +comment_sign = '#' +def discardComments(line): + if comment_sign in line: + line = line[0:line.find(comment_sign)] + return line + +def discardSpaces(line): + line = line.replace(" ", '').replace("\t", '') + return line + +def extractInfo(line): + try: + if '{' not in line and '}' not in line: + raise RhythmSyntaxError(line) + else: + return line[line.find('{')+1 : line.find('}')] + except RhythmSyntaxError: + print 'Rhythmic information needs to be enclosed by "{" and "}"' + + +current_timesig = '' +current_timesigValue = [] +def process(line): + try: + if 't' in line: + current_timesig = extractInfo(line) + if current_timesig in timesigBase: + current_timesigValue = timesigBase[current_timesig] + else: + raise NoTimesigError(current_timesig) + + elif 'v' in line: + if current_timesig == '': + raise InitialTimesigError(line) + else: + rhythmString = extractInfo(line) + rhythm_seq = map(int,rhythmString.split(',')) + Piece.append(Bar(rhythm_seq, current_timesigValue[0], current_timesigValue[1])) + + else: + raise SymbolError(line) + + except InitialTimesigError: + print 'The initial time-signature is not given.' + except NoTimesigError: + print 'The time-signature is not recognised.' + except SymbolError: + print 'Unrecognised symbol.' + + +def readRhythm(fileName): + try: + f = file(fileName) + + # Clean up each line by discarding comments and spaces; extract time-signature or sequence information + isfinished = False + while(not isfinished): + line = f.readline() + if len(line) == 0: + isfinished = True + else: + cleanline = discardSpaces(discardComments(line)) + process(cleanline) + + # Extract time-signature and rhythm sequence information + + except IOError as e: + print "I/O error({0}): {1}".format(e.errno, e.strerror) + except: + print 'Unexpected error.'#, sys.exc_info()[0] + +# To check the +def isInfoValid(info): + # If two parts of information is not seperated by ; + # if 't' in info and 'q' in info: + # print 'Error: time-signature and rhythm sequence needs ";" to seperate. Please check this rhythm file: %s.' %fileName + # Piece = None + # break + # elif '{' not in info and '}' not in info: + # print 'Error: information needs to be enclosed by "{ }". Please check this rhythm file: %s.' %fileName + # Piece = None + # break + # else: + return True + +# To check whether the given time-signature is existed; if not then requires user to add in the new time-signature +#def checkTimesig(input): + + +# TESTING +line = 't{4/4} q{1,0,0,1,0,0,1,0,0,0,1,0,0.8,0,0,0} t{2/4} # This is a comment' +# print discardSpaces(discardComments(line)) +print line[line.find('{')+1:line.find('}')] +#print readRhythm("rhythmbase/testrhythm.txt") +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Syncopation models/syncopation.py Fri Apr 03 11:41:01 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 BasicFuncs 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 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 + + 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')