def generate_coarse(
        self,
        x_semantic: mx.array,
        voice: str = "announcer",
        temperature: float = 0.7,
        max_coarse_history: int = 60,  # min 60 (faster), max 630 (more context)
        sliding_window_len: int = 60,
        use_kv_caching: bool = False,
        **kwargs,
    ):
        """Generate coarse tokens from semantic tokens."""
        verbose = kwargs.get("verbose", False)
        if verbose:
            print("Generating coarse tokens...")
        semantic_to_coarse_ratio = (
            COARSE_RATE_HZ / SEMANTIC_RATE_HZ * N_COARSE_CODEBOOKS
        )
        max_semantic_history = int(
            math.floor(max_coarse_history / semantic_to_coarse_ratio)
        )
        if voice is not None:
            voice_prompt = _load_voice_prompt(voice)
            x_semantic_history = mx.array(voice_prompt["semantic_prompt"])
            x_coarse_history = mx.array(voice_prompt["coarse_prompt"])
            assert (
                isinstance(x_semantic_history, mx.array)
                and len(x_semantic_history.shape) == 1
                and len(x_semantic_history) > 0
                and x_semantic_history.min() >= 0
                and x_semantic_history.max() <= SEMANTIC_VOCAB_SIZE - 1
                and isinstance(x_coarse_history, mx.array)
                and len(x_coarse_history.shape) == 2
                and x_coarse_history.shape[0] == N_COARSE_CODEBOOKS
                and x_coarse_history.shape[-1] >= 0
                and x_coarse_history.min() >= 0
                and x_coarse_history.max() <= CODEBOOK_SIZE - 1
                and (
                    round(x_coarse_history.shape[-1] / len(x_semantic_history), 1)
                    == round(semantic_to_coarse_ratio / N_COARSE_CODEBOOKS, 1)
                )
            )
            x_coarse_history = (
                _flatten_codebooks(x_coarse_history) + SEMANTIC_VOCAB_SIZE
            )
            # trim histories correctly
            n_semantic_hist_provided = min(
                max_semantic_history,
                len(x_semantic_history) - len(x_semantic_history) % 2,
                int(math.floor(len(x_coarse_history) / semantic_to_coarse_ratio)),
            )
            n_coarse_hist_provided = int(
                round(n_semantic_hist_provided * semantic_to_coarse_ratio)
            )
            x_semantic_history = x_semantic_history[-n_semantic_hist_provided:].astype(
                mx.int32
            )
            x_coarse_history = x_coarse_history[-n_coarse_hist_provided:].astype(
                mx.int32
            )
            # TODO: bit of a hack for time alignment (sounds better)
            x_coarse_history = x_coarse_history[:-2]
        else:
            x_semantic_history = mx.array([], dtype=mx.int32)
            x_coarse_history = mx.array([], dtype=mx.int32)

        n_steps = int(
            round(
                math.floor(
                    len(x_semantic) * semantic_to_coarse_ratio / N_COARSE_CODEBOOKS
                )
                * N_COARSE_CODEBOOKS
            )
        )
        x_semantic = mx.concatenate([x_semantic_history, x_semantic]).astype(mx.int32)
        x_coarse = x_coarse_history.astype(mx.int32)
        base_semantic_idx = len(x_semantic_history)
        # Inference
        x_semantic_in = x_semantic.reshape(1, -1)
        x_coarse_in = x_coarse.reshape(1, -1)
        n_window_steps = int(round(n_steps / sliding_window_len))
        n_step = 0
        for _ in tqdm.tqdm(
            range(n_window_steps), total=n_window_steps, disable=not verbose
        ):
            semantic_idx = base_semantic_idx + int(
                round(n_step / semantic_to_coarse_ratio)
            )
            x_in = x_semantic_in[:, max(0, semantic_idx - max_semantic_history) :]
            x_in = x_in[:, :256]
            x_in = mx.pad(
                x_in,
                ((0, 0), (0, 256 - x_in.shape[-1])),
                constant_values=COARSE_SEMANTIC_PAD_TOKEN,
            )
            x_in = mx.concatenate(
                [
                    x_in,
                    mx.array([COARSE_INFER_TOKEN]).reshape(1, -1),
                    x_coarse_in[:, -max_coarse_history:],
                ],
                axis=1,
            )
            kv_cache = None
            for _ in range(sliding_window_len):
                if n_step >= n_steps:
                    continue
                is_major_step = n_step % N_COARSE_CODEBOOKS == 0
                x_input = (
                    x_in[:, -1:] if use_kv_caching and kv_cache is not None else x_in
                )
                logits, kv_cache = self.model.coarse_acoustics(
                    x_input, use_cache=use_kv_caching, past_kv=kv_cache
                )
                logit_start_idx = (
                    SEMANTIC_VOCAB_SIZE + (1 - int(is_major_step)) * CODEBOOK_SIZE
                )
                logit_end_idx = (
                    SEMANTIC_VOCAB_SIZE + (2 - int(is_major_step)) * CODEBOOK_SIZE
                )
                logit_end_idx = min(logit_end_idx, logits.shape[-1])
                relevant_logits = logits[0, 0, logit_start_idx:logit_end_idx]
                item_next = mx.random.categorical(
                    relevant_logits * (1 / temperature), num_samples=1
                ).astype(mx.int32)

                item_next += logit_start_idx
                x_coarse_in = mx.concatenate(
                    [x_coarse_in, item_next.reshape(1, 1)], axis=1
                )
                x_in = mx.concatenate([x_in, item_next.reshape(1, 1)], axis=1)
                n_step += 1

        gen_coarse_arr = x_coarse_in[0, len(x_coarse_history) :]
        gen_coarse_audio_arr = (
            gen_coarse_arr.reshape(-1, N_COARSE_CODEBOOKS).T - SEMANTIC_VOCAB_SIZE
        )
        for n in range(1, N_COARSE_CODEBOOKS):
            gen_coarse_audio_arr[n, :] -= n * CODEBOOK_SIZE

        return gen_coarse_audio_arr
Generate coarse tokens from semantic tokens.
mlx_audio/tts/models/bark/pipeline.py