def align(track1, track2, mat1, mat2):
    """ Constrained search between a settled section and a new section.
        Outputs location in mat2 and the number of rows used in the transition.
    """
    # Get the average marker duration.
    marker1 = average_duration(getattr(track1.analysis, track1.resampled['rate'])[track1.resampled['index']:track1.resampled['index']+rows(mat1)])
    marker2 = average_duration(getattr(track2.analysis, track2.resampled['rate'])[track2.resampled['index']:track2.resampled['index']+rows(mat2)])

    def get_adjustment(tr1, tr2):
        """Update tatum rate if necessary"""
        dist = np.log2(tr1 / tr2)
        if  dist < -0.5: return (1, 2)
        elif dist > 0.5: return (2, 1)
        else:            return (1, 1)
    
    rate1, rate2 = get_adjustment(marker1, marker2)
    if rate1 == 2: mat1 = upsample_matrix(mat1)
    if rate2 == 2: mat2 = upsample_matrix(mat2)
    
    # Update sizes.
    rows2 = rows(mat2)
    rows1 = min( rows(mat1), max(rows2 - MIN_SEARCH, MIN_MARKERS)) # at least the best of MIN_SEARCH choices
    
    # Search for minimum.
    def dist(i):
        return evaluate_distance(mat1[0:rows1,:], mat2[i:i+rows1,:])
    
    min_loc = min(xrange(rows2 - rows1), key=dist)
    min_val = dist(min_loc)
    
    # Let's make sure track2 ends its transition on a regular tatum.
    if rate2 == 2 and (min_loc + rows1) & 1: 
        rows1 -= 1
    
    return min_loc, rows1, rate1, rate2
Beispiel #2
0
def timbre_whiten(mat):
    if rows(mat) < 2: return mat
    m = np.zeros((rows(mat), 12), dtype=np.float32)
    m[:, 0] = mat[:, 0] - np.mean(mat[:, 0], 0)
    m[:, 0] = m[:, 0] / np.std(m[:, 0], 0)
    m[:, 1:] = mat[:, 1:] - np.mean(mat[:, 1:].flatten(), 0)
    m[:, 1:] = m[:, 1:] / np.std(m[:, 1:].flatten(), 0)  # use this!
    return m
Beispiel #3
0
def timbre_whiten(mat):
    if rows(mat) < 2: return mat
    m = np.zeros((rows(mat), 12), dtype=np.float32)
    m[:,0] = mat[:,0] - np.mean(mat[:,0],0)
    m[:,0] = m[:,0] / np.std(m[:,0],0)
    m[:,1:] = mat[:,1:] - np.mean(mat[:,1:].flatten(),0)
    m[:,1:] = m[:,1:] / np.std(m[:,1:].flatten(),0) # use this!
    return m
Beispiel #4
0
def get_paths_slow(matrix, size=MIN_RANGE):
    paths = []
    for i in xrange(rows(matrix)-MIN_ALIGN+1):
        vector = np.zeros((rows(matrix)-MIN_ALIGN+1,), dtype=np.float32)
        for j in xrange(rows(matrix)-MIN_ALIGN+1):
            vector[j] = evaluate_distance(matrix[i:i+MIN_ALIGN,:], matrix[j:j+MIN_ALIGN,:])
        paths.append(get_loop_points(vector, size))
    return paths
Beispiel #5
0
def get_paths_slow(matrix, size=MIN_RANGE):
    paths = []
    for i in xrange(rows(matrix)-MIN_ALIGN+1):
        vector = np.zeros((rows(matrix)-MIN_ALIGN+1,), dtype=np.float32)
        for j in xrange(rows(matrix)-MIN_ALIGN+1):
            vector[j] = evaluate_distance(matrix[i:i+MIN_ALIGN,:], matrix[j:j+MIN_ALIGN,:])
        paths.append(get_loop_points(vector, size))
    return paths
Beispiel #6
0
def initialize(track, inter, transition):
    """find initial cursor location"""
    mat = track.resampled['matrix']
    markers = getattr(track.analysis, track.resampled['rate'])

    try:
        # compute duration of matrix
        mat_dur = markers[track.resampled['index'] + rows(
            mat)].start - markers[track.resampled['index']].start
        start = (mat_dur - inter - transition - FADE_IN) / 2
        dur = start + FADE_IN + inter
        # move cursor to transition marker
        duration, track.resampled['cursor'] = move_cursor(track, dur, 0)
        # work backwards to find the exact locations of initial fade in and playback sections
        fi = Fadein(
            track,
            markers[track.resampled['index'] + track.resampled['cursor']].start
            - inter - FADE_IN, FADE_IN)
        pb = Playback(
            track,
            markers[track.resampled['index'] + track.resampled['cursor']].start
            - inter, inter)
    except:
        track.resampled['cursor'] = FADE_IN + inter
        fi = Fadein(track, 0, FADE_IN)
        pb = Playback(track, FADE_IN, inter)

    return [fi, pb]
Beispiel #7
0
def get_mat_in(track, transition, inter):
    """ Find and output the search matrix to use in the next alignment.
        Assumes that track.resampled exists.
    """
    # search from the start
    cursor = 0
    track.resampled['cursor'] = cursor
    mat = track.resampled['matrix']

    # compute search zone by anticipating what's playing after the transition
    marker_end = getattr(track.analysis,
                         track.resampled['rate'])[track.resampled['index'] +
                                                  rows(mat)].start
    marker_start = getattr(
        track.analysis,
        track.resampled['rate'])[track.resampled['index']].start
    search_dur = (marker_end - marker_start) - inter - 2 * transition

    if search_dur < 0:
        return mat[:MIN_MARKERS, :]

    # find what the location is in rows
    duration, cursor = move_cursor(track, search_dur, cursor)

    return mat[:cursor, :]
Beispiel #8
0
def move_cursor(track, duration, cursor, buf=MIN_MARKERS):
    dur = 0
    while dur < duration and cursor < rows(track.resampled['matrix']) - buf:
        markers = getattr(track.analysis, track.resampled['rate'])
        dur += markers[track.resampled['index'] + cursor].duration
        cursor += 1
    return dur, cursor
def move_cursor(track, duration, cursor, buf=MIN_MARKERS):
    dur = 0
    while dur < duration and cursor < rows(track.resampled['matrix']) - buf:
        markers = getattr(track.analysis, track.resampled['rate'])    
        dur += markers[track.resampled['index'] + cursor].duration
        cursor += 1
    return dur, cursor
Beispiel #10
0
def analyze(track):
    timbre = resample_features(track, rate=RATE, feature='timbre')
    timbre['matrix'] = timbre_whiten(timbre['matrix'])
    pitch = resample_features(track, rate=RATE, feature='pitches')
    #NOTE why not whiten pitch matrix?
    
    # pick a tradeoff between speed and memory size
    if rows(timbre['matrix']) < MAX_SIZE:
        # faster but memory hungry. For euclidean distances only.
        t_paths = get_paths(timbre['matrix'])
        p_paths = get_paths(pitch['matrix'])
    else:
        # slower but memory efficient. Any distance possible.
        t_paths = get_paths_slow(timbre['matrix'])
        p_paths = get_paths_slow(pitch['matrix'])
    
    # intersection of top timbre and pitch results
    paths = path_intersect(t_paths, p_paths)
    
    markers = getattr(track.analysis, timbre['rate'])[timbre['index']:timbre['index']+len(paths)]
    graph = make_graph(paths, markers, timbre['matrix'], pitch['matrix'])
    
    #NOTE remove last node because empty?
    size = graph.number_of_nodes()
    graph.remove_node(size-1)
   
    return graph
def initialize(track, inter, transition):
    """find initial cursor location"""
    mat = track.resampled['matrix']
    markers = getattr(track.analysis, track.resampled['rate'])

    try:
        # compute duration of matrix
        mat_dur = markers[track.resampled['index'] + rows(mat)].start - markers[track.resampled['index']].start
        start = (mat_dur - inter - transition - FADE_IN) / 2
        dur = start + FADE_IN + inter
        # move cursor to transition marker
        duration, track.resampled['cursor'] = move_cursor(track, dur, 0)
        # work backwards to find the exact locations of initial fade in and playback sections
        fi = Fadein(track, markers[track.resampled['index'] + track.resampled['cursor']].start - inter - FADE_IN, FADE_IN)
        pb = Playback(track, markers[track.resampled['index'] + track.resampled['cursor']].start - inter, inter)
    except:
        track.resampled['cursor'] = FADE_IN + inter
        fi = Fadein(track, 0, FADE_IN)
        pb = Playback(track, FADE_IN, inter)

    return [fi, pb]
def get_mat_in(track, transition, inter):
    """ Find and output the search matrix to use in the next alignment.
        Assumes that track.resampled exists.
    """
    # search from the start
    cursor = 0
    track.resampled['cursor'] = cursor
    mat = track.resampled['matrix']
    
    # compute search zone by anticipating what's playing after the transition
    marker_end = getattr(track.analysis, track.resampled['rate'])[track.resampled['index'] + rows(mat)].start
    marker_start = getattr(track.analysis, track.resampled['rate'])[track.resampled['index']].start
    search_dur = (marker_end - marker_start) - inter - 2 * transition
    
    if search_dur < 0: 
        return mat[:MIN_MARKERS,:]
    
    # find what the location is in rows
    duration, cursor = move_cursor(track, search_dur, cursor)
    
    return mat[:cursor,:]
Beispiel #13
0
def get_paths(matrix, size=MIN_RANGE):
    mat = make_similarity_matrix(matrix, size=MIN_ALIGN)
    paths = []
    for i in xrange(rows(mat)):
        paths.append(get_loop_points(mat[i,:], size))
    return paths
Beispiel #14
0
def do_work(track, options):

    dur = float(options.duration)
    mlp = int(options.minimum)
    lgh = bool(options.length)
    inf = bool(options.infinite)
    pkl = bool(options.pickle)
    gml = bool(options.graph)
    plt = bool(options.plot)
    fce = bool(options.force)
    sho = bool(options.shortest)
    lon = bool(options.longest)
    vbs = bool(options.verbose)

    mp3 = track.filename
    try:
        if fce == True:
            raise
        graph = read_graph(mp3+".graph.gpkl")
    except:
        # compute resampled and normalized matrix
        timbre = resample_features(track, rate=RATE, feature='timbre')
        timbre['matrix'] = timbre_whiten(timbre['matrix'])
        pitch = resample_features(track, rate=RATE, feature='pitches')

        # pick a tradeoff between speed and memory size
        if rows(timbre['matrix']) < MAX_SIZE:
            # faster but memory hungry. For euclidean distances only.
            t_paths = get_paths(timbre['matrix'])
            p_paths = get_paths(pitch['matrix'])
        else:
            # slower but memory efficient. Any distance possible.
            t_paths = get_paths_slow(timbre['matrix'])
            p_paths = get_paths_slow(pitch['matrix'])

        # intersection of top timbre and pitch results
        paths = path_intersect(t_paths, p_paths)
        # TEMPORARY -- check that the data looks good
        if vbs == True:
            print_screen(paths)
        # make graph
        markers = getattr(track.analysis, timbre['rate'])[timbre['index']:timbre['index']+len(paths)]
        graph = make_graph(paths, markers)

    # remove smaller loops for quality results
    if 0 < mlp:
        remove_short_loops(graph, mlp)
    # plot graph
    if plt == True:
        save_plot(graph, mp3+".graph.png")
    # save graph
    if pkl == True:
        save_graph(graph, mp3+".graph.gpkl")
    if gml == True:
        save_graph(graph, mp3+".graph.gml")
    # single loops
    if sho == True:
        return one_loop(graph, track, mode='shortest')
    if lon == True:
        return one_loop(graph, track, mode='longest')
    # other infinite loops
    if inf == True:
        if vbs == True:
            print "\nInput Duration:", track.analysis.duration
        # get the optimal path for a given duration
        return infinite(graph, track, dur)

    dur_intro = min(graph.nodes())
    dur_outro = track.analysis.duration - max(graph.nodes())

    if vbs == True:
        print "Input Duration:", track.analysis.duration
    # get the optimal path for a given duration
    path = compute_path(graph, max(dur-dur_intro-dur_outro, 0))
    # build actions
    middle = make_jumps(path, track)
    # complete list of actions
    actions = terminate(dur_intro, middle, dur_outro, dur, lgh)

    return actions
Beispiel #15
0
def do_work(track, options):
    
    dur = float(options.duration)
    mlp = int(options.minimum)
    lgh = bool(options.length)
    inf = bool(options.infinite)
    pkl = bool(options.pickle)
    gml = bool(options.graph)
    plt = bool(options.plot)
    fce = bool(options.force)
    sho = bool(options.shortest)
    lon = bool(options.longest)
    vbs = bool(options.verbose)
    
    mp3 = track.filename
    try:
        if fce == True:
            raise
        graph = read_graph(mp3+".graph.gpkl")
    except:
        # compute resampled and normalized matrix
        timbre = resample_features(track, rate=RATE, feature='timbre')
        timbre['matrix'] = timbre_whiten(timbre['matrix'])
        pitch = resample_features(track, rate=RATE, feature='pitches')
        
        # pick a tradeoff between speed and memory size
        if rows(timbre['matrix']) < MAX_SIZE:
            # faster but memory hungry. For euclidean distances only.
            t_paths = get_paths(timbre['matrix'])
            p_paths = get_paths(pitch['matrix'])
        else:
            # slower but memory efficient. Any distance possible.
            t_paths = get_paths_slow(timbre['matrix'])
            p_paths = get_paths_slow(pitch['matrix'])
            
        # intersection of top timbre and pitch results
        paths = path_intersect(t_paths, p_paths)
        # TEMPORARY -- check that the data looks good
        if vbs == True:
            print_screen(paths)
        # make graph
        markers = getattr(track.analysis, timbre['rate'])[timbre['index']:timbre['index']+len(paths)]
        graph = make_graph(paths, markers)
        
    # remove smaller loops for quality results
    if 0 < mlp:
        remove_short_loops(graph, mlp)
    # plot graph
    if plt == True:
        save_plot(graph, mp3+".graph.png")
    # save graph
    if pkl == True:
        save_graph(graph, mp3+".graph.gpkl")
    if gml == True:
        save_graph(graph, mp3+".graph.gml")
    # single loops
    if sho == True:
        return one_loop(graph, track, mode='shortest')
    if lon == True:
        return one_loop(graph, track, mode='longest')
    # other infinite loops
    if inf == True:
        if vbs == True:
            print "\nInput Duration:", track.analysis.duration
        # get the optimal path for a given duration
        return infinite(graph, track, dur)
        
    dur_intro = min(graph.nodes())
    dur_outro = track.analysis.duration - max(graph.nodes())
    
    if vbs == True:
        print "Input Duration:", track.analysis.duration
    # get the optimal path for a given duration
    path = compute_path(graph, max(dur-dur_intro-dur_outro, 0))
    # build actions
    middle = make_jumps(path, track)
    # complete list of actions
    actions = terminate(dur_intro, middle, dur_outro, dur, lgh)
    
    return actions
Beispiel #16
0
def get_paths(matrix, size=MIN_RANGE):
    mat = make_similarity_matrix(matrix, size=MIN_ALIGN)
    paths = []
    for i in xrange(rows(mat)):
        paths.append(get_loop_points(mat[i,:], size))
    return paths