'''
This script will take your recorded test tracks with their 1kHz pilot tone and subsequent silence after the sweep in 96kHz format.
It will cut out the sweep and, depending on your desired operation, swap channels, so that the measurement script can do its work.
This script assumes that you are using a "temp" subfolder in the directory where your script is located.
The "temp" subfolder is where your recorded audio files should be located.
The naming convention used is that your recorded files are named "1007_L+R.wav" if you recorded Track 3 or 11 on your 1007 Test Record.
This is only good for the Frequency Response and Harmonics; it will NOT give you a Crosstalk measurement!
If you recorded Track 1 or 9 and 2 or 10 of a 1007 Test Record, the files should be named "1007_L.wav" and "1007_R.wav".
The script will prompt you for the variant you want to execute and save "wavefile1.wav" and "wavefile2.wav" in the same temp folder.
You can now go on and use the measurement script. Please check that your naming convention fits these scripts.
1 - Single File, Split Channels
2 - Separate Files, Swap Channels
You may need to adjust your "post_pilot_duration" (in seconds) if the script cuts too early or late for your setup.
'''
import os
import numpy as np
from scipy.io import wavfile
from scipy.signal import stft, butter, sosfilt
def bandpass_filter(data, sample_rate, lowcut=18, highcut=22, order=5):
sos = butter(order, [lowcut / (0.5 * sample_rate), highcut / (0.5 * sample_rate)], btype='band', output='sos')
return sosfilt(sos, data)
def detect_sweep_start(data, sample_rate, post_pilot_duration=50.5):
filtered_data = bandpass_filter(data, sample_rate)
f, t, Zxx = stft(filtered_data, fs=sample_rate, nperseg=1024)
target_freq_index = np.argmin(np.abs(f - 20))
magnitude = np.abs(Zxx[target_freq_index, :])
threshold = np.max(magnitude) * 0.1
sweep_start_idx = np.where(magnitude > threshold)[0][0]
sweep_start_time = t[sweep_start_idx]
sweep_end_time = sweep_start_time + post_pilot_duration
return sweep_start_time, sweep_end_time
def save_trimmed_audio(data, sample_rate, start_time, end_time, source_file, file_name='wavefile', swap_channels=False):
start_sample = int(start_time * sample_rate)
end_sample = int(end_time * sample_rate)
trimmed_data = data[start_sample:end_sample]
if swap_channels and trimmed_data.shape[1] > 1:
trimmed_data = trimmed_data[:, [1, 0]]
output_dir = os.path.dirname(source_file) if source_file else '.'
output_path = os.path.join(output_dir, f"{file_name}.wav")
wavfile.write(output_path, sample_rate, trimmed_data)
return output_path
def process_audio():
choice = input("Choose operation mode:\n1. Single file, split channels\n2. Separate files, with channel swap\nEnter 1 or 2: ")
base_path = os.path.join(os.path.dirname(__file__), 'temp')
if choice == '1':
source_audio_file = os.path.join(base_path, '1007_L+R_Downsample.wav')
sample_rate, data = wavfile.read(source_audio_file)
mono_data = data.mean(axis=1) if data.ndim > 1 else data
sweep_start_time, sweep_end_time = detect_sweep_start(mono_data, sample_rate)
left_file, right_file = save_trimmed_audio(data, sample_rate, sweep_start_time, sweep_end_time, source_audio_file, "wavefile")
print(f"Trimmed audio files saved as {left_file} and {right_file}")
elif choice == '2':
left_audio_file = os.path.join(base_path, '1007_L.wav')
right_audio_file = os.path.join(base_path, '1007_R.wav')
sample_rate, data_left = wavfile.read(left_audio_file)
sweep_start_time, sweep_end_time = detect_sweep_start(data_left.mean(axis=1), sample_rate)
wavefile1_path = save_trimmed_audio(data_left, sample_rate, sweep_start_time, sweep_end_time, left_audio_file, "wavefile1")
sample_rate, data_right = wavfile.read(right_audio_file)
sweep_start_time, sweep_end_time = detect_sweep_start(data_right.mean(axis=1), sample_rate)
wavefile2_path = save_trimmed_audio(data_right, sample_rate, sweep_start_time, sweep_end_time, right_audio_file, "wavefile2", swap_channels=True)
print(f"Trimmed audio files saved as {wavefile1_path} and {wavefile2_path}")
else:
print("Invalid choice. Please run the script again and enter 1 or 2.")
if __name__ == "__main__":
process_audio()