import numpy as np import soundfile as sf import librosa import os from scipy.signal import butter, filtfilt, stft, istft # Step 1: Load audio files def load_audio(audio_path): audio, sr = librosa.load(audio_path, sr=48000) #audio, fs = sf.read(audio_path) return audio, sr # Step 2: Detect effective signal bandwidth def detect_bandwidth_org(signal, fs, energy_threshold=0.95): f, t, Zxx = stft(signal, fs=fs) psd = np.abs(Zxx)**2 total_energy = np.sum(psd) cumulative_energy = np.cumsum(np.sum(psd, axis=1)) / total_energy f_low = f[np.argmax(cumulative_energy > (1 - energy_threshold))] f_high = f[np.argmax(cumulative_energy >= energy_threshold)] return f_low, f_high def detect_bandwidth(signal, fs, energy_threshold=0.99): f, t, Zxx = stft(signal, fs=fs) psd = np.abs(Zxx)**2 total_energy = np.sum(psd) cumulative_energy = np.cumsum(np.sum(psd, axis=1)) / total_energy # Exclude DC component (0 Hz) valid_indices = np.where(f > 0)[0] f_low = f[valid_indices][np.argmax(cumulative_energy[valid_indices] > (1 - energy_threshold))] f_high = f[np.argmax(cumulative_energy >= energy_threshold)] return f_low, f_high # Step 3: Apply bandpass and lowpass filters def bandpass_filter(signal, fs, f_low, f_high): nyquist = 0.5 * fs low = f_low / nyquist high = f_high / nyquist b, a = butter(N=4, Wn=[low, high], btype='band') return filtfilt(b, a, signal) def lowpass_filter(signal, fs, cutoff): nyquist = 0.5 * fs cutoff_normalized = cutoff / nyquist b, a = butter(N=4, Wn=cutoff_normalized, btype='low') return filtfilt(b, a, signal) def highpass_filter(signal, fs, cutoff): nyquist = 0.5 * fs cutoff_normalized = cutoff / nyquist b, a = butter(N=4, Wn=cutoff_normalized, btype='high') return filtfilt(b, a, signal) # Step 4: Replace bandwidth def replace_bandwidth(signal1, signal2, fs, f_low, f_high): # Extract effective band from signal1 #effective_band = bandpass_filter(signal1, fs, f_low, f_high) effective_band = lowpass_filter(signal1, fs, f_high) # Extract lowpass band from signal2 #signal2_lowpass = lowpass_filter(signal2, fs, f_high) signal2_highpass = highpass_filter(signal2, fs, f_high) # Match lengths of the two signals min_length = min(len(effective_band), len(signal2_highpass)) effective_band = effective_band[:min_length] signal2_highpass = signal2_highpass[:min_length] # Combine the two signals return signal2_highpass + effective_band # Step 5: Smooth transitions def smooth_transition(signal1, signal2, fs, transition_band=100): fade = np.linspace(0, 1, int(transition_band * fs / 1000)) crossfade = np.concatenate([fade, np.ones(len(signal1) - len(fade))]) min_length = min(len(signal1), len(signal2)) smoothed_signal = (1 - crossfade) * signal2[:min_length] + crossfade * signal1[:min_length] return smoothed_signal # Step 6: Save audio def save_audio(file_path, audio, fs): sf.write(file_path, audio, fs) def bandwidth_sub(low_bandwidth_audio, high_bandwidth_audio, fs=48000): # Detect effective bandwidth of the first signal f_low, f_high = detect_bandwidth(low_bandwidth_audio, fs) # Replace the lower frequency of the second audio substituted_audio = replace_bandwidth(low_bandwidth_audio, high_bandwidth_audio, fs, f_low, f_high) # Optional: Smooth the transition smoothed_audio = smooth_transition(substituted_audio, low_bandwidth_audio, fs) return smoothed_audio # Main process if __name__ == "__main__": low_spectra_dir = 'LJSpeech_22k' upper_spectra_dir = 'LJSpeech_22k_hifi-sr_speech_g_03925000' output_dir = upper_spectra_dir+'_restored' if not os.path.exists(output_dir): os.mkdir(output_dir) filelist = [file for file in os.listdir(low_spectra_dir) if file.endswith('.wav')] for audio_name in filelist: audio1, fs1 = load_audio(low_spectra_dir + "/" + audio_name) # Source for effective bandwidth audio2, fs2 = load_audio(upper_spectra_dir + "/" + audio_name.replace('.wav', '_generated.wav')) # Target audio to replace lower frequencies if fs1 != 48000 or fs2 != 48000: raise ValueError("Both audio files must have a sampling rate of 48 kHz.") # Detect effective bandwidth of the first signal f_low, f_high = detect_bandwidth(audio1, fs1) print(f"Effective bandwidth: {f_low} Hz to {f_high} Hz") # Replace the lower frequency of the second audio replaced_audio = replace_bandwidth(audio1, audio2, fs2, f_low, f_high) # Optional: Smooth the transition smoothed_audio = smooth_transition(replaced_audio, audio1, fs1) # Save the result save_audio(output_dir+"/"+audio_name, smoothed_audio, fs2)