//  [python]
def run(args):
    num_bins, config_dict = parse_yaml(args.config)
    dataloader_conf = config_dict["dataloader"]
    spectrogram_conf = config_dict["spectrogram_reader"]
    # Load cmvn
    # default: True
    IPD_sincos = config_dict["trainer"]["IPD_sincos"]
    config_dict["model"]["IPD_sincos"] = IPD_sincos
    apply_log = dataloader_conf["apply_log"] if "apply_log" in dataloader_conf else True
    if config_dict["model_type"] == "Conformer":
        nnet = ConformerCSS(**config_dict["model"])

    CSS_config = config_dict["inference"]["CSS_conf"]
    frame_length = spectrogram_conf["frame_length"]
    frame_shift = spectrogram_conf["frame_shift"]
    # window = spectrogram_conf["window"]
    window = scipy.signal.windows.hann(frame_length)
    if frame_length//4 == frame_shift:
        const = (2/3)**0.5
        window = const*window
    elif frame_length//2 == frame_shift:
        window = window**0.5
    
    separator = Separator(nnet, config_dict["inference"]["check_point_dir"], cuda=args.cuda, gpu_id=args.gpu_id)
    
    utt_dict = parse_scps(args.wave_scp)
    num_utts = 0
    for key, utt in utt_dict.items():
        try:
            if config_dict["model"]["num_mics"] == 1:
                samps_in,_ = audio_lib.load(utt, sr=None,mono=True)
            else:
                samps_in,_ = audio_lib.load(utt, sr=None,mono=False)
            samps_factor = 10
            samps_in = samps_in * samps_factor
            samps, stft_mat = stft(
                samps_in,
                frame_length=frame_length,
                frame_shift=frame_shift,
                window=window,
                center=True,
                return_samps=True)
        except FileNotFoundError:
            print("Skip utterance {}... not found".format(key))
            continue
        print("Processing utterance {}".format(key))
        num_utts += 1
        # norm = np.linalg.norm(samps, np.inf)
        mvn = config_dict["trainer"]["mvn"]
        if CSS_config["CSS"]:
            (chunk_list, chunk_shift, N_h, 
             dummy_frame_len, stft_mat_pad) = CSS_chunk_generator(CSS_config, stft_mat, frame_shift)
            spk_spect_chunk = [0,0]
            spk_mvdr_chunk = [0,0]
            for idx, (whole_begin, whole_end) in enumerate(chunk_list):
                stft_mat_chunk = stft_mat_pad[whole_begin:whole_end,:,:]
                spk_mask, spk_spect, spk_mvdr = separator.seperate(
                    stft_mat_chunk, mvn=mvn, apply_log=apply_log)
                if idx == 0:
                    pre_spk_mask_chunk = spk_mask[:,chunk_shift:]
                    spk_mask_chunk = copy.deepcopy(spk_mask[:,N_h:N_h+chunk_shift])
                    spk_mask_stack = copy.deepcopy(spk_mask)
                    mask_concat = copy.deepcopy(spk_mask_chunk)
                    mask_stack = copy.deepcopy(spk_mask_stack[:,:,:,None])
                    spk_spect_out = copy.deepcopy([spk[N_h:N_h+chunk_shift] for spk in spk_spect])
                    spk_mvdr_out = copy.deepcopy([spk[N_h:N_h+chunk_shift] for spk in spk_mvdr])
                else:
                    # Concatenate with the output order aligned
                    align_hypo = [masks_similarity(pre_spk_mask_chunk,spk_mask[:,:-chunk_shift,:],p)
                                    for p in permutations(range(config_dict["model"]["num_spks"]))]
                    align_hypo_val = np.array([i[0] for i in align_hypo])
                    mask_order = align_hypo[align_hypo_val.argmax()][1]
                    for s, t in enumerate(mask_order):
                        pre_spk_mask_chunk[s] = spk_mask[t,chunk_shift:]
                        spk_mask_chunk[s] = spk_mask[t,N_h:N_h+chunk_shift]
                        spk_mask_stack[s] = spk_mask[t]
                        spk_spect_chunk[s] = spk_spect[t][N_h:N_h+chunk_shift]
                        spk_mvdr_chunk[s] = spk_mvdr[t][N_h:N_h+chunk_shift]
                    mask_concat = np.concatenate((mask_concat,spk_mask_chunk),axis=1)
                    mask_stack = np.concatenate((mask_stack,spk_mask_stack[:,:,:,None]),axis=-1)
                    spk_spect_out = [np.concatenate((spk_spect_out[idx],spk),axis=0) for idx, spk in enumerate(spk_spect_chunk)]
                    spk_mvdr_out = [np.concatenate((spk_mvdr_out[idx],spk), axis=0) for idx, spk in enumerate(spk_mvdr_chunk)]
            spk_spect_out = [spk[:-dummy_frame_len] for spk in spk_spect_out]
            spk_mvdr_out = [spk[:-dummy_frame_len] for spk in spk_mvdr_out]
            mask_mean = mask_concat[:,:-dummy_frame_len,:].mean(-1)
            mask_mean = [np.convolve(mask_mean[i], np.ones(50)/50, mode='same') for i in range(2)]
            spk_mvdr_out = [spk_mvdr_out[i]*mask_mean[i][...,None] for i in range(2)]
        else:
            if len(stft_mat.shape) == 3:
                spk_mask, spk_spect_out, spk_mvdr_out = separator.seperate(
                    stft_mat, mvn=mvn, apply_log=apply_log, cos_sin_opt=IPD_sincos)
            else:
                spk_mask, spk_spect_out = separator.seperate(
                    stft_mat, mvn=mvn, apply_log=apply_log)
                spk_mvdr_out = None

        for index, stft_mat in enumerate(spk_spect_out):
            samps_out = istft(
                stft_mat,
                frame_length=frame_length,
                frame_shift=frame_shift,
                window=window,
                center=True,
                norm=config_dict["inference"]["save_conf"]["wav_norm"],
                fs=16000,
                nsamps=samps.shape[-1])
            file = os.path.join(args.dump_dir,'wav', '{}_{}.wav'.format(key[:-4], index))
            fdir = os.path.dirname(file)
            if fdir and not os.path.exists(fdir):
                os.makedirs(fdir)
            # sf.write(file, samps_out, 16000)
            wf.write(file, 16000, samps_out / samps_factor)
            # sf.write(file, samps_out / samps_factor, 16000)
            if spk_mvdr_out:
                samps_out = istft(spk_mvdr_out[index],
                    frame_length=frame_length,
                    frame_shift=frame_shift,
                    window=window,
                    center=True,
                    norm=config_dict["inference"]["save_conf"]["wav_norm"],
                    fs=16000,
                    nsamps=samps.shape[-1])
                file = os.path.join(args.dump_dir,'mvdr', '{}_{}.wav'.format(key[:-4], index))
                fdir = os.path.dirname(file)
                if fdir and not os.path.exists(fdir):
                    os.makedirs(fdir)
                # sf.write(file, samps_out, 16000)
                wf.write(file, 16000, samps_out / samps_factor)
                # sf.write(file, samps_out / samps_factor, 16000)
            if args.dump_mask:
                if CSS_config["CSS"]:
                    file_concat = os.path.join(args.dump_dir,'mask_concat','{}_{}.mat'.format(key[:-4], index))
                    fdir_concat = os.path.dirname(file_concat)
                    if fdir_concat and not os.path.exists(fdir_concat): os.makedirs(fdir_concat)
                    sio.savemat(file_concat, {"mask": mask_concat[index]})                    

                    file_stack = os.path.join(args.dump_dir,'mask_stack','{}_{}.mat'.format(key[:-4], index))
                    fdir_stack = os.path.dirname(file_stack)
                    if fdir_stack and not os.path.exists(fdir_stack): os.makedirs(fdir_stack)
                    sio.savemat(file_stack, {"mask": mask_stack[index]})
                    if index == 0:
                        file_stamp = os.path.join(args.dump_dir,'mask_stack','{}_stamp.mat'.format(key[:-4]))
                        fdir_stamp = os.path.dirname(file_stamp)
                        if fdir_stamp and not os.path.exists(fdir_stamp): os.makedirs(fdir_stamp)
                        sio.savemat(file_stamp, {"chunk_stamp": np.array(chunk_list)})
                else:
                    file = os.path.join(args.dump_dir,'mask','{}_{}.mat'.format(key[:-4], index))
                    fdir = os.path.dirname(file)
                    if fdir and not os.path.exists(fdir): os.makedirs(fdir)
                    sio.savemat(file, {"mask": spk_mask[index]})

    if CSS_config["CSS"]:
        print("Processed {} segments!".format(num_utts))
    else:
        print("Processed {} utterance!".format(num_utts))