Exemplo n.º 1
0
def finalize_midi_sequence(ptrn,
                           name="Track 1",
                           inst=0,
                           channel=0,
                           tsig=(4, 4),
                           bpm=120):
    """
    Makes a geenrated midi sequnce valid for most players 
    by adding TimeSignature, SetTempo and EndOfTrack events.
    """
    has_tsig = False
    has_tempo = False
    has_end = False
    for evnt in utils.evnt_gen(ptrn):
        if isinstance(evnt, midi.SetTempoEvent):
            has_tsig = True
        if isinstance(evnt, midi.TimeSignatureEvent):
            has_tempo = True
        if isinstance(evnt, midi.EndOfTrackEvent):
            has_end = True
    if not has_tsig:
        ptrn[0].insert(0, midi.TimeSignatureEvent(tick=0))
        ptrn[0][0].data[:2] = tsig
        ptrn[0][0].data[2:] = 24, 8
    if not has_tempo:
        ptrn[0].insert(0, midi.SetTempoEvent(tick=0))
        ptrn[0][0].set_bpm(bpm)
    if not has_end:
        ptrn[0].append(midi.EndOfTrackEvent(tick=0))
    ptrn[0].insert(0, midi.TrackNameEvent(tick=0, text=name, data=[]))
    ptrn[0].insert(
        0, midi.ProgramChangeEvent(tick=0, channel=channel, data=[inst]))
    return ptrn
Exemplo n.º 2
0
def has_channels(x, typs=(midi.NoteOnEvent, midi.NoteOffEvent), channels=[9]):
    """
    Returns True if any midi.events types in the tuple 'typs' have channels contained
    in the tuple 'channels'
    """
    for evnt in utils.evnt_gen(x):
        if isinstance(evnt, typs) and evnt.channel in channels:
            return True
Exemplo n.º 3
0
def is_equal_midi_sequences(a, b):
    """
    Returns True if a and b are sequences containing 
    equivalent midi.events objects else False.
    The type, .data and .tick of the evnts are compared.
    """
    if type(a) != type(b):
        return False
    a = list(utils.evnt_gen(a))
    b = list(utils.evnt_gen(b))
    lena, lenb = len(a), len(b)
    if lena != lenb:
        return False
    else:
        for i in range(lena):
            evnt0, evnt1 = a[i], b[i]
            if (type(evnt0) != type(evnt1) or evnt0.data != evnt1.data
                    or evnt0.tick != evnt1.tick):
                return False
    return True
Exemplo n.º 4
0
def is_evnt_typ_uniq(x, typ):
    """
    Returns True if x contains a single instance of typ
    """
    uniq = False
    for evnt in utils.evnt_gen(x):
        if isinstance(evnt, typ):
            if uniq:
                return not uniq
            uniq = True
    return uniq
Exemplo n.º 5
0
def has_insts(x, insts: tuple) -> bool:
    """
    Args:
        x       - list/midi.Pattern/midi.Track/MidiObj
        insts   - int, midi standard numbers for instruments
    Returns:
        boolean - True if ptrn contains any types in typ
    """
    insts = [i - 1 for i in insts]
    for evnt in utils.evnt_gen(x):
        if isinstance(evnt, midi.ProgramChangeEvent) and evnt.data[0] in insts:
            return True
Exemplo n.º 6
0
def has_evnt_typ(x, typ=()) -> bool:
    """
    Args:
        x       - list/midi.Pattern/midi.Track/MidiObj
        typ     - tuple(type(midi.event),..., type(midi.event))
    Returns:
        boolean - True if ptrn contains any types in typ
    """
    for evnt in utils.evnt_gen(x):
        if isinstance(evnt, typ):
            return True
    return False
Exemplo n.º 7
0
def quantize_typ_attr(x, q, typ, func):
    """
    Reduces the number of different available velocity values
    Args:
        x     - MidiObj or midi.Pattern
        typ   - midi.events type, i.e. midi.NoteOnEvent
        q     - int, quantization factor
    """
    for evnt in utils.evnt_gen(x):
        if isinstance(evnt, typ):
            evnt.data[1] = utils.quantize(func(evnt), q)
    return x
Exemplo n.º 8
0
def get_evnt_info(x, evnt_typ, attrs=["tick", "data"], func=None):
    """
    Returns a 2-tuple containing the count (as an int) and a list containing the value
    of each entry for an attribute of a particular event type.
    """
    count, data = 0, []
    for evnt in utils.evnt_gen(x):
        if isinstance(evnt, evnt_typ):
            datum = [getattr(evnt, attr) for attr in attrs]
            if func is not None:
                datum = func(datum)
            data.append(datum)
            count += 1
    return count, data
Exemplo n.º 9
0
def has_only_inst(x, to_keep: set) -> bool:
    """
    Args:
        x         - list/midi.Pattern/midi.Track/MidiObj
        to_keep   - set{int} midi standard numbers for desired instruments
                    all shifted by -1
    Returns:
        bool      - True if isinstance(evnt, typ) and not condition(evnt)
    """
    all_insts = set(range(128))
    to_remove = all_insts - to_keep
    for evnt in utils.evnt_gen(x):
        if isinstance(evnt,
                      midi.ProgramChangeEvent) and evnt.data[0] in to_remove:
            return False
    return True
Exemplo n.º 10
0
def has_tsig(x, tsigs=[(4, 4)]) -> bool:
    """
    Args:
        x       - list/midi.Pattern/midi.Track/MidiObj
        tsigs   - list[tuple(int, int),... tuple(int, int)],
                  time signatures encoded as a 2-tuple(numerator, denominator)
    Returns:
        boolean - True if ptrn contains any time signatures contained in tsigs
    """
    for evnt in utils.evnt_gen(x):
        if isinstance(evnt, midi.TimeSignatureEvent):
            data = list(evnt.data[:2])
            data[1] = utils.nptf(data[1])
            data = tuple(data)
            if any([ts == data for ts in tsigs]):
                return True
Exemplo n.º 11
0
def filter_data_of_insts(data, to_remove=set()):
    """
    Remove midi.Pattern or MidiObj from an iterable data container if they contain
    instrument numbers in 'to_remove'. These numbers are same as midi standard -1.
    """
    ret = []
    for x in data:
        keep = True
        for evnt in utils.evnt_gen(x):
            if isinstance(
                    evnt,
                    midi.ProgramChangeEvent) and evnt.data[0] in to_remove:
                keep = False
                break
        if keep:
            ret.append(x)
    return ret
Exemplo n.º 12
0
def which_insts(x, insts: tuple, uniq: bool = True) -> list:
    """
    Args:
        x       - list/midi.Pattern/midi.Track/MidiObj
        insts   - int, midi standard numbers for instruments
    Returns:
        boolean - True if ptrn contains any types in typ
    """
    ret = []
    insts = [i - 1 for i in insts]
    for evnt in utils.evnt_gen(x):
        if isinstance(evnt, midi.ProgramChangeEvent):
            for i in insts:
                if i == evnt.data[0]:
                    ret.append(i + 1)
    if uniq:
        ret = list(set(ret))
    return ret
Exemplo n.º 13
0
def get_min_max(x, typs=(), func=lambda x: x.tick):
    """
    Get the minimum and maximum values for an event type.
    Args:
        x    - midi.Pattern/midi.Track or python sequence containing
               midi.events
        typs - tuple, contains types of events to analyze
        func - callable function to expose event attribute, default is
               lambda x: x.tick
    Returns:
          min, max - int, int
    """
    min_ = np.inf
    max_ = -np.inf
    for evnt in utils.evnt_gen(x):
        if isinstance(evnt, typs):
            min_ = min(min_, func(evnt))
            max_ = max(max_, func(evnt))
    return min_, max_
Exemplo n.º 14
0
def max_simultaneous_notes(x):
    """
    Returns the maximum number of simultaneous notes in a ptrn
    """
    state = {}
    n_max = 0
    for evnt in utils.evnt_gen(x):
        on = off = False
        if isinstance(evnt, midi.NoteOnEvent):
            on = True
        elif isinstance(evnt, midi.NoteOffEvent):
            off = True
        if on or off:
            note, vel = evnt.data[:2]
            if on and not vel or off:
                state[note] = max(state.get(note, 0) - 1, 0)
            elif on:
                state[note] = state.get(note, 0) + 1
            n = sum(list(state.values()))
            n_max = max(n, n_max)
    return n_max
Exemplo n.º 15
0
def time_split(x):
    """
    Breaks up a list or midi.Track containing midi.events into a nested list
    where each sublist represents events which occur simultaneously.
    """
    if isinstance(x, midi.Pattern) or any(
        [isinstance(trck, (list, midi.Track)) for trck in x]):
        x = [
            trck for trck in x
            if utils.safe_len(trck) and isinstance(trck, (list, midi.Track))
        ]
        x = consolidate_trcks(x)
    if not len(x):
        return []
    ret = []
    sub = []
    for evnt in utils.evnt_gen(x):
        if evnt.tick != 0 and sub:
            ret.append(sub)
            sub = []
        sub.append(evnt)
    ret.append(sub)
    return ret
Exemplo n.º 16
0
def categorize_input(x, q, n_time, off_mode, time_encoder, ekwa, **kwargs):
    """
    This function is the inverse of categorize_output.
    This function will encode a midi sequence in the form of a midi.Track/midi.Pattern
    (with 1 track) or a MuGen.utils.MidiObj into a encoded/serialized sequence of integers. 
    A midi.events object, often referred to in this code as 'evnt' will be encoded as an 
    integer, an 'avnt'. The evnt/avnt terminology is used to imitate efferent/afferent neuron
    terminology in neuroscience.

    Args:
        x             - list/midi.Track/midi.Pattern, iterable containing midi.Events
        q             - int, quantization factor of velocity
        n_time        - int, number of bits in one-hot encoding that are used for time slips
        off_mode      - bool, True if NoteOffEvents are included in input sequence
        time_encoder  - int, a function to encode milliseconds
        ekwa          - dict, keyword arguments for the encoder
        
        n_vel         - int, number of bits in one-hot encoding that are used for velocity, 
                        this value is dependent on q
        q_map         - dict, maps quantized velocities to encoding
        p_map         - dict, maps added pulses/note divisions to encoding
        asarray       - bool, default=False, whether to return output as a numpy array
        dtype         - str, default='int', data type of the returned array
        bpm           - int, default=120, tempo in Beats Per Minute, initial tempo of the input
                        sequence, is updated dynamically as tempo changed in input sequence
        sort_velocity - bool, default=False, whether velocity values should be in sorted order 
        sort_pitch    = bool, default=False, whether pitch values should be in sorted order 
        sort_pulse    = bool, default=False, whether pulse values should be in sorted order 

    Vars:
        n_pitch       - int, number of bits in one-hot encoding that are used for pitch 
                        i.e. NoteOnEvents, if off_mode is True an additional 128 bits are
                        used for NoteOffEvents otherwise x should only contain NoteOnEvents
                        with velocity=0 to signify NoteOffEvents
        n_t_p         - int, n_time + n_pitch
        n_t_p_v       - int, n_time + n_pitch + n_vel
        n_vocab       - int, n_time + n_pitch + n_vel + n_pulse, total number of bits used 
                        for one-hot encoding
        mspt          - float, default=None, milliseconds per tick, updated dynamically as we iterate 
                        through the input sequence (x)
        tick          - int, holds the current tick as we iterate through the input sequence (x)
        timestep      - list, as we iterate through the input sequence all events that occur 
                        simultaneously, in a single 'timestep', will be collected here before being
                        processed/encoded/serialized

    Returns:
        ret           - list[int]/np.ndarray[int] - encoded and serialized midi sequence
    """

    if isinstance(x, utils.MidiObj):
        x = x.ptrn

    n_vel = kwargs.get("n_vel", utils.dynamic_order(128, q))
    q_map = kwargs.get("q_map", maps.create_q_map(128, q))
    p_map = kwargs.get("p_map", None)
    asarray = kwargs.get("asarray", False)
    dtype = kwargs.get("dtype", "int")
    sort_velocity = kwargs.get("sort_velocity", False)
    sort_pitch = kwargs.get("sort_pitch", False)
    sort_pulse = kwargs.get("sort_pulse", False)
    bpm = kwargs.get("bpm", 120)  # beats per minute

    n_pitch = 128 * 2 if off_mode else 128
    n_pulse = len(p_map.keys()) if p_map is not None else 0
    n_t_p = n_time + n_pitch
    n_t_p_v = n_time + n_pitch + n_vel
    n_vocab = n_time + n_pitch + n_vel + n_pulse  # n_t_p_v_p

    mspt = None  # miliseconds per tick
    tick = 0
    timestep = []  # timestep/time bubble
    ret = []  # output sequence

    t_encoder = lambda x: time_encoder(x, **ekwa)
    args = [ret, timestep, tick, bpm, mspt]
    static_args = (
        q,
        n_time,
        n_t_p,
        n_t_p_v,
        q_map,
        p_map,
        t_encoder,
        sort_velocity,
        sort_pitch,
        sort_pulse,
    )
    _processor = lambda x: process_timestep(*x, *static_args)

    for evnt in utils.evnt_gen(x):
        if evnt.tick != 0:
            args = _processor(args)
            args[2] = tick = evnt.tick
        args[1].append(evnt)
    ret = _processor(args)[0]
    if asarray:
        ret = np.array(ret, dtype=dtype)
    return ret
Exemplo n.º 17
0
def display_evnt_typs(x):
    """
    A quick count of each unique event type in a midi.Track or midi.Pattern
    """
    typs = [type(evnt) for evnt in utils.evnt_gen(x)]
    return counter(typs)