ziqiangao commited on
Commit
13586a0
·
1 Parent(s): 26c1442

surround presets

Browse files
Files changed (1) hide show
  1. app.py +49 -23
app.py CHANGED
@@ -22,15 +22,15 @@ def convert_to_wav_float(input_file):
22
  return temp_wav.name
23
 
24
 
25
- def apply_reverb_wet_only(audio, samplerate):
26
  """
27
- Apply wet-only reverb using SoX to a single channel.
28
  """
29
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tin, \
30
  tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tout:
31
  sf.write(tin.name, audio, samplerate, subtype='FLOAT')
32
  subprocess.run(
33
- ["sox", tin.name, tout.name, "reverb", '-w', '85', '50', '100', '95', '10', '-2'],
34
  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True
35
  )
36
  wet, _ = sf.read(tout.name, dtype='float32')
@@ -39,6 +39,7 @@ def apply_reverb_wet_only(audio, samplerate):
39
  return wet
40
 
41
 
 
42
  def sox_filter(audio, samplerate, filter_type, cutoff):
43
  """
44
  Apply highpass or lowpass filter via SoX.
@@ -82,38 +83,55 @@ def extract_phantom_center(input_file, rdf=0.99999):
82
  return fs, FL[:len(L)], FR[:len(R)], FC[:len(M)]
83
 
84
 
85
- def create_5_1_surround(input_file):
86
- # 1. Extract fronts and centre
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  fs, FL, FR, FC = extract_phantom_center(input_file)
88
 
89
- # 2. Read original for reverb and LFE source as float WAV
90
  wav = convert_to_wav_float(input_file)
91
  stereo, _ = sf.read(wav, dtype='float32')
92
  os.unlink(wav)
93
- L_orig, R_orig = stereo[:,0], stereo[:,1]
94
 
95
- # 3. Wet-only reverb for surrounds using original L/R
96
- SL = apply_reverb_wet_only(L_orig, fs)
97
- SR = apply_reverb_wet_only(R_orig, fs)
98
 
99
- # 4. High-pass filter to all but LFE
100
- FL_hp = sox_filter(FL, fs, 'highpass', 120)
101
- FR_hp = sox_filter(FR, fs, 'highpass', 120)
102
- FC_hp = sox_filter(FC, fs, 'highpass', 120)
103
- SL_hp = sox_filter(SL, fs, 'highpass', 120)
104
- SR_hp = sox_filter(SR, fs, 'highpass', 120)
105
 
106
- # 5. LFE from pre-filtered sum of FL/FR
107
  bass_sum = 0.5 * (FL + FR)
108
- LFE = sox_filter(bass_sum, fs, 'lowpass', 120)
109
 
110
- # 6. Pad to equal length
111
  channels = [FL_hp, FR_hp, FC_hp, LFE, SL_hp, SR_hp]
112
  length = max(len(ch) for ch in channels)
113
  def pad(x): return np.pad(x, (0, length - len(x)))
114
  multich = np.column_stack([pad(ch) for ch in channels])
115
 
116
- # 7. Write and encode
117
  out_wav = tempfile.NamedTemporaryFile(suffix='.wav', delete=False)
118
  sf.write(out_wav.name, multich, fs, subtype='FLOAT')
119
  out_wav.close()
@@ -126,14 +144,22 @@ def create_5_1_surround(input_file):
126
  os.unlink(out_wav.name)
127
  return out_ogg.name
128
 
 
129
  # ========== Gradio UI ==========
130
  with gr.Blocks(title="Stereo to 5.1 Surround") as demo:
131
  gr.Markdown("# 🎧 Stereo to 5.1 OGG Converter")
132
- gr.Markdown("Phantom centre extraction + wet-only reverb on original L/R + sox highpass/lowpass + float I/O")
 
133
  inp = gr.Audio(label="Upload stereo audio", type="filepath")
 
 
 
 
 
134
  btn = gr.Button("Convert to 5.1 OGG")
135
  out = gr.File(label="Download 5.1 OGG")
136
- btn.click(fn=create_5_1_surround, inputs=[inp], outputs=[out])
 
137
 
138
  if __name__ == "__main__":
139
- demo.launch()
 
22
  return temp_wav.name
23
 
24
 
25
+ def apply_reverb_wet_only(audio, samplerate, reverb_args):
26
  """
27
+ Apply wet-only reverb using SoX to a single channel with custom reverb args.
28
  """
29
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tin, \
30
  tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tout:
31
  sf.write(tin.name, audio, samplerate, subtype='FLOAT')
32
  subprocess.run(
33
+ ["sox", tin.name, tout.name, "reverb", "-w"] + reverb_args,
34
  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True
35
  )
36
  wet, _ = sf.read(tout.name, dtype='float32')
 
39
  return wet
40
 
41
 
42
+
43
  def sox_filter(audio, samplerate, filter_type, cutoff):
44
  """
45
  Apply highpass or lowpass filter via SoX.
 
83
  return fs, FL[:len(L)], FR[:len(R)], FC[:len(M)]
84
 
85
 
86
+ def create_5_1_surround(input_file, preset="music"):
87
+ # Preset-based parameters
88
+ # Reverberance (50%) HF-damping (50%) room-scale (100%) stereo-depth (100%) pre-delay (0ms) wet-gain (0dB)
89
+ if preset == "music":
90
+ hp_cutoff = 120
91
+ lfe_cutoff = 120
92
+ reverb_args = ['85', '70', '100', '95', '10', '-2']
93
+ elif preset == "speech":
94
+ hp_cutoff = 120
95
+ lfe_cutoff = 120
96
+ reverb_args = ['50', '99', '50', '70', '0', '0']
97
+ elif preset == "open":
98
+ hp_cutoff = 120
99
+ lfe_cutoff = 120
100
+ reverb_args = ['20', '50', '100', '100', '100', '0']
101
+ else:
102
+ raise ValueError(f"Unknown preset: {preset}")
103
+
104
+ # 1. Extract FL/FR/phantom centre
105
  fs, FL, FR, FC = extract_phantom_center(input_file)
106
 
107
+ # 2. Get stereo original for reverb
108
  wav = convert_to_wav_float(input_file)
109
  stereo, _ = sf.read(wav, dtype='float32')
110
  os.unlink(wav)
111
+ L_orig, R_orig = stereo[:, 0], stereo[:, 1]
112
 
113
+ # 3. Wet-only reverb with chosen settings
114
+ SL = apply_reverb_wet_only(L_orig, fs, reverb_args)
115
+ SR = apply_reverb_wet_only(R_orig, fs, reverb_args)
116
 
117
+ # 4. Highpass filter everything except LFE
118
+ FL_hp = sox_filter(FL, fs, 'highpass', hp_cutoff)
119
+ FR_hp = sox_filter(FR, fs, 'highpass', hp_cutoff)
120
+ FC_hp = sox_filter(FC, fs, 'highpass', hp_cutoff)
121
+ SL_hp = sox_filter(SL, fs, 'highpass', hp_cutoff)
122
+ SR_hp = sox_filter(SR, fs, 'highpass', hp_cutoff)
123
 
124
+ # 5. Lowpass for LFE
125
  bass_sum = 0.5 * (FL + FR)
126
+ LFE = sox_filter(bass_sum, fs, 'lowpass', lfe_cutoff)
127
 
128
+ # 6. Stack and pad
129
  channels = [FL_hp, FR_hp, FC_hp, LFE, SL_hp, SR_hp]
130
  length = max(len(ch) for ch in channels)
131
  def pad(x): return np.pad(x, (0, length - len(x)))
132
  multich = np.column_stack([pad(ch) for ch in channels])
133
 
134
+ # 7. Write WAV and encode to OGG
135
  out_wav = tempfile.NamedTemporaryFile(suffix='.wav', delete=False)
136
  sf.write(out_wav.name, multich, fs, subtype='FLOAT')
137
  out_wav.close()
 
144
  os.unlink(out_wav.name)
145
  return out_ogg.name
146
 
147
+
148
  # ========== Gradio UI ==========
149
  with gr.Blocks(title="Stereo to 5.1 Surround") as demo:
150
  gr.Markdown("# 🎧 Stereo to 5.1 OGG Converter")
151
+ gr.Markdown("Choose music or speech preset for surround processing")
152
+
153
  inp = gr.Audio(label="Upload stereo audio", type="filepath")
154
+ preset = gr.Dropdown(
155
+ label="Select Preset",
156
+ choices=["music", "speech", "open"],
157
+ value="music" # or whichever you want as the default
158
+ )
159
  btn = gr.Button("Convert to 5.1 OGG")
160
  out = gr.File(label="Download 5.1 OGG")
161
+
162
+ btn.click(fn=create_5_1_surround, inputs=[inp, preset], outputs=[out])
163
 
164
  if __name__ == "__main__":
165
+ demo.launch()