code: def create_metadata(
      output_filename,
      n_sessions,
      configs,
      utterances_dict,
      words_dict,
      rir_list,
      impulsive_noises_list=None,
      background_noises_list=None,
  ):
      dataset_metadata = {}
      for n_sess in tqdm(range(n_sessions)):
          # we sample randomly n_speakers ids
          c_speakers = np.random.choice(
              list(utterances_dict.keys()),
              configs["n_speakers"],
              replace=False,
          )
          # we select all utterances from selected speakers
          c_utts = [utterances_dict[spk_id] for spk_id in c_speakers]
  
          activity = {}
          for spk in c_speakers:
              activity[spk] = []
  
          tot_length = 0
          min_spk_lvl = np.inf
          for i in range(len(c_speakers)):
              c_spk = c_speakers[i]
              spk_utts = c_utts[i]
              np.random.shuffle(spk_utts)  # random shuffle
              # we use same technique as in EEND repo for intervals distribution
              intervals = np.random.exponential(
                  configs["interval_factor_speech"], len(spk_utts)
              )
              cursor = 0
              for j, wait in enumerate(intervals):
                  meta, channel = _read_metadata(spk_utts[j], configs)
                  c_rir = np.random.choice(rir_list, 1)[0]
                  # check if the rir is monaural
                  meta_rir, rir_channel = _read_metadata(c_rir, configs)
                  length = meta.num_frames / meta.sample_rate
                  id_utt = Path(spk_utts[j]).stem
                  cursor += wait
                  if cursor + length > configs["max_length"]:
                      break
  
                  lvl = np.clip(
                      np.random.normal(
                          configs["speech_lvl_mean"],
                          configs["speech_lvl_var"],
                      ),
                      configs["speech_lvl_min"],
                      configs["speech_lvl_max"],
                  )
                  min_spk_lvl = min(lvl, min_spk_lvl)
                  # we save to metadata only relative paths
                  activity[c_spk].append(
                      {
                          "start": cursor,
                          "stop": cursor + length,
                          "words": words_dict[id_utt],
                          "rir": str(
                              Path(c_rir).relative_to(
                                  configs["rirs_noises_root"]
                              )
                          ),
                          "utt_id": id_utt,
                          "file": str(
                              Path(spk_utts[j]).relative_to(
                                  configs["librispeech_root"]
                              )
                          ),
                          "lvl": lvl,
                          "channel": channel,
                          "rir_channel": rir_channel,
                      }
                  )
                  tot_length = max(cursor + length, tot_length)
                  cursor = cursor + length
  
          # we add also impulsive noises as it were a speaker
          if impulsive_noises_list:
              activity["noises"] = []
              # sampling intervals for impulsive noises.
              intervals = np.random.exponential(
                  configs["interval_factor_noises"],
                  len(impulsive_noises_list),
              )
              cursor = 0
              for j, wait in enumerate(intervals):
                  # we sample with replacement an impulsive noise.
                  c_noise = np.random.choice(impulsive_noises_list, 1)[
                      0
                  ]
                  meta, channel = _read_metadata(c_noise, configs)
                  c_rir = np.random.choice(rir_list, 1)[0]
                  # we reverberate it.
                  meta_rir, rir_channel = _read_metadata(c_rir, configs)
                  length = meta.num_frames / meta.sample_rate
                  cursor += wait
                  if cursor + length > configs["max_length"]:
                      break
                  lvl = np.clip(
                      np.random.normal(
                          configs["imp_lvl_mean"],
                          configs["imp_lvl_var"],
                      ),
                      configs["imp_lvl_min"],
                      min(min_spk_lvl + configs["imp_lvl_rel_max"], 0),
                  )
  
                  activity["noises"].append(
                      {
                          "start": cursor,
                          "stop": cursor + length,
                          "rir": str(
                              Path(c_rir).relative_to(
                                  configs["rirs_noises_root"]
                              )
                          ),
                          "file": str(
                              Path(c_noise).relative_to(
                                  configs["rirs_noises_root"]
                              )
                          ),
                          "lvl": lvl,
                          "channel": channel,
                          "rir_channel": rir_channel,
                      }
                  )
                  tot_length = max(tot_length, cursor + length)
                  cursor += length
  
          if background_noises_list:
              # we add also background noise.
              lvl = np.random.randint(
                  configs["background_lvl_min"],
                  min(
                      min_spk_lvl + configs["background_lvl_rel_max"], 0
                  ),
              )
              # we scale the level but do not reverberate.
              background = np.random.choice(background_noises_list, 1)[
                  0
              ]
              meta, channel = _read_metadata(background, configs)
              assert (
                  meta.num_frames
                  >= configs["max_length"] * configs["samplerate"]
              ), "background noise files should be >= max_length in duration"
              offset = 0
              if (
                  meta.num_frames
                  > configs["max_length"] * configs["samplerate"]
              ):
                  offset = np.random.randint(
                      0,
                      meta.num_frames
                      - int(
                          configs["max_length"] * configs["samplerate"]
                      ),
                  )
  
              activity["background"] = {
                  "start": 0,
                  "stop": tot_length,
                  "file": str(
                      Path(background).relative_to(
                          configs["backgrounds_root"]
                      )
                  ),
                  "lvl": lvl,
                  "orig_start": offset,
                  "orig_stop": offset
                  + int(tot_length * configs["samplerate"]),
                  "channel": channel,
              }
          else:
              # we use as background gaussian noise
              lvl = np.random.randint(
                  configs["background_lvl_min"],
                  min(
                      min_spk_lvl + configs["background_lvl_rel_max"], 0
                  ),
              )
              activity["background"] = {
                  "start": 0,
                  "stop": tot_length,
                  "file": None,
                  "lvl": lvl,
                  "orig_start": None,
                  "orig_stop": None,
                  "channel": None,
              }
  
          dataset_metadata["session_{}".format(n_sess)] = activity
  
      with open(output_filename + ".json", "w") as f:
          json.dump(dataset_metadata, f, indent=4)
  
imports: import numpy
  from pathlib import Path
  import json
  from tqdm import tqdm
  import torchaudio
label_desc: Use image node_id 2 for calling a global function with example usage: create_metadata(output_filename, n_sessions, configs, utterances_dict, words_dict, rir_list, impulsive_noises_list, background_noises_list) without return types