def score_transition(song_chunk, new_frame, smooth=True, cache=None): num_frames = utils.song_length(song_chunk) prev_frames = ["|".join([str(song_chunk[0][i]), str(song_chunk[1][i]), str(song_chunk[2][i])]) for i in range(0, num_frames)] denominator_obs = ".".join(prev_frames) numerator_obs = denominator_obs + "." + "|".join([str(n) for n in new_frame]) if cache is not None: if numerator_obs in cache: numerator_count = cache[numerator_obs] else: numerator_count = count_for_obs(numerator_obs) or 0 numerator_count += 1 if smooth else 0 cache[numerator_obs] = numerator_count if denominator_obs in cache: denominator_count = cache[denominator_obs] else: denominator_count = count_for_obs(denominator_obs) or 0 denominator_count += num_possible_prev_states if smooth else 0 cache[denominator_obs] = denominator_count else: numerator_count = count_for_obs(numerator_obs) or 0 numerator_count += 1 if smooth else 0 denominator_count = count_for_obs(denominator_obs) or 0 denominator_count += num_possible_prev_states if smooth else 0 return None if numerator_count == 0 and not smooth else math.log(float(numerator_count) / denominator_count, 10)
def predict_song(song_start, scoring_function, frame_filter=None, length=100, order=1, variability=0): from copy import copy from random import randint song = copy(song_start) init_song_len = utils.song_length(song) possible_frames = [[int(note) for note in frame.split("|")] for frame in hmm.all_observations()] cache = dict() for i in range(0, length - init_song_len): print "SONG: %s" % (song) if i == 0: current_frame_obs = [[channel[i]] for channel in song] else: obs_to_pull = min(utils.song_length(song), order - 1) current_frame_obs = [channel[-1 * obs_to_pull:] for channel in song] scores = {} prev_frame = [channel[-1] for channel in song] if frame_filter is not None: filtered_frames = [frame for frame in possible_frames if frame_filter(prev_frame, frame)] # if we filtered everything out, easy back and let the full set back in if len(filtered_frames) > 0: local_possible_frames = filtered_frames else: local_possible_frames = possible_frames else: local_possible_frames = possible_frames for a_frame in local_possible_frames: score = scoring_function(current_frame_obs, a_frame, smooth=False, cache=cache) scores["|".join([str(note) for note in a_frame])] = score sorted_scores = sorted([(value, key) for (key, value) in scores.items() if value is not None], reverse=True) print current_frame_obs print sorted_scores[0:10] # If we don't have any valid transitions from this state, we just have # to guess a new one at random (not great!) We just use semi popular # observations, to limit the damage if len(sorted_scores) == 0: print "WARNING, Random Transition!" random_frames = all_observations(cutoff=200) selected_observation = (0, random_frames[randint(0, len(random_frames) - 1)]) elif variability == 0 or len(sorted_scores) == 1: selected_observation = sorted_scores[0] else: selected_observation = sorted_scores[randint(0, min(variability - 1, len(sorted_scores) - 1))] print selected_observation frame_parts = [int(part) for part in selected_observation[1].split("|")] for i in range(0, 3): song[i].append(frame_parts[i]) print "Generated note {0}/{1}".format(utils.song_length(song), length) print song return song