def add_buffer_to_intervals(ranges, n_channels, pad_channels=5):
    """Extend interval range on both sides by a number of channels.

    Parameters
    ----------
    ranges : list
        List of intervals [(low, upp), ...].
    n_channels : int
        Number of spectral channels.
    pad_channels : int
        Number of channels by which an interval (low, upp) gets extended on both sides, resulting in (low - pad_channels, upp + pad_channels).

    Returns
    -------
    ranges_new : list
        New list of intervals [(low - pad_channels, upp + pad_channels), ...].

    """
    ranges_new, intervals = ([] for i in range(2))
    for i, (low, upp) in enumerate(ranges):
        low, upp = low - pad_channels, upp + pad_channels
        if low < 0:
            low = 0
        if upp > n_channels:
            upp = n_channels

        intervals.append((low, upp))

    # merge intervals if they are overlapping
    sorted_by_lower_bound = sorted(intervals, key=lambda tup: tup[0])

    for higher in sorted_by_lower_bound:
        if not ranges_new:
            ranges_new.append(higher)
        else:
            lower = ranges_new[-1]
            # test for intersection between lower and higher:
            # we know via sorting that lower[0] <= higher[0]
            if higher[0] <= lower[1]:
                upper_bound = max(lower[1], higher[1])
                ranges_new[-1] = (lower[0], upper_bound)  # replace by merged interval
            else:
                ranges_new.append(higher)

    return ranges_new