Bils commited on
Commit
7b80999
·
verified ·
1 Parent(s): b1a481e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +26 -73
app.py CHANGED
@@ -1,7 +1,6 @@
1
  import numpy as np
2
  import soundfile as sf
3
  import gradio as gr
4
- import math
5
 
6
  def binauralize(audio_file, simulate_rotation, rotation_speed):
7
  """
@@ -18,25 +17,30 @@ def binauralize(audio_file, simulate_rotation, rotation_speed):
18
  status (str): Status message.
19
  """
20
  try:
 
21
  audio, sr = sf.read(audio_file)
22
  except Exception as e:
23
  return None, f"Error reading input audio file: {e}"
24
 
25
- # Convert to mono if needed.
26
  if audio.ndim > 1:
27
  audio = np.mean(audio, axis=1)
28
 
 
29
  t = np.arange(len(audio)) / sr
30
 
31
  if simulate_rotation:
32
  # Compute a time-varying angle for a full cycle (2π) at the desired rotation speed.
33
  angle = 2 * np.pi * rotation_speed * t
 
34
  left = np.cos(angle) * audio
35
  right = np.sin(angle) * audio
36
  else:
 
37
  left = audio
38
  right = audio
39
 
 
40
  binaural_audio = np.stack((left, right), axis=-1)
41
 
42
  # Normalize to prevent clipping.
@@ -44,6 +48,7 @@ def binauralize(audio_file, simulate_rotation, rotation_speed):
44
  if max_val > 0:
45
  binaural_audio = binaural_audio / max_val
46
 
 
47
  output_file = "output_binaural.wav"
48
  try:
49
  sf.write(output_file, binaural_audio, sr)
@@ -52,66 +57,16 @@ def binauralize(audio_file, simulate_rotation, rotation_speed):
52
 
53
  return output_file, "Binaural conversion complete!"
54
 
55
- def simulate_map(audio_file, listener_x, listener_y):
56
- """
57
- Process an input audio file and simulate binaural panning based on the listener's position.
58
- The source is fixed at (0,0). Listener coordinates (listener_x, listener_y) determine the angle.
59
- Also applies optional distance attenuation.
60
- """
61
- try:
62
- audio, sr = sf.read(audio_file)
63
- except Exception as e:
64
- return None, f"Error reading input audio file: {e}"
65
-
66
- if audio.ndim > 1:
67
- audio = np.mean(audio, axis=1)
68
-
69
- # Compute the angle (in radians) between the listener position and the source at (0,0)
70
- # Here, we use atan2(listener_x, listener_y) so that a positive X (to the right) yields a positive angle.
71
- theta_rad = math.atan2(listener_x, listener_y)
72
- theta_deg = theta_rad * 180 / math.pi
73
-
74
- # Clamp theta to [-90, 90] degrees (for panning purposes)
75
- theta_deg = max(-90, min(90, theta_deg))
76
-
77
- # Map theta from [-90, 90] to a panning parameter p in radians:
78
- # When theta_deg = -90, p = 0 (full left); theta_deg = 0, p = 45° in radians; theta_deg = 90, p = 90° (full right)
79
- p = (theta_deg + 90) * math.pi / 360
80
-
81
- left_gain = math.cos(p)
82
- right_gain = math.sin(p)
83
-
84
- # Optional distance attenuation: the further away the listener, the lower the volume.
85
- distance = math.sqrt(listener_x**2 + listener_y**2)
86
- attenuation = 1 / (1 + distance)
87
-
88
- left = audio * left_gain * attenuation
89
- right = audio * right_gain * attenuation
90
-
91
- binaural_audio = np.stack((left, right), axis=-1)
92
-
93
- max_val = np.max(np.abs(binaural_audio))
94
- if max_val > 0:
95
- binaural_audio = binaural_audio / max_val
96
-
97
- output_file = "output_map.wav"
98
- try:
99
- sf.write(output_file, binaural_audio, sr)
100
- except Exception as e:
101
- return None, f"Error writing output audio file: {e}"
102
-
103
- return output_file, f"Listener: ({listener_x}, {listener_y}), Angle: {theta_deg:.1f}°"
104
-
105
  # Create an enhanced UI using Gradio Blocks and Tabs.
106
  with gr.Blocks(title="SonicOrbit", css="""
 
107
  .title { font-size: 2.5em; font-weight: bold; text-align: center; margin-bottom: 0.5em; }
108
  .subtitle { font-size: 1.2em; text-align: center; margin-bottom: 1em; }
109
  .footer { text-align: center; font-size: 0.9em; margin-top: 2em; color: #555; }
110
- .tab-description { margin: 10px; font-size: 1em; }
111
  """) as demo:
112
 
113
  gr.Markdown("<div class='title'>SonicOrbit</div>")
114
- gr.Markdown("<div class='subtitle'>Binaural 360 Audio Converter & Interactive Map</div>")
115
 
116
  with gr.Tabs():
117
  with gr.Tab("Converter"):
@@ -131,27 +86,25 @@ with gr.Blocks(title="SonicOrbit", css="""
131
  outputs=[output_audio, status_text]
132
  )
133
 
134
- with gr.Tab("Interactive Map"):
135
- gr.Markdown("<div class='tab-description'>Move the listener around the source (fixed at (0,0)) using the sliders. The binaural panning will update based on the listener's position and distance.</div>")
136
- with gr.Row():
137
- map_audio = gr.Audio(type="filepath", label="Upload Audio (Mono or Stereo)")
138
- with gr.Row():
139
- listener_x = gr.Slider(-10, 10, value=0, step=0.1, label="Listener X Position")
140
- listener_y = gr.Slider(-10, 10, value=1, step=0.1, label="Listener Y Position")
141
- map_button = gr.Button("Update Listener Position")
142
- with gr.Row():
143
- map_output = gr.Audio(type="filepath", label="Binaural Map Output")
144
- map_status = gr.Textbox(label="Status", interactive=False)
145
-
146
- map_button.click(
147
- fn=simulate_map,
148
- inputs=[map_audio, listener_x, listener_y],
149
- outputs=[map_output, map_status]
150
- )
151
-
152
  gr.Markdown("""
153
  <div class='footer'>
154
- © 2025 SonicOrbit. All rights reserved.<br>
 
155
  Created with ❤️ by <a href="https://bilsimaging.com" target="_blank" style="color: #88aaff;">bilsimaging.com</a>
156
  and this <a href="https://visitorbadge.io/status?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2FBils%2FSonicOrbit" target="_blank">
157
  <img src="https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2FBils%2FSonicOrbit&countColor=%23263759" alt="visitor badge" /></a>
 
1
  import numpy as np
2
  import soundfile as sf
3
  import gradio as gr
 
4
 
5
  def binauralize(audio_file, simulate_rotation, rotation_speed):
6
  """
 
17
  status (str): Status message.
18
  """
19
  try:
20
+ # Load input audio file
21
  audio, sr = sf.read(audio_file)
22
  except Exception as e:
23
  return None, f"Error reading input audio file: {e}"
24
 
25
+ # If the audio is stereo, convert to mono by averaging channels
26
  if audio.ndim > 1:
27
  audio = np.mean(audio, axis=1)
28
 
29
+ # Create a time vector for the audio length
30
  t = np.arange(len(audio)) / sr
31
 
32
  if simulate_rotation:
33
  # Compute a time-varying angle for a full cycle (2π) at the desired rotation speed.
34
  angle = 2 * np.pi * rotation_speed * t
35
+ # Constant power panning: left uses cosine, right uses sine.
36
  left = np.cos(angle) * audio
37
  right = np.sin(angle) * audio
38
  else:
39
+ # If rotation is not enabled, duplicate the audio to both channels.
40
  left = audio
41
  right = audio
42
 
43
+ # Combine the channels into a stereo signal.
44
  binaural_audio = np.stack((left, right), axis=-1)
45
 
46
  # Normalize to prevent clipping.
 
48
  if max_val > 0:
49
  binaural_audio = binaural_audio / max_val
50
 
51
+ # Save the output to a WAV file.
52
  output_file = "output_binaural.wav"
53
  try:
54
  sf.write(output_file, binaural_audio, sr)
 
57
 
58
  return output_file, "Binaural conversion complete!"
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  # Create an enhanced UI using Gradio Blocks and Tabs.
61
  with gr.Blocks(title="SonicOrbit", css="""
62
+ /* Custom CSS to enhance spacing and font styling */
63
  .title { font-size: 2.5em; font-weight: bold; text-align: center; margin-bottom: 0.5em; }
64
  .subtitle { font-size: 1.2em; text-align: center; margin-bottom: 1em; }
65
  .footer { text-align: center; font-size: 0.9em; margin-top: 2em; color: #555; }
 
66
  """) as demo:
67
 
68
  gr.Markdown("<div class='title'>SonicOrbit</div>")
69
+ gr.Markdown("<div class='subtitle'>Binaural 360 Audio Converter with Dynamic Rotation</div>")
70
 
71
  with gr.Tabs():
72
  with gr.Tab("Converter"):
 
86
  outputs=[output_audio, status_text]
87
  )
88
 
89
+ with gr.Tab("Instructions"):
90
+ gr.Markdown("""
91
+ ### How to Use SonicOrbit
92
+ 1. **Upload Audio:**
93
+ Upload a mono or stereo audio file. If you upload a stereo file, it will be converted to mono by averaging the channels.
94
+ 2. **Simulate Rotation:**
95
+ Enable this option to apply a dynamic panning effect that simulates a rotating sound source.
96
+ 3. **Rotation Speed:**
97
+ Adjust the slider to set the speed of the rotation effect (in Hertz). A higher value rotates the audio field faster.
98
+ 4. **Convert Audio:**
99
+ Click the **Convert Audio** button to process your audio file. The output is a binaural (stereo) audio file with the simulated 360° effect.
100
+
101
+ Enjoy your immersive 3D audio experience!
102
+ """)
103
+
 
 
 
104
  gr.Markdown("""
105
  <div class='footer'>
106
+ © 2025 SonicOrbit. All rights reserved.
107
+ <br>
108
  Created with ❤️ by <a href="https://bilsimaging.com" target="_blank" style="color: #88aaff;">bilsimaging.com</a>
109
  and this <a href="https://visitorbadge.io/status?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2FBils%2FSonicOrbit" target="_blank">
110
  <img src="https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2FBils%2FSonicOrbit&countColor=%23263759" alt="visitor badge" /></a>