annotate Syncopation models/WNBD.py @ 42:121d0e1f1748

Added the R plots
author csong <csong@eecs.qmul.ac.uk>
date Thu, 23 Apr 2015 22:08:48 +0100
parents df1e7c378ee0
children
rev   line source
csong@0 1 '''
csong@0 2 Author: Chunyang Song
csong@0 3 Institution: Centre for Digital Music, Queen Mary University of London
csong@0 4
csong@1 5 '''
csong@20 6 from basic_functions import repeat, get_note_indices
csong@0 7
csong@2 8 # To find the product of multiple numbers
csong@1 9 def cumu_multiply(numbers):
csong@1 10 product = 1
csong@1 11 for n in numbers:
csong@1 12 product = product*n
csong@1 13 return product
csong@0 14
csong@20 15 def get_syncopation(bar, parameters = None):
csong@1 16 syncopation = None
csong@1 17
csong@23 18 noteSequence = bar.get_note_sequence()
csong@23 19 barTicks = bar.get_bar_ticks()
csong@20 20 subdivisionSequence = bar.get_subdivision_sequence()
csong@20 21 strongBeatLevel = bar.get_beat_level()
csong@23 22
csong@23 23 nextbarNoteSequence = None
csong@23 24 if bar.get_next_bar() != None:
csong@23 25 nextbarNoteSequence = bar.get_next_bar().get_note_sequence()
csong@20 26
csong@23 27 # calculate each strong beat ticks
csong@23 28 numberOfBeats = cumu_multiply(subdivisionSequence[:strongBeatLevel+1])
csong@23 29 beatIntervalTicks = barTicks/numberOfBeats
csong@23 30 # beatsTicks represents the ticks for all the beats in the current bar and the first two beats in the next bar
csong@23 31 beatsTicks = [i*beatIntervalTicks for i in range(numberOfBeats+2)]
csong@23 32 #print beatsTicks
csong@23 33 totalSyncopation = 0
csong@23 34 for note in noteSequence:
csong@23 35 # print note.to_string()
csong@23 36 # find such beatIndex such that note.startTime is located between (including) beatsTicks[beatIndex] and (not including) beatsTicks[beatIndex+1]
csong@23 37 beatIndex = 0
csong@23 38 while note.startTime < beatsTicks[beatIndex] or note.startTime >= beatsTicks[beatIndex+1]:
csong@23 39 beatIndex += 1
csong@20 40
csong@23 41 # print beatIndex
csong@23 42 # calculate the distance of this note to its nearest beat
csong@23 43 distanceToBeatOnLeft = abs(note.startTime - beatsTicks[beatIndex])/float(beatIntervalTicks)
csong@23 44 distanceToBeatOnRight = abs(note.startTime - beatsTicks[beatIndex+1])/float(beatIntervalTicks)
csong@23 45 distanceToNearestBeat = min(distanceToBeatOnLeft,distanceToBeatOnRight)
csong@23 46 # print distanceToNearestBeat
csong@23 47
csong@23 48 # calculate the WNBD measure for this note, and add to total syncopation value for this bar
csong@23 49 if distanceToNearestBeat == 0:
csong@23 50 totalSyncopation += 0
csong@23 51 # or if this note is held on past the following beat, but ends on or before the later beat
csong@23 52 elif beatsTicks[beatIndex+1] < note.startTime+note.duration <= beatsTicks[beatIndex+2]:
csong@23 53 totalSyncopation += float(2)/distanceToNearestBeat
csong@23 54 else:
csong@23 55 totalSyncopation += float(1)/distanceToNearestBeat
csong@23 56 # print totalSyncopation
csong@23 57
csong@23 58 return totalSyncopation
csong@23 59
csong@23 60 #def get_syncopation(seq, subdivision_seq, strong_beat_level, postbar_seq):
csong@23 61 # def get_syncopation(bar, parameters = None):
csong@23 62 # syncopation = None
csong@2 63
csong@23 64 # binarySequence = bar.get_binary_sequence()
csong@23 65 # sequenceLength = len(binarySequence)
csong@23 66 # subdivisionSequence = bar.get_subdivision_sequence()
csong@23 67 # strongBeatLevel = bar.get_beat_level()
csong@23 68 # nextbarBinarySequence = None
csong@0 69
csong@23 70 # if bar.get_next_bar() != None:
csong@23 71 # nextbarBinarySequence = bar.get_next_bar().get_binary_sequence()
csong@0 72
csong@23 73 # numberOfBeats = cumu_multiply(subdivisionSequence[0:strongBeatLevel+1]) # numberOfBeats is the number of strong beats
csong@23 74
csong@23 75 # if sequenceLength % numberOfBeats != 0:
csong@23 76 # print 'Error: the length of sequence is not subdivable by the subdivision factor in subdivision sequence.'
csong@23 77 # else:
csong@23 78 # # Find the indices of all the strong-beats
csong@23 79 # beatIndices = []
csong@23 80 # beatInterval = sequenceLength / numberOfBeats
csong@23 81 # for i in range(numberOfBeats+1):
csong@23 82 # beatIndices.append(i*beatInterval)
csong@23 83 # if nextbarBinarySequence != None: # if there is a postbar_seq, add another two beats index for later calculation
csong@23 84 # beatIndices += [sequenceLength+beatInterval, sequenceLength+ 2* beatInterval]
csong@23 85
csong@23 86 # noteIndices = get_note_indices(binarySequence) # all the notes
csong@23 87
csong@23 88 # # Calculate the WNBD measure for each note
csong@23 89 # def measure_pernote(noteIndices, nextNoteIndex):
csong@23 90 # # Find the nearest beats where this note locates - in [beat_indices[j], beat_indices[j+1])
csong@23 91 # j = 0
csong@23 92 # while noteIndices < beatIndices[j] or noteIndices >= beatIndices[j+1]:
csong@23 93 # j = j + 1
csong@1 94
csong@23 95 # # The distance of note to nearest beat normalised by the beat interval
csong@23 96 # distanceToNearestBeat = min(abs(noteIndices - beatIndices[j]), abs(noteIndices - beatIndices[j+1]))/float(beatInterval)
csong@0 97
csong@23 98 # # if this note is on-beat
csong@23 99 # if distanceToNearestBeat == 0:
csong@23 100 # measure = 0
csong@23 101 # # or if this note is held on past the following beat, but ends on or before the later beat
csong@23 102 # elif beatIndices[j+1] < nextNoteIndex <= beatIndices[j+2]:
csong@23 103 # measure = float(2)/distanceToNearestBeat
csong@23 104 # else:
csong@23 105 # measure = float(1)/distanceToNearestBeat
csong@23 106 # return measure
csong@0 107
csong@23 108 # total = 0
csong@23 109 # for i in range(len(noteIndices)):
csong@23 110 # # if this is the last note, end_time is the index of the following note in the next bar
csong@23 111 # if i == len(noteIndices)-1:
csong@23 112 # # if the next bar is not none or a bar of full rest,
csong@23 113 # # the nextNoteIndex is the sum of sequence length in the current bar and the noteIndex in the next bar
csong@23 114 # if nextbarBinarySequence != None and nextbarBinarySequence != repeat([0],len(nextbarBinarySequence)):
csong@23 115 # nextNoteIndex = get_note_indices(nextbarBinarySequence)[0]+sequenceLength
csong@23 116 # # else when the next bar is none or full rest, end_time is the end of this sequence.
csong@23 117 # else:
csong@23 118 # nextNoteIndex = sequenceLength
csong@23 119 # # else this is not the last note, the nextNoteIndex is the following element in the noteIndices list
csong@23 120 # else:
csong@23 121 # nextNoteIndex = noteIndices[i+1]
csong@23 122 # # sum up the syncopation value for individual note at noteIndices[i]
csong@23 123 # total += measure_pernote(noteIndices[i],nextNoteIndex)
csong@0 124
csong@23 125 # #syncopation = float(total) / len(note_indices)
csong@0 126
csong@23 127 # # return the total value, leave the normalisation done in the end
csong@23 128 # return total