def partial_at(p: np.ndarray, t: float, extend=False) -> Opt[np.ndarray]: """ Evaluates partial `p` at time `t` Args: p: the partial, a 2D numpy array t: the time to evaluate the partial at extend: should the partial be extended to -inf, +inf? If True, querying a partial outside its boundaries will result in the values at the boundaries. Otherwise, None is returned Returns: the breakpoint at t (a np array of shape (4,) with columns (time, freq, amp, bw). Returns None if the array is not defined at the given time """ if extend: bp = npx.table_interpol_linear(p, np.array([t], dtype=float)) else: t0, t1 = p[0, 0], p[-1, 0] if t0 <= t <= t1: bp = npx.table_interpol_linear(p, np.array([t], dtype=float)) else: return None bp.shape = (4, ) return bp
def partial_at(p, t, extend=False): """ Evaluates partial `p` at time `t` p: the partial t: the time to evaluate the partial at extend: should the partial be extended to -inf, +inf? If True, querying a partial outside its boundaries will result in the values at the boundaries. Otherwise, None is returned """ # TODO: implement this as a bisected search on times, interpolate if extend: bp = npx.table_interpol_linear(p, np.array([t], dtype=float)) else: t0, t1 = p[0, 0], p[-1, 0] if t0 <= t <= t1: bp = npx.table_interpol_linear(p, np.array([t], dtype=float)) else: return None bp.shape = (4, ) return bp
def partial_at(p, t, extend=False): """ Evaluates partial `p` at time `t` p: the partial t: the time to evaluate the partial at extend: should the partial be extended to -inf, +inf? If True, querying a partial outside its boundaries will result in the values at the boundaries. Otherwise, None is returned """ # TODO: implement this as a bisected search on times, interpolate if extend: bp = npx.table_interpol_linear(p, np.array([t], dtype=float)) else: t0, t1 = p[0, 0], p[-1, 0] if t0 <= t <= t1: bp = npx.table_interpol_linear(p, np.array([t], dtype=float)) else: return None bp.shape = (4,) return bp
def partial_sample_at(p, times): # type: (np.ndarray, t.Union[np.ndarray, list]) -> np.ndarray """ Sample a partial `p` at given times p: a partial represented as a 2D-array with columns times, freqs, amps, phases, bws Returns a partial (2D-array with columns times, freqs, amps, phases, bws) """ times = np.asarray(times, dtype=float) data = npx.table_interpol_linear(p, times) timescol = times.reshape((times.shape[0], 1)) return np.hstack((timescol, data))
def partial_sample_at(p: np.ndarray, times: np.ndarray) -> np.ndarray: """ Sample a partial `p` at given times Args: p: a partial represented as a 2D-array with columns times, freqs, amps, phases, bws times: the times to evaluate partial at Returns: a partial (2D-array with columns times, freqs, amps, phases, bws) """ assert isinstance(times, np.ndarray) t0 = p[0, 0] t1 = p[-1, 0] index0 = npx.searchsorted1(times, t0) index1 = npx.searchsorted1(times, t1) - 1 times = times[index0:index1] data = npx.table_interpol_linear(p, times) timescol = times.reshape((times.shape[0], 1)) return np.hstack((timescol, data))
def partials_sample(sp, dt=0.002, t0=-1, t1=-1, maxactive=0, interleave=True): # type: (t.List[np.ndarray], float, float, float, int, bool) -> t.Any """ Samples the partials between times `t0` and `t1` with a sampling period `dt`. sp: a list of 2D-arrays, each representing a partial dt: sampling period t0: start time, or None to use the start time of the spectrum t1: end time, or None to use the end time of the spectrum maxactive: limit the number of active partials to this number. If the number of active streams (partials with non-zero amplitude) if higher than `maxactive`, the softest partials will be zeroed. During resynthesis, zeroed partials are skipped. This strategy is followed to allow to pack all partials at the cost of having a great amount of streams, and limit the streams (for better performance) at the synthesis stage. interleave: if True, all columns of each partial are interleaved (see below) To be used in connection with `pack`, which packs short non-simultaneous partials into longer ones. The result is a 2D matrix representing the partials. Sampling times is calculated as: times = arange(t0, t1+dt, dt) * If interleave is True, it returns a big matrix of format [[f0, amp0, bw0, f1, amp1, bw1, …, fN, ampN, bwN], # times[0] [f0, amp0, bw0, f1, amp1, bw1, …, fN, ampN, bwN], # times[1] ... ] Where (f0, amp0, bw0) represent the freq, amplitude and bandwidth of partial 0 at a given time, (f1, amp1, bw0) the corresponding data for partial 1, etc. * If interleave is False, it returns three arrays: freqs, amps, bws of the form [[f0, f1, f2, ..., fn] @ times[0] [f0, f1, f2, ..., fn] @ times[1] ] See also ~~~~~~~~ * matrix_save * partials_save_matrix NB: phase information is not sampled """ if t0 < 0: t0 = min(p[0, 0] for p in sp) if t1 <= 0: t1 = max(p[-1, 0] for p in sp) times = np.arange(t0, t1 + dt, dt) if not interleave: freqs, amps, bws = [], [], [] for p in sp: out = npx.table_interpol_linear(p, times) freqs.append(out[:, 0]) amps.append(out[:, 1]) bws.append(out[:, 3]) freqarray = np.column_stack(freqs) amparray = np.column_stack(amps) bwarray = np.column_stack(bws) if maxactive > 0: _limit_matrix(amparray, maxactive) return freqarray, amparray, bwarray else: cols = [] for p in sp: p_resampled = npx.table_interpol_linear(p, times) # Extract columns: freq, amp, bw (freq is now index 0, because # the resampled partial has no times column) cols.append(p_resampled[:, (0, 1, 3)]) m = np.hstack(cols) if maxactive > 0: _limit_matrix_interleaved(m, maxactive) return m
def partials_sample(sp, dt=0.002, t0=-1, t1=-1, maxactive=0, interleave=True): # type: (t.List[np.ndarray], float, float, float, int, bool) -> t.Any """ Samples the partials between times `t0` and `t1` with a sampling period `dt`. sp: a list of 2D-arrays, each representing a partial dt: sampling period t0: start time, or None to use the start time of the spectrum t1: end time, or None to use the end time of the spectrum maxactive: limit the number of active partials to this number. If the number of active streams (partials with non-zero amplitude) if higher than `maxactive`, the softest partials will be zeroed. During resynthesis, zeroed partials are skipped. This strategy is followed to allow to pack all partials at the cost of having a great amount of streams, and limit the streams (for better performance) at the synthesis stage. interleave: if True, all columns of each partial are interleaved (see below) To be used in connection with `pack`, which packs short non-simultaneous partials into longer ones. The result is a 2D matrix representing the partials. Sampling times is calculated as: times = arange(t0, t1+dt, dt) * If interleave is True, it returns a big matrix of format [[f0, amp0, bw0, f1, amp1, bw1, …, fN, ampN, bwN], # times[0] [f0, amp0, bw0, f1, amp1, bw1, …, fN, ampN, bwN], # times[1] ... ] Where (f0, amp0, bw0) represent the freq, amplitude and bandwidth of partial 0 at a given time, (f1, amp1, bw0) the corresponding data for partial 1, etc. * If interleave is False, it returns three arrays: freqs, amps, bws of the form [[f0, f1, f2, ..., fn] @ times[0] [f0, f1, f2, ..., fn] @ times[1] ] See also ~~~~~~~~ * matrix_save * partials_save_matrix NB: phase information is not sampled """ if t0 < 0: t0 = min(p[0, 0] for p in sp) if t1 <= 0: t1 = max(p[-1, 0] for p in sp) times = np.arange(t0, t1+dt, dt) if not interleave: freqs, amps, bws = [], [], [] for p in sp: out = npx.table_interpol_linear(p, times) freqs.append(out[:,0]) amps.append(out[:,1]) bws.append(out[:,3]) freqarray = np.column_stack(freqs) amparray = np.column_stack(amps) bwarray = np.column_stack(bws) if maxactive > 0: _limit_matrix(amparray, maxactive) return freqarray, amparray, bwarray else: cols = [] for p in sp: p_resampled = npx.table_interpol_linear(p, times) # Extract columns: freq, amp, bw (freq is now index 0, because # the resampled partial has no times column) cols.append(p_resampled[:,(0, 1, 3)]) m = np.hstack(cols) if maxactive > 0: _limit_matrix_interleaved(m, maxactive) return m