| import os |
| import glob |
| import torch |
| import torchaudio |
| import torchaudio.transforms as T |
| from tqdm import tqdm |
|
|
| def merge_audio_data(root_dir, output_wav_root, output_tsv_path): |
| """ |
| 遍历 root_dir 下的 lst 文件,将 prompt 和 target 音频拼接。 |
| 输出音频到 output_wav_root,输出元数据到 output_tsv_path。 |
| """ |
| |
| |
| sub_dirs = ['en', 'zh'] |
| silence_duration = 0.1 |
| |
| |
| os.makedirs(output_wav_root, exist_ok=True) |
| |
| tsv_lines = [] |
| |
| print(f"Scanning root directory: {root_dir}") |
|
|
| |
| lst_files = [] |
| for lang in sub_dirs: |
| lang_dir = os.path.join(root_dir, lang) |
| if not os.path.exists(lang_dir): |
| continue |
| curr_lst_files = glob.glob(os.path.join(lang_dir, "*.lst")) |
| lst_files.extend(curr_lst_files) |
|
|
| print(f"Found {len(lst_files)} .lst files.") |
|
|
| success_count = 0 |
| |
| for lst_path in tqdm(lst_files, desc="Merging Audios"): |
| |
| |
| lang_category = os.path.basename(os.path.dirname(lst_path)) |
| |
| |
| save_dir = os.path.join(output_wav_root, lang_category) |
| os.makedirs(save_dir, exist_ok=True) |
| |
| base_dir = os.path.dirname(lst_path) |
|
|
| with open(lst_path, 'r', encoding='utf-8') as f: |
| for line in f: |
| line = line.strip() |
| if not line: |
| continue |
| |
| parts = line.split('|') |
| if len(parts) < 4: |
| continue |
| |
| utt_id = parts[0] |
| prompt_text = parts[1] |
| prompt_rel_path = parts[2] |
| target_text = parts[3] |
|
|
| |
| |
| |
| if lang_category == 'zh': |
| |
| full_text = f"{prompt_text}{target_text}" |
| else: |
| |
| full_text = f"{prompt_text} {target_text}" |
|
|
| |
| |
| |
| prompt_abs_path = os.path.join(base_dir, prompt_rel_path) |
| target_abs_path = os.path.join(base_dir, "wavs", f"{utt_id}.wav") |
| |
| new_filename = f"{utt_id}_merged.wav" |
| new_file_path = os.path.join(save_dir, new_filename) |
| |
| if not (os.path.exists(prompt_abs_path) and os.path.exists(target_abs_path)): |
| continue |
|
|
| try: |
| |
| |
| |
| |
| wav_p, sr_p = torchaudio.load(prompt_abs_path) |
| wav_t, sr_t = torchaudio.load(target_abs_path) |
| |
| |
| if wav_p.shape[0] > 1: wav_p = torch.mean(wav_p, dim=0, keepdim=True) |
| if wav_t.shape[0] > 1: wav_t = torch.mean(wav_t, dim=0, keepdim=True) |
|
|
| |
| target_sr = sr_p |
| |
| if sr_t != target_sr: |
| resampler = T.Resample(sr_t, target_sr) |
| wav_t = resampler(wav_t) |
| |
| |
| silence_samples = int(silence_duration * target_sr) |
| silence_wav = torch.zeros(1, silence_samples) |
|
|
| |
| merged_wav = torch.cat([wav_p, silence_wav, wav_t], dim=1) |
| |
| |
| torchaudio.save(new_file_path, merged_wav, target_sr) |
| |
| |
| total_duration = merged_wav.shape[1] / target_sr |
| |
| |
| tsv_lines.append(f"{new_file_path}\t{full_text}\t{total_duration:.4f}\t{target_sr}") |
| success_count += 1 |
| |
| except Exception as e: |
| print(f"[Error] Failed to process {utt_id}: {e}") |
| continue |
|
|
| |
| print(f"Saving metadata to {output_tsv_path}...") |
| with open(output_tsv_path, 'w', encoding='utf-8') as f: |
| for line in tsv_lines: |
| f.write(line + "\n") |
| |
| print(f"Done. Processed {success_count} files.") |
|
|
| if __name__ == "__main__": |
| |
| INPUT_ROOT = "/workspace/echoloc/datas/ntu_enzh_speech/" |
| OUTPUT_WAV_ROOT = "/workspace/echoloc/datas/ntu_enzh_speech/merged_reconstruction/wavs" |
| OUTPUT_TSV_PATH = "/workspace/echoloc/datas/ntu_enzh_speech/merged_reconstruction/test_merged.tsv" |
| |
| merge_audio_data(INPUT_ROOT, OUTPUT_WAV_ROOT, OUTPUT_TSV_PATH) |
|
|