picodrive/pico/sound/blipper.h
2022-03-31 19:51:15 +02:00

195 lines
6.9 KiB
C

/*
* Copyright (C) 2013 - Hans-Kristian Arntzen
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and
* associated documentation files (the "Software"),
* to deal in the Software without restriction,
* including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef BLIPPER_H__
#define BLIPPER_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Compile time configurables. */
#ifndef BLIPPER_LOG_PERFORMANCE
#define BLIPPER_LOG_PERFORMANCE 0
#endif
#ifndef BLIPPER_FIXED_POINT
#define BLIPPER_FIXED_POINT 1
#endif
/* Set to float or double.
* long double is unlikely to provide any improved precision. */
#ifndef BLIPPER_REAL_T
#define BLIPPER_REAL_T float
#endif
/* Allows including several implementations in one lib. */
#if BLIPPER_FIXED_POINT
#define BLIPPER_MANGLE(x) x##_fixed
#else
#define BLIPPER_CONCAT2(a, b) a ## b
#define BLIPPER_CONCAT(a, b) BLIPPER_CONCAT2(a, b)
#define BLIPPER_MANGLE(x) BLIPPER_CONCAT(x##_, BLIPPER_REAL_T)
#endif
#include <limits.h>
typedef struct blipper blipper_t;
typedef BLIPPER_REAL_T blipper_real_t;
#if BLIPPER_FIXED_POINT
#ifdef HAVE_STDINT_H
#include <stdint.h>
typedef int16_t blipper_sample_t;
typedef int32_t blipper_long_sample_t;
#else
#if SHRT_MAX == 0x7fff
typedef short blipper_sample_t;
#elif INT_MAX == 0x7fff
typedef int blipper_sample_t;
#else
#error "Cannot find suitable type for blipper_sampler_t."
#endif
#if INT_MAX == 0x7fffffffl
typedef int blipper_long_sample_t;
#elif LONG_MAX == 0x7fffffffl
typedef long blipper_long_sample_t;
#else
#error "Cannot find suitable type for blipper_long_sample_t."
#endif
#endif
#else
typedef BLIPPER_REAL_T blipper_sample_t;
typedef BLIPPER_REAL_T blipper_long_sample_t; /* Meaningless for float version. */
#endif
/* Create a new blipper.
* taps: Number of filter taps per impulse.
*
* cutoff: Cutoff frequency in the passband. Has a range of [0, 1].
*
* beta: Beta used for Kaiser window.
*
* decimation: Sets decimation rate.
* The input sampling rate is then output_rate * decimation.
* buffer_samples: The maximum number of processed output samples that can be
* buffered up by blipper.
*
* filter_bank: An optional filter which has already been created by
* blipper_create_filter_bank(). blipper_new() does not take ownership
* of the buffer and must be freed by caller.
* If non-NULL, cutoff and beta will be ignored.
*
* Some sane values:
* taps = 64, cutoff = 0.85, beta = 8.0
*/
#define blipper_new BLIPPER_MANGLE(blipper_new)
blipper_t *blipper_new(unsigned taps, double cutoff, double beta,
unsigned decimation, unsigned buffer_samples, const blipper_sample_t *filter_bank);
/* Reset the blipper to its initiate state. */
#define blipper_reset BLIPPER_MANGLE(blipper_reset)
void blipper_reset(blipper_t *blip);
/* Create a filter which can be passed to blipper_new() in filter_bank.
* Arguments to decimation and taps must match. */
#define blipper_create_filter_bank BLIPPER_MANGLE(blipper_create_filter_bank)
blipper_sample_t *blipper_create_filter_bank(unsigned decimation,
unsigned taps, double cutoff, double beta);
/* Frees the blipper. blip can be NULL (no-op). */
#define blipper_free BLIPPER_MANGLE(blipper_free)
void blipper_free(blipper_t *blip);
/* Add a ramp to the synthesized wave. The ramp is added to the integrator
* on every input sample.
* The amount added is delta / clocks per input sample.
* The interface is fractional to have better accuract with fixed point.
* This can be combined with a delta train to synthesize e.g. sawtooth waves.
* When using a ramp, care must be taken to ensure that the integrator does not saturate.
* It is recommended to use floating point implementation when using the ramp. */
#define blipper_set_ramp BLIPPER_MANGLE(blipper_set_ramp)
void blipper_set_ramp(blipper_t *blip, blipper_long_sample_t delta,
unsigned clocks);
/* Data pushing interfaces. One of these should be used exclusively. */
/* Push a single delta, which occurs clock_step input samples after the
* last time a delta was pushed. The delta value is the difference signal
* between the new sample and the previous.
* It is unnecessary to pass a delta of 0.
* If the deltas are known beforehand (e.g. when synthesizing a waveform),
* this is a more efficient interface than blipper_push_samples().
*
* The caller must ensure not to push deltas in a way that can destabilize
* the final integration.
*/
#define blipper_push_delta BLIPPER_MANGLE(blipper_push_delta)
void blipper_push_delta(blipper_t *blip, blipper_long_sample_t delta, unsigned clocks_step);
/* Push raw samples. blipper will find the deltas themself and push them.
* stride is the number of samples between each sample to be used.
* This can be used to push interleaved stereo data to two independent
* blippers.
*/
#define blipper_push_samples BLIPPER_MANGLE(blipper_push_samples)
void blipper_push_samples(blipper_t *blip, const blipper_sample_t *delta,
unsigned samples, unsigned stride, unsigned clocks_step);
#define blipper_push_long_samples BLIPPER_MANGLE(blipper_push_long_samples)
void blipper_push_long_samples(blipper_t *blip, const blipper_long_sample_t *delta,
unsigned samples, unsigned stride, unsigned clocks_step);
/* Returns the number of samples available for reading using
* blipper_read().
*/
#define blipper_read_avail BLIPPER_MANGLE(blipper_read_avail)
unsigned blipper_read_avail(blipper_t *blip);
/* Returns the current filter phase
*/
#define blipper_read_phase BLIPPER_MANGLE(blipper_read_phase)
unsigned blipper_read_phase(blipper_t *blip);
/* Reads processed samples. The caller must ensure to not read
* more than what is returned from blipper_read_avail().
* As in blipper_push_samples(), stride is the number of samples
* between each output sample in output.
* Can be used to write to an interleaved stereo buffer.
*/
#define blipper_read BLIPPER_MANGLE(blipper_read)
void blipper_read(blipper_t *blip, blipper_sample_t *output, unsigned samples,
unsigned stride);
#define blipper_read_long BLIPPER_MANGLE(blipper_long_read)
void blipper_read_long(blipper_t *blip, blipper_long_sample_t *output, unsigned samples,
unsigned stride);
#ifdef __cplusplus
}
#endif
#endif