def groove(model_name: str, interpolate_sequence: NoteSequence,
           num_steps_per_sample: int, num_output: int,
           total_bars: int) -> NoteSequence:
    """
  Adds groove to the given sequence by splitting it in manageable sequences
  and using the given model to humanize it.
  """
    model = get_model(model_name)

    # Split the sequences in chunks of 4 seconds (which is 2 bars at 120 qpm),
    # which is necessary since the model is trained for 2 bars
    split_interpolate_sequences = mm.sequences_lib.split_note_sequence(
        interpolate_sequence, 4)

    if len(split_interpolate_sequences) != num_output:
        raise Exception(f"Wrong number of interpolate size, "
                        f"expected: 10, actual: {split_interpolate_sequences}")

    # Uses the model to encode the list of sequences, returning the encoding
    # (also called z or latent vector) which will the used in the decoding,
    # The other values mu and sigma are not used, but kept in the code for
    # clarity.
    #
    # The resulting array shape is (a, b), where a is the number of
    # split sequences (should correspond to num_output), and b is the encoding
    # size.
    #
    # This might throw a NoExtractedExamplesError exception if the
    # sequences are not properly formed (for example if the sequences
    # are not quantized, a sequence is empty or not of the proper length).
    encoding, mu, sigma = model.encode(
        note_sequences=split_interpolate_sequences)

    # Uses the model to decode the encoding (also called z or latent vector),
    # returning a list of humanized sequence with one element per encoded
    # sequences (each of length num_steps_per_sample).
    groove_sequences = model.decode(z=encoding, length=num_steps_per_sample)

    # Concatenates the resulting sequences (of length num_output) into one
    # single sequence.
    groove_sequence = mm.sequences_lib.concatenate_sequences(
        groove_sequences, [4] * num_output)

    # Saves the midi and the plot in the groove folder,
    # with the plot having total_bars size
    save_midi(groove_sequence, "groove", model_name)
    save_plot(groove_sequence,
              "groove",
              model_name,
              plot_max_length_bar=total_bars,
              show_velocity=True,
              bar_fill_alphas=[0.50, 0.50, 0.05, 0.05])

    return groove_sequence
def interpolate(model_name: str, sample_sequences: List[NoteSequence],
                num_steps_per_sample: int, num_output: int,
                total_bars: int) -> NoteSequence:
    """
  Interpolates between 2 sequences using the given model.
  """
    if len(sample_sequences) != 2:
        raise Exception(f"Wrong number of sequences, "
                        f"expected: 2, actual: {len(sample_sequences)}")
    if not sample_sequences[0].notes or not sample_sequences[1].notes:
        raise Exception(
            f"Empty note sequences, "
            f"sequence 1 length: {len(sample_sequences[0].notes)}, "
            f"sequence 2 length: {len(sample_sequences[1].notes)}")

    model = get_model(model_name)

    # Use the model to interpolate between the 2 input sequences,
    # with the number of output (counting the start and end sequence),
    # number of steps per sample and default temperature
    #
    # This might throw a NoExtractedExamplesError exception if the
    # sequences are not properly formed (for example if the sequences
    # are not quantized, a sequence is empty or not of the proper length).
    interpolate_sequences = model.interpolate(
        start_sequence=sample_sequences[0],
        end_sequence=sample_sequences[1],
        num_steps=num_output,
        length=num_steps_per_sample)

    # Saves the midi and the plot in the interpolate folder
    save_midi(interpolate_sequences, "interpolate", model_name)
    save_plot(interpolate_sequences, "interpolate", model_name)

    # Concatenates the resulting sequences (of length num_output) into one
    # single sequence.
    # The second parameter is a list containing the number of seconds
    # for each input sequence. This is useful if some of the input
    # sequences do not have notes at the end (for example the last
    # note ends at 3.5 seconds instead of 4)
    interpolate_sequence = mm.sequences_lib.concatenate_sequences(
        interpolate_sequences, [4] * num_output)

    # Saves the midi and the plot in the merge folder,
    # with the plot having total_bars size
    save_midi(interpolate_sequence, "merge", model_name)
    save_plot(interpolate_sequence,
              "merge",
              model_name,
              plot_max_length_bar=total_bars,
              bar_fill_alphas=[0.50, 0.50, 0.05, 0.05])

    return interpolate_sequence
def sample(model_name: str, num_steps_per_sample: int) -> List[NoteSequence]:
    """
  Samples 2 sequences using the given model.
  """
    model = get_model(model_name)

    # Uses the model to sample 2 sequences,
    # with the number of steps and default temperature
    sample_sequences = model.sample(n=2, length=num_steps_per_sample)

    # Saves the midi and the plot in the sample folder
    save_midi(sample_sequences, "sample", model_name)
    save_plot(sample_sequences, "sample", model_name)

    return sample_sequences