~hecanjog/pippi

3d1113a061b7cbe70dcdfb8aa89861fef51e8384 — Erik Schoster 10 months ago ad6cc63
Upgrade cython to latest stable, yay!

Also update rpi deps and check in
a few misc projects:

- More work on libpippi pulsar osc
- Add variable freq input to shape generators
- Fix off by one error in collection shuffling
M banner.png => banner.png +0 -0
M libpippi/src/oscs.pulsar.c => libpippi/src/oscs.pulsar.c +28 -16
@@ 54,7 54,6 @@ lppulsarosc_t * create_pulsarosc(
}

lpfloat_t process_pulsarosc(lppulsarosc_t * p) {
    /*
    lpfloat_t ipw, isr, sample, mod, burst, a, b, 
              wavetable_phase, window_phase,
              wtmorphpos, wtmorphfrac,


@@ 79,58 78,71 @@ lpfloat_t process_pulsarosc(lppulsarosc_t * p) {
    burst = 1.f;
    isr = 1.f / p->samplerate;

    /* Store the inverse pulsewidth if non-zero */
    if(p->pulsewidth > 0) ipw = 1.0/p->pulsewidth;

    /* Look up the burst value if there's a burst table */
    if(p->burst != NULL) {
        
    }

    /*
    if(p->burst != NULL && p->burst->data != NULL && p->burst->phase < p->burst->length) {
        burst = p->burst->data[(int)p->burst->phase];
    }
    */

    /* Override burst if desaturation is triggered */
    if(p->saturation < 1.f && LPRand.rand(0.f, 1.f) > p->saturation) {
        burst = 0; 
    }

    /* If there's a non-zero pulsewidth, and the burst value is 1, 
     * then syntesize a pulse */
    if(ipw > 0 && burst > 0) {
        if(p->num_wavetables == 1) {
            sample = interpolate_waveset(p->wavetables, wavetable_phase * ipw, p->wavetable_lengths[0]);
        } else {
            wavetable_length = p->wavetable_lengths[wavetable_index];
            wtmorphmul = wavetable_length-1 > 1 ? wavetable_length-1 : 1;

            wtmorphpos = lpwv(p->wts->pos, 0, 1) * wtmorphmul;
            wtmorphpos = lpwv(p->wavetable_positions[wavetable_index], 0, 1) * wtmorphmul;
            wavetable_index = (int)wtmorphpos;
            wtmorphfrac = wtmorphpos - wavetable_index;
            a = LPInterpolation.linear_pos(p->wavetables[wavetable_index], p->wts->phase * ipw);
            b = LPInterpolation.linear_pos(p->wavetables[wtmorphidx+1], p->wts->phase * ipw);

            a = LPInterpolation.linear_pos2(&p->wavetables[wavetable_index], p->wavetable_lengths[wavetable_index], p->wavetable_phase * ipw);
            b = LPInterpolation.linear_pos2(&p->wavetables[wtmorphidx+1], p->wavetable_lengths[wtmorphidx+1], p->wavetable_phase * ipw);
            sample = (1.0 - wtmorphfrac) * a + (wtmorphfrac * b);
        }

        if(p->num_windows == 1) {
            mod = interpolate_waveset(p->windows, window_phase * ipw, p->window_lengths[0]);
        } else {
            winmorphmul = p->wins->length-1 > 1 ? p->wins->length-1 : 1;
            winmorphpos = p->wins->pos * winmorphmul;
            winmorphidx = (int)winmorphpos;
            winmorphfrac = winmorphpos - winmorphidx;
            a = LPInterpolation.linear_pos(p->wins->stack[winmorphidx], p->wins->phase * ipw);
            b = LPInterpolation.linear_pos(p->wins->stack[winmorphidx+1], p->wins->phase * ipw);
            window_length = p->window_lengths[window_index];
            winmorphmul = window_length-1 > 1 ? window_length-1 : 1;
            winmorphpos = lpwv(p->window_positions[window_index], 0, 1) * winmorphmul;
            window_index = (int)winmorphpos;
            winmorphfrac = winmorphpos - window_index;

            a = LPInterpolation.linear_pos2(&p->windows[window_index], p->window_lengths[window_index], p->window_phase * ipw);
            b = LPInterpolation.linear_pos2(&p->windows[winmorphidx+1], p->window_lengths[winmorphidx+1], p->window_phase * ipw);
            mod = (1.0 - winmorphfrac) * a + (winmorphfrac * b);
        }
    } 

    p->wts->phase += isr * p->freq;
    p->wins->phase += isr * p->freq;
    p->wavetable_phase += isr * p->freq;
    p->window_phase += isr * p->freq;

    /*
    if(p->burst != NULL && window_phase >= p->window_lengths[window_index]) {
        p->burst->phase += 1;
    }
    */

    if(wavetable_phase >= 1.f) wavetable_phase -= 1.f;
    if(window_phase >= 1.f) window_phase -= 1.f;
    if(p->burst != NULL && p->burst->phase >= p->burst->length) p->burst->phase -= p->burst->length;
    //if(p->burst != NULL && p->burst->phase >= p->burst->length) p->burst->phase -= p->burst->length;

    return sample * mod;
    */
    return 0.f * p->freq;
}

void destroy_pulsarosc(lppulsarosc_t* p) {

M libpippi/src/oscs.pulsar.h => libpippi/src/oscs.pulsar.h +7 -1
@@ 8,13 8,19 @@ typedef struct lppulsarosc_t {
    int num_wavetables;
    size_t * wavetable_onsets;
    size_t * wavetable_lengths;
    lpfloat_t * wavetable_positions;
    lpfloat_t wavetable_phase;

    lpfloat_t * windows;  /* Window stack */
    int num_windows;
    size_t * window_onsets;
    size_t * window_lengths;
    lpfloat_t * window_positions;
    lpfloat_t window_phase;

    lparray_t * burst;    /* Burst table - null always on */
    void * burst;         /* Burst table - null table == pulses always on */
    size_t burst_size;
    lpfloat_t burst_pos;

    lpfloat_t saturation; /* Probability of all pulses to no pulses */
    lpfloat_t pulsewidth;

M libpippi/src/pippicore.c => libpippi/src/pippicore.c +23 -2
@@ 92,6 92,7 @@ lpfloat_t interpolate_hermite(lpbuffer_t * buf, lpfloat_t phase);
lpfloat_t interpolate_hermite_pos(lpbuffer_t * buf, lpfloat_t pos);
lpfloat_t interpolate_linear(lpbuffer_t * buf, lpfloat_t phase);
lpfloat_t interpolate_linear_pos(lpbuffer_t * buf, lpfloat_t pos);
lpfloat_t interpolate_linear_pos2(lpfloat_t * buf, size_t length, lpfloat_t pos);
lpfloat_t interpolate_linear_channel(lpbuffer_t* buf, lpfloat_t phase, int channel);

lpbuffer_t * param_create_from_float(lpfloat_t value);


@@ 121,7 122,7 @@ lprand_t LPRand = { LOGISTIC_SEED_DEFAULT, LOGISTIC_X_DEFAULT, \
lpmemorypool_factory_t LPMemoryPool = { 0, 0, 0, memorypool_init, memorypool_custom_init, memorypool_alloc, memorypool_custom_alloc, memorypool_free };
const lparray_factory_t LPArray = { create_array, create_array_from, destroy_array };
const lpbuffer_factory_t LPBuffer = { create_buffer, create_buffer_from_float, create_buffer_from_bytes, create_uniform_stack, copy_buffer, clear_buffer, split2_buffer, scale_buffer, min_buffer, max_buffer, mag_buffer, play_buffer, pan_stereo_buffer, mix_buffers, remix_buffer, clip_buffer, cut_buffer, cut_into_buffer, varispeed_buffer, resample_buffer, multiply_buffer, scalar_multiply_buffer, add_buffers, scalar_add_buffer, subtract_buffers, scalar_subtract_buffer, divide_buffers, scalar_divide_buffer, concat_buffers, buffers_are_equal, buffers_are_close, dub_buffer, dub_scalar, env_buffer, pad_buffer, taper_buffer, trim_buffer, fill_buffer, repeat_buffer, reverse_buffer, resize_buffer, plot_buffer, destroy_buffer, destroy_stack };
const lpinterpolation_factory_t LPInterpolation = { interpolate_linear_pos, interpolate_linear, interpolate_linear_channel, interpolate_hermite_pos, interpolate_hermite };
const lpinterpolation_factory_t LPInterpolation = { interpolate_linear_pos, interpolate_linear_pos2, interpolate_linear, interpolate_linear_channel, interpolate_hermite_pos, interpolate_hermite };
const lpparam_factory_t LPParam = { param_create_from_float, param_create_from_int };
const lpwavetable_factory_t LPWavetable = { create_wavetable, create_wavetable_stack, destroy_wavetable };
const lpwindow_factory_t LPWindow = { create_window, create_window_stack, destroy_window };


@@ 253,7 254,7 @@ int rand_randbool(void) {
int rand_choice(int numchoices) {
    assert(numchoices > 0);
    if(numchoices == 1) return 0;
    return rand_randint(0, numchoices-1);
    return rand_randint(0, numchoices);
}

lparray_t * create_array(size_t length) {


@@ 1586,6 1587,26 @@ lpfloat_t interpolate_linear_pos(lpbuffer_t* buf, lpfloat_t pos) {
    return interpolate_linear(buf, pos * buf->length);
}

lpfloat_t interpolate_linear_pos2(lpfloat_t * buf, size_t length, lpfloat_t pos) {
    lpfloat_t frac, a, b, phase;
    size_t i;

    phase = pos * length;

    if(length == 1) return buf[0];
    
    frac = phase - (int)phase;
    i = (int)phase;

    if (i >= length-1) return 0;

    a = buf[i];
    b = buf[i+1];

    return (1.0f - frac) * a + (frac * b);
}


/* Wavetable generators
 * 
 * All these functions return a table of values 

M libpippi/src/pippicore.h => libpippi/src/pippicore.h +1 -0
@@ 282,6 282,7 @@ typedef struct lpmemorypool_factory_t {

typedef struct lpinterpolation_factory_t {
    lpfloat_t (*linear_pos)(lpbuffer_t *, lpfloat_t);
    lpfloat_t (*linear_pos2)(lpfloat_t *, size_t, lpfloat_t);
    lpfloat_t (*linear)(lpbuffer_t *, lpfloat_t);
    lpfloat_t (*linear_channel)(lpbuffer_t *, lpfloat_t, int);
    lpfloat_t (*hermite_pos)(lpbuffer_t *, lpfloat_t);

M pippi/shapes.pxd => pippi/shapes.pxd +3 -3
@@ 5,7 5,7 @@ from pippi.soundbuffer cimport SoundBuffer

cpdef list onsets(double length, object density, object periodicity, object stability, double minfreq, double maxfreq)
cpdef SoundBuffer synth(object wt, double length=*, object density=*, object periodicity=*, object stability=*, double minfreq=*, double maxfreq=*, int samplerate=*, int channels=*)
cdef double[:] _table(double[:] out, unsigned int length, double[:] wt, double[:] density, double[:] periodicity, double[:] stability, double maxfreq, double minfreq, int samplerate)
cpdef Wavetable win(object waveform, double lowvalue=*, double highvalue=*, double length=*, object density=*, object periodicity=*, object stability=*, double minfreq=*, double maxfreq=*, int samplerate=*)
cpdef Wavetable wt(object waveform, double lowvalue=*, double highvalue=*, double length=*, object density=*, object periodicity=*, object stability=*, double minfreq=*, double maxfreq=*, int samplerate=*)
cdef double[:] _table(double[:] out, unsigned int length, double[:] wt, double[:] density, double[:] periodicity, double[:] stability, double[:] maxfreq, double[:] minfreq, int samplerate)
cpdef Wavetable win(object waveform, double lowvalue=*, double highvalue=*, double length=*, object density=*, object periodicity=*, object stability=*, object minfreq=*, object maxfreq=*, int samplerate=*)
cpdef Wavetable wt(object waveform, double lowvalue=*, double highvalue=*, double length=*, object density=*, object periodicity=*, object stability=*, object minfreq=*, object maxfreq=*, int samplerate=*)


M pippi/shapes.pyx => pippi/shapes.pyx +23 -12
@@ 102,18 102,21 @@ cpdef SoundBuffer synth(

    return SoundBuffer(out, samplerate=samplerate, channels=channels)

cdef double[:] _table(double[:] out, unsigned int length, double[:] wt, double[:] density, double[:] periodicity, double[:] stability, double maxfreq, double minfreq, int samplerate):
cdef double[:] _table(double[:] out, unsigned int length, double[:] wt, double[:] density, double[:] periodicity, double[:] stability, double[:] maxfreq, double[:] minfreq, int samplerate):
    cdef unsigned int wt_length = len(wt)
    cdef unsigned int wt_boundry = max(wt_length-1, 1)

    cdef int i=0
    cdef double isamplerate = 1.0/samplerate
    cdef double pos=0, d=0, p=0, s=0, freq=1, phase=0
    cdef double freqwidth = maxfreq - minfreq
    cdef double freqwidth, _maxfreq, _minfreq

    d = density[0]
    p = 1 - periodicity[0]
    freq = max((d * freqwidth) + minfreq + rand(freqwidth * -p, freqwidth * p), minfreq)
    _minfreq = minfreq[0]
    _maxfreq = maxfreq[0]
    freqwidth = _maxfreq - _minfreq
    freq = max((d * freqwidth) + _minfreq + rand(freqwidth * -p, freqwidth * p), _minfreq)

    for i in range(length):
        pos = <double>i / <double>length


@@ 128,44 131,52 @@ cdef double[:] _table(double[:] out, unsigned int length, double[:] wt, double[:
            d = math.log(d * (math.e-1) + 1)
            p = 1 - _linear_pos(periodicity, pos)
            #p = math.log(p * (math.e-1) + 1)
            freq = max((d * freqwidth) + minfreq + rand(freqwidth * -p, freqwidth * p), minfreq)
            _minfreq = _linear_pos(minfreq, pos)
            _maxfreq = _linear_pos(maxfreq, pos)
            freqwidth = _maxfreq - _minfreq
            freq = max((d * freqwidth) + _minfreq + rand(freqwidth * -p, freqwidth * p), _minfreq)

        while phase >= wt_boundry:
            phase -= wt_boundry

    return out

cpdef Wavetable win(object waveform, double lowvalue=0, double highvalue=1, double length=1, object density=0.5, object periodicity=0.5, object stability=0.5, double minfreq=0, double maxfreq=0, int samplerate=DEFAULT_SAMPLERATE):
    if minfreq <= 0:
cpdef Wavetable win(object waveform, double lowvalue=0, double highvalue=1, double length=1, object density=0.5, object periodicity=0.5, object stability=0.5, object minfreq=None, object maxfreq=None, int samplerate=DEFAULT_SAMPLERATE):
    if minfreq is None:
        minfreq = MIN_WT_FREQ

    if maxfreq <= 0:
    if maxfreq is None:
        maxfreq = MAX_WT_FREQ

    cdef double[:] _wt = to_window(waveform)
    cdef double[:] _density = to_window(density)
    cdef double[:] _periodicity = to_window(periodicity)
    cdef double[:] _stability = to_window(stability)
    cdef double[:] _minfreq = to_window(minfreq)
    cdef double[:] _maxfreq = to_window(maxfreq)

    cdef unsigned int framelength = <unsigned int>(length * samplerate)
    cdef double[:] out = np.zeros(framelength, dtype='d')

    return Wavetable(_table(out, framelength, _wt, _density, _periodicity, _stability, maxfreq, minfreq, samplerate), lowvalue, highvalue)
    return Wavetable(_table(out, framelength, _wt, _density, _periodicity, _stability, _maxfreq, _minfreq, samplerate), lowvalue, highvalue)

cpdef Wavetable wt(object waveform, double lowvalue=-1, double highvalue=1, double length=1, object density=0.5, object periodicity=0.5, object stability=0.5, double minfreq=0, double maxfreq=0, int samplerate=DEFAULT_SAMPLERATE):
    if minfreq <= 0:
cpdef Wavetable wt(object waveform, double lowvalue=-1, double highvalue=1, double length=1, object density=0.5, object periodicity=0.5, object stability=0.5, object minfreq=None, object maxfreq=None, int samplerate=DEFAULT_SAMPLERATE):
    if minfreq is None:
        minfreq = MIN_WT_FREQ

    if maxfreq <= 0:
    if maxfreq is None:
        maxfreq = MAX_WT_FREQ

    cdef double[:] _wt = to_wavetable(waveform)
    cdef double[:] _density = to_window(density)
    cdef double[:] _periodicity = to_window(periodicity)
    cdef double[:] _stability = to_window(stability)
    cdef double[:] _minfreq = to_window(minfreq)
    cdef double[:] _maxfreq = to_window(maxfreq)


    cdef unsigned int framelength = <unsigned int>(length * samplerate)
    cdef double[:] out = np.zeros(framelength, dtype='d')

    return Wavetable(_table(out, framelength, _wt, _density, _periodicity, _stability, maxfreq, minfreq, samplerate), lowvalue, highvalue)
    return Wavetable(_table(out, framelength, _wt, _density, _periodicity, _stability, _maxfreq, _minfreq, samplerate), lowvalue, highvalue)


M requirements.txt => requirements.txt +1 -1
@@ 1,4 1,4 @@
Cython==3.0.0a11
Cython==3.0.5
importlib-resources==5.12.0
mido==1.2.10
numpy==1.24.2

M rpi-requirements.txt => rpi-requirements.txt +4 -4
@@ 1,5 1,5 @@
Cython==3.0.0a11
importlib-resources==5.4.0
soundfile==0.11.0
Cython==3.0.5
importlib-resources==5.12.0
soundfile==0.12.1
python-rtmidi==1.5.4
wheel==0.37.1
wheel==0.41.3