import gradio as gr from chord_extractor.extractors import Chordino import pandas as pd # Initialize the extractor once chordino = Chordino() # Minimum duration to consider a chord "real" (0.4s is usually a good sweet spot for standard tempos) MIN_DURATION = 0.4 def format_timestamp(ts): """Convert seconds to mm:ss format""" minutes = int(ts // 60) seconds = int(ts % 60) return f"{minutes}:{seconds:02}" def process_audio(audio_path): if audio_path is None: return None, "Please upload an audio file." try: # Extract raw chords extracted_chords = chordino.extract(audio_path) if not extracted_chords: return None, "No chords could be detected." filtered_data = [] # Process the sequence of chords for i in range(len(extracted_chords)): current = extracted_chords[i] # 1. Calculate the duration of the current chord by looking at the next chord if i + 1 < len(extracted_chords): duration = extracted_chords[i+1].timestamp - current.timestamp else: duration = 999.0 # The last chord rings out to the end of the song # 2. Skip tiny passing notes/artifacts (unless it's the very first chord) if duration < MIN_DURATION and i != 0: continue # 3. Skip extremely short 'N' (No Chord / Silence) artifacts if current.chord == 'N' and duration < 1.0: continue # 4. Prevent duplicate consecutive chords in the final table if filtered_data and filtered_data[-1][1] == current.chord: continue # If it passes all filters, add it to our display data filtered_data.append([format_timestamp(current.timestamp), current.chord]) return filtered_data, f"Successfully extracted {len(filtered_data)} stable chord changes." except Exception as e: return None, f"Error: {str(e)}" # Define Gradio interface with gr.Blocks(title="Guitar Chord Extractor") as demo: gr.Markdown("# 🎸 Guitar Chord Extractor") gr.Markdown("Upload an audio file (mp3, wav, flac) to extract the chord progression. Fast passing tones and noise are automatically filtered out.") with gr.Row(): with gr.Column(): audio_input = gr.Audio(label="Upload Audio", type="filepath") submit_btn = gr.Button("Extract Chords", variant="primary") with gr.Column(): status_output = gr.Textbox(label="Status") chord_output = gr.Dataframe( headers=["Timestamp", "Chord"], datatype=["str", "str"], # 'str' is the correct Gradio datatype label="Extracted Progression" ) submit_btn.click( fn=process_audio, inputs=[audio_input], outputs=[chord_output, status_output] ) # Launch the app if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860)