Spaces:
Running
Running
| 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) |