def vanDerWeijPerform(score, segments, expression_vectors): deviations = Deviations() tempo_deviations = {} for segment, expression in zip(segments, expression_vectors): start_tempo = expression[3] tempo_direction = expression[5] start_loudness = expression[4] loudness_direction = expression[6] articulation = expression[2] i = 0 beat = 0 for note in segment: velocity = start_loudness + i * loudness_direction i += 1 score.tempo = tempo performance = NoteList() time = 0 for i in range(len(score)): on = time + structure.ioi(score, i) * math.exp(expression[i][0]) loudness = average_loudness * math.exp(expression[i][1]) off = on + structure.duration(score, i) * math.exp(expression[i][3]) performance.insert(Note(int(on), int(off), score[i].pitch, int(loudness), 0)) time = on return performance
def expressionWidmer(alignment): performance = alignment.expressiveMelody() melodyscore = alignment.melody() score = tools.parseScore(melodyscore) # The two above should be guaranteed to be of equal length. # However, better be safe than sorry if len(performance) != len(score): print('This shouldn\'t happen: melodyscore and performance lengths don\'t match: {0} and {1}'.format(len(score), len(performance))) else: print("This is good, performance length and score length match") # Mean loudness mean_l = 0.0 for note in performance: mean_l += note.onvelocity mean_l = mean_l / float(len(performance)) expression = [] lasttempo = float(alignment.deviations.bpm) lastdynamics = mean_l # Assume same note order in score and performance (am I being naive?) for i in range(len(performance)): ioi_ratio = math.log(structure.ioi(performance, i) / float(structure.ioi(score, i))) loudness_ratio = math.log(performance[i].onvelocity / mean_l) # This obviously results in zero divisions #articulation = math.log(structure.silence(performance, i) / float(structure.silence(score, i))) articulation = 0 if(structure.duration(performance, i) < 1): print("Invalid performance note :( skipping") continue duration_ratio = math.log(structure.duration(performance, i) / float(structure.duration(score, i))) # To be implemented: second order ioi loudness and articulation ioi_change = 0 loudness_change = 0 articulation_change = 0 # E = (ioi_r, loudness_r, articulation, duration_r, ioi_ch, loundess_ch) e = (ioi_ratio, loudness_ratio, articulation, duration_ratio, ioi_change, loudness_change) expression.append(e) return expression
def widmerPerform(score, expression, average_loudness=80, tempo=80): score.tempo = tempo performance = NoteList() time = 0 for i in range(len(score)): on = time + structure.ioi(score, i) * math.exp(expression[i][0]) loudness = average_loudness * math.exp(expression[i][1]) off = on + structure.duration(score, i) * math.exp(expression[i][3]) performance.insert(Note(int(on), int(off), score[i].pitch, int(loudness), 0)) time = on return performance
def vanDerWeijExpression(alignment, segments): performance = alignment.expressiveMelody() scorenotes = [] average_loudness = 0 for s in segments: for n in s: scorenotes.append(n) average_loudness += n.onvelocity average_loudness /= float(len(scorenotes)) # The two above should be guaranteed to be of equal length. # However, better be safe than sorry if len(performance) != sum([len(x) for x in segments]): print('WARNING: Melodyscore and performance are different (should not happen): {0} and {1}'.format(len(sum([len(x) for x in segments])), len(performance))) expression = [] # Counter for position in notelists performance and scorenotes i = 0 for segment in segments: length = float(len(segment)) average_articulation = 0.0 average_ioi_ratio = 0.0 loudnesses = [] for note in segment: pointer = note.annotation scorepart = alignment.melody()[pointer[0]] scoremeasure = scorepart[pointer[1]] scorevoice = scoremeasure[pointer[2]] scorenote = scorevoice[pointer[3]] measure = scoremeasure.number # Find out if the next note is a rest, if so use the ratio between expressive duration and duration useScoreDuration = False # Last note of this measure? if pointer[3] + 1 == len(scorevoice): # Last measure? if pointer[1] + 1 >= len(scorepart): useScoreDuration = True # Don't know what to do if the voice in the next measure contains no notes elif scorepart[pointer[1]+1].getElementById(scorevoice.id) == None: measure = scorepart[pointer[1]+1] useScoreDuration = True elif len(scorepart[pointer[1]+1].getElementById(scorevoice.id).notes) == 0: measure = scorepart[pointer[1]+1] useScoreDuration = True # First note of this voice in the next measure is a rest? elif scorepart[pointer[1]+1].getElementById(scorevoice.id).notes[0].isRest: measure = scorepart[pointer[1]+1] useScoreDuration = True elif scorevoice[pointer[3]+1].isRest: useScoreDuration = True ioi = 1 if useScoreDuration or i+1 == len(performance): ioi = performance.microseconds_to_ticks(alignment.deviations.getExpressiveDuration(scoremeasure.number, scorenote.offset, scorenote.duration.quarterLength)) else: ioi = structure.ioi(performance, i+1) # Ugly hack to fix something if ioi == 0: ioi = performance.microseconds_to_ticks( alignment.deviations.getExpressiveDuration(scoremeasure.number, scorenote.offset, scorenote.duration.quarterLength) ) #print "Performance ioi: {0}, score + tempo ioi: {1}, performance duration: {2}, measure{3}, offset {4}".format(ioi,\ # performance.microseconds_to_ticks(alignment.deviations.getExpressiveDuration(scoremeasure.number, scorenote.offset,\ # scorenote.duration.quarterLength)), structure.duration(performance, i), scoremeasure.number, scorenote.offset) # Results in zero division error in Mozart: 28 (not needed anyway so let's kick it out) #average_ioi_ratio += math.log(structure.ioi(performance, i) / float(structure.ioi(scorenotes, i))) average_ioi_ratio += 0 average_articulation += structure.duration(performance, i) / float(ioi) loudnesses.append(performance[i].onvelocity) i += 1 tempos = [] r = list(range(segment[0].annotation[1], segment[int(length)-1].annotation[1]+1)) for m in r: pointer = note.annotation scoremeasure = alignment.melody()[pointer[0]][pointer[1]] measure = scoremeasure.number #print scoremeasure.duration.quarterLength lasttempo = 1.0 for b in range(int(scoremeasure.barDuration.quarterLength)): if (scoremeasure.number, b) in alignment.deviations.tempo_deviations: lasttempo = alignment.deviations.tempo_deviations[scoremeasure.number, b] tempos.append(lasttempo) else: tempos.append(lasttempo) # Calculate performance parameters/features average_ioi_ratio /= length average_articulation /= length average_tempo = sum(tempos) / float(len(tempos)) #average_relative_loudness = math.log((sum(loudnesses) / length) / average_loudness) average_relative_loudness = (sum(loudnesses) / length) / float(average_loudness) if len(segment) == 1: (start_loudness, loudness_direction) = (average_loudness, 0) (start_tempo, tempo_direction) = (tempos[0], 0) else: note_onsets = [n.on for n in segment] (start_loudness, loudness_direction) = (0, 0) #linear_fit(note_onsets, loudnesses) (start_tempo, tempo_direction) = (0, 0) #linear_fit(range(len(tempos)), tempos) expression.append((average_ioi_ratio, average_relative_loudness, average_articulation, average_tempo, start_tempo, start_loudness, tempo_direction, loudness_direction)) return expression