def apply(self, transition_cost, penalty, song, beat_names): changepoints = np.array(novelty.novelty(song)) beats = song.analysis["beats"] n_beats = len(beats) n_target = penalty.shape[1] cp_beats_i = [np.argmin(np.abs(beats - cp)) for cp in changepoints] cp_beats = [beats[i] for i in cp_beats_i] # find emotional changes at each changepoint, if any changes = [] for i in cp_beats_i: # check the previous and next 4 beats n_prev = min(4, i) n_next = min(4, n_beats - i) labs = [self.in_labels[j] for j in range(i - n_prev, i + n_next + 1)] # check first and last beat in this range... assuming a sort of # coarse-grained emotional labeling if labs[0] != labs[-1]: # there is an emotional change at this point in the music changes.append((i, labs[0], labs[-1])) for change in changes: print "Found emotional change near changepoint: " +\ change[1] + " -> " + change[2] # find those emotional changes in the target output for l in xrange(1, n_target): target = self.out_labels[l] prev_target = self.out_labels[l - 1] if target != prev_target: for change in changes: if prev_target == change[1] and target == change[2]: print "setting change:\t" +\ change[1] + " -> " + change[2] print "\tat beat " + str(l) + " " +\ str(l * song.analysis[BEAT_DUR_KEY]) # give huge preference to hitting the changepoint here beat_i = change[0] penalty[:n_beats, l] += 1.0 n_prev = min(2, beat_i) n_next = min(2, n_beats - beat_i) penalty[beat_i - n_prev:beat_i + n_next, l] -= 1.0 return transition_cost, penalty, beat_names
def retarget_with_change_points(song, cp_times, duration): """Create a composition of a song of a given duration that reaches music change points at specified times. This is still under construction. It might not work as well with more than 2 ``cp_times`` at the moment. Here's an example of retargeting music to be 40 seconds long and hit a change point at the 10 and 30 second marks:: song = Song("instrumental_music.wav") composition, change_points = retarget.retarget_with_change_points(song, [10, 30], 40) composition.export(filename="retargeted_instrumental_music.") :param song: Song to retarget :type song: :py:class:`radiotool.composer.Song` :param cp_times: Times to reach change points (in seconds) :type cp_times: list of floats :param duration: Target length of retargeted music (in seconds) :type duration: float :returns: Composition of retargeted song and list of locations of change points in the retargeted composition :rtype: (:py:class:`radiotool.composer.Composition`, list) """ analysis = song.analysis beat_length = analysis["avg_beat_duration"] beats = N.array(analysis["beats"]) # find change points cps = N.array(novelty(song, nchangepoints=4)) cp_times = N.array(cp_times) # mark change points in original music def music_labels(t): # find beat closest to t closest_beat_idx = N.argmin(N.abs(beats - t)) closest_beat = beats[closest_beat_idx] closest_cp = cps[N.argmin(N.abs(cps - closest_beat))] if N.argmin(N.abs(beats - closest_cp)) == closest_beat_idx: return "cp" else: return "noncp" # mark where we want change points in the output music # (a few beats of slack to improve the quality of the end result) def out_labels(t): if N.min(N.abs(cp_times - t)) < 1.5 * beat_length: return "cp" return "noncp" # lower penalty around the target locations for change points # because we don't actually want each of them to be change points- # we just want one of the 4 beats covered to be a change point. def out_penalty(t): if N.min(N.abs(cp_times - t)) < 1.5 * beat_length: return .25 return 1.0 comp, info = retarget(song, duration, music_labels, out_labels, out_penalty) final_cp_locations = [beat_length * i for i, label in enumerate(info['result_labels']) if label == 'cp'] return comp, final_cp_locations
seg_times, files = seg_parser.seg_parse(album_num) precision = 0 recall = 0 f_measure = 0 for i in np.arange(len(files)): filepath = audio_root + albums[album_num] + '/' + songs[i] chromagram, fs_chromagram = get_chromagram.get_chromagram(filepath, plot) N, recurrence, look_back = recurrence_matrix.recurrence_matrix(chromagram,fs_chromagram, plot) L = timelag_matrix.timelag_matrix(N, recurrence, plot) P = gaussian_matrix.gaussian_matrix(fs_chromagram, L, plot) c = novelty.novelty(P, plot) # Get relevant array seg_times_i = seg_times[files[i]] onset_a, onset_t = peak_pick.peak_pick(c, fs_chromagram, look_back, seg_times_i, plot) precision_, recall_, f_measure_ = get_metrics.get_metrics(seg_times_i, files, onset_t) precision += precision_ recall += recall_ f_measure += f_measure_ num_songs = len(files) precision_avg = precision/num_songs recall_avg = recall/num_songs
def retarget_with_change_points(song, cp_times, duration): """Create a composition of a song of a given duration that reaches music change points at specified times. This is still under construction. It might not work as well with more than 2 ``cp_times`` at the moment. Here's an example of retargeting music to be 40 seconds long and hit a change point at the 10 and 30 second marks:: song = Song("instrumental_music.wav") composition, change_points =\ retarget.retarget_with_change_points(song, [10, 30], 40) composition.export(filename="retargeted_instrumental_music.") :param song: Song to retarget :type song: :py:class:`radiotool.composer.Song` :param cp_times: Times to reach change points (in seconds) :type cp_times: list of floats :param duration: Target length of retargeted music (in seconds) :type duration: float :returns: Composition of retargeted song and list of locations of change points in the retargeted composition :rtype: (:py:class:`radiotool.composer.Composition`, list) """ analysis = song.analysis beat_length = analysis[BEAT_DUR_KEY] beats = np.array(analysis["beats"]) # find change points cps = np.array(novelty(song, nchangepoints=4)) cp_times = np.array(cp_times) # mark change points in original music def music_labels(t): # find beat closest to t closest_beat_idx = np.argmin(np.abs(beats - t)) closest_beat = beats[closest_beat_idx] closest_cp = cps[np.argmin(np.abs(cps - closest_beat))] if np.argmin(np.abs(beats - closest_cp)) == closest_beat_idx: return "cp" else: return "noncp" # mark where we want change points in the output music # (a few beats of slack to improve the quality of the end result) def out_labels(t): if np.min(np.abs(cp_times - t)) < 1.5 * beat_length: return "cp" return "noncp" m_labels = [music_labels(i) for i in np.arange(0, song.duration_in_seconds, beat_length)] o_labels = [out_labels(i) for i in np.arange(0, duration, beat_length)] constraints = [ rt_constraints.TimbrePitchConstraint( context=0, timbre_weight=1.0, chroma_weight=1.0), rt_constraints.EnergyConstraint(penalty=.5), rt_constraints.MinimumLoopConstraint(8), rt_constraints.NoveltyConstraint(m_labels, o_labels, 1.0) ] comp, info = retarget( [song], duration, constraints=[constraints], fade_in_len=None, fade_out_len=None) final_cp_locations = [beat_length * i for i, label in enumerate(info['result_labels']) if label == 'cp'] return comp, final_cp_locations
def apply(self, transition_cost, penalty, song, beat_names): changepoints = np.array(novelty.novelty(song)) beats = song.analysis["beats"] n_beats = len(beats) n_target = penalty.shape[1] cp_beats_i = [np.argmin(np.abs(beats - cp)) for cp in changepoints] cp_beats = [beats[i] for i in cp_beats_i] far_threshold = .2 close_threshold = .1 # find emotional changes at each changepoint changes = [] for i in cp_beats_i: # check the previous and next 4 beats n_prev = min(4, i) n_next = min(4, n_beats - i) vas = [self.in_va[j] for j in range(i - n_prev, i + n_next + 1)] # check first and last beat in this range... assuming a sort of # coarse-grained emotional labeling # before_va = np.mean(vas[:3], axis=0) # after_va = np.mean(vas[-3:], axis=0) before_va = vas[0] after_va = vas[-1] if np.linalg.norm(before_va - after_va) > far_threshold: # there is an emotional change at this point in the music changes.append((i, before_va, after_va)) for change in changes: print "Found emotional change near changepoint:",\ change[1], "->", change[2] # find those emotional changes in the target output for l in xrange(1, n_target): target = self.out_va[l] prev_target = self.out_va[l - 1] if np.linalg.norm(target - prev_target) > far_threshold: for change in changes: # print np.linalg.norm(prev_target - change[1]),\ # np.linalg.norm(target - change[2]) if np.linalg.norm(prev_target - change[1]) <\ close_threshold and\ np.linalg.norm(target - change[2]) <\ close_threshold: print "setting change:\t", change[1], "->", change[2] print "\tat beat " + str(l) + " " +\ str(l * song.analysis[BEAT_DUR_KEY]) # give huge preference to hitting the changepoint here beat_i = change[0] penalty[:n_beats, l] += 1.0 n_prev = min(2, beat_i) n_next = min(2, n_beats - beat_i) penalty[beat_i - n_prev:beat_i + n_next, l] -= 1.0 return transition_cost, penalty, beat_names