Skip to content

util

Utilities for bpf4


Function Description
asbpf Convert obj to a bpf
binarymask Creates a binary mask
blendwithceil Returns a blend of b with its maximum y value
blendwithfloor Returns a blend of b with its minimum y value
bpf_to_csv Write this bpf as a csv representation
bpf_to_dict convert a bpf to a dict with the following format
bpf_to_json convert this bpf to json format.
bpf_to_yaml Convert this bpf to json format.
bpfavg Return a Bpf which is the average of b over the range dx
calculate_projection Calculate a projection needed to map the interval x0:x1 to p0:p1
concat_bpfs Concatenate these bpfs together, one after the other
csv_to_bpf Read a bpf from a csv file
dict_to_bpf Convert a dict to a bpf
dumpbpf Dump the data of this bpf as human readable text
histbpf Create a historgram of b
jagged_band Create a jagged bpf between lowerbpf and upperbpf at the x values given
loadbpf Load a bpf saved with dumpbpf
makebpf Create a bpf from the given descriptor and points
max_ Return a bpf representing the max over the given elements
maximum return the x where bpf(x) is the maximum of bpf
min_ Return a bpf representing the min over elements
minimum Find the x where bpf(x) is minimized
multi_parseargs Parse args of a multi bpf
parseargs Convert the args and kws to the canonical form (xs, ys, kws)
parsedescr Parse interpolation description
projection_fixedpoint Returns the fixed point given the projection parameters
randombw Create a random bpf
rms The rms of this bpf
rmsbpf Return a bpf representing the rms of the given samples as a function of time
select Create a new bpf which interpolates between adjacent bpfs
simplify_linear_coords Simplify the linear bpf defined by the points xs and ys
smoothen Return a bpf representing a smooth version of b
split_fragments Split a bpf into its fragments
sum_ Return a bpf representing the sum of elements
warped Represents the curvature of a linear space.
zigzag Creates a curve formed of lines from b0(x) to b1(x) for each x in xs

asbpf

def asbpf(obj, bounds: tuple = (-inf, inf)) -> core.BpfInterface

Convert obj to a bpf

Args

  • obj: the object to convert to a bpf (a function, a dict, a constant or a bpf, in which case it is returned as is)
  • bounds (tuple): the lower and upper bounds where this bpf is defined (default: (-inf, inf))

Returns

    (core.BpfInterface) the resulting bpf


binarymask

def binarymask(mask: str | list[int], durs: Sequence[float] = None, 
               offset: float = 0.0, cycledurs: bool = True) -> core.NoInterpol

Creates a binary mask

Example

>>> mask = binarymask("x--x-x---")

Args

  • mask (str | list[int]): a mask string ('x'=1, '-'=0) or a sequence of states (a state is either 0 or 1)
  • durs (Sequence[float]): a sequence of durations (default=[1]) (default: None)
  • offset (float): (default: 0.0)
  • cycledurs (bool): (default: True)

Returns

    (core.NoInterpol) A NoInterpol bpf representing the binary mask


blendwithceil

def blendwithceil(b, mix: float = 0.5) -> core._BpfBlend

Returns a blend of b with its maximum y value

Args

  • b:
  • mix (float): (default: 0.5)

blendwithfloor

def blendwithfloor(b: core.BpfInterface, mix: float = 0.5) -> core._BpfBlend

Returns a blend of b with its minimum y value

Args

  • b (core.BpfInterface):
  • mix (float): (default: 0.5)

bpf_to_csv

def bpf_to_csv(bpf: core.BpfInterface, csvfile: str) -> None

Write this bpf as a csv representation

Args

  • bpf (core.BpfInterface): the bpf to write as csv
  • csvfile (str): the output filename

bpf_to_dict

def bpf_to_dict(bpf: core.BpfInterface) -> dict

convert a bpf to a dict with the following format

>>> b = bpf.expon(3.0, 0, 0, 1, 10, 2, 20)
>>> bpf_to_dict(b)
{
    'interpolation': 'expon(3.0)',
    'points': [0, 0, 1, 10, 20, 20]  # [x0, y0, x1, y1, ...]
}

>>> b = bpf.multi(0, 0, 'linear',
                  1, 10, 'expon(2)',
                  3, 25)
>>> bpf_to_dict(b)
{
    'interpolation': 'multi',
    'segments': [
        [0, 0, 'linear'],
        [1, 10, 'expon(2)',
        [3, 25, '']]
}

Args

  • bpf (core.BpfInterface): the bpf to convert to a dict

Returns

    (dict) The bpf as a dictionary


bpf_to_json

def bpf_to_json(bpf: core.BpfInterface, outfile: str = None) -> str

convert this bpf to json format.

If outfile is not given, it returns a string, as in dumps

Args

  • bpf (core.BpfInterface): the bpf to dump as json
  • outfile (str): the output filename. If given, output is saved here (default: None)

Returns

    (str) The json text


bpf_to_yaml

def bpf_to_yaml(bpf: core.BpfInterface, outfile: str = None) -> str

Convert this bpf to json format.

Args

  • bpf (core.BpfInterface): the bpf to convert
  • outfile (str): if given, the yaml text is saved to this file (default: None)

Returns

    (str) The yaml text


bpfavg

def bpfavg(b: core.BpfInterface, dx: float) -> core.BpfInterface

Return a Bpf which is the average of b over the range dx

Args

  • b (core.BpfInterface): the bpf
  • dx (float): the period to average b over

Returns

    (core.BpfInterface) a bpf representing the average of b along the bounds of b over a sliding period of dx


calculate_projection

def calculate_projection(x0, x1, p0, p1) -> tuple[float, float, float]

Calculate a projection needed to map the interval x0:x1 to p0:p1

Args

  • x0:
  • x1:
  • p0:
  • p1:

Returns

    (tuple[float, float, float]) A tuple (rx, dx, offset)


concat_bpfs

def concat_bpfs(bpfs: list[core.BpfInterface]) -> core._BpfConcat

Concatenate these bpfs together, one after the other

Args

  • bpfs (list[core.BpfInterface]):

csv_to_bpf

def csv_to_bpf(csvfile: str) -> core.BpfInterface

Read a bpf from a csv file

Args

  • csvfile (str):

dict_to_bpf

def dict_to_bpf(d: dict) -> bpf.BpfInterface

Convert a dict to a bpf

Format 1

bpf = {
    'interpolation': 'expon(2)',
    10: 0.1,
    15: 1,
    25: -1
}

Format 2

bpf = {
    'interpolation': 'linear',
    'points': [x0, y0, x1, y1, ...]
}

Format 2b

bpf = {
    'interpolation': 'linear',
    'points': [(x0, y0), (x1, y1), ...]
}

Format 3 (multi)

bpf = {
    'interpolation': 'multi',
    'segments': [
        [x0, y0, 'descr0'],
        [x1, y1, 'descr1'],
        ...
        [xn, yn, '']
    ]
}

Args

  • d (dict): the dictionary to convert to a bpf

Returns

    (bpf.BpfInterface) the converted bpf


dumpbpf

def dumpbpf(bpf: core.BpfInterface, fmt: str = yaml) -> str

Dump the data of this bpf as human readable text

The bpf can then be reconstructed via loadbpf

Args

  • bpf (core.BpfInterface): the bpf to dump
  • fmt (str): the format, one of 'csv', 'yaml', 'json' (default: yaml)

Returns

    (str) the text representation according to the format


histbpf

def histbpf(b: core.BpfInterface, numbins: int = 20, numsamples: int = 400
            ) -> core.Linear

Create a historgram of b

Example

>>> from sndfileio import *
>>> import bpf4
>>> samples, sr = sndread("path/to/soundfile.wav")
>>> dbcurve = bpf4.util.rmsbpf(samples, sr=sr).amp2db()
>>> dbval2hist = bpf4.util.histbpf(dbcurve)
# Find the db percentile at a given time, this gives a measurement of the
# relative strength of the sound at a given moment
>>> dur = len(samples)/sr
>>> percentile = dbval2hist(dur*0.5)
0.312Z
>>> dbhist2val = dbval2hist.inverted()

This indicates that at the middle of the sound the amplitude is at percentile ~30

Args

  • b (core.BpfInterface): the bpf
  • numbins (int): the number of bins (default: 20)
  • numsamples (int): how many samples to take to determine the histogram (default: 400)

Returns

    (core.Linear) a bpf mapping values to percentiles. The returned bpf can be inverted (see example) to map percentiles to values


jagged_band

def jagged_band(xs: list[float], upperbpf: core.BpfInterface, lowerbpf: int = 0, 
                curve: str = linear) -> core.BpfInterface

Create a jagged bpf between lowerbpf and upperbpf at the x values given

At each x in xs the, the value is equal to lowerbpf, sweeping with curvature 'curve' to upperbpf just before the next x

Example

from bpf4 import *
import numpy as np
a = expon(0, 0, 1, 10, exp=2)
b = expon(0, 0, 1, 5, exp=4)
j = util.jagged_band(list(np.arange(0, 1, 0.1)), a, b, curve='expon(1.5)')
j.plot()

Args

  • xs (list[float]):
  • upperbpf (core.BpfInterface):
  • lowerbpf (int): (default: 0)
  • curve (str): (default: linear)

loadbpf

def loadbpf(path: str, fmt: str = auto) -> core.BpfInterface

Load a bpf saved with dumpbpf

Possible formats: auto, csv, yaml, json

Args

  • path (str): the path of the saved bpf
  • fmt (str): the format used to save the bpf ('auto' to detect the format) (default: auto)

Returns

    (core.BpfInterface) a bpf


makebpf

def makebpf(descr: str, X: Sequence[float], Y: Sequence[float]
            ) -> core.BpfInterface

Create a bpf from the given descriptor and points

Args

  • descr (str): a string descriptor of the interpolation ("linear", "expon(xx)", ...)
  • X (Sequence[float]): the array of xs
  • Y (Sequence[float]): the array of ys

Returns

    (core.BpfInterface) the created bpf


max_

def max_(elements) -> core.Max

Return a bpf representing the max over the given elements

Args

  • elements: each element can be a bpf or a scalar

Returns

    (core.Max) a Max bpf


maximum

def maximum(bpf: core.BpfInterface, N: int = 10) -> float | None

return the x where bpf(x) is the maximum of bpf

Args

  • bpf (core.BpfInterface): the bpf to analyze
  • N (int): (default: 10)

Returns

    (float | None) is the maximum. Returns None if no maximum found


min_

def min_(elements) -> core.Min

Return a bpf representing the min over elements

Args

  • elements: each can be a bpf or a scalar

Returns

    (core.Min) a Min bpf


minimum

def minimum(bpf: core.BpfInterface, N: int = 10) -> float | None

Find the x where bpf(x) is minimized

Args

  • bpf (core.BpfInterface): the bpf to analyze
  • N (int): the number of estimates (default: 10)

Returns

    (float | None) is minimized. Returns None if no minimum found


multi_parseargs

def multi_parseargs(args) -> tuple[list[float], list[float], list[str]]

Parse args of a multi bpf

Given a list of args of the form (x0, y0, interpol) or (x0, y0) (or a flat version thereof), fills the possibly missing interpolation descriptions and returns a tuple (xs, ys, interpolations)

Args

  • args:

Returns

    (tuple[list[float], list[float], list[str]]) a tuple (xs, ys, interpolations), where len(interpolations) == len(xs) - 1


parseargs

def parseargs(args, kws) -> tuple[list[float], list[float], dict]

Convert the args and kws to the canonical form (xs, ys, kws)

Raises ValueError if failed

All the following variants result in the same result:

x0, y0, x1, y1, , exp=0.5
(x0, y0), (x1, y1), , exp=0.5           
{x0:y0, x1:y1, }, exp=0.5               
[x0, x1, ], [y0, y1, ], exp=0.5        

Result: [x0, x1, ], [y0, y1, ], {exp:0.5}

Args

  • args:
  • kws:

Returns

    (tuple[list[float], list[float], dict]) A tuple (xs, ys, kws)


parsedescr

def parsedescr(descr: str, validate: bool = True) -> tuple[str, dict]

Parse interpolation description

descr output
linear linear, {}
expon(0.4) expon, {'exp': 0.4}
halfcos(2.5, numiter=1) halfcos, {'exp':2.5, 'numiter': 1}

Args

  • descr (str):
  • validate (bool): (default: True)

projection_fixedpoint

def projection_fixedpoint(rx, dx, offset) -> None

Returns the fixed point given the projection parameters

x2 = (x-offset)*rx + dx

For a fixed point, x2 == x

Args

  • rx:
  • dx:
  • offset:

randombw

def randombw(bw: float | core.BpfInterface, center: float | core.BpfInterface
             ) -> core.BpfInterface

Create a random bpf

if randombw is 0.1 and center is 1, the bpf will render values between 0.95 and 1.05

Note

This bpf will always be different, since the random numbers are calculated as needed. Sample it to freeze it to a known state.

Example

>>> l = bpf.linear(0, 0, 1, 1)
>>> r = bpf.util.randombw(0.1)
>>> l2 = (l*r)[::0.01]

Args

  • bw (float | core.BpfInterface): a (time-varying) bandwidth
  • center (float | core.BpfInterface): the center of the random distribution

Returns

    (core.BpfInterface) a bpf


rms

def rms(bpf: core.BpfInterface, rmstime: float = 0.1) -> core.BpfInterface

The rms of this bpf

Args

  • bpf (core.BpfInterface): the bpf
  • rmstime (float): the time to calculate the rms over (default: 0.1)

Returns

    (core.BpfInterface) a bpf representing the rms of this bpf at any x coord


rmsbpf

def rmsbpf(samples: np.ndarray, sr: int, dt: float = 0.01, overlap: int = 2, 
           smoothen: float = 0.0) -> core.BpfInterface

Return a bpf representing the rms of the given samples as a function of time

Args

  • samples (np.ndarray): the audio samples
  • sr (int): the sample rate
  • dt (float): analysis time period (default: 0.01)
  • overlap (int): overlap of analysis frames (default: 2)
  • smoothen (float): if given, the returned bpf is smoothen using the given value as window (default: 0.0)

Returns

    (core.BpfInterface) a sampled bpf if not smoothening operation is performed, or a linear bpf if smoothening is required


select

def select(which: core.BpfInterface, bpfs: Sequence[core.BpfInterface], 
           shape: str = linear) -> core._BpfSelect

Create a new bpf which interpolates between adjacent bpfs

Example

>>> which = nointerpol(0, 0, 5, 1)
>>> bpfs = [linear(0, 0, 10, 10), linear(0, 10, 10, 0)]
>>> s = select(which, bpfs)
>>> s(1)     # at time=1, the first bpf will be selected
0

Args

  • which (core.BpfInterface): returns at any x, which bpf from bpfs should return the result
  • bpfs (Sequence[core.BpfInterface]): a list of bpfs
  • shape (str): interpolation shape between consecutive bpfs (default: linear)

Returns

    (core._BpfSelect) a BpfSelect


simplify_linear_coords

def simplify_linear_coords(xs: np.ndarray, ys: np.ndarray, 
                           threshold: float = 0.0, ratio: float = 0.0
                           ) -> tuple[np.ndarray, np.ndarray]

Simplify the linear bpf defined by the points xs and ys

Args

  • xs (np.ndarray): the x coord array
  • ys (np.ndarray): the y coord array
  • threshold (float): the simplification threshold. Points which deviate less than this value will be simplified. The first and last points are never simplified (default: 0.0)
  • ratio (float): (default: 0.0)

Returns

    (tuple[np.ndarray, np.ndarray]) the simplified line as a tuple (xs, ys)


smoothen

def smoothen(b: core.BpfInterface, window: float, N: int = 1000, 
             interpol: str = linear) -> core.BpfInterface

Return a bpf representing a smooth version of b

Example

>>> import bpf4 as bpf
>>> b = bpf.linear(0, 0, 0.1, 1, 0.2, 10, 0.3, 1, 0.5, 3, 0.8, -2)
>>> bsmooth = bpf.util.smoothen(b, window=0.05)
>>> axes = b.plot(show=False)
>>> bsmooth.plot(axes=axes)

Args

  • b (core.BpfInterface): a bpf
  • window (float): the width (in x coords) of the smoothing window
  • N (int): number of points to resample the bpf (default: 1000)
  • interpol (str): the interpolation to use. One of 'linear' or 'smooth' (default: linear)

Returns

    (core.BpfInterface) a bpf representing a smoother version of b


split_fragments

def split_fragments(b: core.BpfBase, sep: float = nan) -> list[core.BpfBase]

Split a bpf into its fragments

Fragments are defined by the separator, which is NAN by default. This separator splits the points in this bpf into fragments. A fragment must at least have two items

Example

>>> a = bpf.linear(0, 0, 1, 10, 2, 5, 3, 30, 4, nan, 5, nan, 6, 0, 7, 1, 8, 0.5, 9, nan, 10, 2, 11, 3)
>>> split_fragments(a)
[Linear[0.0:3.0], Linear[6.0:8.0], Linear[10.0:11.0]]

Args

  • b (core.BpfBase): the bpf to split. This bpf must be a Linear, Sampled or any other BpfBase subclass (HalfCos, Smooth, etc.). For any other bpf the bpf needs to be sampled (bpf[::period])
  • sep (float): the separator to use (default: nan)

Returns

    (list[core.BpfBase]) a list of bpfs representing the fragments


sum_

def sum_(elements) -> Any

Return a bpf representing the sum of elements

Args

  • elements: each can be a bpf or a scalar

Returns

    a bpf representing the sum of all elements


warped

def warped(bpf: core.BpfInterface, dx: float = None, numpoints: int = 1000
           ) -> core.Sampled

Represents the curvature of a linear space.

The result is a warped bpf so that:

position_bpf | warped_bpf = corresponding position after warping

Example

Find the theoretical position of a given point according to a probability distribution

>>> from bpf4 import *
>>> import matplotlib.pyplot as plt
>>> distribution = halfcos(0,0, 0.5,1, 1, 0)
>>> w = util.warped(distribution)
>>> distribution.plot()
>>> w.plot()

Now plot the histrogram of the warped bpf. It should resemble the original distribution

plt.hist(w.map(10000), bins=200, density=True)

Using another distribution, notice that the histogram follows the distribution again:

distribution = halfcos(0,0, 0.8,1, 1, 0, exp=3.)
w = util.warped(distribution)
distribution.plot()
w.plot()
_ = plt.hist(w.map(10000), bins=200, density=True)[2]

Args

  • bpf (core.BpfInterface):
  • dx (float): the accuracy of the measurement (default: None)
  • numpoints (int): if dx is not given, the bpf is sampled numpoints times across its bounds (default: 1000)

Returns

    (core.Sampled) The warped bpf


zigzag

def zigzag(b0: core.BpfInterface, b1: core.BpfInterface, xs: Sequence[float], 
           shape: str = linear) -> core.BpfInterface

Creates a curve formed of lines from b0(x) to b1(x) for each x in xs

   *.
    *...  b0
     *  ...
     *     ...
      *       ....
       *          ...
        *         :  ...
         *        :*    ...
         *        : *      ...
          *       :  **       ...
           *      :    *         :*.
            *     :     *        : **...
             *    :      *       :   *  ...
             *    :       *      :    *    ...
              *   :        *     :     **     .:.
               *  :         *    :       *     :**..
                * :          **  :        **   :  ****.
                 *:            * :          *  :      ****
    -----------  *:             *:           * :          ****
      b1       ---*--------------*---         **:             ****
                                     -----------*----------      .**
                                                           -----------
    x0            x1              x2                       x3

Args

  • b0 (core.BpfInterface): a bpf
  • b1 (core.BpfInterface): a bpf
  • xs (Sequence[float]): a seq. of x values to evaluate b0 and b1
  • shape (str): the shape of each segment (default: linear)

Returns

    (core.BpfInterface) The resulting bpf