diff --git a/.gitignore b/.gitignore index 090a1f0..047759f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .idea .DS_Store +tmp +*.mp3 diff --git a/dashboard_pianoroll.py b/dashboard_pianoroll.py index 61af6c8..fee2d65 100644 --- a/dashboard_pianoroll.py +++ b/dashboard_pianoroll.py @@ -1,9 +1,9 @@ import os import pandas as pd -import fortepyan as ff import streamlit as st from fortepyan import MidiFile, MidiPiece +from streamlit_pianoroll import from_fortepyan from fortepyan.audio import render as render_audio from fortepyan.analytics.clustering import process as clustering_process @@ -32,49 +32,65 @@ def generated_piece_av(piece: MidiPiece, save_base: str) -> dict: def main(): uploaded_file = st.file_uploader("Choose a file", type=["midi", "mid"]) - if uploaded_file is not None: piece = MidiFile(uploaded_file).piece st.markdown("### Showing a pianoroll of the uploaded MIDI file") - fig = ff.view.draw_pianoroll_with_velocities(piece) - st.pyplot(fig, clear_figure=True) - - generated_piece_av(piece, "uploaded_file") - st.audio("uploaded_file.mp3") + from_fortepyan(piece, key=0) - n_clustering = st.number_input(label="N parameter:", value=16) + n_clustering = 16 st.markdown("The N parameter specifies how many consecutive pitch values are used to distinguish identical fragments") + df = clustering_process.run(piece, n=n_clustering) fragments = prepare_fragments(df=df, piece=piece, n=n_clustering) + filtering_method = st.selectbox( + label="Filtering method", + options=["Top 5", "Fastest", "Longest"], + ) + st.markdown("## Summary") n_fragments = len(fragments) st.markdown(f"Detected: {n_fragments} fragments") - for it, fragment in enumerate(fragments): - st.markdown(f"### Fragment {it}") - - variants = fragment["variants"] - n_variants = len(variants) + if filtering_method == "Top 5": + filtered_fragments = top_five_filtering(fragments) + elif filtering_method == "Fastest": + filtered_fragments = fastest_filtering(fragments) + elif filtering_method == "Longest": + filtered_fragments = longest_filtering(fragments) + else: + raise ValueError(f"Unknown filtering method: {filtering_method}") + + st.markdown("## Filtered Fragments") + for it, fragment in enumerate(filtered_fragments): + st.markdown(f"### Filtered Fragment {it}") + n_variants = len(fragment) st.markdown(f"This fragment has {n_variants} variants") + for it_v, variant in enumerate(fragment): + start = variant["start_note_index"] + finish = variant["finish_note_index"] + part_piece = piece[start:finish] + + st.markdown("Showing a pianoroll for one of the variants") + st.markdown(f"This variant has {part_piece.size} notes and {part_piece.duration:.2f} seconds") + + widget_key = f"widget_{it}_{it_v}" + from_fortepyan(part_piece, key=widget_key) + + +def top_five_filtering(fragments: list[list[dict]]): + return fragments[:5] - variant = variants[0] - start = variant["start_note_index"] - finish = variant["finish_note_index"] - part_piece = piece[start:finish] - st.markdown("Showing a pianoroll for one of the variants") - st.markdown(f"This variant has {part_piece.size} notes and {part_piece.duration:.2f} seconds") +def fastest_filtering(fragments: list[list[dict]]): + return sorted(fragments, key=lambda x: sum(v["finish_time"] - v["start_time"] for v in x))[:5] - fig = ff.view.draw_pianoroll_with_velocities(part_piece) - st.pyplot(fig, clear_figure=True) - generated_piece_av(part_piece, "part_piece") - st.audio("part_piece.mp3") +def longest_filtering(fragments: list[list[dict]]): + return sorted(fragments, key=lambda x: sum(v["finish_time"] - v["start_time"] for v in x), reverse=True)[:5] -def prepare_fragments(df: pd.DataFrame, piece: MidiPiece, n: int) -> list[dict]: - # Unpack +def prepare_fragments(df: pd.DataFrame, piece: MidiPiece, n: int) -> list[list[dict]]: fragments = [] for it, row in df.iterrows(): variants = [] @@ -87,15 +103,14 @@ def prepare_fragments(df: pd.DataFrame, piece: MidiPiece, n: int) -> list[dict]: finish_idx = min(finish_idx, piece.size - 1) finish_time = piece.df.iloc[finish_idx].end - variant = dict( - start_time=start_time, - finish_time=finish_time, - start_note_index=int(start_idx), - finish_note_index=int(finish_idx), - ) + variant = { + "start_time": start_time, + "finish_time": finish_time, + "start_note_index": start_idx, + "finish_note_index": finish_idx, + } variants.append(variant) - fragment = dict(variants=variants) - fragments.append(fragment) + fragments.append(variants) return fragments