def process_folder(folder_path, quantization, temporal_granularity): # Get instrus and prs from a folder name name pr0, instru0, _, name0, pr1, instru1, _, name1 = build_data_aux.get_instru_and_pr_from_folder_path(folder_path, quantization) # Temporal granularity if temporal_granularity == 'event_level': pr0 = warp_pr_aux(pr0, get_event_ind_dict(pr0)) pr1 = warp_pr_aux(pr1, get_event_ind_dict(pr1)) # Get trace from needleman_wunsch algorithm # Traces are binary lists, 0 meaning a gap is inserted trace_0, trace_1, this_sum_score, this_nbId, this_nbDiffs = needleman_chord_wrapper(sum_along_instru_dim(pr0), sum_along_instru_dim(pr1)) # Wrap dictionnaries according to the traces assert(len(trace_0) == len(trace_1)), "size mismatch" pr0_warp = warp_dictionnary_trace(pr0, trace_0) pr1_warp = warp_dictionnary_trace(pr1, trace_1) # Get pr warped and duration# In fact we just discard 0 in traces for both pr trace_prod = [e1 * e2 for (e1,e2) in zip(trace_0, trace_1)] duration = sum(trace_prod) if duration == 0: return [None]*7 pr0_aligned = remove_zero_in_trace(pr0_warp, trace_prod) pr1_aligned = remove_zero_in_trace(pr1_warp, trace_prod) return pr0_aligned, instru0, name0, pr1_aligned, instru1, name1, duration
def align_tracks(pr0, pr1, unit_type, gapopen, gapextend): # Get trace from needleman_wunsch algorithm # First extract binary representation, whatever unit_type is pr0_binary = Unit_type.from_type_to_binary(pr0, unit_type) pr1_binary = Unit_type.from_type_to_binary(pr1, unit_type) pr0_trace = sum_along_instru_dim(pr0_binary) pr1_trace = sum_along_instru_dim(pr1_binary) # Traces are computed from binaries matrices # Traces are binary lists, 0 meaning a gap is inserted trace_0, trace_1, this_sum_score, this_nbId, this_nbDiffs = needleman_chord_wrapper(pr0_trace, pr1_trace, gapopen, gapextend) #################################### # Wrap dictionnaries according to the traces assert(len(trace_0) == len(trace_1)), "size mismatch" pr0_warp = warp_dictionnary_trace(pr0, trace_0) pr1_warp = warp_dictionnary_trace(pr1, trace_1) #################################### # Trace product trace_prod = [e1 * e2 for (e1, e2) in zip(trace_0, trace_1)] duration = sum(trace_prod) if duration == 0: return [None]*6 # Remove gaps pr0_aligned = remove_zero_in_trace(pr0_warp, trace_prod) pr1_aligned = remove_zero_in_trace(pr1_warp, trace_prod) return pr0_aligned, trace_0, pr1_aligned, trace_1, trace_prod, duration
def get_dim_matrix(index_files_dict, meta_info_path='temp.p', quantization=12, temporal_granularity='frame_level', logging=None): # Determine the temporal size of the matrices # If the two files have different sizes, we use the shortest (to limit the use of memory, # we better contract files instead of expanding them). # Get instrument names instrument_list_from_dico = build_dico().keys() instru_mapping = {} # instru_mapping = {'piano': {'pitch_min': 24, 'pitch_max':117, 'ind_min': 0, 'ind_max': 92}, # 'harp' ... } T_dict = {} # indexed by set_identifier for set_identifier, index_files in index_files_dict.iteritems(): logging.info("##########") logging.info(set_identifier) # Get the full size of the tracks and instrument present T = 0 for index_file in index_files: # Read the csv file indexing the database with open(index_file, 'rb') as f: for folder_path in f: folder_path = folder_path.rstrip() logging.info(folder_path) if not os.path.isdir(folder_path): continue # Read pr try: pr0, instru0, T0, name0, pr1, instru1, T1, name1 = build_data_aux.get_instru_and_pr_from_folder_path(folder_path, quantization) except: with open('log', 'wb') as f: f.write('Bad file' + folder_path + '\n') continue # Temporal granularity if temporal_granularity == 'event_level': new_event_0 = get_event_ind_dict(pr0) pr0 = warp_pr_aux(pr0, new_event_0) new_event_1 = get_event_ind_dict(pr1) pr1 = warp_pr_aux(pr1, new_event_1) # Get T trace_0, trace_1, this_sum_score, this_nbId, this_nbDiffs = needleman_chord_wrapper(sum_along_instru_dim(pr0), sum_along_instru_dim(pr1)) trace_prod = [e1 * e2 for (e1,e2) in zip(trace_0, trace_1)] T += sum(trace_prod) # Modify the mapping from instrument to indices in pianorolls and pitch bounds instru_mapping = build_data_aux.instru_pitch_range(instrumentation=instru0, pr=pr0, instru_mapping=instru_mapping, instrument_list_from_dico=instrument_list_from_dico, ) # remark : instru_mapping would be modified if it is only passed to the function, # f(a) where a is modified inside the function # but i prefer to make the reallocation explicit # a = f(a) with f returning the modified value of a. # Does it change anything for computation speed ? (Python pass by reference, # but a slightly different version of it, not clear to me) instru_mapping = build_data_aux.instru_pitch_range(instrumentation=instru1, pr=pr1, instru_mapping=instru_mapping, instrument_list_from_dico=instrument_list_from_dico ) # Delete prs del pr0, pr1, instru0, instru1 T_dict[set_identifier] = T # Build the index_min and index_max in the instru_mapping dictionary counter = 0 for k, v in instru_mapping.iteritems(): if k == 'piano': index_min = 0 index_max = v['pitch_max'] - v['pitch_min'] v['index_min'] = index_min v['index_max'] = index_max continue index_min = counter counter = counter + v['pitch_max'] - v['pitch_min'] index_max = counter v['index_min'] = index_min v['index_max'] = index_max # Instanciate the matrices ######################################## ######################################## ######################################## temp = {} temp['instru_mapping'] = instru_mapping temp['quantization'] = quantization temp['T'] = T_dict temp['N_orchestra'] = counter pickle.dump(temp, open(meta_info_path, 'wb')) return
def check_orchestration_alignment(path_db, subfolder_names, quantization, gapopen, gapextend): output_dir = 'DEBUG/' + str(quantization) +\ '_' + str(gapopen) +\ '_' + str(gapextend) if not os.path.exists(output_dir): os.makedirs(output_dir) else: # Avoid re-running the algo on already tested parameters return counter = 0 sum_score = 0 nbFrame = 0 nbId = 0 nbDiffs = 0 # num_track_browsed = 30 for sub_db in subfolder_names: print '#' * 30 print sub_db sub_db_path = path_db + '/' + sub_db if not os.path.isdir(sub_db_path): continue # list_tracks_dir = os.listdir(sub_db_path) # ind_folder = np.random.permutation(len(list_tracks_dir)) # for ind in ind_folder[:num_track_browsed]: # for ind in list_tracks_dir: # folder_name = list_tracks_dir[ind] for folder_name in os.listdir(sub_db_path): print '#' * 20 print '#' + folder_name + '\n' folder_path = sub_db_path + '/' + folder_name if not os.path.isdir(folder_path): continue # Get instrus and prs from a folder name name pr0, instru0, T0, path_0, pr1, instru1, T1, path_1 = build_data_aux.get_instru_and_pr_from_folder_path(folder_path, quantization=quantization, clip=True) # name_0 = re.split('/', path_0)[-1] # name_1 = re.split('/', path_1)[-1] ################################################ ################################################ # def auxiaux(pr, limit): # pr_bis = pr # pr = {} # for k,v in pr_bis.iteritems(): # pr[k] = v[:limit,:] # return pr # pr0 = auxiaux(pr0, 26) # pr1 = auxiaux(pr1, 48) ################################################ ################################################ # Get trace from needleman_wunsch algorithm # Traces are binary lists, 0 meaning a gap is inserted trace_0, trace_1, this_sum_score, this_nbId, this_nbDiffs = needleman_chord_wrapper(sum_along_instru_dim(pr0), sum_along_instru_dim(pr1)) # Wrap dictionnaries according to the traces assert(len(trace_0) == len(trace_1)), "size mismatch" pr0_warp = warp_dictionnary_trace(pr0, trace_0) pr1_warp = warp_dictionnary_trace(pr1, trace_1) # In fact we just discard 0 in traces for both pr trace_prod = [e1 * e2 for (e1,e2) in zip(trace_0, trace_1)] if sum(trace_prod) == 0: # It's definitely not a match... # Check for the files : are they really an piano score and its orchestration ?? with(open('log.txt', 'a')) as f: f.write(folder_path + '\n') continue pr0_aligned = remove_zero_in_trace(pr0_warp, trace_prod) pr1_aligned = remove_zero_in_trace(pr1_warp, trace_prod) # Sum all instrument AAA_warp = sum_along_instru_dim(pr0_warp) BBB_warp = sum_along_instru_dim(pr1_warp) OOO_warp = np.zeros((BBB_warp.shape[0], 30), dtype=np.int16) CCC_warp = np.concatenate((AAA_warp, OOO_warp, BBB_warp), axis=1) AAA_aligned = sum_along_instru_dim(pr0_aligned) BBB_aligned = sum_along_instru_dim(pr1_aligned) OOO_aligned = np.zeros((BBB_aligned.shape[0], 30), dtype=np.int16) CCC_aligned = np.concatenate((AAA_aligned, OOO_aligned, BBB_aligned), axis=1) # Update statistics nbFrame += len(trace_0) sum_score += this_sum_score nbId += this_nbId nbDiffs += this_nbDiffs counter = counter + 1 # Save every 100 example if not counter % 10 == 0: continue save_folder_name = output_dir +\ '/' + sub_db + '_' + folder_name if not os.path.exists(save_folder_name): os.makedirs(save_folder_name) temp_csv = save_folder_name + '/warp.csv' np.savetxt(temp_csv, CCC_warp, delimiter=',') dump_to_csv(temp_csv, temp_csv) write_numpy_array_html(save_folder_name + "/pr_warp.html", "warp") temp_csv = save_folder_name + '/aligned.csv' np.savetxt(temp_csv, CCC_aligned, delimiter=',') dump_to_csv(temp_csv, temp_csv) write_numpy_array_html(save_folder_name + "/pr_aligned.html", "aligned") write_midi(pr={'piano1': sum_along_instru_dim(pr0)}, quantization=quantization, write_path=save_folder_name + '/0.mid', tempo=80) write_midi(pr={'piano1': sum_along_instru_dim(pr1)}, quantization=quantization, write_path=save_folder_name + '/1.mid', tempo=80) write_midi(pr={'piano1': AAA_warp, 'piano2': BBB_warp}, quantization=quantization, write_path=save_folder_name + '/both__warp.mid', tempo=80) write_midi(pr={'piano1': AAA_aligned, 'piano2': BBB_aligned}, quantization=quantization, write_path=save_folder_name + '/both__aligned.mid', tempo=80) # Write statistics mean_score = float(sum_score) / nbFrame nbId_norm = nbId / quantization nbDiffs_norm = nbDiffs / quantization with open(output_dir + '/log.txt', 'wb') as f: f.write("##########################\n" + "quantization = %d\n" % quantization + "Gapopen = %d\n" % gapopen + "Gapextend = %d\n" % gapextend + "Number frame = %d\n" % nbFrame + "\n\n\n" + "Sum score = %d\n" % sum_score+ "Mean score = %f\n" % mean_score+ "Number id = %d\n" % nbId + "Number id / quantization = %d\n" % nbId_norm+ "Number diffs = %d\n" % nbDiffs+ "Number diffs / quantization = %d\n" % nbDiffs_norm)
def align_tracks_removing_silences(pr0, pr1, unit_type, gapopen, gapextend): # Mapping_0 is a vector of size pr0, with values of the index in the new pr and -1 for a silence # Remove zeros pr0_no_silence, mapping_0 = remove_silence(pr0) pr1_no_silence, mapping_1 = remove_silence(pr1) # Get trace from needleman_wunsch algorithm # Traces are computed from binaries matrices # Traces are binary lists, 0 meaning a gap is inserted pr0_trace = sum_along_instru_dim(Unit_type.from_type_to_binary(pr0_no_silence, unit_type)) pr1_trace = sum_along_instru_dim(Unit_type.from_type_to_binary(pr1_no_silence, unit_type)) trace_0, trace_1, this_sum_score, this_nbId, this_nbDiffs = needleman_chord_wrapper(pr0_trace, pr1_trace, gapopen, gapextend) #################################### #################################### # Wrap dictionnaries according to the traces assert(len(trace_0) == len(trace_1)), "size mismatch" pr0_warp = warp_dictionnary_trace(pr0_no_silence, trace_0) pr1_warp = warp_dictionnary_trace(pr1_no_silence, trace_1) #################################### #################################### #################################### #################################### # Trace product trace_prod = [e1 * e2 for (e1, e2) in zip(trace_0, trace_1)] duration = sum(trace_prod) if duration == 0: return [None]*5 # Remove gaps pr0_aligned = remove_zero_in_trace(pr0_warp, trace_prod) pr1_aligned = remove_zero_in_trace(pr1_warp, trace_prod) # New mapping : # some element are lost, replace them by silences # and decrease the indices def remove_gaps_mapping(mapping, trace, trace_prod): index = 0 counter = 0 for (t, t_prod) in zip(trace, trace_prod): if (t == 1) and (t_prod == 0): # Element lost while(mapping[index] == -1): index += 1 # Replace i with a silence mapping[index] = -1 elif (t == 1) and (t_prod == 1): while(mapping[index] == -1): index += 1 mapping[index] = counter counter += 1 index += 1 return mapping mapping_0_aligned = remove_gaps_mapping(mapping_0, trace_0, trace_prod) mapping_1_aligned = remove_gaps_mapping(mapping_1, trace_1, trace_prod) # Actually it is easier to have the indices of the non silent frames in the original score : non_silent_0 = np.where(mapping_0_aligned != -1)[0] non_silent_1 = np.where(mapping_1_aligned != -1)[0] #################################### #################################### # # Remove zeros in one score, but not in the other # pr0_no_unmatched_silence, pr1_no_unmatched_silence, duration = remove_unmatched_silence(pr0_aligned, pr1_aligned) # # # Remove zeros in both piano and orchestra : we don't want to learn mapping from zero to zero # pr0_out, pr1_out, duration = remove_match_silence(pr0_no_unmatched_silence, pr1_no_unmatched_silence) return pr0_aligned, non_silent_0, pr1_aligned, non_silent_1, duration