File size: 6,432 Bytes
d9da484
 
 
5d53ece
d9da484
5d53ece
d9da484
 
 
5d53ece
 
 
d9da484
 
 
 
 
5d53ece
d9da484
 
 
 
 
 
5d53ece
d9da484
 
 
 
7b80999
d9da484
 
 
5d53ece
 
 
 
 
 
6a1e9e7
 
5d53ece
 
 
 
 
 
 
7b80999
d9da484
 
 
 
 
7b80999
d9da484
 
 
7b80999
d9da484
 
 
7b80999
d9da484
 
 
 
 
 
 
7b80999
d9da484
 
 
 
 
 
5d53ece
d9da484
 
 
7b80999
d9da484
 
 
 
 
 
5d53ece
d9da484
 
 
 
732135c
d9da484
 
5d53ece
 
d9da484
 
0a324b7
d9da484
 
 
 
5d53ece
d9da484
 
 
7b80999
 
 
 
 
 
 
 
5d53ece
 
 
 
7b80999
 
 
 
 
2f3270f
 
7b80999
 
2f3270f
3f05781
 
 
 
 
2f3270f
 
 
3f05781
d9da484
 
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
143
import numpy as np
import soundfile as sf
import gradio as gr
import librosa

def binauralize(audio_file, simulate_rotation, rotation_speed, auto_rotation):
    """
    Simulate a binaural (stereo) effect by applying a dynamic panning effect 
    to an input audio file. No HRIR files are required.

    If auto_rotation is enabled, AI beat detection (via librosa) is used to 
    determine the rotation speed based on the tempo of the audio.
    
    Parameters:
        audio_file (str): Path to input audio file (mono or stereo).
        simulate_rotation (bool): If True, apply a dynamic rotation (panning) effect.
        rotation_speed (float): Speed of the rotation effect (in Hz).
        auto_rotation (bool): If True, auto-detect rotation speed using AI beat detection.
        
    Returns:
        output_file (str): Path to the output stereo audio file.
        status (str): Status message.
    """
    try:
        # Load input audio file using soundfile
        audio, sr = sf.read(audio_file)
    except Exception as e:
        return None, f"Error reading input audio file: {e}"
    
    # If the audio is stereo, convert to mono by averaging channels
    if audio.ndim > 1:
        audio = np.mean(audio, axis=1)
    
    # If auto_rotation is enabled, use librosa to detect tempo and adjust rotation speed.
    if auto_rotation:
        try:
            # librosa expects float32 input.
            audio_float = audio.astype(np.float32)
            tempo, _ = librosa.beat.beat_track(y=audio_float, sr=sr)
            # Cast tempo to float in case it's a NumPy array.
            tempo = float(tempo)
            rotation_speed = tempo / 60.0  # Convert BPM to Hz (approx.)
            status_msg = f"Auto rotation enabled: Detected tempo = {tempo:.1f} BPM, setting rotation speed = {rotation_speed:.3f} Hz."
        except Exception as e:
            status_msg = f"Auto rotation failed, using user provided rotation speed. Error: {e}"
    else:
        status_msg = "Using user provided rotation speed."
    
    # Create a time vector for the audio length
    t = np.arange(len(audio)) / sr
    
    if simulate_rotation:
        # Compute a time-varying angle for a full cycle (2π) at the desired rotation speed.
        angle = 2 * np.pi * rotation_speed * t
        # Constant power panning: left uses cosine, right uses sine.
        left = np.cos(angle) * audio
        right = np.sin(angle) * audio
    else:
        # If rotation is not enabled, duplicate the audio to both channels.
        left = audio
        right = audio
    
    # Combine the channels into a stereo signal.
    binaural_audio = np.stack((left, right), axis=-1)
    
    # Normalize to prevent clipping.
    max_val = np.max(np.abs(binaural_audio))
    if max_val > 0:
        binaural_audio = binaural_audio / max_val
    
    # Save the output to a WAV file.
    output_file = "output_binaural.wav"
    try:
        sf.write(output_file, binaural_audio, sr)
    except Exception as e:
        return None, f"Error writing output audio file: {e}"
    
    return output_file, f"Binaural conversion complete! {status_msg}"

# Create an enhanced UI using Gradio Blocks and Tabs.
with gr.Blocks(title="SonicOrbit", css="""
    /* Custom CSS to enhance spacing and font styling */
    .title { font-size: 2.5em; font-weight: bold; text-align: center; margin-bottom: 0.5em; }
    .subtitle { font-size: 1.2em; text-align: center; margin-bottom: 1em; }
    .footer { text-align: center; font-size: 0.9em; margin-top: 2em; color: #555; }
    """) as demo:
    
    gr.Markdown("<div class='title'>SonicOrbit</div>")
    gr.Markdown("<div class='subtitle'>Binaural 360 Audio Converter with Dynamic Rotation & AI Beat Detection</div>")
    
    with gr.Tabs():
        with gr.Tab("Converter"):
            with gr.Row():
                input_audio = gr.Audio(type="filepath", label="Upload Audio (Mono or Stereo)")
            with gr.Row():
                simulate_rotation = gr.Checkbox(label="Simulate Rotation", value=True)
                rotation_speed = gr.Slider(0.01, 5.0, value=0.1, step=0.01, label="Rotation Speed (Hz)")
                auto_rotation = gr.Checkbox(label="Auto Detect Rotation Speed (AI)", value=False)
            convert_button = gr.Button("Convert Audio")
            with gr.Row():
                output_audio = gr.Audio(type="filepath", label="Binaural Audio Output")
                status_text = gr.Textbox(label="Status", interactive=False)
            
            convert_button.click(
                fn=binauralize,
                inputs=[input_audio, simulate_rotation, rotation_speed, auto_rotation],
                outputs=[output_audio, status_text]
            )
            
        with gr.Tab("Instructions"):
            gr.Markdown("""
            ### How to Use SonicOrbit
            1. **Upload Audio:**  
               Upload a mono or stereo audio file. If you upload a stereo file, it will be converted to mono by averaging the channels.
            2. **Simulate Rotation:**  
               Enable this option to apply a dynamic panning effect that simulates a rotating sound source.
            3. **Rotation Speed:**  
               Adjust the slider to set the speed of the rotation effect (in Hertz).
            4. **Auto Detect Rotation Speed (AI):**  
               Enable this option to let SonicOrbit analyze your audio and automatically set the rotation speed based on the detected tempo.
            5. **Convert Audio:**  
               Click the **Convert Audio** button to process your audio file. The output is a binaural (stereo) audio file with the simulated 360° effect.
               
            Enjoy your immersive 3D audio experience!
            """)
    
    gr.Markdown("""
    <div class='footer'>
      © 2025 SonicOrbit. All rights reserved.
      <br>
      Created with ❤️ by <a href="https://bilsimaging.com" target="_blank" style="color: #88aaff;">bilsimaging.com</a>
    </div>
    """)
    gr.HTML("""
    <div style="text-align: center; margin-top: 1rem;">
       <a href="https://visitorbadge.io/status?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2FBils%2FSonicOrbit" target="_blank">
      <img src="https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2FBils%2FSonicOrbit&countColor=%23263759" alt="visitor badge" /></a>
    </div>
    """)
    
if __name__ == "__main__":
    demo.launch()