Example #1
0
 def sequence_to_midi(self,
                      sequence,
                      bpm: int = 80) -> pretty_midi.PrettyMIDI:
     pm = pretty_midi.PrettyMIDI(initial_tempo=bpm)
     instrument = pretty_midi.Instrument(0)
     pm.instruments.append(instrument)
     time_signature = pretty_midi.containers.TimeSignature(4, 4, 0.0)
     pm.time_signature_changes.append(time_signature)
     instrument_events = collections.defaultdict(
         lambda: collections.defaultdict(list))
     time = 0
     tick = 60 / bpm / (self.q / 4)
     for i, encoding in enumerate(sequence, 1):
         if encoding not in ('<START>', '<BAR>', '<END>', '<PAD>'):
             encoding = self.encoder.decode(encoding)
             if encoding:  # empty means tick rest
                 for pitch in encoding:
                     instrument_events[(pitch, 9, True)]['notes'].append(
                         pretty_midi.Note(100, pitch, time, time + tick))
             time += tick
     for (instr_id, prog_id, is_drum) in sorted(instrument_events.keys(),
                                                reverse=True):
         if instr_id > 0:
             instrument = pretty_midi.Instrument(
                 prog_id,
                 is_drum,
                 name=pretty_midi.note_number_to_drum_name(instr_id))
             pm.instruments.append(instrument)
         instrument.program = prog_id
         instrument.notes = instrument_events[(instr_id, prog_id,
                                               is_drum)]['notes']
     return pm
Example #2
0
 def visualize(self,
               ax_subplot,
               color: Union[NDArray, str],
               marker: str = "2"):
     """
     Visualize the pattern.
     """
     x_length = np.arange(0, self.pattern.shape[-1])
     for note_row in self.pattern:
         values = [
             note.pitch if note is not None else np.nan for note in note_row
         ]
         ax_subplot.scatter(x_length, values, color=color, marker=marker)
     ax_subplot.yaxis.set_major_formatter(
         FuncFormatter(lambda tick, pos: note_number_to_drum_name(tick)))
     ax_subplot.xaxis.set_major_locator(MultipleLocator(base=self.steps))
     return ax_subplot
Example #3
0
def synthesize_drum_instrument(instrument, fs=44100):
    '''
    Synthesize a pretty_midi.Instrument object with drum sounds.

    Parameters
    ----------
    instrument : pretty_midi.Instrument
        Instrument to synthesize

    Returns
    -------
    synthesized : np.ndarray
        Audio data of the instrument synthesized
    '''
    # Allocate audio data
    synthesized = np.zeros(int((instrument.get_end_time() + 1)*fs))
    for note in instrument.notes:
        # Get the name of the drum
        drum_name = pretty_midi.note_number_to_drum_name(note.pitch)
        # Based on the drum name, synthesize using the tonal or noise functions
        if drum_name in ['Acoustic Bass Drum', 'Bass Drum 1']:
            d = tonal(fs, fs/2, 80, 8.)
        elif drum_name in ['Side Stick']:
            d = tonal(fs, fs/20, 400, 8.)
        elif drum_name in ['Acoustic Snare', 'Electric Snare']:
            d = .4*tonal(fs, fs/10, 200, 20.) + .6*noise(fs/10)
        elif drum_name in ['Hand Clap', 'Vibraslap']:
            d = .1*tonal(fs, fs/10, 400, 8.) + .9*noise(fs/10)
        elif drum_name in ['Low Floor Tom', 'Low Tom', 'Low Bongo',
                           'Low Conga', 'Low Timbale']:
            d = tonal(fs, fs/4, 120, 8.)
        elif drum_name in ['Closed Hi Hat', 'Cabasa', 'Maracas',
                           'Short Guiro']:
            d = noise(fs/20)
        elif drum_name in ['High Floor Tom', 'High Tom', 'Hi Bongo',
                           'Open Hi Conga', 'High Timbale']:
            d = tonal(fs, fs/4, 480, 4.)
        elif drum_name in ['Pedal Hi Hat', 'Open Hi Hat', 'Crash Cymbal 1',
                           'Ride Cymbal 1', 'Chinese Cymbal', 'Crash Cymbal 2',
                           'Ride Cymbal 2', 'Tambourine',  'Long Guiro',
                           'Splash Cymbal']:
            d = .8*noise(fs)
        elif drum_name in ['Low-Mid Tom']:
            d = tonal(fs, fs/4, 240, 4.)
        elif drum_name in ['Hi-Mid Tom']:
            d = tonal(fs, fs/4, 360, 4.)
        elif drum_name in ['Mute Hi Conga', 'Mute Cuica', 'Cowbell',
                           'Low Agogo', 'Low Wood Block']:
            d = tonal(fs, fs/10, 480, 4.)
        elif drum_name in ['Ride Bell', 'High Agogo', 'Claves',
                           'Hi Wood Block']:
            d = tonal(fs, fs/20, 960, 4.)
        elif drum_name in ['Short Whistle']:
            d = tonal(fs, fs/4, 480, 1.)
        elif drum_name in ['Long Whistle']:
            d = tonal(fs, fs, 480, 1.)
        elif drum_name in ['Mute Triangle']:
            d = tonal(fs, fs/10, 1960, 1.)
        elif drum_name in ['Open Triangle']:
            d = tonal(fs, fs, 1960, 1.)
        else:
            if drum_name is not '':
                # This should never happen
                print('Unexpected drum {}'.format(drum_name))
            continue
        # Add in the synthesized waveform
        start = int(note.start*fs)
        synthesized[start:start+d.size] += d*note.velocity
    return synthesized
Example #4
0
def plot_pianoroll(ax,
                   pianoroll,
                   is_drum=False,
                   beat_resolution=None,
                   downbeats=None,
                   normalization='standard',
                   preset='default',
                   cmap='Blues',
                   tick_loc=None,
                   xtick='auto',
                   ytick='octave',
                   xticklabel='on',
                   yticklabel='auto',
                   direction='in',
                   label='both',
                   grid='both',
                   grid_linestyle=':',
                   grid_linewidth=.5):
    """
    Plot a piano-roll given as a numpy array

    Parameters
    ----------
    ax : matplotlib.axes.Axes object
         The :class:`matplotlib.axes.Axes` object where the piano-roll will
         be plotted on.
    pianoroll : np.ndarray
        The piano-roll to be plotted. The values should be in [0, 1] when
        `normalized` is False.

        - For 2D array, shape=(num_time_step, num_pitch).
        - For 3D array, shape=(num_time_step, num_pitch, num_channel), where
          channels can be either RGB or RGBA.

    is_drum : bool
        Drum indicator. True for drums. False for other instruments. Default
        to False.
    beat_resolution : int
        Resolution of a beat (in time step). Required and only effective
        when `xticklabel` is 'beat'.
    downbeats : list
        Indices of time steps that contain downbeats., i.e. the first time
        step of a bar.
    normalization : {'standard', 'auto', 'none'}
        The normalization method to apply to the piano-roll. Default to
        'standard'. If `pianoroll` is binarized, use 'none' anyway.

        - For 'standard' normalization, the normalized values are given by
          N = P / 128, where P, N is the original and normalized piano-roll,
          respectively
        - For 'auto' normalization, the normalized values are given by
          N = (P - m) / (M - m), where P, N is the original and normalized
          piano-roll, respectively, and M, m is the maximum and minimum of
          the original piano-roll, respectively.
        - If 'none', no normalization will be applied to the piano-roll. In
          this case, the values of `pianoroll` should be in [0, 1] in order
          to plot it correctly.

    preset : {'default', 'plain', 'frame'}
        Preset themes for the plot.

        - In 'default' preset, the ticks, grid and labels are on.
        - In 'frame' preset, the ticks and grid are both off.
        - In 'plain' preset, the x- and y-axis are both off.

    cmap :  `matplotlib.colors.Colormap`
        Colormap to use in :func:`matplotlib.pyplot.imshow`. Default to
        'Blues'. Only effective when `pianoroll` is 2D.
    tick_loc : tuple or list
        List of locations to put ticks. Availables elements are 'bottom',
        'top', 'left' and 'right'. If None, default to ('bottom', 'left').
    xtick : {'auto', 'beat', 'step', 'off'}
        Use beat number or step number as ticks along the x-axis, or
        automatically set to 'beat' when `beat_resolution` is given and set
        to 'step', otherwise. Default to 'auto'.
    ytick : {'octave', 'pitch', 'off'}
        Use octave or pitch as ticks along the y-axis. Default to 'octave'.
    xticklabel : {'on', 'off'}
        Indicate whether to add tick labels along the x-axis. Only effective
        when `xtick` is not 'off'.
    yticklabel : {'auto', 'name', 'number', 'off'}
        If 'name', use octave name and pitch name (key name when `is_drum`
        is True) as tick labels along the y-axis. If 'number', use pitch
        number. If 'auto', set to 'name' when `ytick` is 'octave' and
        'number' when `ytick` is 'pitch'. Default to 'auto'. Only effective
        when `ytick` is not 'off'.
    direction : {'in', 'out', 'inout'}
        Put ticks inside the axes, outside the axes, or both. Default to
        'in'. Only effective when `xtick` and `ytick` are not both 'off'.
    label : {'x', 'y', 'both', 'off'}
        Add label to the x-axis, y-axis, both or neither. Default to 'both'.
    grid : {'x', 'y', 'both', 'off'}
        Add grid to the x-axis, y-axis, both or neither. Default to 'both'.
    grid_linestyle : str
        Will be passed to :meth:`matplotlib.axes.Axes.grid` as 'linestyle'
        argument.
    grid_linewidth : float
        Will be passed to :meth:`matplotlib.axes.Axes.grid` as 'linewidth'
        argument.

    """
    if pianoroll.ndim not in (2, 3):
        raise ValueError("`pianoroll` must be a 2D or 3D numpy array")
    if pianoroll.shape[1] != 128:
        raise ValueError("The shape of `pianoroll` must be (num_time_step, "
                         "128)")
    if xtick not in ('auto', 'beat', 'step', 'off'):
        raise ValueError("`xtick` must be one of {'auto', 'beat', 'step', "
                         "'none'}")
    if xtick is 'beat' and beat_resolution is None:
        raise ValueError("`beat_resolution` must be a number when `xtick` "
                         "is 'beat'")
    if ytick not in ('octave', 'pitch', 'off'):
        raise ValueError("`ytick` must be one of {octave', 'pitch', 'off'}")
    if xticklabel not in ('on', 'off'):
        raise ValueError("`xticklabel` must be 'on' or 'off'")
    if yticklabel not in ('auto', 'name', 'number', 'off'):
        raise ValueError("`yticklabel` must be one of {'auto', 'name', "
                         "'number', 'off'}")
    if direction not in ('in', 'out', 'inout'):
        raise ValueError("`direction` must be one of {'in', 'out', 'inout'}")
    if label not in ('x', 'y', 'both', 'off'):
        raise ValueError("`label` must be one of {'x', 'y', 'both', 'off'}")
    if grid not in ('x', 'y', 'both', 'off'):
        raise ValueError("`grid` must be one of {'x', 'y', 'both', 'off'}")

    # plotting
    if pianoroll.ndim > 2:
        to_plot = pianoroll.transpose(1, 0, 2)
    else:
        to_plot = pianoroll.T
    if normalization == 'standard':
        to_plot = to_plot / 128.
    elif normalization == 'auto':
        max_value = np.max(to_plot)
        min_value = np.min(to_plot)
        to_plot = to_plot - min_value / (max_value - min_value)
    ax.imshow(to_plot,
              cmap=cmap,
              aspect='auto',
              vmin=0,
              vmax=1,
              origin='lower',
              interpolation='none')

    # tick setting
    if tick_loc is None:
        tick_loc = ('bottom', 'left')
    if xtick == 'auto':
        xtick = 'beat' if beat_resolution is not None else 'step'
    if yticklabel == 'auto':
        yticklabel = 'name' if ytick == 'octave' else 'number'

    if preset == 'plain':
        ax.axis('off')
    elif preset == 'frame':
        ax.tick_params(direction=direction,
                       bottom='off',
                       top='off',
                       left='off',
                       right='off',
                       labelbottom='off',
                       labeltop='off',
                       labelleft='off',
                       labelright='off')
    else:
        labelbottom = 'on' if xticklabel != 'off' else 'off'
        labelleft = 'on' if yticklabel != 'off' else 'off'

        ax.tick_params(direction=direction,
                       bottom=('bottom' in tick_loc),
                       top=('top' in tick_loc),
                       left=('left' in tick_loc),
                       right=('right' in tick_loc),
                       labelbottom=labelbottom,
                       labeltop='off',
                       labelleft=labelleft,
                       labelright='off')

    # x-axis
    if xtick == 'beat' and preset != 'frame':
        num_beat = pianoroll.shape[0] // beat_resolution
        xticks_major = beat_resolution * np.arange(0, num_beat)
        xticks_minor = beat_resolution * (0.5 + np.arange(0, num_beat))
        xtick_labels = np.arange(1, 1 + num_beat)
        ax.set_xticks(xticks_major)
        ax.set_xticklabels('')
        ax.set_xticks(xticks_minor, minor=True)
        ax.set_xticklabels(xtick_labels, minor=True)
        ax.tick_params(axis='x', which='minor', width=0)

    # y-axis
    if ytick == 'octave':
        ax.set_yticks(np.arange(0, 128, 12))
        if yticklabel == 'name':
            ax.set_yticklabels(['C{}'.format(i - 2) for i in range(11)])
    elif ytick == 'step':
        ax.set_yticks(np.arange(0, 128))
        if yticklabel == 'name':
            if is_drum:
                ax.set_yticklabels([
                    pretty_midi.note_number_to_drum_name(i) for i in range(128)
                ])
            else:
                ax.set_yticklabels(
                    [pretty_midi.note_number_to_name(i) for i in range(128)])

    # axis labels
    if label == 'x' or label == 'both':
        if xtick == 'step' or xticklabel == 'off':
            ax.set_xlabel('time (step)')
        else:
            ax.set_xlabel('time (beat)')

    if label == 'y' or label == 'both':
        if is_drum:
            ax.set_ylabel('key name')
        else:
            ax.set_ylabel('pitch')

    # grid
    if grid != 'off':
        ax.grid(axis=grid,
                color='k',
                linestyle=grid_linestyle,
                linewidth=grid_linewidth)

    # downbeat boarder
    if downbeats is not None and preset != 'plain':
        for step in downbeats:
            ax.axvline(x=step, color='k', linewidth=1)
Example #5
0
def plot_pianoroll(
    ax,
    pianoroll,
    is_drum=False,
    beat_resolution=None,
    downbeats=None,
    preset="default",
    cmap="Blues",
    xtick="auto",
    ytick="octave",
    xticklabel=True,
    yticklabel="auto",
    tick_loc=None,
    tick_direction="in",
    label="both",
    grid="both",
    grid_linestyle=":",
    grid_linewidth=0.5,
):
    """
    Plot a pianoroll given as a numpy array.

    Parameters
    ----------
    ax : matplotlib.axes.Axes object
        A :class:`matplotlib.axes.Axes` object where the pianoroll will be
        plotted on.
    pianoroll : np.ndarray
        A pianoroll to be plotted. The values should be in [0, 1] when data type
        is float, and in [0, 127] when data type is integer.

        - For a 2D array, shape=(num_time_step, num_pitch).
        - For a 3D array, shape=(num_time_step, num_pitch, num_channel), where
          channels can be either RGB or RGBA.

    is_drum : bool
        A boolean number that indicates whether it is a percussion track.
        Defaults to False.
    beat_resolution : int
        The number of time steps used to represent a beat. Required and only
        effective when `xtick` is 'beat'.
    downbeats : list
        An array that indicates whether the time step contains a downbeat (i.e.,
        the first time step of a bar).

    preset : {'default', 'plain', 'frame'}
        A string that indicates the preset theme to use.

        - In 'default' preset, the ticks, grid and labels are on.
        - In 'frame' preset, the ticks and grid are both off.
        - In 'plain' preset, the x- and y-axis are both off.

    cmap :  `matplotlib.colors.Colormap`
        The colormap to use in :func:`matplotlib.pyplot.imshow`. Defaults to
        'Blues'. Only effective when `pianoroll` is 2D.
    xtick : {'auto', 'beat', 'step', 'off'}
        A string that indicates what to use as ticks along the x-axis. If 'auto'
        is given, automatically set to 'beat' if `beat_resolution` is also given
        and set to 'step', otherwise. Defaults to 'auto'.
    ytick : {'octave', 'pitch', 'off'}
        A string that indicates what to use as ticks along the y-axis.
        Defaults to 'octave'.
    xticklabel : bool
        Whether to add tick labels along the x-axis. Only effective when `xtick`
        is not 'off'.
    yticklabel : {'auto', 'name', 'number', 'off'}
        If 'name', use octave name and pitch name (key name when `is_drum` is
        True) as tick labels along the y-axis. If 'number', use pitch number. If
        'auto', set to 'name' when `ytick` is 'octave' and 'number' when `ytick`
        is 'pitch'. Defaults to 'auto'. Only effective when `ytick` is not
        'off'.
    tick_loc : tuple or list
        The locations to put the ticks. Availables elements are 'bottom', 'top',
        'left' and 'right'. Defaults to ('bottom', 'left').
    tick_direction : {'in', 'out', 'inout'}
        A string that indicates where to put the ticks. Defaults to 'in'. Only
        effective when one of `xtick` and `ytick` is on.
    label : {'x', 'y', 'both', 'off'}
        A string that indicates whether to add labels to the x-axis and y-axis.
        Defaults to 'both'.
    grid : {'x', 'y', 'both', 'off'}
        A string that indicates whether to add grids to the x-axis, y-axis, both
        or neither. Defaults to 'both'.
    grid_linestyle : str
        Will be passed to :meth:`matplotlib.axes.Axes.grid` as 'linestyle'
        argument.
    grid_linewidth : float
        Will be passed to :meth:`matplotlib.axes.Axes.grid` as 'linewidth'
        argument.

    """
    if not HAS_MATPLOTLIB:
        raise ImportError(
            "matplotlib package is required for plotting supports.")

    if pianoroll.ndim not in (2, 3):
        raise ValueError("`pianoroll` must be a 2D or 3D numpy array")
    if pianoroll.shape[1] != 128:
        raise ValueError(
            "The length of the second axis of `pianoroll` must be 128.")
    if xtick not in ("auto", "beat", "step", "off"):
        raise ValueError(
            "`xtick` must be one of {'auto', 'beat', 'step', 'none'}.")
    if xtick == "beat" and beat_resolution is None:
        raise ValueError(
            "`beat_resolution` must be specified when `xtick` is 'beat'.")
    if ytick not in ("octave", "pitch", "off"):
        raise ValueError("`ytick` must be one of {octave', 'pitch', 'off'}.")
    if not isinstance(xticklabel, bool):
        raise TypeError("`xticklabel` must be bool.")
    if yticklabel not in ("auto", "name", "number", "off"):
        raise ValueError(
            "`yticklabel` must be one of {'auto', 'name', 'number', 'off'}.")
    if tick_direction not in ("in", "out", "inout"):
        raise ValueError(
            "`tick_direction` must be one of {'in', 'out', 'inout'}.")
    if label not in ("x", "y", "both", "off"):
        raise ValueError("`label` must be one of {'x', 'y', 'both', 'off'}.")
    if grid not in ("x", "y", "both", "off"):
        raise ValueError("`grid` must be one of {'x', 'y', 'both', 'off'}.")

    # plotting
    if pianoroll.ndim > 2:
        to_plot = pianoroll.transpose(1, 0, 2)
    else:
        to_plot = pianoroll.T
    if np.issubdtype(pianoroll.dtype, np.bool_) or np.issubdtype(
            pianoroll.dtype, np.floating):
        ax.imshow(
            to_plot,
            cmap=cmap,
            aspect="auto",
            vmin=0,
            vmax=1,
            origin="lower",
            interpolation="none",
        )
    elif np.issubdtype(pianoroll.dtype, np.integer):
        ax.imshow(
            to_plot,
            cmap=cmap,
            aspect="auto",
            vmin=0,
            vmax=127,
            origin="lower",
            interpolation="none",
        )
    else:
        raise TypeError("Unsupported data type for `pianoroll`.")

    # tick setting
    if tick_loc is None:
        tick_loc = ("bottom", "left")
    if xtick == "auto":
        xtick = "beat" if beat_resolution is not None else "step"
    if yticklabel == "auto":
        yticklabel = "name" if ytick == "octave" else "number"

    if preset == "plain":
        ax.axis("off")
    elif preset == "frame":
        ax.tick_params(
            direction=tick_direction,
            bottom=False,
            top=False,
            left=False,
            right=False,
            labelbottom=False,
            labeltop=False,
            labelleft=False,
            labelright=False,
        )
    else:
        ax.tick_params(
            direction=tick_direction,
            bottom=("bottom" in tick_loc),
            top=("top" in tick_loc),
            left=("left" in tick_loc),
            right=("right" in tick_loc),
            labelbottom=(xticklabel != "off"),
            labelleft=(yticklabel != "off"),
            labeltop=False,
            labelright=False,
        )

    # x-axis
    if xtick == "beat" and preset != "frame":
        num_beat = pianoroll.shape[0] // beat_resolution
        ax.set_xticks(beat_resolution * np.arange(num_beat) - 0.5)
        ax.set_xticklabels("")
        ax.set_xticks(beat_resolution * (np.arange(num_beat) + 0.5) - 0.5,
                      minor=True)
        ax.set_xticklabels(np.arange(1, num_beat + 1), minor=True)
        ax.tick_params(axis="x", which="minor", width=0)

    # y-axis
    if ytick == "octave":
        ax.set_yticks(np.arange(0, 128, 12))
        if yticklabel == "name":
            ax.set_yticklabels(["C{}".format(i - 2) for i in range(11)])
    elif ytick == "step":
        ax.set_yticks(np.arange(0, 128))
        if yticklabel == "name":
            if is_drum:
                ax.set_yticklabels([
                    pretty_midi.note_number_to_drum_name(i) for i in range(128)
                ])
            else:
                ax.set_yticklabels(
                    [pretty_midi.note_number_to_name(i) for i in range(128)])

    # axis labels
    if label in ("x", "both"):
        if xtick == "step" or not xticklabel:
            ax.set_xlabel("time (step)")
        else:
            ax.set_xlabel("time (beat)")

    if label in ("y", "both"):
        if is_drum:
            ax.set_ylabel("key name")
        else:
            ax.set_ylabel("pitch")

    # grid
    if grid != "off":
        ax.grid(axis=grid,
                color="k",
                linestyle=grid_linestyle,
                linewidth=grid_linewidth)

    # downbeat boarder
    if downbeats is not None and preset != "plain":
        for step in downbeats:
            ax.axvline(x=step, color="k", linewidth=1)
def synthesize_drum_instrument(instrument, fs=44100):
    '''
    Synthesize a pretty_midi.Instrument object with drum sounds.

    Parameters
    ----------
    instrument : pretty_midi.Instrument
        Instrument to synthesize

    Returns
    -------
    synthesized : np.ndarray
        Audio data of the instrument synthesized
    '''
    # Allocate audio data
    synthesized = np.zeros(int((instrument.get_end_time() + 1) * fs))
    for note in instrument.notes:
        # Get the name of the drum
        drum_name = pretty_midi.note_number_to_drum_name(note.pitch)
        # Based on the drum name, synthesize using the tonal or noise functions
        if drum_name in ['Acoustic Bass Drum', 'Bass Drum 1']:
            d = tonal(fs, fs / 2, 80, 8.)
        elif drum_name in ['Side Stick']:
            d = tonal(fs, fs / 20, 400, 8.)
        elif drum_name in ['Acoustic Snare', 'Electric Snare']:
            d = .4 * tonal(fs, fs / 10, 200, 20.) + .6 * noise(fs / 10)
        elif drum_name in ['Hand Clap', 'Vibraslap']:
            d = .1 * tonal(fs, fs / 10, 400, 8.) + .9 * noise(fs / 10)
        elif drum_name in [
                'Low Floor Tom', 'Low Tom', 'Low Bongo', 'Low Conga',
                'Low Timbale'
        ]:
            d = tonal(fs, fs / 4, 120, 8.)
        elif drum_name in [
                'Closed Hi Hat', 'Cabasa', 'Maracas', 'Short Guiro'
        ]:
            d = noise(fs / 20)
        elif drum_name in [
                'High Floor Tom', 'High Tom', 'Hi Bongo', 'Open Hi Conga',
                'High Timbale'
        ]:
            d = tonal(fs, fs / 4, 480, 4.)
        elif drum_name in [
                'Pedal Hi Hat', 'Open Hi Hat', 'Crash Cymbal 1',
                'Ride Cymbal 1', 'Chinese Cymbal', 'Crash Cymbal 2',
                'Ride Cymbal 2', 'Tambourine', 'Long Guiro', 'Splash Cymbal'
        ]:
            d = .8 * noise(fs)
        elif drum_name in ['Low-Mid Tom']:
            d = tonal(fs, fs / 4, 240, 4.)
        elif drum_name in ['Hi-Mid Tom']:
            d = tonal(fs, fs / 4, 360, 4.)
        elif drum_name in [
                'Mute Hi Conga', 'Mute Cuica', 'Cowbell', 'Low Agogo',
                'Low Wood Block'
        ]:
            d = tonal(fs, fs / 10, 480, 4.)
        elif drum_name in [
                'Ride Bell', 'High Agogo', 'Claves', 'Hi Wood Block'
        ]:
            d = tonal(fs, fs / 20, 960, 4.)
        elif drum_name in ['Short Whistle']:
            d = tonal(fs, fs / 4, 480, 1.)
        elif drum_name in ['Long Whistle']:
            d = tonal(fs, fs, 480, 1.)
        elif drum_name in ['Mute Triangle']:
            d = tonal(fs, fs / 10, 1960, 1.)
        elif drum_name in ['Open Triangle']:
            d = tonal(fs, fs, 1960, 1.)
        else:
            if drum_name is not '':
                # This should never happen
                print('Unexpected drum {}'.format(drum_name))
            continue
        # Add in the synthesized waveform
        start = int(note.start * fs)
        synthesized[start:start + d.size] += d * note.velocity
    return synthesized
Example #7
0
def plot_pianoroll(
    ax: Axes,
    pianoroll: ndarray,
    is_drum: bool = False,
    resolution: Optional[int] = None,
    downbeats: Optional[Sequence[int]] = None,
    preset: str = "full",
    cmap: str = "Blues",
    xtick: str = "auto",
    ytick: str = "octave",
    xticklabel: bool = True,
    yticklabel: str = "auto",
    tick_loc: Sequence[str] = ("bottom", "left"),
    tick_direction: str = "in",
    label: str = "both",
    grid_axis: str = "both",
    grid_linestyle: str = ":",
    grid_linewidth: float = 0.5,
    **kwargs,
):
    """
    Plot a piano roll.

    Parameters
    ----------
    ax : :class:`matplotlib.axes.Axes`
        Axes to plot the piano roll on.
    pianoroll : ndarray, shape=(?, 128), (?, 128, 3) or (?, 128, 4)
        Piano roll to plot. For a 3D piano-roll array, the last axis can
        be either RGB or RGBA.
    is_drum : bool
        Whether it is a percussion track. Defaults to False.
    resolution : int
        Time steps per quarter note. Required if `xtick` is 'beat'.
    downbeats : list
        Boolean array that indicates whether the time step contains a
        downbeat (i.e., the first time step of a bar).
    preset : {'full', 'frame', 'plain'}
        Preset theme. For 'full' preset, ticks, grid and labels are on.
        For 'frame' preset, ticks and grid are both off. For 'plain'
        preset, the x- and y-axis are both off. Defaults to 'full'.
    cmap : str or :class:`matplotlib.colors.Colormap`
        Colormap. Will be passed to :func:`matplotlib.pyplot.imshow`.
        Only effective when `pianoroll` is 2D. Defaults to 'Blues'.
    xtick : {'auto', 'beat', 'step', 'off'}
        Tick format for the x-axis. For 'auto' mode, set to 'beat' if
        `resolution` is given, otherwise set to 'step'. Defaults to
        'auto'.
    ytick : {'octave', 'pitch', 'off'}
        Tick format for the y-axis. Defaults to 'octave'.
    xticklabel : bool
        Whether to add tick labels along the x-axis.
    yticklabel : {'auto', 'name', 'number', 'off'}
        Tick label format for the y-axis. For 'name' mode, use pitch
        name as tick labels. For 'number' mode, use pitch number. For
        'auto' mode, set to 'name' if `ytick` is 'octave' and 'number'
        if `ytick` is 'pitch'. Defaults to 'auto'.
    tick_loc : sequence of {'bottom', 'top', 'left', 'right'}
        Tick locations. Defaults to `('bottom', 'left')`.
    tick_direction : {'in', 'out', 'inout'}
        Tick direction. Defaults to 'in'.
    label : {'x', 'y', 'both', 'off'}
        Whether to add labels to x- and y-axes. Defaults to 'both'.
    grid_axis : {'x', 'y', 'both', 'off'}
        Whether to add grids to the x- and y-axes. Defaults to 'both'.
    grid_linestyle : str
        Grid line style. Will be passed to
        :meth:`matplotlib.axes.Axes.grid`.
    grid_linewidth : float
        Grid line width. Will be passed to
        :meth:`matplotlib.axes.Axes.grid`.
    **kwargs
        Keyword arguments to be passed to
        :meth:`matplotlib.axes.Axes.imshow`.

    """
    # Plot the piano roll
    if pianoroll.ndim == 2:
        transposed = pianoroll.T
    elif pianoroll.ndim == 3:
        transposed = pianoroll.transpose(1, 0, 2)
    else:
        raise ValueError("`pianoroll` must be a 2D or 3D numpy array")

    img = ax.imshow(
        transposed,
        cmap=cmap,
        aspect="auto",
        vmin=0,
        vmax=1 if pianoroll.dtype == np.bool_ else 127,
        origin="lower",
        interpolation="none",
        **kwargs,
    )

    # Format ticks and labels
    if xtick == "auto":
        xtick = "beat" if resolution is not None else "step"
    elif xtick not in ("beat", "step", "off"):
        raise ValueError(
            "`xtick` must be one of 'auto', 'beat', 'step' or 'off', not "
            f"{xtick}.")
    if yticklabel == "auto":
        yticklabel = "name" if ytick == "octave" else "number"
    elif yticklabel not in ("name", "number", "off"):
        raise ValueError(
            "`yticklabel` must be one of 'auto', 'name', 'number' or 'off', "
            f"{yticklabel}.")

    if preset == "full":
        ax.tick_params(
            direction=tick_direction,
            bottom=("bottom" in tick_loc),
            top=("top" in tick_loc),
            left=("left" in tick_loc),
            right=("right" in tick_loc),
            labelbottom=xticklabel,
            labelleft=(yticklabel != "off"),
            labeltop=False,
            labelright=False,
        )
    elif preset == "frame":
        ax.tick_params(
            direction=tick_direction,
            bottom=False,
            top=False,
            left=False,
            right=False,
            labelbottom=False,
            labeltop=False,
            labelleft=False,
            labelright=False,
        )
    elif preset == "plain":
        ax.axis("off")
    else:
        raise ValueError(
            f"`preset` must be one of 'full', 'frame' or 'plain', not {preset}"
        )

    # Format x-axis
    if xtick == "beat" and preset != "frame":
        if resolution is None:
            raise ValueError(
                "`resolution` must not be None when `xtick` is 'beat'.")
        n_beats = pianoroll.shape[0] // resolution
        ax.set_xticks(resolution * np.arange(n_beats) - 0.5)
        ax.set_xticklabels("")
        ax.set_xticks(resolution * (np.arange(n_beats) + 0.5) - 0.5,
                      minor=True)
        ax.set_xticklabels(np.arange(1, n_beats + 1), minor=True)
        ax.tick_params(axis="x", which="minor", width=0)

    # Format y-axis
    if ytick == "octave":
        ax.set_yticks(np.arange(0, 128, 12))
        if yticklabel == "name":
            ax.set_yticklabels(["C{}".format(i - 2) for i in range(11)])
    elif ytick == "step":
        ax.set_yticks(np.arange(0, 128))
        if yticklabel == "name":
            if is_drum:
                ax.set_yticklabels(
                    [note_number_to_drum_name(i) for i in range(128)])
            else:
                ax.set_yticklabels(
                    [note_number_to_name(i) for i in range(128)])
    elif ytick != "off":
        raise ValueError(
            f"`ytick` must be one of 'octave', 'pitch' or 'off', not {ytick}.")

    # Format axis labels
    if label not in ("x", "y", "both", "off"):
        raise ValueError(
            f"`label` must be one of 'x', 'y', 'both' or 'off', not {label}.")

    if label in ("x", "both"):
        if xtick == "step" or not xticklabel:
            ax.set_xlabel("time (step)")
        else:
            ax.set_xlabel("time (beat)")

    if label in ("y", "both"):
        if is_drum:
            ax.set_ylabel("key name")
        else:
            ax.set_ylabel("pitch")

    # Plot the grid
    if grid_axis not in ("x", "y", "both", "off"):
        raise ValueError(
            "`grid` must be one of 'x', 'y', 'both' or 'off', not "
            f"{grid_axis}.")
    if grid_axis != "off":
        ax.grid(
            axis=grid_axis,
            color="k",
            linestyle=grid_linestyle,
            linewidth=grid_linewidth,
        )

    # Plot downbeat boundaries
    if downbeats is not None:
        for downbeat in downbeats:
            ax.axvline(x=downbeat, color="k", linewidth=1)

    return img
Example #8
0
def plot_pianoroll(ax,
                   pianoroll,
                   is_drum=False,
                   beat_resolution=None,
                   downbeats=None,
                   preset='default',
                   cmap='Blues',
                   xtick='auto',
                   ytick='octave',
                   xticklabel=True,
                   yticklabel='auto',
                   tick_loc=None,
                   tick_direction='in',
                   label='both',
                   grid='both',
                   grid_linestyle=':',
                   grid_linewidth=.5):
    """
    Plot a piano-roll given as a numpy array.

    Parameters
    ----------
    ax : matplotlib.axes.Axes object
         The :class:`matplotlib.axes.Axes` object where the piano-roll will
         be plotted on.
    pianoroll : np.ndarray
        The piano-roll to be plotted. The values should be in [0, 1] when data
        type is float, and in [0, 127] when data type is integer.

        - For a 2D array, shape=(num_time_step, num_pitch).
        - For a 3D array, shape=(num_time_step, num_pitch, num_channel),
          where channels can be either RGB or RGBA.

    is_drum : bool
        Drum indicator. True for drums. False for other instruments. Default
        to False.
    beat_resolution : int
        Resolution of a beat (in time step). Required and only effective
        when `xticklabel` is 'beat'.
    downbeats : list
        Indices of time steps that contain downbeats., i.e. the first time
        step of a bar.
    preset : {'default', 'plain', 'frame'}
        Preset themes for the plot.

        - In 'default' preset, the ticks, grid and labels are on.
        - In 'frame' preset, the ticks and grid are both off.
        - In 'plain' preset, the x- and y-axis are both off.

    cmap :  `matplotlib.colors.Colormap`
        Colormap to use in :func:`matplotlib.pyplot.imshow`. Default to
        'Blues'. Only effective when `pianoroll` is 2D.
    xtick : {'auto', 'beat', 'step', 'off'}
        Use beat number or step number as ticks along the x-axis, or
        automatically set to 'beat' when `beat_resolution` is given and set
        to 'step', otherwise. Default to 'auto'.
    ytick : {'octave', 'pitch', 'off'}
        Use octave or pitch as ticks along the y-axis. Default to 'octave'.
    xticklabel : bool
        Indicate whether to add tick labels along the x-axis. Only effective
        when `xtick` is not 'off'.
    yticklabel : {'auto', 'name', 'number', 'off'}
        If 'name', use octave name and pitch name (key name when `is_drum`
        is True) as tick labels along the y-axis. If 'number', use pitch
        number. If 'auto', set to 'name' when `ytick` is 'octave' and
        'number' when `ytick` is 'pitch'. Default to 'auto'. Only effective
        when `ytick` is not 'off'.
    tick_loc : tuple or list
        List of locations to put ticks. Availables elements are 'bottom',
        'top', 'left' and 'right'. If None, default to ('bottom', 'left').
    tick_direction : {'in', 'out', 'inout'}
        Put ticks inside the axes, outside the axes, or both. Default to
        'in'. Only effective when `xtick` and `ytick` are not both 'off'.
    label : {'x', 'y', 'both', 'off'}
        Add label to the x-axis, y-axis, both or neither. Default to 'both'.
    grid : {'x', 'y', 'both', 'off'}
        Add grid to the x-axis, y-axis, both or neither. Default to 'both'.
    grid_linestyle : str
        Will be passed to :meth:`matplotlib.axes.Axes.grid` as 'linestyle'
        argument.
    grid_linewidth : float
        Will be passed to :meth:`matplotlib.axes.Axes.grid` as 'linewidth'
        argument.

    """
    if not HAS_MATPLOTLIB:
        raise ImportError("matplotlib package is required for plotting "
                          "supports.")

    if pianoroll.ndim not in (2, 3):
        raise ValueError("`pianoroll` must be a 2D or 3D numpy array")
    if pianoroll.shape[1] != 128:
        raise ValueError("The shape of `pianoroll` must be (num_time_step, "
                         "128)")
    if xtick not in ('auto', 'beat', 'step', 'off'):
        raise ValueError("`xtick` must be one of {'auto', 'beat', 'step', "
                         "'none'}")
    if xtick == 'beat' and beat_resolution is None:
        raise ValueError("`beat_resolution` must be a number when `xtick` "
                         "is 'beat'")
    if ytick not in ('octave', 'pitch', 'off'):
        raise ValueError("`ytick` must be one of {octave', 'pitch', 'off'}")
    if not isinstance(xticklabel, bool):
        raise TypeError("`xticklabel` must be of bool type")
    if yticklabel not in ('auto', 'name', 'number', 'off'):
        raise ValueError("`yticklabel` must be one of {'auto', 'name', "
                         "'number', 'off'}")
    if tick_direction not in ('in', 'out', 'inout'):
        raise ValueError("`tick_direction` must be one of {'in', 'out',"
                         "'inout'}")
    if label not in ('x', 'y', 'both', 'off'):
        raise ValueError("`label` must be one of {'x', 'y', 'both', 'off'}")
    if grid not in ('x', 'y', 'both', 'off'):
        raise ValueError("`grid` must be one of {'x', 'y', 'both', 'off'}")

    # plotting
    if pianoroll.ndim > 2:
        to_plot = pianoroll.transpose(1, 0, 2)
    else:
        to_plot = pianoroll.T
    if (np.issubdtype(pianoroll.dtype, np.bool_)
            or np.issubdtype(pianoroll.dtype, np.floating)):
        ax.imshow(to_plot,
                  cmap=cmap,
                  aspect='auto',
                  vmin=0,
                  vmax=1,
                  origin='lower',
                  interpolation='none')
    elif np.issubdtype(pianoroll.dtype, np.integer):
        ax.imshow(to_plot,
                  cmap=cmap,
                  aspect='auto',
                  vmin=0,
                  vmax=127,
                  origin='lower',
                  interpolation='none')
    else:
        raise TypeError("Unsupported data type for `pianoroll`")

    # tick setting
    if tick_loc is None:
        tick_loc = ('bottom', 'left')
    if xtick == 'auto':
        xtick = 'beat' if beat_resolution is not None else 'step'
    if yticklabel == 'auto':
        yticklabel = 'name' if ytick == 'octave' else 'number'

    if preset == 'plain':
        ax.axis('off')
    elif preset == 'frame':
        ax.tick_params(direction=tick_direction,
                       bottom=False,
                       top=False,
                       left=False,
                       right=False,
                       labelbottom=False,
                       labeltop=False,
                       labelleft=False,
                       labelright=False)
    else:
        ax.tick_params(direction=tick_direction,
                       bottom=('bottom' in tick_loc),
                       top=('top' in tick_loc),
                       left=('left' in tick_loc),
                       right=('right' in tick_loc),
                       labelbottom=(xticklabel != 'off'),
                       labelleft=(yticklabel != 'off'),
                       labeltop=False,
                       labelright=False)

    # x-axis
    if xtick == 'beat' and preset != 'frame':
        num_beat = pianoroll.shape[0] // beat_resolution
        xticks_major = beat_resolution * np.arange(0, num_beat)
        xticks_minor = beat_resolution * (0.5 + np.arange(0, num_beat))
        xtick_labels = np.arange(1, 1 + num_beat)
        ax.set_xticks(xticks_major)
        ax.set_xticklabels('')
        ax.set_xticks(xticks_minor, minor=True)
        ax.set_xticklabels(xtick_labels, minor=True)
        ax.tick_params(axis='x', which='minor', width=0)

    # y-axis
    if ytick == 'octave':
        ax.set_yticks(np.arange(0, 128, 12))
        if yticklabel == 'name':
            ax.set_yticklabels(['C{}'.format(i - 2) for i in range(11)])
    elif ytick == 'step':
        ax.set_yticks(np.arange(0, 128))
        if yticklabel == 'name':
            if is_drum:
                ax.set_yticklabels([
                    pretty_midi.note_number_to_drum_name(i) for i in range(128)
                ])
            else:
                ax.set_yticklabels(
                    [pretty_midi.note_number_to_name(i) for i in range(128)])

    # axis labels
    if label == 'x' or label == 'both':
        if xtick == 'step' or not xticklabel:
            ax.set_xlabel('time (step)')
        else:
            ax.set_xlabel('time (beat)')

    if label == 'y' or label == 'both':
        if is_drum:
            ax.set_ylabel('key name')
        else:
            ax.set_ylabel('pitch')

    # grid
    if grid != 'off':
        ax.grid(axis=grid,
                color='k',
                linestyle=grid_linestyle,
                linewidth=grid_linewidth)

    # downbeat boarder
    if downbeats is not None and preset != 'plain':
        for step in downbeats:
            ax.axvline(x=step, color='k', linewidth=1)
Example #9
0
#!/usr/local/bin/python
import sys
import pretty_midi
midi_data = pretty_midi.PrettyMIDI('drums.mid')


pr = midi_data.instruments[0].get_piano_roll().tolist()
pr_len = len(pr[0])
new_pr = []
print pr_len
for i in range(0,pr_len):
	tmp_pr = []
	for j in range(0,127):
		if pr[j][i] > 0:
			if midi_data.instruments[0].is_drum:
				tmp_pr.append(pretty_midi.note_number_to_drum_name(j))
			else:
				tmp_pr.append(pretty_midi.note_number_to_name(j))
	new_pr.append(tmp_pr)
print new_pr

# Synthesize the resulting MIDI data using sine waves
#audio_data = midi_data.synthesize()

print pretty_midi.note_name_to_number("C3")