File size: 4,006 Bytes
c1e08a0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""Script for demonstrating pitch detection functionality."""

import argparse
import time

import gradio as gr

from improvisation_lab.config import Config
from improvisation_lab.domain.analysis import PitchDetector
from improvisation_lab.domain.music_theory import Notes
from improvisation_lab.infrastructure.audio import (DirectAudioProcessor,
                                                    WebAudioProcessor)


def create_process_audio(pitch_detector: PitchDetector):
    """Create audio processing callback function.

    Args:
        pitch_detector: PitchDetector instance

    Returns:
        Callback function for processing audio data
    """

    def process_audio(audio_data):
        frequency = pitch_detector.detect_pitch(audio_data)
        if frequency > 0:  # voice detected
            note_name = Notes.convert_frequency_to_note(frequency)
            print(
                f"\rFrequency: {frequency:6.1f} Hz | Note: {note_name:<5}",
                end="",
                flush=True,
            )
        else:  # no voice detected
            print("\rNo voice detected                        ", end="", flush=True)

    return process_audio


def run_direct_audio_demo(config: Config):
    """Run pitch detection demo using microphone input.

    Args:
        config: Configuration object
    """
    pitch_detector = PitchDetector(config.audio.pitch_detector)
    mic_input = DirectAudioProcessor(
        sample_rate=config.audio.sample_rate,
        buffer_duration=config.audio.buffer_duration,
    )

    print("Starting pitch detection demo (Microphone)...")
    print("Sing or hum a note!")
    print("-" * 50)

    try:
        mic_input._callback = create_process_audio(pitch_detector)
        mic_input.start_recording()
        while True:
            time.sleep(0.1)
    except KeyboardInterrupt:
        print("\nStopping...")
    finally:
        mic_input.stop_recording()


def run_web_audio_demo(config: Config):
    """Run pitch detection demo using Gradio interface.

    Args:
        config: Configuration object
    """
    pitch_detector = PitchDetector(config.audio.pitch_detector)
    audio_input = WebAudioProcessor(
        sample_rate=config.audio.sample_rate,
        buffer_duration=config.audio.buffer_duration,
    )

    print("Starting pitch detection demo (Gradio)...")
    result = {"text": "No voice detected"}

    def process_audio(audio_data):
        frequency = pitch_detector.detect_pitch(audio_data)
        if frequency > 0:
            note_name = Notes.convert_frequency_to_note(frequency)
            result["text"] = f"Frequency: {frequency:6.1f} Hz | Note: {note_name}"
        else:
            result["text"] = "No voice detected"

    audio_input._callback = process_audio

    def handle_audio(audio):
        """Handle audio input from Gradio."""
        if audio is None:
            return result["text"]
        if not audio_input.is_recording:
            audio_input.start_recording()
        audio_input.process_audio(audio)
        return result["text"]

    interface = gr.Interface(
        fn=handle_audio,
        inputs=gr.Audio(
            sources=["microphone"],
            streaming=True,
            type="numpy",
        ),
        outputs=gr.Text(label="Detection Result"),
        live=True,
        title="Pitch Detection Demo",
        allow_flagging="never",
        stream_every=0.05,
    )
    interface.queue()
    interface.launch(
        share=False,
        debug=True,
    )


def main():
    """Run the pitch detection demo."""
    parser = argparse.ArgumentParser(description="Run pitch detection demo")
    parser.add_argument(
        "--input",
        choices=["direct", "web"],
        default="web",
        help="Input method (direct: microphone or web: browser)",
    )
    args = parser.parse_args()

    config = Config()

    if args.input == "web":
        run_web_audio_demo(config)
    else:
        run_direct_audio_demo(config)


if __name__ == "__main__":
    main()