~hecanjog/pippi

315e05bfd4826a519d8e3fff9e35f720e2648a9f — Erik Schoster 30 days ago 80d9de2
Add longtone and rec instruments
3 files changed, 363 insertions(+), 2 deletions(-)

M astrid/Makefile
A astrid/orc/longtone.c
A astrid/orc/rec.c
M astrid/Makefile => astrid/Makefile +9 -2
@@ 1,5 1,3 @@
PYLIB := $(shell python -c "from distutils import sysconfig; print(sysconfig.get_config_var('LIBRARY')[3:-2])")

LPDIR = ../libpippi

LPSOURCES = $(LPDIR)/vendor/fft/fft.c \


@@ 155,6 153,15 @@ rolling:

	$(CC) $(LPFLAGS) $(LPINCLUDES) $(LPSOURCES) src/astrid.c orc/rolling.c $(LPLIBS) -o build/rolling

longtone:
	mkdir -p build

	$(CC) $(LPFLAGS) $(LPINCLUDES) $(LPSOURCES) src/astrid.c orc/longtone.c $(LPLIBS) -o build/longtone

rec:
	mkdir -p build

	$(CC) $(LPFLAGS) $(LPINCLUDES) $(LPSOURCES) src/astrid.c orc/rec.c $(LPLIBS) -o build/rec

build: clean astrid-q astrid-serial-tools astrid-ipc


A astrid/orc/longtone.c => astrid/orc/longtone.c +228 -0
@@ 0,0 1,228 @@
#include "astrid.h"

#define NAME "longtone"

#define NUMFREQS 8
#define VOICES 8
#define WTSIZE 4096
#define SR 48000
#define INPUT_CHANNELS 2
#define OUTPUT_CHANNELS 2

lpfloat_t FREQS_A[NUMFREQS] = {55.f, 110.f, 220.f, 330.f, 440.f, 550.f, 660.f, 770.f};
lpfloat_t FREQS_B[NUMFREQS] = {61.735f, 123.471f, 246.942f, 370.413f, 493.883f, 617.355f, 740.826, 987.767f};

enum InstrumentParams {
    PARAM_NOOP,
    PARAM_PULSEWIDTH, 
    PARAM_FREQS_A,
    PARAM_FREQS_B,
    PARAM_OSCA_VOLUME,
    PARAM_OSCB_VOLUME,
    NUMPARAMS
};

typedef struct localctx_t {
    lpfloat_t limitprev;
    lpbuffer_t * limitbuf;
    lpbuffer_t * sinewt;
    lpbuffer_t * hannwin;
    lpbuffer_t * hanninwin;
    lpbuffer_t * hannoutwin;
    lppulsarosc_t * voicesA[VOICES];
    lppulsarosc_t * voicesB[VOICES];
    lpbuffer_t * voice_amp[VOICES];
    lpfloat_t param_phase;
    lpfloat_t voice_amp_phase[VOICES];
    lpfloat_t voice_amp_phaseinc[VOICES];
    lpfloat_t voice_foldback_prev[VOICES];
    lpsmoother_t pw_smooth;
    int numfreqs_a;
    int numfreqs_b;
} localctx_t;

lpfloat_t interp(lpfloat_t * buf, size_t size, lpfloat_t phase) {
    lpfloat_t frac, a, b;
    size_t i;

    phase *= size;
    frac = phase - (int)phase;
    i = (int)phase;

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

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

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

int param_map_callback(void * arg, char * keystr, char * valstr) {
    lpinstrument_t * instrument = (lpinstrument_t *)arg;
    localctx_t * ctx = (localctx_t *)instrument->context;
    float val_f = 0;
    int32_t val_i32 = 0;
    lpfloat_t val_floatlist[NUMFREQS] = {220.};

    syslog(LOG_ERR, "Got param %s=%s\n", keystr, valstr);

    if(strcmp(keystr, "pw") == 0) {
        extract_float_from_token(valstr, &val_f);
        astrid_instrument_set_param_float(instrument, PARAM_PULSEWIDTH, val_f);
    } else if(strcmp(keystr, "afreqs") == 0) {
        ctx->numfreqs_a = extract_floatlist_from_token(valstr, val_floatlist, NUMFREQS);
        astrid_instrument_set_param_float_list(instrument, PARAM_FREQS_A, val_floatlist, ctx->numfreqs_a);
    } else if(strcmp(keystr, "bfreqs") == 0) {
        ctx->numfreqs_b = extract_floatlist_from_token(valstr, val_floatlist, NUMFREQS);
        astrid_instrument_set_param_float_list(instrument, PARAM_FREQS_B, val_floatlist, ctx->numfreqs_b);

    } else if(strcmp(keystr, "av") == 0) {
        extract_float_from_token(valstr, &val_f);
        astrid_instrument_set_param_float(instrument, PARAM_OSCA_VOLUME, val_f);
    } else if(strcmp(keystr, "bv") == 0) {
        extract_float_from_token(valstr, &val_f);
        astrid_instrument_set_param_float(instrument, PARAM_OSCB_VOLUME, val_f);

    } else if(strcmp(keystr, "save") == 0) {
        extract_int32_from_token(valstr, &val_i32);
        astrid_instrument_save_param_session_snapshot(instrument, NUMPARAMS, val_i32);
    } else if(strcmp(keystr, "restore") == 0) {
        extract_int32_from_token(valstr, &val_i32);
        astrid_instrument_restore_param_session_snapshot(instrument, val_i32);
    }    

    return 0;
}


int audio_callback(size_t blocksize, __attribute__((unused)) float ** input, float ** output, void * arg) {
    size_t i;
    int v;
    lpfloat_t out, osc_sample, voice, av, bv, amp, ab, pw;
    lpinstrument_t * instrument = (lpinstrument_t *)arg;
    localctx_t * ctx = (localctx_t *)instrument->context;

    lpfloat_t freqs_a[NUMFREQS];
    lpfloat_t freqs_b[NUMFREQS];

    amp = interp(ctx->hanninwin->data, WTSIZE, ctx->param_phase) * 2.f;
    ab = interp(ctx->hannoutwin->data, WTSIZE, ctx->param_phase);
    pw = interp(ctx->hannoutwin->data, WTSIZE, ctx->param_phase);

    syslog(LOG_ERR, "amp: %f\nphase:%f\n\n", amp, ctx->param_phase);

    av = astrid_instrument_get_param_float(instrument, PARAM_OSCA_VOLUME, 1.f);
    bv = astrid_instrument_get_param_float(instrument, PARAM_OSCB_VOLUME, 0.f);

    av = 1.f-ab;
    bv = ab;

    astrid_instrument_get_param_float_list(instrument, PARAM_FREQS_A, ctx->numfreqs_a, freqs_a);
    astrid_instrument_get_param_float_list(instrument, PARAM_FREQS_B, ctx->numfreqs_b, freqs_b);

    if(!instrument->is_running) return 1;

    for(i=0; i < blocksize; i++) {
        osc_sample = out = 0.f;

        for(v=0; v < VOICES; v++) {
            voice = LPPulsarOsc.process(ctx->voicesA[v]) * av;
            voice += LPPulsarOsc.process(ctx->voicesB[v]) * bv;
            voice *= LPInterpolation.linear_pos(ctx->voice_amp[v], ctx->voice_amp_phase[v]);
            ctx->voice_amp_phase[v] += ctx->voice_amp_phaseinc[v];
            if(ctx->voice_amp_phase[v] >= 1.f) {
                ctx->voicesA[v]->freq = (freqs_a[v % ctx->numfreqs_a]*1) + LPRand.rand(-1.f, 1.f);
                ctx->voicesB[v]->freq = (freqs_b[v % ctx->numfreqs_b]*1) + LPRand.rand(-1.f, 1.f);
                ctx->voicesA[v]->pulsewidth = pw;
                ctx->voicesB[v]->pulsewidth = pw;
            }
            while(ctx->voice_amp_phase[v] >= 1.f) ctx->voice_amp_phase[v] -= 1.f;

            voice = LPFX.fold(voice, &ctx->voice_foldback_prev[v], instrument->samplerate);
            osc_sample += voice * 0.5f;
        }

        out += osc_sample;
        out = LPFX.limit(out*1.f, &ctx->limitprev, 0.8f, 0.2f, ctx->limitbuf);
        //out *= amp;

        output[0][i] = out;
        output[1][i] = out;

        ctx->param_phase += (1.f / instrument->samplerate) * 0.000833f;
        while(ctx->param_phase >= 1.f) ctx->param_phase -= 1.f;
    }

    return 0;
}


int main() {
    int i;
    lpinstrument_t * instrument;
    lpinstrument_config_t config = astrid_instrument_init_config(NAME);
    localctx_t * ctx;

    ctx = (localctx_t *)calloc(1, sizeof(localctx_t));
    if(ctx == NULL) {
        printf("Could not alloc ctx: (%d) %s\n", errno, strerror(errno));
        exit(1);
    }

    ctx->limitprev = 1.f;
    ctx->limitbuf = LPBuffer.create(1024, 1, (lpfloat_t)SR);

    ctx->sinewt = LPWavetable.create(WT_SINE, WTSIZE);
    ctx->hannwin = LPWindow.create(WIN_HANN, WTSIZE);
    ctx->hannoutwin = LPWindow.create(WIN_HANNOUT, WTSIZE);
    ctx->hanninwin = LPWindow.create(WIN_SINEIN, WTSIZE);
    ctx->numfreqs_a = NUMFREQS;
    ctx->numfreqs_b = NUMFREQS;

    for(i=0; i < VOICES; i++) {
        ctx->voicesA[i] = LPPulsarOsc.create(2, 2, // number of wavetables, windows
            WT_SINE, WTSIZE, WT_TRI2, WTSIZE,   // wavetables and sizes
            WIN_SINE, WTSIZE, WIN_HANN, WTSIZE  // windows and sizes
        );
        ctx->voicesA[i]->freq = FREQS_A[i % NUMFREQS] + LPRand.rand(-1.f, 1.f);

        ctx->voicesB[i] = LPPulsarOsc.create(2, 2, // number of wavetables, windows
            WT_SINE, WTSIZE, WT_TRI2, WTSIZE,   // wavetables and sizes
            WIN_SINE, WTSIZE, WIN_HANN, WTSIZE  // windows and sizes
        );
        ctx->voicesB[i]->freq = FREQS_B[i % NUMFREQS] + LPRand.rand(-1.f, 1.f);

        ctx->voice_amp[i] = LPWindow.create(WIN_HANN, WTSIZE);
        ctx->voice_amp_phase[i] = LPRand.rand(0.f, 1.f);
        ctx->voice_amp_phaseinc[i] = (1.f/SR) * LPRand.rand(0.08f, 0.15f);
    }

    config.input_channels = INPUT_CHANNELS;
    config.output_channels = OUTPUT_CHANNELS;
    config.ctx = (void*)ctx;
    config.stream_callback = audio_callback;
    config.update_callback = param_map_callback;
    config.initial_volume = 0.2f;

    if((instrument = astrid_instrument_start_from_config(config)) == NULL) {
        fprintf(stderr, "Could not start instrument: (%d) %s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    astrid_instrument_set_param_float_list(instrument, PARAM_FREQS_A, FREQS_A, NUMFREQS);
    astrid_instrument_set_param_float_list(instrument, PARAM_FREQS_B, FREQS_B, NUMFREQS);

    /* twiddle thumbs until shutdown */
    while(instrument->is_running) {
        astrid_instrument_tick(instrument);
    }

    /* stop jack and cleanup threads */
    if(astrid_instrument_stop(instrument) < 0) {
        fprintf(stderr, "There was a problem stopping the instrument. (%d) %s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    printf("Done!\n");
    return 0;
}

A astrid/orc/rec.c => astrid/orc/rec.c +126 -0
@@ 0,0 1,126 @@
#include "astrid.h"

#define NAME "rec"

#define WTSIZE 4096
#define SR 48000
#define INPUT_CHANNELS 2
#define OUTPUT_CHANNELS 2

enum InstrumentParams {
    PARAM_NOOP,
    PARAM_REC_ENABLED,
    NUMPARAMS
};

typedef struct localctx_t {
    lpbuffer_t * recbuf;
} localctx_t;

void ringbuffer_write_channel(lpbuffer_t * ringbuf, lpfloat_t sample, int channel, size_t offset) {
    size_t index = 0;
    if (channel >= ringbuf->channels) return;
    index = ((ringbuf->pos+offset) * ringbuf->channels + channel) % (ringbuf->length * ringbuf->channels);
    ringbuf->data[index] = sample;
}

lpfloat_t ringbuffer_read_channel(lpbuffer_t * ringbuf, int channel, size_t offset) {
    size_t index = 0;
    if (channel >= ringbuf->channels) return 0.0f;
    index = ((ringbuf->pos+offset) * ringbuf->channels + channel) % (ringbuf->length * ringbuf->channels);
    return ringbuf->data[index];
}

/*
int param_map_callback(void * arg, char * keystr, char * valstr) {
    lpinstrument_t * instrument = (lpinstrument_t *)arg;
    int32_t val_i32 = 0;
    syslog(LOG_ERR, "Got param %s=%s\n", keystr, valstr);

    if(strcmp(keystr, "rec") == 0) {
        extract_int32_from_token(valstr, &val_i32);
        astrid_instrument_set_param_int32(instrument, PARAM_REC_ENABLED, val_i32);
    } else if(strcmp(keystr, "save") == 0) {
        extract_int32_from_token(valstr, &val_i32);
        astrid_instrument_save_param_session_snapshot(instrument, NUMPARAMS, val_i32);
    } else if(strcmp(keystr, "restore") == 0) {
        extract_int32_from_token(valstr, &val_i32);
        astrid_instrument_restore_param_session_snapshot(instrument, val_i32);
    }    

    return 0;
}
*/


int audio_callback(size_t blocksize, float ** input, float ** output, void * arg) {
    size_t i, c, offset;
    int32_t rec_enabled;
    lpinstrument_t * instrument = (lpinstrument_t *)arg;
    localctx_t * ctx = (localctx_t *)instrument->context;

    rec_enabled = astrid_instrument_get_param_int32(instrument, PARAM_REC_ENABLED, 1);
    rec_enabled = 1;
    offset = SR*7;

    if(!instrument->is_running) return 1;

    for(i=0; i < blocksize; i++) {
        if(rec_enabled) {
            for(c=0; c < INPUT_CHANNELS; c++) {
                ringbuffer_write_channel(ctx->recbuf, input[c][i], c, i);
            }
        }

        for(c=0; c < OUTPUT_CHANNELS; c++) {
            output[c][i] = ringbuffer_read_channel(ctx->recbuf, c, i-offset);
        }
    }

    ctx->recbuf->pos += blocksize;
    ctx->recbuf->pos = ctx->recbuf->pos % ctx->recbuf->length;

    return 0;
}

int main() {
    lpinstrument_t * instrument;
    lpinstrument_config_t config = astrid_instrument_init_config(NAME);
    localctx_t * ctx;

    ctx = (localctx_t *)calloc(1, sizeof(localctx_t));
    if(ctx == NULL) {
        printf("Could not alloc ctx: (%d) %s\n", errno, strerror(errno));
        exit(1);
    }

    ctx->recbuf = LPBuffer.create(SR * 10, INPUT_CHANNELS, SR);

    config.input_channels = INPUT_CHANNELS;
    config.output_channels = OUTPUT_CHANNELS;
    config.ctx = (void*)ctx;
    config.stream_callback = audio_callback;
    //config.update_callback = param_map_callback;
    config.initial_volume = 0.2f;

    //astrid_config_register_param_int32(&config, PARAM_REC_ENABLED, "rec");

    if((instrument = astrid_instrument_start_from_config(config)) == NULL) {
        fprintf(stderr, "Could not start instrument: (%d) %s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    /* twiddle thumbs until shutdown */
    while(instrument->is_running) {
        astrid_instrument_tick(instrument);
    }

    /* stop jack and cleanup threads */
    if(astrid_instrument_stop(instrument) < 0) {
        fprintf(stderr, "There was a problem stopping the instrument. (%d) %s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    printf("Done!\n");
    return 0;
}