From 8c44ff472bd24fc4d22da63f7519e375c004d47f Mon Sep 17 00:00:00 2001 From: DerWaldi Date: Thu, 24 Sep 2020 12:30:06 +0200 Subject: [PATCH 1/4] update obsolete bazel workspace urls --- note_seq/alignment/WORKSPACE | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/note_seq/alignment/WORKSPACE b/note_seq/alignment/WORKSPACE index 39df4da..26d8cad 100644 --- a/note_seq/alignment/WORKSPACE +++ b/note_seq/alignment/WORKSPACE @@ -20,10 +20,9 @@ http_archive( http_archive( name = "eigen_repo", build_file = "//:eigen.BUILD", - sha256 = "7e84ef87a07702b54ab3306e77cea474f56a40afa1c0ab245bb11725d006d0da", - strip_prefix = "eigen-eigen-323c052e1731", + strip_prefix = "eigen-3.3.7", urls = [ - "https://bitbucket.org/eigen/eigen/get/3.3.7.tar.gz", + "https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.zip", ], ) @@ -47,9 +46,8 @@ http_archive( http_archive( name = "bazel_skylib", - sha256 = "bbccf674aa441c266df9894182d80de104cabd19be98be002f6d478aaa31574d", - strip_prefix = "bazel-skylib-2169ae1c374aab4a09aa90e65efe1a3aad4e279b", - urls = ["https://github.com/bazelbuild/bazel-skylib/archive/2169ae1c374aab4a09aa90e65efe1a3aad4e279b.tar.gz"], + strip_prefix = "bazel-skylib-master", + urls = ["https://github.com/bazelbuild/bazel-skylib/archive/master.zip"], ) From c8ea0ba12a28cdc24ebf3ae99daddbbcee19d5fe Mon Sep 17 00:00:00 2001 From: DerWaldi Date: Thu, 24 Sep 2020 12:58:21 +0200 Subject: [PATCH 2/4] update alignement code to python3 --- note_seq/alignment/align_fine.py | 50 +++--- note_seq/alignment/align_fine_lib.py | 242 +++++++++++++-------------- 2 files changed, 146 insertions(+), 146 deletions(-) diff --git a/note_seq/alignment/align_fine.py b/note_seq/alignment/align_fine.py index 1b7fab5..ac8568a 100644 --- a/note_seq/alignment/align_fine.py +++ b/note_seq/alignment/align_fine.py @@ -38,35 +38,35 @@ def main(unused_argv): - logging.set_verbosity(FLAGS.log) - if not os.path.exists(FLAGS.output_dir): - os.makedirs(FLAGS.output_dir) - for input_file in sorted(os.listdir(FLAGS.input_dir)): - if not input_file.endswith('.wav'): - continue - wav_filename = input_file - midi_filename = input_file.replace('.wav', '.mid') - logging.info('Aligning %s to %s', midi_filename, wav_filename) + logging.set_verbosity(FLAGS.log) + if not os.path.exists(FLAGS.output_dir): + os.makedirs(FLAGS.output_dir) + for input_file in sorted(os.listdir(FLAGS.input_dir)): + if not input_file.endswith('.wav'): + continue + wav_filename = input_file + midi_filename = input_file.replace('.wav', '.mid') + logging.info('Aligning %s to %s', midi_filename, wav_filename) - samples = audio_io.load_audio( - os.path.join(FLAGS.input_dir, wav_filename), align_fine_lib.SAMPLE_RATE) - ns = midi_io.midi_file_to_sequence_proto( - os.path.join(FLAGS.input_dir, midi_filename)) + samples = audio_io.load_audio( + os.path.join(FLAGS.input_dir, wav_filename), align_fine_lib.SAMPLE_RATE) + ns = midi_io.midi_file_to_sequence_proto( + os.path.join(FLAGS.input_dir, midi_filename)) - aligned_ns, unused_stats = align_fine_lib.align_cpp( - samples, - align_fine_lib.SAMPLE_RATE, - ns, - align_fine_lib.CQT_HOP_LENGTH_FINE, - sf2_path=FLAGS.sf2_path, - penalty_mul=FLAGS.penalty_mul) + aligned_ns, unused_stats = align_fine_lib.align_cpp( + samples, + align_fine_lib.SAMPLE_RATE, + ns, + align_fine_lib.CQT_HOP_LENGTH_FINE, + sf2_path=FLAGS.sf2_path, + penalty_mul=FLAGS.penalty_mul) - midi_io.sequence_proto_to_midi_file( - aligned_ns, os.path.join(FLAGS.output_dir, midi_filename)) + midi_io.sequence_proto_to_midi_file( + aligned_ns, os.path.join(FLAGS.output_dir, midi_filename)) - logging.info('Done') + logging.info('Done') if __name__ == '__main__': - flags.mark_flags_as_required(['input_dir', 'output_dir']) - app.run(main) + flags.mark_flags_as_required(['input_dir', 'output_dir']) + app.run(main) diff --git a/note_seq/alignment/align_fine_lib.py b/note_seq/alignment/align_fine_lib.py index 38877f3..d60c457 100644 --- a/note_seq/alignment/align_fine_lib.py +++ b/note_seq/alignment/align_fine_lib.py @@ -45,18 +45,18 @@ def extract_cqt(samples, sample_rate, cqt_hop_length): - """Transforms the contents of a wav/mp3 file into a series of CQT frames.""" - cqt = np.abs(librosa.core.cqt( - samples, - sample_rate, - hop_length=cqt_hop_length, - fmin=CQT_FMIN, - n_bins=CQT_N_BINS, - bins_per_octave=CQT_BINS_PER_OCTAVE), dtype=np.float32) + """Transforms the contents of a wav/mp3 file into a series of CQT frames.""" + cqt = np.abs(librosa.core.cqt( + samples, + sample_rate, + hop_length=cqt_hop_length, + fmin=CQT_FMIN, + n_bins=CQT_N_BINS, + bins_per_octave=CQT_BINS_PER_OCTAVE), dtype=np.float32) - # Compute log-amplitude - cqt = librosa.power_to_db(cqt) - return cqt + # Compute log-amplitude + cqt = librosa.power_to_db(cqt) + return cqt def align_cpp(samples, @@ -66,113 +66,113 @@ def align_cpp(samples, sf2_path, penalty_mul=1.0, band_radius_seconds=.5): - """Aligns the notesequence to the wav file using C++ DTW. - - Args: - samples: Samples to align. - sample_rate: Sample rate for samples. - ns: The source notesequence to align. - cqt_hop_length: Hop length to use for CQT calculations. - sf2_path: Path to SF2 file for synthesis. - penalty_mul: Penalty multiplier to use for non-diagonal moves. - band_radius_seconds: What size of band radius to use for restricting DTW. - - Raises: - RuntimeError: If notes are skipped during alignment. - - Returns: - samples: The samples used from the wav file. - aligned_ns: The aligned version of the notesequence. - remaining_ns: Any remaining notesequence that extended beyond the length - of the wav file. - """ - logging.info('Synthesizing') - ns_samples = midi_synth.fluidsynth( - ns, sf2_path=sf2_path, sample_rate=sample_rate).astype(np.float32) - - # It is critical that ns_samples and samples are the same length because the - # alignment code does not do subsequence alignment. - ns_samples = np.pad(ns_samples, - (0, max(0, samples.shape[0] - ns_samples.shape[0])), - 'constant') - - # Pad samples too, if needed, because there are some cases where the - # synthesized NoteSequence is actually longer. - samples = np.pad(samples, - (0, max(0, ns_samples.shape[0] - samples.shape[0])), - 'constant') - - # Note that we skip normalization here becasue it happens in C++. - logging.info('source_cqt') - source_cqt = extract_cqt(ns_samples, sample_rate, cqt_hop_length) - - logging.info('dest_cqt') - dest_cqt = extract_cqt(samples, sample_rate, cqt_hop_length) - - alignment_task = alignment_pb2.AlignmentTask() - alignment_task.sequence_1.x = source_cqt.shape[0] - alignment_task.sequence_1.y = source_cqt.shape[1] - for c in source_cqt.reshape([-1]): - alignment_task.sequence_1.content.append(c) - - alignment_task.sequence_2.x = dest_cqt.shape[0] - alignment_task.sequence_2.y = dest_cqt.shape[1] - for c in dest_cqt.reshape([-1]): - alignment_task.sequence_2.content.append(c) - - seconds_per_frame = cqt_hop_length / sample_rate - - alignment_task.band_radius = int(band_radius_seconds / seconds_per_frame) - alignment_task.penalty = 0 - alignment_task.penalty_mul = penalty_mul - - # Write to file. - fh, temp_path = tempfile.mkstemp(suffix='.proto') - os.close(fh) - with open(temp_path, 'w') as f: - f.write(alignment_task.SerializeToString()) - - # Align with C++ program. - subprocess.check_call([ALIGN_BINARY, temp_path]) - - # Read file. - with open(temp_path + '.result') as f: - result = alignment_pb2.AlignmentResult.FromString(f.read()) - - # Clean up. - os.remove(temp_path) - os.remove(temp_path + '.result') - - logging.info('Aligning NoteSequence with warp path.') - - warp_seconds_i = np.array([i * seconds_per_frame for i in result.i]) - warp_seconds_j = np.array([j * seconds_per_frame for j in result.j]) - - time_diffs = np.abs(warp_seconds_i - warp_seconds_j) - warps = np.abs(time_diffs[1:] - time_diffs[:-1]) - - stats = { - 'alignment_score': result.score, - 'warp_mean_s': np.mean(warps), - 'warp_median_s': np.median(warps), - 'warp_max_s': np.max(warps), - 'warp_min_s': np.min(warps), - 'time_diff_mean_s': np.mean(time_diffs), - 'time_diff_median_s': np.median(time_diffs), - 'time_diff_max_s': np.max(time_diffs), - 'time_diff_min_s': np.min(time_diffs), - } - - for name, value in sorted(stats.iteritems()): - logging.info('%s: %f', name, value) - - aligned_ns, skipped_notes = sequences_lib.adjust_notesequence_times( - ns, - lambda t: np.interp(t, warp_seconds_i, warp_seconds_j), - minimum_duration=seconds_per_frame) - if skipped_notes > 0: - raise RuntimeError('Skipped {} notes'.format(skipped_notes)) - - logging.debug('done') - - return aligned_ns, stats + """Aligns the notesequence to the wav file using C++ DTW. + + Args: + samples: Samples to align. + sample_rate: Sample rate for samples. + ns: The source notesequence to align. + cqt_hop_length: Hop length to use for CQT calculations. + sf2_path: Path to SF2 file for synthesis. + penalty_mul: Penalty multiplier to use for non-diagonal moves. + band_radius_seconds: What size of band radius to use for restricting DTW. + + Raises: + RuntimeError: If notes are skipped during alignment. + + Returns: + samples: The samples used from the wav file. + aligned_ns: The aligned version of the notesequence. + remaining_ns: Any remaining notesequence that extended beyond the length + of the wav file. + """ + logging.info('Synthesizing') + ns_samples = midi_synth.fluidsynth( + ns, sf2_path=sf2_path, sample_rate=sample_rate).astype(np.float32) + + # It is critical that ns_samples and samples are the same length because the + # alignment code does not do subsequence alignment. + ns_samples = np.pad(ns_samples, + (0, max(0, samples.shape[0] - ns_samples.shape[0])), + 'constant') + + # Pad samples too, if needed, because there are some cases where the + # synthesized NoteSequence is actually longer. + samples = np.pad(samples, + (0, max(0, ns_samples.shape[0] - samples.shape[0])), + 'constant') + + # Note that we skip normalization here becasue it happens in C++. + logging.info('source_cqt') + source_cqt = extract_cqt(ns_samples, sample_rate, cqt_hop_length) + + logging.info('dest_cqt') + dest_cqt = extract_cqt(samples, sample_rate, cqt_hop_length) + + alignment_task = alignment_pb2.AlignmentTask() + alignment_task.sequence_1.x = source_cqt.shape[0] + alignment_task.sequence_1.y = source_cqt.shape[1] + for c in source_cqt.reshape([-1]): + alignment_task.sequence_1.content.append(c) + + alignment_task.sequence_2.x = dest_cqt.shape[0] + alignment_task.sequence_2.y = dest_cqt.shape[1] + for c in dest_cqt.reshape([-1]): + alignment_task.sequence_2.content.append(c) + + seconds_per_frame = cqt_hop_length / sample_rate + + alignment_task.band_radius = int(band_radius_seconds / seconds_per_frame) + alignment_task.penalty = 0 + alignment_task.penalty_mul = penalty_mul + + # Write to file. + fh, temp_path = tempfile.mkstemp(suffix='.proto') + os.close(fh) + with open(temp_path, 'wb') as f: + f.write(alignment_task.SerializeToString()) + + # Align with C++ program. + subprocess.check_call([ALIGN_BINARY, temp_path]) + + # Read file. + with open(temp_path + '.result', "rb") as f: + result = alignment_pb2.AlignmentResult.FromString(f.read()) + + # Clean up. + os.remove(temp_path) + os.remove(temp_path + '.result') + + logging.info('Aligning NoteSequence with warp path.') + + warp_seconds_i = np.array([i * seconds_per_frame for i in result.i]) + warp_seconds_j = np.array([j * seconds_per_frame for j in result.j]) + + time_diffs = np.abs(warp_seconds_i - warp_seconds_j) + warps = np.abs(time_diffs[1:] - time_diffs[:-1]) + + stats = { + 'alignment_score': result.score, + 'warp_mean_s': np.mean(warps), + 'warp_median_s': np.median(warps), + 'warp_max_s': np.max(warps), + 'warp_min_s': np.min(warps), + 'time_diff_mean_s': np.mean(time_diffs), + 'time_diff_median_s': np.median(time_diffs), + 'time_diff_max_s': np.max(time_diffs), + 'time_diff_min_s': np.min(time_diffs), + } + + for name, value in sorted(stats.items()): + logging.info('%s: %f', name, value) + + aligned_ns, skipped_notes = sequences_lib.adjust_notesequence_times( + ns, + lambda t: np.interp(t, warp_seconds_i, warp_seconds_j), + minimum_duration=seconds_per_frame) + if skipped_notes > 0: + raise RuntimeError('Skipped {} notes'.format(skipped_notes)) + + logging.debug('done') + + return aligned_ns, stats From 9d32dc65043f3f7b0af5f1213f0070052013aec5 Mon Sep 17 00:00:00 2001 From: DerWaldi Date: Fri, 25 Sep 2020 20:36:14 +0200 Subject: [PATCH 3/4] reformat the code to match 2-space indentation standard --- note_seq/alignment/align_fine.py | 50 +++--- note_seq/alignment/align_fine_lib.py | 242 +++++++++++++-------------- 2 files changed, 146 insertions(+), 146 deletions(-) diff --git a/note_seq/alignment/align_fine.py b/note_seq/alignment/align_fine.py index ac8568a..1b7fab5 100644 --- a/note_seq/alignment/align_fine.py +++ b/note_seq/alignment/align_fine.py @@ -38,35 +38,35 @@ def main(unused_argv): - logging.set_verbosity(FLAGS.log) - if not os.path.exists(FLAGS.output_dir): - os.makedirs(FLAGS.output_dir) - for input_file in sorted(os.listdir(FLAGS.input_dir)): - if not input_file.endswith('.wav'): - continue - wav_filename = input_file - midi_filename = input_file.replace('.wav', '.mid') - logging.info('Aligning %s to %s', midi_filename, wav_filename) + logging.set_verbosity(FLAGS.log) + if not os.path.exists(FLAGS.output_dir): + os.makedirs(FLAGS.output_dir) + for input_file in sorted(os.listdir(FLAGS.input_dir)): + if not input_file.endswith('.wav'): + continue + wav_filename = input_file + midi_filename = input_file.replace('.wav', '.mid') + logging.info('Aligning %s to %s', midi_filename, wav_filename) - samples = audio_io.load_audio( - os.path.join(FLAGS.input_dir, wav_filename), align_fine_lib.SAMPLE_RATE) - ns = midi_io.midi_file_to_sequence_proto( - os.path.join(FLAGS.input_dir, midi_filename)) + samples = audio_io.load_audio( + os.path.join(FLAGS.input_dir, wav_filename), align_fine_lib.SAMPLE_RATE) + ns = midi_io.midi_file_to_sequence_proto( + os.path.join(FLAGS.input_dir, midi_filename)) - aligned_ns, unused_stats = align_fine_lib.align_cpp( - samples, - align_fine_lib.SAMPLE_RATE, - ns, - align_fine_lib.CQT_HOP_LENGTH_FINE, - sf2_path=FLAGS.sf2_path, - penalty_mul=FLAGS.penalty_mul) + aligned_ns, unused_stats = align_fine_lib.align_cpp( + samples, + align_fine_lib.SAMPLE_RATE, + ns, + align_fine_lib.CQT_HOP_LENGTH_FINE, + sf2_path=FLAGS.sf2_path, + penalty_mul=FLAGS.penalty_mul) - midi_io.sequence_proto_to_midi_file( - aligned_ns, os.path.join(FLAGS.output_dir, midi_filename)) + midi_io.sequence_proto_to_midi_file( + aligned_ns, os.path.join(FLAGS.output_dir, midi_filename)) - logging.info('Done') + logging.info('Done') if __name__ == '__main__': - flags.mark_flags_as_required(['input_dir', 'output_dir']) - app.run(main) + flags.mark_flags_as_required(['input_dir', 'output_dir']) + app.run(main) diff --git a/note_seq/alignment/align_fine_lib.py b/note_seq/alignment/align_fine_lib.py index d60c457..96c8d67 100644 --- a/note_seq/alignment/align_fine_lib.py +++ b/note_seq/alignment/align_fine_lib.py @@ -45,18 +45,18 @@ def extract_cqt(samples, sample_rate, cqt_hop_length): - """Transforms the contents of a wav/mp3 file into a series of CQT frames.""" - cqt = np.abs(librosa.core.cqt( - samples, - sample_rate, - hop_length=cqt_hop_length, - fmin=CQT_FMIN, - n_bins=CQT_N_BINS, - bins_per_octave=CQT_BINS_PER_OCTAVE), dtype=np.float32) + """Transforms the contents of a wav/mp3 file into a series of CQT frames.""" + cqt = np.abs(librosa.core.cqt( + samples, + sample_rate, + hop_length=cqt_hop_length, + fmin=CQT_FMIN, + n_bins=CQT_N_BINS, + bins_per_octave=CQT_BINS_PER_OCTAVE), dtype=np.float32) - # Compute log-amplitude - cqt = librosa.power_to_db(cqt) - return cqt + # Compute log-amplitude + cqt = librosa.power_to_db(cqt) + return cqt def align_cpp(samples, @@ -66,113 +66,113 @@ def align_cpp(samples, sf2_path, penalty_mul=1.0, band_radius_seconds=.5): - """Aligns the notesequence to the wav file using C++ DTW. - - Args: - samples: Samples to align. - sample_rate: Sample rate for samples. - ns: The source notesequence to align. - cqt_hop_length: Hop length to use for CQT calculations. - sf2_path: Path to SF2 file for synthesis. - penalty_mul: Penalty multiplier to use for non-diagonal moves. - band_radius_seconds: What size of band radius to use for restricting DTW. - - Raises: - RuntimeError: If notes are skipped during alignment. - - Returns: - samples: The samples used from the wav file. - aligned_ns: The aligned version of the notesequence. - remaining_ns: Any remaining notesequence that extended beyond the length - of the wav file. - """ - logging.info('Synthesizing') - ns_samples = midi_synth.fluidsynth( - ns, sf2_path=sf2_path, sample_rate=sample_rate).astype(np.float32) - - # It is critical that ns_samples and samples are the same length because the - # alignment code does not do subsequence alignment. - ns_samples = np.pad(ns_samples, - (0, max(0, samples.shape[0] - ns_samples.shape[0])), - 'constant') - - # Pad samples too, if needed, because there are some cases where the - # synthesized NoteSequence is actually longer. - samples = np.pad(samples, - (0, max(0, ns_samples.shape[0] - samples.shape[0])), - 'constant') - - # Note that we skip normalization here becasue it happens in C++. - logging.info('source_cqt') - source_cqt = extract_cqt(ns_samples, sample_rate, cqt_hop_length) - - logging.info('dest_cqt') - dest_cqt = extract_cqt(samples, sample_rate, cqt_hop_length) - - alignment_task = alignment_pb2.AlignmentTask() - alignment_task.sequence_1.x = source_cqt.shape[0] - alignment_task.sequence_1.y = source_cqt.shape[1] - for c in source_cqt.reshape([-1]): - alignment_task.sequence_1.content.append(c) - - alignment_task.sequence_2.x = dest_cqt.shape[0] - alignment_task.sequence_2.y = dest_cqt.shape[1] - for c in dest_cqt.reshape([-1]): - alignment_task.sequence_2.content.append(c) - - seconds_per_frame = cqt_hop_length / sample_rate - - alignment_task.band_radius = int(band_radius_seconds / seconds_per_frame) - alignment_task.penalty = 0 - alignment_task.penalty_mul = penalty_mul - - # Write to file. - fh, temp_path = tempfile.mkstemp(suffix='.proto') - os.close(fh) - with open(temp_path, 'wb') as f: - f.write(alignment_task.SerializeToString()) - - # Align with C++ program. - subprocess.check_call([ALIGN_BINARY, temp_path]) - - # Read file. - with open(temp_path + '.result', "rb") as f: - result = alignment_pb2.AlignmentResult.FromString(f.read()) - - # Clean up. - os.remove(temp_path) - os.remove(temp_path + '.result') - - logging.info('Aligning NoteSequence with warp path.') - - warp_seconds_i = np.array([i * seconds_per_frame for i in result.i]) - warp_seconds_j = np.array([j * seconds_per_frame for j in result.j]) - - time_diffs = np.abs(warp_seconds_i - warp_seconds_j) - warps = np.abs(time_diffs[1:] - time_diffs[:-1]) - - stats = { - 'alignment_score': result.score, - 'warp_mean_s': np.mean(warps), - 'warp_median_s': np.median(warps), - 'warp_max_s': np.max(warps), - 'warp_min_s': np.min(warps), - 'time_diff_mean_s': np.mean(time_diffs), - 'time_diff_median_s': np.median(time_diffs), - 'time_diff_max_s': np.max(time_diffs), - 'time_diff_min_s': np.min(time_diffs), - } - - for name, value in sorted(stats.items()): - logging.info('%s: %f', name, value) - - aligned_ns, skipped_notes = sequences_lib.adjust_notesequence_times( - ns, - lambda t: np.interp(t, warp_seconds_i, warp_seconds_j), - minimum_duration=seconds_per_frame) - if skipped_notes > 0: - raise RuntimeError('Skipped {} notes'.format(skipped_notes)) - - logging.debug('done') - - return aligned_ns, stats + """Aligns the notesequence to the wav file using C++ DTW. + + Args: + samples: Samples to align. + sample_rate: Sample rate for samples. + ns: The source notesequence to align. + cqt_hop_length: Hop length to use for CQT calculations. + sf2_path: Path to SF2 file for synthesis. + penalty_mul: Penalty multiplier to use for non-diagonal moves. + band_radius_seconds: What size of band radius to use for restricting DTW. + + Raises: + RuntimeError: If notes are skipped during alignment. + + Returns: + samples: The samples used from the wav file. + aligned_ns: The aligned version of the notesequence. + remaining_ns: Any remaining notesequence that extended beyond the length + of the wav file. + """ + logging.info('Synthesizing') + ns_samples = midi_synth.fluidsynth( + ns, sf2_path=sf2_path, sample_rate=sample_rate).astype(np.float32) + + # It is critical that ns_samples and samples are the same length because the + # alignment code does not do subsequence alignment. + ns_samples = np.pad(ns_samples, + (0, max(0, samples.shape[0] - ns_samples.shape[0])), + 'constant') + + # Pad samples too, if needed, because there are some cases where the + # synthesized NoteSequence is actually longer. + samples = np.pad(samples, + (0, max(0, ns_samples.shape[0] - samples.shape[0])), + 'constant') + + # Note that we skip normalization here becasue it happens in C++. + logging.info('source_cqt') + source_cqt = extract_cqt(ns_samples, sample_rate, cqt_hop_length) + + logging.info('dest_cqt') + dest_cqt = extract_cqt(samples, sample_rate, cqt_hop_length) + + alignment_task = alignment_pb2.AlignmentTask() + alignment_task.sequence_1.x = source_cqt.shape[0] + alignment_task.sequence_1.y = source_cqt.shape[1] + for c in source_cqt.reshape([-1]): + alignment_task.sequence_1.content.append(c) + + alignment_task.sequence_2.x = dest_cqt.shape[0] + alignment_task.sequence_2.y = dest_cqt.shape[1] + for c in dest_cqt.reshape([-1]): + alignment_task.sequence_2.content.append(c) + + seconds_per_frame = cqt_hop_length / sample_rate + + alignment_task.band_radius = int(band_radius_seconds / seconds_per_frame) + alignment_task.penalty = 0 + alignment_task.penalty_mul = penalty_mul + + # Write to file. + fh, temp_path = tempfile.mkstemp(suffix='.proto') + os.close(fh) + with open(temp_path, 'wb') as f: + f.write(alignment_task.SerializeToString()) + + # Align with C++ program. + subprocess.check_call([ALIGN_BINARY, temp_path]) + + # Read file. + with open(temp_path + '.result', "rb") as f: + result = alignment_pb2.AlignmentResult.FromString(f.read()) + + # Clean up. + os.remove(temp_path) + os.remove(temp_path + '.result') + + logging.info('Aligning NoteSequence with warp path.') + + warp_seconds_i = np.array([i * seconds_per_frame for i in result.i]) + warp_seconds_j = np.array([j * seconds_per_frame for j in result.j]) + + time_diffs = np.abs(warp_seconds_i - warp_seconds_j) + warps = np.abs(time_diffs[1:] - time_diffs[:-1]) + + stats = { + 'alignment_score': result.score, + 'warp_mean_s': np.mean(warps), + 'warp_median_s': np.median(warps), + 'warp_max_s': np.max(warps), + 'warp_min_s': np.min(warps), + 'time_diff_mean_s': np.mean(time_diffs), + 'time_diff_median_s': np.median(time_diffs), + 'time_diff_max_s': np.max(time_diffs), + 'time_diff_min_s': np.min(time_diffs), + } + + for name, value in sorted(stats.items()): + logging.info('%s: %f', name, value) + + aligned_ns, skipped_notes = sequences_lib.adjust_notesequence_times( + ns, + lambda t: np.interp(t, warp_seconds_i, warp_seconds_j), + minimum_duration=seconds_per_frame) + if skipped_notes > 0: + raise RuntimeError('Skipped {} notes'.format(skipped_notes)) + + logging.debug('done') + + return aligned_ns, stats From cf81906501dd71907c6ea999c63bc0303abdd1db Mon Sep 17 00:00:00 2001 From: DerWaldi Date: Fri, 25 Sep 2020 21:07:38 +0200 Subject: [PATCH 4/4] change double quotes to single ones --- note_seq/alignment/align_fine_lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/note_seq/alignment/align_fine_lib.py b/note_seq/alignment/align_fine_lib.py index 96c8d67..edc499e 100644 --- a/note_seq/alignment/align_fine_lib.py +++ b/note_seq/alignment/align_fine_lib.py @@ -136,7 +136,7 @@ def align_cpp(samples, subprocess.check_call([ALIGN_BINARY, temp_path]) # Read file. - with open(temp_path + '.result', "rb") as f: + with open(temp_path + '.result', 'rb') as f: result = alignment_pb2.AlignmentResult.FromString(f.read()) # Clean up.