import os import re import tqdm import collections import argparse import numpy as np from suno_utils.audio import Audio from suno_utils.utils.text import write_jsonl, read_jsonl, write_json, read_json, normalize_whitespace from suno_utils.utils.s3 import read_from_s3, check_s3_file_exists, open_from_s3 METAS_DIR = "/app/suno/data/audio_mono_24khz/pond5/" # get track metadata metas_fn = os.path.join(METAS_DIR, "pond5_metadata.jsonl") track_paths = [] if os.path.exists(metas_fn): print("files exsist") metas = read_jsonl(metas_fn) track_paths = np.load(os.path.join(METAS_DIR, "file_paths.npy")) print("files loaded") else: def _clean_tag(s): if s is None or not isinstance(s, str): return "" # remove symbold with special meaning s = re.sub(r"[\{\}\_\[\]]", " ", s) # squash whitespace return normalize_whitespace(s) pd5_base_metas = read_from_s3("s3://suno-data/datasets/bundles/v2/pond5_music/metas.jsonl", read_f=read_jsonl) pd5_extra_metas = read_from_s3("s3://suno-data/datasets/harvest/pond5_music/pond5_metas.jsonl", read_f=read_jsonl) extra_info = {} seen_ids = set() genre_counter = collections.Counter() for m in tqdm.tqdm(pd5_extra_metas): if "s3_filepath" not in m: continue if m["id"] in seen_ids: continue if m["duration"] < 30: continue if m["duration"] > 60 * 4: continue name = m.get("name", "") description = m.get("description", "") tags = m.get("tags", []) genre = m.get("genre", "") if not genre: continue genre_counter[genre.lower().strip()] += 1 if not description or not tags or not name: continue if len(description.strip().split()) < 10: continue if len(description.strip().split()) > 100: continue if not isinstance(tags, list) or len(tags) < 5 or len(tags) > 50: continue # if there are weird tags if max(len(tag) for tag in tags) > 30: continue extra_info[m["id"]] = { "name": name if isinstance(name, str) else "", "description": (description if isinstance(description, str) else ""), "tags": ([genre] if genre else []) + tags if isinstance(tags, list) else "", } seen_ids.add(m["id"]) metas = [] total_duration = 0 n_c =0 for m in tqdm.tqdm(pd5_base_metas): # if n_c > 5: # break if m["id"] not in seen_ids: continue n_c += 1 info = extra_info[m["id"]] new_m = {"id": m["id"]} # print(m, info) tags = [ info["name"], info["description"], ] tags.extend(info["tags"]) tags = [_clean_tag(t) for t in tags] tags = [t for t in tags if len(t) > 0] if len(tags) > 10: new_m["tags"] = list(set(tags)) metas.append(new_m) total_duration += m["duration_s"] track_paths.append(m.get("audio_filepath", m.get("s3_filepath", m.get("filepath")))) print(f"{len(metas):,} entries, total duration {total_duration/60/60:,.0f} hr") write_jsonl(metas, os.path.join(METAS_DIR, "pond5_metadata.jsonl")) np.save(open(os.path.join(METAS_DIR, "file_paths.npy"), "wb"), track_paths) # parse parser = argparse.ArgumentParser() parser.add_argument("--index", required=True, help="partial index") parser.add_argument("--num_partial", required=True, help="number of partial data") args = parser.parse_args() index = int(args.index) num_partial = int(args.num_partial) # split data hop = len(metas) // num_partial if index == num_partial: metas = metas[hop * index - 1:] track_paths = track_paths[hop * index - 1:] else: metas = metas[hop * index : (index + 1) * hop] track_paths = track_paths[hop * index : (index + 1) * hop] # resample audio print("start resampling...") audio_path = "/app/suno/data/audio_mono_24khz/pond5/audio/" for i in tqdm.tqdm(range(len(metas))): _id = metas[i]["id"] save_path = os.path.join(audio_path, _id + ".wav") if not os.path.exists(save_path): audio = Audio.from_s3(track_paths[i], sample_rate=24000, n_channels=1) audio.write_wav(save_path)