M libpippi/Makefile => libpippi/Makefile +0 -12
@@ 58,9 58,6 @@ osc-examples:
echo "Building pulsarosc.c example...";
gcc $(LPFLAGS) examples/pulsarosc.c $(LPSOURCES) $(LPLIBS) -o build/pulsarosc
- #echo "Building pulsarosc2.c example...";
- #gcc $(LPFLAGS) examples/pulsarosc2.c $(LPSOURCES) $(LPLIBS) -o build/pulsarosc2
-
echo "Building phasorosc.c example...";
gcc $(LPFLAGS) examples/phasorosc.c $(LPSOURCES) $(LPLIBS) -o build/phasorosc
@@ 85,9 82,6 @@ osc-examples:
echo "Building tapeosc.c example...";
gcc $(LPFLAGS) examples/tapeosc.c $(LPSOURCES) $(LPLIBS) -o build/tapeosc
- echo "Building tapeosc2.c example...";
- gcc $(LPFLAGS) examples/tapeosc2.c $(LPSOURCES) $(LPLIBS) -o build/tapeosc2
-
echo "Building additive_synthesis.c example...";
gcc $(LPFLAGS) examples/additive_synthesis.c $(LPSOURCES) $(LPLIBS) -o build/additive_synthesis
@@ 152,12 146,6 @@ microsound-examples:
echo "Building grainformation.c example...";
gcc $(LPFLAGS) examples/grainformation.c $(LPSOURCES) $(LPLIBS) -o build/grainformation
- echo "Building grainformation2.c example...";
- gcc $(LPFLAGS) examples/grainformation2.c $(LPSOURCES) $(LPLIBS) -o build/grainformation2
-
- echo "Building grainformation3.c example...";
- gcc $(LPFLAGS) examples/grainformation3.c $(LPSOURCES) $(LPLIBS) -o build/grainformation3
-
convolution-examples:
mkdir -p build renders
M libpippi/examples/grainformation.c => libpippi/examples/grainformation.c +19 -33
@@ 4,52 4,38 @@
#define CHANNELS 2
int main() {
- size_t i, c, length, numlayers, grainlength;
- lpbuffer_t * fake_input;
- lpbuffer_t * out;
- lpbuffer_t * freq;
- lpbuffer_t * amp;
+ size_t i, length;
+ lpbuffer_t * out, * src, * win;
lpformation_t * formation;
- lpsineosc_t * osc;
- int window_type;
+ int c, numgrains=6;
- length = 10 * SR;
- numlayers = 1;
- grainlength = SR/10.;
- window_type = WIN_HANN;
+ src = LPSoundFile.read("../tests/sounds/living.wav");
+ win = LPWindow.create(WIN_HANN, 4096);
- out = LPBuffer.create(length, CHANNELS, SR);
- formation = LPFormation.create(window_type, numlayers, grainlength, length, CHANNELS, SR, NULL);
-
- /* Render a sine tone and fill the ringbuffer with it,
- * to simulate a live input. */
- osc = LPSineOsc.create();
- osc->samplerate = SR;
-
- freq = LPParam.from_float(440.0f);
- amp = LPParam.from_float(0.8f);
-
- fake_input = LPSineOsc.render(osc, length, freq, amp, CHANNELS);
- LPRingBuffer.write(formation->rb, fake_input);
-
- LPSoundFile.write("renders/grainformation-rb-out.wav", formation->rb);
+ length = 600 * src->samplerate;
+ out = LPBuffer.create(length, src->channels, src->samplerate);
+ formation = LPFormation.create(numgrains, src, win);
/* Render each frame of the grainformation */
for(i=0; i < length; i++) {
+ if(LPRand.rand(0,1) > 0.99f) {
+ formation->offset += LPRand.rand(0, LPRand.rand(.000005f, .0001f));
+ formation->speed = LPRand.randint(0,6)*0.5f+0.125f;
+ formation->grainlength = LPRand.rand(0.01f, 0.5f);
+ }
LPFormation.process(formation);
- for(c=0; c < CHANNELS; c++) {
- out->data[i * CHANNELS + c] = formation->current_frame->data[c];
+
+ for(c=0; c < out->channels; c++) {
+ out->data[i * out->channels + c] = formation->current_frame->data[c];
}
}
- printf("wat %f\n", amp->data[0]);
+ LPFX.norm(out, 0.8f);
LPSoundFile.write("renders/grainformation-out.wav", out);
- LPSineOsc.destroy(osc);
- LPBuffer.destroy(freq);
- LPBuffer.destroy(amp);
LPBuffer.destroy(out);
- LPBuffer.destroy(fake_input);
+ LPBuffer.destroy(src);
+ LPBuffer.destroy(win);
LPFormation.destroy(formation);
return 0;
D libpippi/examples/grainformation2.c => libpippi/examples/grainformation2.c +0 -75
@@ 1,75 0,0 @@
-#include "pippi.h"
-
-#define SR 48000
-#define CHANNELS 2
-
-int main() {
- size_t i, c, length;
- lpbuffer_t * snd;
- lpbuffer_t * out;
- lpbuffer_t * pw;
- int window_type;
-
- /*
- lpmultishapeosc_t * cutoffs;
- */
- lpformation_t * formation;
-
- /*
- lpfloat_t cutoff;
- lpfloat_t ys[CHANNELS];
- */
-
- window_type = WIN_HANN;
- length = 10 * SR;
-
- /*
- ys[0] = 0.f;
- ys[1] = 0.f;
- */
-
- LPRand.seed(112244);
-
- out = LPBuffer.create(length, CHANNELS, SR);
- snd = LPSoundFile.read("../tests/sounds/living.wav");
-
- formation = LPFormation.create(window_type, 1, SR/20.f, length, CHANNELS, SR, NULL);
- formation->speed = 1.f;
-
- /*
- cutoffs = LPShapeOsc.multi(4, WT_COS, WT_TRI, WT_SINE, WT_SINE);
- cutoffs->min = 20.0f;
- cutoffs->max = 20000.0f;
- cutoffs->maxfreq = 3.f;
- */
-
- pw = LPWindow.create(WIN_SINE, 4096);
- LPBuffer.scale(pw, 0, 1, 0.f, 0.5f);
-
- LPRingBuffer.write(formation->rb, snd);
-
- /* Render each frame of the grainformation */
- for(i=0; i < length; i++) {
- /*formation->pulsewidth = LPInterpolation.linear_pos(pw, (float)i / length);*/
- LPFormation.process(formation);
- /*
- cutoff = LPShapeOsc.multiprocess(cutoffs);
- */
-
- for(c=0; c < CHANNELS; c++) {
- /*out->data[i * CHANNELS + c] = LPFX.lpf1(formation->current_frame->data[c] * 0.5f, &ys[c], cutoff, SR);*/
- out->data[i * CHANNELS + c] = formation->current_frame->data[c] * 0.5f;
- }
- }
-
- LPSoundFile.write("renders/grainformation2-out.wav", out);
-
- LPBuffer.destroy(out);
- LPBuffer.destroy(snd);
- LPFormation.destroy(formation);
- /*
- LPShapeOsc.multidestroy(cutoffs);
- */
-
- return 0;
-}
D libpippi/examples/grainformation3.c => libpippi/examples/grainformation3.c +0 -64
@@ 1,64 0,0 @@
-#include "pippi.h"
-
-#define SR 48000
-#define CHANNELS 2
-
-int main() {
- size_t i, c, length;
- lpbuffer_t * snd;
- lpbuffer_t * out;
- lpbuffer_t * win;
- lpbuffer_t * pw;
- int window_type;
-
- lpmultishapeosc_t * cutoffs;
- lpformation_t * formation;
-
- lpfloat_t cutoff;
- lpfloat_t ys[CHANNELS];
-
- window_type = WIN_USER;
- length = 10 * SR;
-
- ys[0] = 0.f;
- ys[1] = 0.f;
-
- LPRand.seed(112244);
-
- win = LPWindow.create(WIN_HANN, 4096);
- out = LPBuffer.create(length, CHANNELS, SR);
- snd = LPSoundFile.read("../tests/sounds/living.wav");
-
- formation = LPFormation.create(window_type, 1, SR/4.f, length, CHANNELS, SR, win);
- formation->speed = 1.f;
-
- cutoffs = LPShapeOsc.multi(4, WT_COS, WT_TRI, WT_SINE, WT_SINE);
- cutoffs->min = 20.0f;
- cutoffs->max = 20000.0f;
- cutoffs->maxfreq = 3.f;
-
- pw = LPWindow.create(WIN_SINE, 4096);
- LPBuffer.scale(pw, 0, 1, 0.f, 0.5f);
-
- LPRingBuffer.write(formation->rb, snd);
-
- /* Render each frame of the grainformation */
- for(i=0; i < length; i++) {
- formation->pulsewidth = LPInterpolation.linear_pos(pw, (float)i / length);
- LPFormation.process(formation);
- cutoff = LPShapeOsc.multiprocess(cutoffs);
-
- for(c=0; c < CHANNELS; c++) {
- out->data[i * CHANNELS + c] = LPFX.lpf1(formation->current_frame->data[c] * 0.5f, &ys[c], cutoff, SR);
- }
- }
-
- LPSoundFile.write("renders/grainformation3-out.wav", out);
-
- LPBuffer.destroy(out);
- LPBuffer.destroy(snd);
- LPFormation.destroy(formation);
- LPShapeOsc.multidestroy(cutoffs);
-
- return 0;
-}
D libpippi/examples/pulsarosc2.c => libpippi/examples/pulsarosc2.c +0 -66
@@ 1,66 0,0 @@
-#include "pippi.h"
-
-#define CHANNELS 2
-#define SR 48000
-#define TABLESIZE 128
-
-#define NUMWT 3
-#define NUMWIN 2
-#define WTSIZE 4096
-
-int main() {
- size_t length = SR * 10;
- size_t i, c;
- lpbuffer_t * wt;
- lpbuffer_t * win;
-
- lppulsarosc_t * osc;
- lpfloat_t freq = 220.f;
- lpfloat_t sample = 0;
-
- size_t wt_onsets[NUMWT] = {};
- size_t wt_lengths[NUMWT] = {};
- size_t win_onsets[NUMWIN] = {};
- size_t win_lengths[NUMWIN] = {};
-
- wt = LPWavetable.create_stack(NUMWT,
- wt_onsets, wt_lengths,
- WT_SINE, WTSIZE,
- WT_RND, WTSIZE,
- WT_TRI, WTSIZE
- );
-
- win = LPWindow.create_stack(NUMWIN,
- win_onsets, win_lengths,
- WIN_HANN, WTSIZE,
- WIN_SINE, WTSIZE
- );
-
- lpbuffer_t * buf = LPBuffer.create(length, CHANNELS, SR);
-
- osc = LPPulsarOsc.create(
- NUMWT, wt->data, wt->length, wt_onsets, wt_lengths,
- NUMWIN, win->data, win->length, win_onsets, win_lengths
- );
-
- osc->samplerate = SR;
- osc->freq = freq;
-
- for(i=0; i < length; i++) {
- sample = LPPulsarOsc.process(osc);
- for(c=0; c < CHANNELS; c++) {
- buf->data[i * CHANNELS + c] = sample * 0.1f;
- }
- }
-
- LPSoundFile.write("renders/pulsarosc2-out.wav", buf);
-
- LPPulsarOsc.destroy(osc);
- LPBuffer.destroy(buf);
- LPBuffer.destroy(wt);
- LPBuffer.destroy(win);
-
- return 0;
-}
-
-
M libpippi/examples/tapeosc.c => libpippi/examples/tapeosc.c +1 -1
@@ 26,7 26,7 @@ int main() {
LPBuffer.scale(speeds, 0, 1, 0.5f, 2.f);
out = LPBuffer.create(length, CHANNELS, SR);
- osc = LPTapeOsc.create(sine, SR);
+ osc = LPTapeOsc.create(sine);
osc->samplerate = SR;
speedphaseinc = 1.f/speeds->length;
D libpippi/examples/tapeosc2.c => libpippi/examples/tapeosc2.c +0 -50
@@ 1,50 0,0 @@
-#include "pippi.h"
-
-#define BS 4096
-#define SR 48000
-#define CHANNELS 2
-
-int main() {
- size_t i, c, length;
- lpbuffer_t * snd;
- lpbuffer_t * out;
- lpbuffer_t * speeds;
- lptapeosc_t * osc;
- lpfloat_t speedphase, speedphaseinc;
-
- length = 60 * SR;
-
- snd = LPSoundFile.read("../tests/sounds/living.wav");
-
- speeds = LPWindow.create(WIN_HANN, BS);
- LPBuffer.scale(speeds, 0, 1, SR/10.f, (float)SR);
-
- out = LPBuffer.create(length, CHANNELS, SR);
- osc = LPTapeOsc.create(snd, snd->length);
- osc->samplerate = SR;
-
- speedphaseinc = 1.f/speeds->length;
- speedphase = 0.f;
-
- for(i=0; i < length; i++) {
- /*osc->range = LPInterpolation.linear(speeds, ((float)i/length) * speeds->length);*/
-
- LPTapeOsc.process(osc);
- for(c=0; c < CHANNELS; c++) {
- out->data[i * CHANNELS + c] = osc->current_frame->data[c];
- }
- speedphase += speedphaseinc;
- if(speedphase >= speeds->length) {
- speedphase -= speeds->length;
- }
- }
-
- LPSoundFile.write("renders/tapeosc2-out.wav", out);
-
- LPTapeOsc.destroy(osc);
- LPBuffer.destroy(out);
- LPBuffer.destroy(snd);
- LPBuffer.destroy(speeds);
-
- return 0;
-}
M libpippi/src/microsound.c => libpippi/src/microsound.c +85 -154
@@ 1,189 1,123 @@
#include "microsound.h"
void grain_process(lpgrain_t * g, lpbuffer_t * out) {
- lpfloat_t sample, ipw, phase, window_phase;
- int c;
+ int c, oc=0;
+ lpfloat_t win=0.f;
- ipw = 1.f;
- if(g->pulsewidth > 0) ipw = 1.0f/g->pulsewidth;
+ assert(!isnan(g->src->phase));
+ assert(g->samplerate > 0);
+ assert(g->grainlength > 0);
+ assert(out->length == 1); // outbuf is just a single frame vector
- phase = g->phase * ipw + g->start;
+ if(g->pulsewidth <= 0) return;
- window_phase = (g->phase / g->length) * ipw;
- while(window_phase >= 1.f) window_phase -= 1.f;
- window_phase *= g->window->length;
+ g->src->range = g->grainlength * g->samplerate;
+ g->src->start = g->offset * g->samplerate;
+ g->win->phase = g->src->phase;
+ g->src->pulsewidth = g->pulsewidth;
+ g->win->pulsewidth = g->pulsewidth;
- if(ipw > 0.f && phase < g->buf->length - 1) {
- for(c=0; c < g->buf->channels; c++) {
- sample = LPInterpolation.linear_channel(g->buf, phase, c);
- sample *= LPInterpolation.linear(g->window, window_phase);
+ LPTapeOsc.process(g->src);
+ LPTapeOsc.process(g->win);
- if(g->pan != 0.5f) {
- if((2-(c & 1)) == 1) { /* checks if c is odd */
- sample *= (1.f - g->pan);
- } else {
- sample *= g->pan;
- }
- }
+ g->gate = g->src->gate;
- out->data[c] += sample * g->amp;
- }
+ /* window sources always get mixed to mono */
+ for(c=0; c < g->win->buf->channels; c++) {
+ win += g->win->current_frame->data[c];
}
- g->phase += g->speed;
-
- if(g->phase >= g->length) {
- /* recycle this grain, we're done with it now */
- g->phase = 0;
- g->in_use = 0;
+ /* grain sources get mapped to the grain output channels */
+ for(c=0; c < out->channels; c++) {
+ oc = c;
+ while(oc >= g->src->current_frame->channels) oc -= g->src->current_frame->channels;
+ out->data[c] += g->src->current_frame->data[oc] * win;
}
}
-lpformation_t * formation_create(int window_type, int numlayers, size_t grainlength, size_t rblength, int channels, int samplerate, lpbuffer_t * user_window) {
- lpformation_t * formation;
-
- formation = (lpformation_t *)LPMemoryPool.alloc(1, sizeof(lpformation_t));
- if(window_type == WIN_USER) {
- formation->window = user_window;
- } else {
- formation->window = LPWindow.create(window_type, 4096);
- }
-
- formation->rb = LPRingBuffer.create(rblength, channels, samplerate);
- formation->grainlength = grainlength;
- formation->numlayers = numlayers;
- formation->amp = 1.f;
- formation->current_frame = LPBuffer.create(1, channels, samplerate);
- formation->speed = 1.f;
- formation->scrub = 1.f;
- formation->spread = 0.f;
- formation->skew = 0.f;
- formation->pulsewidth = 1.f;
- formation->pos = 0.f;
- formation->pan = 0.5f;
-
- formation->num_active_grains = 0;
-
- formation->phase = 0.f;
- formation->phase_inc = 1.f / samplerate;
-
- formation->onset_phase = 0.f;
- formation->onset_phase_inc = 1.f / rblength;
-
- formation->graininterval = grainlength / 2;
-
- return formation;
+void grain_init(lpgrain_t * grain, lpbuffer_t * src, lpbuffer_t * win) {
+ win->samplerate = src->samplerate;
+ grain->src = LPTapeOsc.create(src);
+ grain->win = LPTapeOsc.create(win);
+ grain->offset = 0.f;
+ grain->channels = src->channels;
+ grain->samplerate = src->samplerate;
+ grain->pulsewidth = 1.f;
}
-void formation_process(lpformation_t * c) {
- int i, g, gi, active_grains, activated_grains, requested_grains, new_grain;
- size_t grainlength;
- lpfloat_t pan;
- int grain_indexes[LPFORMATION_MAXGRAINS];
-
- for(i=0; i < c->current_frame->channels; i++) {
- c->current_frame->data[i] = 0.f;
+lpformation_t * formation_create(int numgrains, lpbuffer_t * src, lpbuffer_t * win) {
+ lpformation_t * f;
+ lpfloat_t phaseinc, grainlength=.3f, pulsewidth=1.f,
+ offset=0.f, speed=1.f, pan=0.5f;
+ int g;
+
+ assert(src->samplerate > 0);
+ assert(src->length > 0);
+ assert(src->channels > 0);
+ assert(numgrains < LPFORMATION_MAXGRAINS);
+
+ f = (lpformation_t *)LPMemoryPool.alloc(1, sizeof(lpformation_t));
+ f->current_frame = LPBuffer.create(1, src->channels, src->samplerate);
+ f->numgrains = numgrains;
+ f->grainlength = grainlength;
+ f->pulsewidth = pulsewidth;
+ f->offset = offset;
+ f->speed = speed;
+ f->pan = pan;
+
+ phaseinc = 1.f/numgrains;
+ for(g=0; g < numgrains; g++) {
+ grain_init(&f->grains[g], src, win);
+ f->grains[g].grainlength = grainlength;
+ f->grains[g].offset = offset;
+ f->grains[g].pulsewidth = pulsewidth;
+ f->grains[g].pan = pan;
+ f->grains[g].src->speed = speed;
+ f->grains[g].src->phase = g*phaseinc;
+ f->grains[g].win->phase = f->grains[g].src->phase;
}
- /* calculate the grid phase */
-
- /* if the grid phase has reset, add some grains to the stack
- * at this point, formation params are taken as a snapshot and
- * copied into the new grains.
- * */
- requested_grains = 0;
- if(c->onset_phase >= 1.f) {
- requested_grains = c->numlayers;
- }
+ return f;
+}
- /* adding a grain to the stack: */
- /* reset grain indexes, loop over to find active indexes,
- * use first open indexes for new grains */
- active_grains = 0;
- activated_grains = 0;
- g = 0;
- gi = 0;
+void formation_process(lpformation_t * f) {
+ int g;
- if(requested_grains == 0 && c->num_active_grains == 0) {
- requested_grains += 1;
- }
+ memset(f->current_frame->data, 0, sizeof(lpfloat_t) * f->current_frame->channels);
- while(1) {
- if(active_grains == 0 && requested_grains == 0) break;
+ for(g=0; g < f->numgrains; g++) {
+ grain_process(&f->grains[g], f->current_frame);
+ if(f->grains[g].gate) {
+ f->grains[g].pulsewidth = f->pulsewidth;
+ f->grains[g].src->speed = f->speed;
- new_grain = 0;
- if(c->grains[g].in_use == 0 && activated_grains < requested_grains) {
- if(c->grainlength_jitter > 0) {
- grainlength = c->grainlength + (size_t)LPRand.rand(0, c->grainlength_jitter * c->grainlength_maxjitter);
+ if(f->spread > 0) {
+ f->grains[g].pan = .5f + LPRand.rand(-.5f, .5f) * f->spread;
} else {
- grainlength = c->grainlength;
+ f->grains[g].pan = f->pan;
}
- /* add a new grain to the stack by reusing this one */
- c->grains[g].in_use = 1;
- c->grains[g].phase = 0;
-
- c->grains[g].buf = c->rb;
- c->grains[g].offset = c->offset / (lpfloat_t)c->rb->samplerate;
- c->grains[g].pulsewidth = c->pulsewidth;
-
- c->grains[g].phase = 0.f;
- c->grains[g].phase_offset = LPRand.rand(0.f, 1.f);
-
- c->grains[g].amp = c->amp;
-
- c->grains[g].window = c->window;
-
- c->grains[g].skew = c->skew;
- c->grains[g].speed = c->speed;
-
- c->grains[g].length = grainlength;
- c->grains[g].range = grainlength;
- c->grains[g].start = (size_t)(c->rb->length * c->pos);
-
- c->grains[g].pan = c->pan;
- if(c->spread > 0) {
- pan = 0.5f + LPRand.rand(-.5f, 0.5f) * c->spread;
- c->grains[g].pan = pan;
+ if(f->grainlength_jitter > 0) {
+ f->grains[g].grainlength = f->grainlength + (size_t)LPRand.rand(0, f->grainlength_jitter * f->grainlength_maxjitter);
+ } else {
+ f->grains[g].grainlength = f->grainlength;
}
- activated_grains += 1;
- new_grain = 1;
- }
+ if(f->grid_jitter > 0) {
+ f->grains[g].offset = f->offset + (size_t)LPRand.rand(0, f->grid_jitter * f->grid_maxjitter);
+ } else {
+ f->grains[g].offset = f->offset;
+ }
- if(c->grains[g].in_use == 1) {
- grain_indexes[gi] = g;
- gi += 1;
- if(new_grain == 0) active_grains += 1;
}
-
- g += 1;
- if(g >= LPFORMATION_MAXGRAINS) g -= LPFORMATION_MAXGRAINS;
- if(gi >= LPFORMATION_MAXGRAINS) break;
- if(active_grains + activated_grains >= c->num_active_grains + requested_grains) break;
- }
-
- /* process all the active grains into the output buffer */
- active_grains += activated_grains;
- c->num_active_grains = active_grains;
- for(gi=0; gi < active_grains; gi++) {
- grain_process(&c->grains[grain_indexes[gi]], c->current_frame);
}
- /* increment the internal phases */
- c->phase += c->phase_inc;
- while(c->phase >= 1.f) c->phase -= 1.f;
-
- c->onset_phase += c->onset_phase_inc;
- while(c->onset_phase >= 1.f) c->onset_phase -= 1.f;
-
- c->pos += c->phase_inc;
- while(c->pos >= 1.f) c->pos -= 1.f;
+ while(f->offset >= f->grains[0].src->buf->length) f->offset -= f->grains[0].src->buf->length;
}
void formation_destroy(lpformation_t * c) {
LPBuffer.destroy(c->window);
- LPBuffer.destroy(c->rb);
+ LPBuffer.destroy(c->source);
LPBuffer.destroy(c->current_frame);
LPMemoryPool.free(c);
}
@@ 241,7 175,4 @@ int extract_wavesets(
return 0;
}
-
const lpformation_factory_t LPFormation = { formation_create, formation_process, formation_destroy };
-
-
M libpippi/src/microsound.h => libpippi/src/microsound.h +15 -24
@@ 9,62 9,53 @@
typedef struct lpgrain_t {
size_t length;
int channels;
+ lpfloat_t samplerate;
lpfloat_t pulsewidth;
+ lpfloat_t grainlength;
+ lpfloat_t offset; /* in seconds */
- size_t range;
- size_t start;
- size_t offset;
-
- lpfloat_t phase_offset;
- lpfloat_t phase;
lpfloat_t pan;
lpfloat_t amp;
lpfloat_t speed;
lpfloat_t skew; /* phase distortion on the grain window */
- int in_use;
int gate;
- lpbuffer_t * buf;
- lpbuffer_t * window;
+ lptapeosc_t * src;
+ lptapeosc_t * win;
} lpgrain_t;
typedef struct lpformation_t {
lpgrain_t grains[LPFORMATION_MAXGRAINS];
- int num_active_grains;
- size_t numlayers;
- size_t grainlength;
+ int numgrains;
+ lpfloat_t grainlength;
lpfloat_t grainlength_maxjitter;
lpfloat_t grainlength_jitter; /* 0-1 proportional to grainlength_maxjitter */
- size_t graininterval;
+ lpfloat_t grid_maxjitter;
+ lpfloat_t grid_jitter;
lpfloat_t spread; /* pan spread */
lpfloat_t speed;
- lpfloat_t scrub;
- lpfloat_t offset;
+ lpfloat_t offset; /* in seconds */
lpfloat_t skew;
lpfloat_t amp;
lpfloat_t pan;
lpfloat_t pulsewidth;
- lpfloat_t phase; /* internal phase */
- lpfloat_t phase_inc;
- lpfloat_t pos; /* sample start position in source buffer: 0-1 */
-
- lpfloat_t onset_phase;
- lpfloat_t onset_phase_inc;
-
+ lpbuffer_t * source;
lpbuffer_t * window;
lpbuffer_t * current_frame;
- lpbuffer_t * rb;
} lpformation_t;
typedef struct lpformation_factory_t {
- lpformation_t * (*create)(int window_type, int numlayers, size_t grainlength, size_t rblength, int channels, int samplerate, lpbuffer_t * user_window);
+ lpformation_t * (*create)(int numgrains, lpbuffer_t * src, lpbuffer_t * win);
void (*process)(lpformation_t *);
void (*destroy)(lpformation_t *);
} lpformation_factory_t;
+void grain_init(lpgrain_t * grain, lpbuffer_t * src, lpbuffer_t * win);
+void grain_process(lpgrain_t * g, lpbuffer_t * out);
+
extern const lpformation_factory_t LPFormation;
#endif
M libpippi/src/oscs.tape.c => libpippi/src/oscs.tape.c +26 -68
@@ 1,6 1,6 @@
#include "oscs.tape.h"
-lptapeosc_t * create_tapeosc(lpbuffer_t * buf, lpfloat_t range);
+lptapeosc_t * create_tapeosc(lpbuffer_t * buf);
void process_tapeosc(lptapeosc_t * osc);
void rewind_tapeosc(lptapeosc_t * osc);
lpbuffer_t * render_tapeosc(lptapeosc_t * osc, size_t length, lpbuffer_t * amp, int channels);
@@ 14,111 14,69 @@ const lptapeosc_factory_t LPTapeOsc = {
destroy_tapeosc
};
-lptapeosc_t * create_tapeosc(lpbuffer_t * buf, lpfloat_t range) {
- lpfloat_t samplerate;
- int channels;
+lptapeosc_t * create_tapeosc(lpbuffer_t * buf) {
+ assert(buf != NULL);
+ assert(buf->channels > 0);
+ assert(buf->samplerate > 0);
lptapeosc_t* osc = (lptapeosc_t*)LPMemoryPool.alloc(1, sizeof(lptapeosc_t));
osc->buf = buf;
- if(buf == NULL) {
- samplerate = (lpfloat_t)DEFAULT_SAMPLERATE;
- channels = DEFAULT_CHANNELS;
- } else {
- samplerate = buf->samplerate;
- channels = buf->channels;
- }
-
- osc->samplerate = samplerate;
- osc->range = range;
+ osc->samplerate = buf->samplerate;
+ osc->range = buf->length;
osc->gate = 0;
osc->pulsewidth = 1.f;
osc->phase = 0.f;
osc->speed = 1.f;
osc->start = 0.f;
- osc->start_increment = range;
- osc->current_frame = LPBuffer.create(1, channels, samplerate);
+ osc->current_frame = LPBuffer.create(1, buf->channels, buf->samplerate);
return osc;
}
void rewind_tapeosc(lptapeosc_t * osc) {
osc->start = 0;
- osc->phase = osc->phase - (int)osc->phase;
+ osc->phase = 0;
}
void process_tapeosc(lptapeosc_t * osc) {
- lpfloat_t sample, f, a, b;
+ lpfloat_t sample, f, a, b, phase, ipw=0.f;
int c, channels;
- size_t idxa, idxb, boundry;
+ size_t idxa, idxb;
- channels = osc->buf->channels;
- boundry = osc->range + osc->start;
+ assert(osc->range != 0);
- //printf("phase %f channels %i boundry %ld speed %f\n", osc->phase, channels, boundry, osc->speed);
-
- f = osc->phase - (int)osc->phase;
- idxa = (size_t)osc->phase;
- idxb = idxa + 1;
-
- for(c=0; c < channels; c++) {
- a = osc->buf->data[idxa * channels + c];
- b = osc->buf->data[idxb * channels + c];
- sample = (1.f - f) * a + (f * b);
- osc->current_frame->data[c] = sample;
- }
-
- osc->phase += osc->speed;
- //printf("phase %f channels %i boundry %ld speed %f\n", osc->phase, channels, boundry, osc->speed);
-
- if(osc->phase >= boundry) {
- osc->phase = osc->start;
- osc->gate = 1;
- } else {
- osc->gate = 0;
- }
-}
-
-/*
-void process_tapeosc(lptapeosc_t * osc) {
- lpfloat_t sample, f, a, b, ipw, phase;
- int c, channels;
- size_t idxa, idxb, boundry;
-
- ipw = 1.f;
- if(osc->pulsewidth > 0) ipw = 1.0f/osc->pulsewidth;
-
- phase = osc->phase * ipw;
channels = osc->buf->channels;
- boundry = osc->range + osc->start;
+ if(osc->pulsewidth > 0 && osc->phase < osc->pulsewidth) {
+ ipw = 1.f/osc->pulsewidth;
- f = phase - (int)phase;
- idxa = (size_t)phase;
- idxb = idxa + 1;
+ phase = osc->phase * (osc->range * ipw) + osc->start;
+ while(phase >= osc->buf->length-1) phase -= osc->buf->length-1;
+
+ f = phase - (int)phase;
+ idxa = (size_t)phase;
+ idxb = idxa + 1;
- if(ipw == 0.f || phase >= osc->buf->length - 1) {
- for(c=0; c < channels; c++) {
- osc->current_frame->data[c] = 0.f;
- }
- } else {
for(c=0; c < channels; c++) {
a = osc->buf->data[idxa * channels + c];
b = osc->buf->data[idxb * channels + c];
sample = (1.f - f) * a + (f * b);
osc->current_frame->data[c] = sample;
}
+ } else {
+ memset(osc->current_frame->data, 0, sizeof(lpfloat_t) * channels);
}
- osc->phase += osc->speed;
+ osc->phase += osc->speed * (1.f/osc->range) * osc->pulsewidth;
- if(osc->phase >= boundry) {
- osc->phase = osc->start;
+ if(osc->phase >= 1.f) {
osc->gate = 1;
} else {
osc->gate = 0;
}
+
+ while(osc->phase >= 1.f) osc->phase -= 1.f;
}
-*/
lpbuffer_t * render_tapeosc(lptapeosc_t * osc, size_t length, lpbuffer_t * amp, int channels) {
lpbuffer_t * out;
M libpippi/src/oscs.tape.h => libpippi/src/oscs.tape.h +1 -2
@@ 9,7 9,6 @@ typedef struct lptapeosc_t {
lpfloat_t pulsewidth;
lpfloat_t samplerate;
lpfloat_t start;
- lpfloat_t start_increment;
lpfloat_t range;
lpbuffer_t * buf;
lpbuffer_t * current_frame;
@@ 17,7 16,7 @@ typedef struct lptapeosc_t {
} lptapeosc_t;
typedef struct lptapeosc_factory_t {
- lptapeosc_t * (*create)(lpbuffer_t *, lpfloat_t);
+ lptapeosc_t * (*create)(lpbuffer_t *);
void (*process)(lptapeosc_t *);
void (*rewind)(lptapeosc_t *);
lpbuffer_t * (*render)(lptapeosc_t *, size_t, lpbuffer_t *, int);
M libpippi/src/pippiconstants.h => libpippi/src/pippiconstants.h +1 -0
@@ 85,6 85,7 @@ enum Wavetables {
};
enum Windows {
+ WIN_NONE,
WIN_SINE,
WIN_SINEIN,
WIN_SINEOUT,
M libpippi/src/pippicore.c => libpippi/src/pippicore.c +29 -10
@@ 69,6 69,7 @@ lpfloat_t fx_hpf1(lpfloat_t x, lpfloat_t * y, lpfloat_t cutoff, lpfloat_t sample
void fx_convolve(lpbuffer_t * a, lpbuffer_t * b, lpbuffer_t * out);
void fx_norm(lpbuffer_t * buf, lpfloat_t ceiling);
lpfloat_t fx_fold(lpfloat_t val, lpfloat_t * prev, lpfloat_t samplerate);
+lpfloat_t fx_crossover(lpfloat_t val, lpfloat_t amount, lpfloat_t smooth, lpfloat_t fade);
lpfloat_t fx_limit(lpfloat_t val, lpfloat_t * prev, lpfloat_t threshold, lpfloat_t release, lpbuffer_t * del);
lpfloat_t fx_crush(lpfloat_t val, int bits);
lpbfilter_t * fx_butthp_create(lpfloat_t cutoff, lpfloat_t samplerate);
@@ 133,7 134,7 @@ const lpparam_factory_t LPParam = { param_create_from_float, param_create_from_i
const lpwavetable_factory_t LPWavetable = { create_wavetable, create_wavetable_stack, destroy_wavetable };
const lpwindow_factory_t LPWindow = { create_window, create_window_stack, destroy_window };
const lpringbuffer_factory_t LPRingBuffer = { ringbuffer_create, ringbuffer_fill, ringbuffer_read, ringbuffer_readinto, ringbuffer_writefrom, ringbuffer_write, ringbuffer_readone, ringbuffer_writeone, ringbuffer_dub, ringbuffer_destroy };
-const lpfx_factory_t LPFX = { read_skewed_buffer, fx_lpf1, fx_hpf1, fx_convolve, fx_norm, fx_fold, fx_limit, fx_crush };
+const lpfx_factory_t LPFX = { read_skewed_buffer, fx_lpf1, fx_hpf1, fx_convolve, fx_norm, fx_crossover, fx_fold, fx_limit, fx_crush };
const lpfilter_factory_t LPFilter = { fx_butthp_create, fx_butthp, fx_buttlp_create, fx_buttlp };
/* Platform-specific random seed, called
@@ 1289,7 1290,7 @@ lpbfilter_t * fx_butthp_create(lpfloat_t cutoff, lpfloat_t samplerate) {
filter->sr = samplerate;
filter->freq = cutoff;
- filter->pidsr = PI / samplerate;
+ filter->pidsr = (lpfloat_t)PI / samplerate;
return filter;
}
@@ 1307,11 1308,11 @@ lpfloat_t fx_butthp(lpbfilter_t * filter, lpfloat_t in) {
c = tanf(filter->pidsr * filter->lkf);
#endif
- filter->a[1] = 1.f / (1.f + ROOT2 * c + c * c);
+ filter->a[1] = 1.f / (1.f + (lpfloat_t)ROOT2 * c + c * c);
filter->a[2] = -(filter->a[1] + filter->a[1]);
filter->a[3] = filter->a[1];
filter->a[4] = 2.f * (c*c - 1.f) * filter->a[1];
- filter->a[5] = (1.f - ROOT2 * c + c * c) * filter->a[1];
+ filter->a[5] = (1.f - (lpfloat_t)ROOT2 * c + c * c) * filter->a[1];
}
t = in - filter->a[4] * filter->a[6] - filter->a[5] * filter->a[7];
@@ 1329,7 1330,7 @@ lpbfilter_t * fx_buttlp_create(lpfloat_t cutoff, lpfloat_t samplerate) {
filter->sr = samplerate;
filter->freq = cutoff;
- filter->pidsr = PI / samplerate;
+ filter->pidsr = (lpfloat_t)PI / samplerate;
return filter;
}
@@ 1347,11 1348,11 @@ lpfloat_t fx_buttlp(lpbfilter_t * filter, lpfloat_t in) {
c = 1.f / tanf(filter->pidsr * filter->lkf);
#endif
- filter->a[1] = 1.f / (1.f + ROOT2 * c + c * c);
+ filter->a[1] = 1.f / (1.f + (lpfloat_t)ROOT2 * c + c * c);
filter->a[2] = filter->a[1] + filter->a[1];
filter->a[3] = filter->a[1];
filter->a[4] = 2.f * (1.f - c*c) * filter->a[1];
- filter->a[5] = (1.f - ROOT2 * c + c * c) * filter->a[1];
+ filter->a[5] = (1.f - (lpfloat_t)ROOT2 * c + c * c) * filter->a[1];
}
t = in - filter->a[4] * filter->a[6] - filter->a[5] * filter->a[7];
@@ 1363,6 1364,14 @@ lpfloat_t fx_buttlp(lpbfilter_t * filter, lpfloat_t in) {
return out;
}
+/* Crossover distortion ported from the supercollider CrossoverDistortion ugen */
+lpfloat_t fx_crossover(lpfloat_t val, lpfloat_t amount, lpfloat_t smooth, lpfloat_t fade) {
+ lpfloat_t out;
+ out = lpfabs(val) - amount;
+ if(out < 0.f) out *= (1.f + (out*fade)) * smooth;
+ if(val < 0.f) out *= -1.f;
+ return out;
+}
lpfloat_t fx_fold(lpfloat_t val, lpfloat_t * prev, lpfloat_t samplerate) {
// Adapted from https://ccrma.stanford.edu/~jatin/ComplexNonlinearities/Wavefolder.html
@@ 1371,8 1380,8 @@ lpfloat_t fx_fold(lpfloat_t val, lpfloat_t * prev, lpfloat_t samplerate) {
lpfloat_t z = tanhf(val) + (tanhf(*prev) * 0.9f);
out = z + (-0.5f * sinf(2.f * (float)PI * val * (samplerate/2.f) / samplerate));
#else
- lpfloat_t z = tanh(val) + (tanh(*prev) * 0.9);
- out = z + (-0.5 * sin(2. * PI * val * (samplerate/2.) / samplerate));
+ lpfloat_t z = tanh(val) + (tanh(*prev) * 0.9f);
+ out = z + (-0.5f * sin(2.f * (lpfloat_t)PI * val * (samplerate/2.f) / samplerate));
#endif
*prev = out;
//return lpzapgremlins(out);
@@ 1997,7 2006,9 @@ void window_hanning(lpfloat_t* out, int length) {
/* create a window (0 to 1) */
lpbuffer_t * create_window(int name, size_t length) {
lpbuffer_t* buf = LPBuffer.create(length, 1, DEFAULT_SAMPLERATE);
- if(name == WIN_SINE) {
+ if(name == WIN_NONE) {
+ memset(buf->data, 1.f, length * sizeof(lpfloat_t));
+ } else if(name == WIN_SINE) {
window_sine(buf->data, length);
} else if (name == WIN_SINEIN) {
window_sinein(buf->data, length);
@@ 2099,6 2110,14 @@ lpfloat_t lpfpow(lpfloat_t value, int exp) {
return result;
}
+lpfloat_t lpmstofreq(lpfloat_t ms) {
+ return 1.f / (ms * 0.001f);
+}
+
+lpfloat_t lpstofreq(lpfloat_t seconds) {
+ return 1.f / seconds;
+}
+
/* FNV-1 hash implementation adapted from:
* http://www.isthe.com/chongo/src/fnv/hash_32.c */
u_int32_t lphashstr(char * str) {
M libpippi/src/pippicore.h => libpippi/src/pippicore.h +11 -0
@@ 26,6 26,14 @@
/* ugen wrapper interface */
typedef struct ugen_t ugen_t;
struct ugen_t {
+ // outlets / inlets include all params
+ int num_outlets;
+ int num_inlets;
+
+ // audio-only inputs and outputs
+ int num_outputs;
+ int num_inputs;
+
void * params;
lpfloat_t (*get_output)(ugen_t * u, int index);
void (*set_param)(ugen_t * u, int index, void * value);
@@ 187,6 195,7 @@ typedef struct lpfx_factory_t {
lpfloat_t (*hpf1)(lpfloat_t x, lpfloat_t * y, lpfloat_t cutoff, lpfloat_t samplerate);
void (*convolve)(lpbuffer_t * a, lpbuffer_t * b, lpbuffer_t * out);
void (*norm)(lpbuffer_t * buf, lpfloat_t ceiling);
+ lpfloat_t (*crossover)(lpfloat_t val, lpfloat_t amount, lpfloat_t smooth, lpfloat_t fade);
lpfloat_t (*fold)(lpfloat_t val, lpfloat_t * prev, lpfloat_t samplerate);
lpfloat_t (*limit)(lpfloat_t val, lpfloat_t * prev, lpfloat_t threshold, lpfloat_t release, lpbuffer_t * del);
lpfloat_t (*crush)(lpfloat_t val, int bits);
@@ 243,6 252,8 @@ lpfloat_t lpfmax(lpfloat_t a, lpfloat_t b);
lpfloat_t lpfmin(lpfloat_t a, lpfloat_t b);
lpfloat_t lpfabs(lpfloat_t value);
lpfloat_t lpfpow(lpfloat_t value, int exp);
+lpfloat_t lpmstofreq(lpfloat_t ms);
+lpfloat_t lpstofreq(lpfloat_t seconds);
u_int32_t lphashstr(char * str);
lpfloat_t lpphaseinc(lpfloat_t freq, lpfloat_t samplerate);
M libpippi/src/ugens.sine.c => libpippi/src/ugens.sine.c +6 -0
@@ 48,6 48,12 @@ ugen_t * create_sine_ugen(void) {
u->get_output = get_sine_ugen_output;
u->set_param = set_sine_ugen_param;
+ u->num_outlets = 3; // three param outlets
+ u->num_inlets = 2; // two param inlets
+
+ u->num_outputs = 1; // one audio output
+ u->num_inputs = 0; // no audio inputs
+
return u;
}
M libpippi/src/ugens.tape.c => libpippi/src/ugens.tape.c +22 -1
@@ 52,7 52,21 @@ void set_tape_ugen_param(ugen_t * u, int index, void * value) {
params->osc->current_frame = LPBuffer.create(1, buf->channels, buf->samplerate);
}
params->osc->range = buf->length-1;
+ break;
+ case UTAPEIN_PULSEWIDTH:
+ v = (lpfloat_t *)value;
+ params->osc->pulsewidth = *v;
+ break;
+
+ case UTAPEIN_START:
+ v = (lpfloat_t *)value;
+ params->osc->start = *v;
+ break;
+
+ case UTAPEIN_RANGE:
+ v = (lpfloat_t *)value;
+ params->osc->range = *v;
break;
default:
@@ 69,9 83,10 @@ lpfloat_t get_tape_ugen_output(ugen_t * u, int index) {
ugen_t * create_tape_ugen(void) {
ugen_t * u;
lpugentape_t * params;
+ lpbuffer_t * frame = LPBuffer.create(1,1,1); // FIXME this leaks -- add req init params?
params = (lpugentape_t *)LPMemoryPool.alloc(sizeof(lpugentape_t), 1);
- params->osc = LPTapeOsc.create(NULL, 1);
+ params->osc = LPTapeOsc.create(frame);
u = (ugen_t *)LPMemoryPool.alloc(sizeof(ugen_t), 1);
u->params = (void *)params;
@@ 80,6 95,12 @@ ugen_t * create_tape_ugen(void) {
u->get_output = get_tape_ugen_output;
u->set_param = set_tape_ugen_param;
+ u->num_outlets = 4; // three param outlets
+ u->num_inlets = 7; // seven param inlets
+
+ u->num_outputs = 1; // one audio output
+ u->num_inputs = 0; // no audio inputs
+
return u;
}
M libpippi/src/ugens.tape.h => libpippi/src/ugens.tape.h +29 -3
@@ 9,18 9,44 @@
enum UgenTapeParams {
UTAPEIN_SPEED,
UTAPEIN_PHASE,
- UTAPEIN_BUF
+ UTAPEIN_BUF,
+ UTAPEIN_PULSEWIDTH,
+ UTAPEIN_START,
+ UTAPEIN_START_INCREMENT,
+ UTAPEIN_RANGE,
};
+/*
+u_int32_t UgenTapeParamHashmap[7] = {
+ LPHASHSTR("speed"),
+ LPHASHSTR("phase"),
+ LPHASHSTR("buf"),
+ LPHASHSTR("pulsewidth"),
+ LPHASHSTR("start"),
+ LPHASHSTR("startinc"),
+ LPHASHSTR("range"),
+};
+*/
+
enum UgenTapeOutputs {
UTAPEOUT_MAIN,
UTAPEOUT_SPEED,
- UTAPEOUT_PHASE
+ UTAPEOUT_PHASE,
+ UTAPEOUT_GATE,
+};
+
+/*
+u_int32_t UgenTapeParamHashmap[4] = {
+ LPHASHSTR("main"),
+ LPHASHSTR("speed"),
+ LPHASHSTR("phase"),
+ LPHASHSTR("gate"),
};
+*/
typedef struct lpugentape_t {
lptapeosc_t * osc;
- lpfloat_t outputs[3];
+ lpfloat_t outputs[4];
} lpugentape_t;
ugen_t * create_tape_ugen(void);
M pippi/fx.pxd => pippi/fx.pxd +24 -0
@@ 61,7 61,31 @@ ctypedef struct HBAP:
cdef extern from "pippicore.h":
ctypedef double lpfloat_t
+ ctypedef struct lpbuffer_t:
+ size_t length;
+ int samplerate;
+ int channels;
+ lpfloat_t phase
+ size_t boundry
+ size_t range
+ size_t pos
+ size_t onset
+ int is_looping
+ lpfloat_t data[]
+
cdef lpfloat_t lpzapgremlins(lpfloat_t x)
+ ctypedef struct lpfx_factory_t:
+ lpfloat_t (*read_skewed_buffer)(lpfloat_t freq, lpbuffer_t * buf, lpfloat_t phase, lpfloat_t skew)
+ lpfloat_t (*lpf1)(lpfloat_t x, lpfloat_t * y, lpfloat_t cutoff, lpfloat_t samplerate)
+ lpfloat_t (*hpf1)(lpfloat_t x, lpfloat_t * y, lpfloat_t cutoff, lpfloat_t samplerate)
+ void (*convolve)(lpbuffer_t * a, lpbuffer_t * b, lpbuffer_t * out)
+ void (*norm)(lpbuffer_t * buf, lpfloat_t ceiling)
+ lpfloat_t (*crossover)(lpfloat_t val, lpfloat_t amount, lpfloat_t smooth, lpfloat_t fade)
+ lpfloat_t (*fold)(lpfloat_t val, lpfloat_t * prev, lpfloat_t samplerate)
+ lpfloat_t (*limit)(lpfloat_t val, lpfloat_t * prev, lpfloat_t threshold, lpfloat_t release, lpbuffer_t * d)
+ lpfloat_t (*crush)(lpfloat_t val, int bits)
+
+ extern const lpfx_factory_t LPFX
cdef extern from "fx.softclip.h":
ctypedef struct lpfxsoftclip_t:
M pippi/fx.pyx => pippi/fx.pyx +3 -11
@@ 155,9 155,8 @@ cpdef SoundBuffer softclip2(SoundBuffer snd):
@cython.cdivision(True)
cdef double[:,:] _crossover(double[:,:] snd, double[:,:] out, double[:] amount, double[:] smooth, double[:] fade):
""" Crossover distortion ported from the supercollider CrossoverDistortion ugen """
- cdef int i=0, c=0
- cdef unsigned int framelength = len(snd)
- cdef int channels = snd.shape[1]
+ cdef size_t i=0, framelength=len(snd)
+ cdef int c=0, channels=snd.shape[1]
cdef double s=0, pos=0, a=0, f=0, m=0
for i in range(framelength):
@@ 167,14 166,7 @@ cdef double[:,:] _crossover(double[:,:] snd, double[:,:] out, double[:] amount,
f = _linear_pos(fade, pos)
for c in range(channels):
- s = abs(snd[i,c]) - a
- if s < 0:
- s *= (1.0 + (s * f)) * m
-
- if snd[i,c] < 0:
- s *= -1
-
- out[i,c] = s
+ out[i,c] = LPFX.crossover(snd[i,c], a, m, f)
return out
M pippi/grains2.pxd => pippi/grains2.pxd +30 -31
@@ 1,5 1,6 @@
cdef extern from "pippicore.h":
cdef enum Windows:
+ WIN_NONE,
WIN_SINE,
WIN_SINEIN,
WIN_SINEOUT,
@@ 82,10 83,15 @@ cdef extern from "pippicore.h":
void (*dub)(lpbuffer_t *, lpbuffer_t *)
void (*destroy)(lpbuffer_t *)
+ ctypedef struct lpwindow_factory_t:
+ lpbuffer_t * (*create)(int name, size_t length)
+ lpbuffer_t * (*create_stack)(int numtables, size_t * onsets, size_t * lengths, ...)
+ void (*destroy)(lpbuffer_t*)
+
extern const lpparam_factory_t LPParam
extern const lpbuffer_factory_t LPBuffer
extern const lpringbuffer_factory_t LPRingBuffer
-
+ extern const lpwindow_factory_t LPWindow
cdef extern from "oscs.tape.h":
ctypedef struct lptapeosc_t:
@@ 94,7 100,6 @@ cdef extern from "oscs.tape.h":
lpfloat_t pulsewidth
lpfloat_t samplerate
lpfloat_t start
- lpfloat_t start_increment
lpfloat_t range
lpbuffer_t * buf
lpbuffer_t * current_frame
@@ 104,52 109,44 @@ cdef extern from "microsound.h":
ctypedef struct lpgrain_t:
size_t length
int channels
- lpfloat_t pulsewidth
-
- size_t range
- size_t start
- size_t offset
+ lpfloat_t samplerate;
+ lpfloat_t pulsewidth
+ lpfloat_t grainlength
+ lpfloat_t offset
- lpfloat_t phase_offset
- lpfloat_t phase
lpfloat_t pan
lpfloat_t amp
lpfloat_t speed
lpfloat_t skew
- int unused
int gate
- lpbuffer_t * buf
- lpbuffer_t * window
+ lptapeosc_t * src
+ lptapeosc_t * win
ctypedef struct lpformation_t:
- int num_active_grains
- size_t numlayers
- size_t grainlength
+ lpgrain_t grains[512]
+ int numgrains
+ lpfloat_t grainlength
lpfloat_t grainlength_maxjitter
lpfloat_t grainlength_jitter
-
- size_t graininterval
- lpfloat_t graininterval_phase
- lpfloat_t graininterval_phase_inc
+ lpfloat_t grid_maxjitter
+ lpfloat_t grid_jitter
lpfloat_t spread
lpfloat_t speed
- lpfloat_t scrub
lpfloat_t offset
lpfloat_t skew
lpfloat_t amp
lpfloat_t pan
- lpfloat_t pulsewidth
+ lpfloat_t pulsewidth
- lpfloat_t pos
+ lpbuffer_t * source
lpbuffer_t * window
lpbuffer_t * current_frame
- lpbuffer_t * rb
ctypedef struct lpformation_factory_t:
- lpformation_t * (*create)(int, int, size_t, size_t, int, int, lpbuffer_t *)
+ lpformation_t * (*create)(int numgrains, lpbuffer_t * src, lpbuffer_t * win);
void (*process)(lpformation_t *)
void (*destroy)(lpformation_t *)
@@ 161,17 158,19 @@ cdef class Cloud2:
cdef lpformation_t * formation
- cdef double[:] grainlength
- cdef double[:] grid
- cdef double[:] phase
-
- """
- cdef double[:] position
cdef double[:] amp
+ cdef double[:] pulsewidth
+ cdef double[:] grainlength
+ cdef double[:] grainmaxjitter
+ cdef double[:] grainjitter
+ cdef double[:] gridmaxjitter
+ cdef double[:] gridjitter
cdef double[:] speed
cdef double[:] spread
- cdef double[:] jitter
+ cdef double[:] grid
+ cdef bint gridincrement
+ """
cdef int[:] mask
cdef bint has_mask
"""
M pippi/grains2.pyx => pippi/grains2.pyx +56 -36
@@ 57,6 57,9 @@ cdef lpbuffer_t * to_lpbuffer_window_from_soundbuffer(SoundBuffer window):
return win
cdef int to_window_flag(str window_name=None):
+ if window_name == 'none':
+ return WIN_NONE
+
if window_name == 'sine':
return WIN_SINE
@@ 103,24 106,23 @@ cdef class Cloud2:
object amp=1.0,
object speed=1.0,
object spread=0.0,
- object jitter=0.0,
- object grainlength=0.2,
+ object pulsewidth=1.0,
+ object grainmaxjitter=0.5,
+ object grainjitter=0.0,
+ object grainlength=0.1,
+ object gridmaxjitter=0.5,
+ object gridjitter=0.0,
object grid=None,
object mask=None,
- object phase=None,
+ double phase=0,
int numgrains=2,
unsigned int wtsize=4096,
+ bint gridincrement=False,
):
- """ TODO:
- [ ] position
- [ ] amp
- [ ] speed
- [ ] spread
- [ ] jitter
- [ ] mask
- [ ] numgrains modulation
- """
+ # TODO:
+ # - mask / burst support
+ # - set initial phase for formation
cdef size_t i, c, sndlength
cdef lpbuffer_t * win
cdef int window_type
@@ 139,17 141,23 @@ cdef class Cloud2:
else:
window_type = to_window_flag(window)
- win = NULL
-
- if phase is None:
- phase = [0,1]
- self.phase = to_window(phase)
+ win = LPWindow.create(window_type, 4096)
if grid is None:
- self.grid = np.multiply(self.grainlength, 0.3)
+ self.grid = np.multiply(self.grainlength, 0.5)
else:
self.grid = to_window(grid)
+ self.amp = to_window(amp)
+ self.speed = to_window(speed)
+ self.spread = to_window(spread)
+ self.pulsewidth = to_window(pulsewidth)
+ self.gridmaxjitter = to_window(gridmaxjitter)
+ self.gridjitter = to_window(gridjitter)
+ self.grainmaxjitter = to_window(grainmaxjitter)
+ self.grainjitter = to_window(grainjitter)
+ self.gridincrement = gridincrement
+
sndlength = <size_t>len(snd.frames)
srcbuf = LPBuffer.create(sndlength, self.channels, self.samplerate)
@@ 157,39 165,51 @@ cdef class Cloud2:
for c in range(self.channels):
srcbuf.data[i * self.channels + c] = snd.frames[i, c]
- self.formation = LPFormation.create(
- window_type,
- numgrains,
- 0,
- sndlength,
- self.channels,
- self.samplerate,
- win
- )
-
- LPRingBuffer.write(self.formation.rb, srcbuf)
- LPBuffer.destroy(srcbuf)
+ self.formation = LPFormation.create(numgrains, srcbuf, win)
def __dealloc__(self):
if self.formation != NULL:
LPFormation.destroy(self.formation)
+ LPBuffer.destroy(self.formation.source)
+ LPBuffer.destroy(self.formation.window)
def play(self, double length):
- cdef size_t i, c, framelength
+ cdef size_t i, c, framelength, incpos, increment
cdef SoundBuffer out
- cdef double phase=0
+ cdef double pos, amp
+ increment = <size_t>(self.formation.grainlength * self.samplerate)
framelength = <size_t>(length * self.samplerate)
out = SoundBuffer(length=length, channels=self.channels, samplerate=self.samplerate)
+ incpos = 0
for i in range(framelength):
- phase = _linear_pos(self.phase, <double>i / framelength)
- self.formation.grainlength = <size_t>(_linear_pos(self.grainlength, phase) * self.samplerate)
- self.formation.graininterval = <size_t>(_linear_pos(self.grid, phase) * self.samplerate)
+ pos = i / <double>framelength
+ amp = _linear_pos(self.amp, pos)
+
+ self.formation.pulsewidth = _linear_pos(self.pulsewidth, pos)
+ self.formation.grainlength = _linear_pos(self.grainlength, pos)
+
+ self.formation.grainlength_jitter = _linear_pos(self.grainjitter, pos)
+ self.formation.grainlength_maxjitter = _linear_pos(self.grainmaxjitter, pos)
+ self.formation.speed = _linear_pos(self.speed, pos)
+ self.formation.spread = _linear_pos(self.spread, pos)
+ self.formation.grid_jitter = _linear_pos(self.gridjitter, pos)
+ self.formation.grid_maxjitter = _linear_pos(self.gridmaxjitter, pos)
+
+ if not self.gridincrement:
+ self.formation.offset = pos * length
+ elif incpos >= increment:
+ self.formation.offset += _linear_pos(self.grid, pos)
+ while incpos >= increment:
+ incpos -= increment
+ increment = <size_t>(self.formation.grainlength * self.samplerate)
LPFormation.process(self.formation)
for c in range(self.channels):
- out.frames[i, c] = self.formation.current_frame.data[c]
+ out.frames[i, c] = self.formation.current_frame.data[c] * amp
+
+ incpos += 1
return out
M pippi/soundbuffer.pyx => pippi/soundbuffer.pyx +2 -2
@@ 715,8 715,8 @@ cdef class SoundBuffer:
def cloud(SoundBuffer self, double length=-1, *args, **kwargs):
""" Create a new Cloud from this SoundBuffer
"""
- #return grains2.Cloud2(self, *args, **kwargs).play(length)
- return grains.Cloud(self, *args, **kwargs).play(length)
+ return grains2.Cloud2(self, *args, **kwargs).play(length)
+ #return grains.Cloud(self, *args, **kwargs).play(length)
def copy(self):
""" Return a new copy of this SoundBuffer.
M tests/test_graincloud.py => tests/test_graincloud.py +69 -6
@@ 22,8 22,7 @@ class TestCloud(TestCase):
framelength = int(length * sound.samplerate)
out = cloud.play(length)
- out = fx.compressor(out*4, -15, 15)
- out = fx.norm(out, 0.5)
+ out = fx.norm(out, 1)
out.write('tests/renders/graincloud_libpippi_unmodulated.wav')
@@ 33,26 32,90 @@ class TestCloud(TestCase):
snd = dsp.read('tests/sounds/living.wav')
grainlength = shapes.win('sine', dsp.MS*10, 0.2)
out = snd.cloud(snd.dur*2, grainlength=grainlength)
+ out = fx.norm(out, 1)
out.write('tests/renders/graincloud_libpippi_grainlength_modulated.wav')
def test_user_window(self):
+ # Alix Dobkin
snd = dsp.read('tests/sounds/living.wav')
- win = dsp.win('pluckout')
- grainlength = shapes.win('sine', dsp.MS*10, 0.2)
- out = snd.cloud(snd.dur*2, window=win, grainlength=grainlength)
+
+ length = 12
+
+ # right half of a sharply tapered hann window, basically
+ win = dsp.win('pluckout').taper(dsp.randint(10, 100))
+
+ # empty buffer 2x the length of the sample
+ out = dsp.buffer(length=length, channels=snd.channels, samplerate=snd.samplerate)
+
+ # four layers of grains
+ for _ in range(4):
+ # grain playback speed
+ speed = shapes.win('sine', dsp.rand(0.125, 0.5), dsp.rand(1, 2))
+
+ amp = shapes.win('sine', 0.3, 1)
+
+ # stereo spread
+ spread = shapes.win('sine', 0, 1)
+
+ # start increment in seconds
+ grid = shapes.win('sine', -1, 1, length=dsp.rand(1, 10))
+
+ # length of the grain in seconds
+ grainlength = shapes.win('sine', dsp.MS*1, 0.4, length=dsp.rand(1, 10))
+
+ gridjitter = shapes.win('sine', 0, 1)
+ grainjitter = shapes.win('sine', 0, 1)
+
+ # pulsewidth of the grain window between 0 & 1
+ pulsewidth = shapes.win('sine', 0.5, 2)
+
+ # render the layer
+ layer = snd.cloud(length,
+ amp=amp,
+ window=win,
+ grainlength=grainlength,
+ numgrains=2,
+ speed=speed,
+ pulsewidth=pulsewidth,
+ spread=spread,
+ gridincrement=True,
+ grainmaxjitter=dsp.rand(0.01,10),
+ grainjitter=grainjitter,
+ gridmaxjitter=dsp.rand(0.01,1),
+ gridjitter=gridjitter,
+ )
+
+ # and dub it into the output buffer
+ out.dub(layer)
+
+ # squish
+ out = fx.compressor(out*8, -15, 15)
+ out = fx.norm(out, 1)
+
+ # done
out.write('tests/renders/graincloud_libpippi_user_window.wav')
def test_phase_modulation(self):
snd = dsp.read('tests/sounds/living.wav')
phase = [1,0.5,1,0,0.5]
+ phase = 3
out = snd.cloud(snd.dur*2, grainlength=0.1, phase=phase)
+ out = fx.norm(out, 1)
out.write('tests/renders/graincloud_libpippi_phase_modulated.wav')
def test_phase_unmodulated(self):
snd = dsp.read('tests/sounds/living.wav')
- out = snd.cloud(snd.dur*2, grainlength=0.1)
+ out = snd.cloud(snd.dur, grainlength=0.1)
+ out = fx.norm(out, 1)
out.write('tests/renders/graincloud_libpippi_phase_unmodulated.wav')
+ def test_speed_modulated(self):
+ snd = dsp.read('tests/sounds/living.wav')
+ speed = shapes.win('sine', 0.5, 2)
+ out = snd.cloud(snd.dur, grainlength=0.1, speed=speed)
+ out = fx.norm(out, 1)
+ out.write('tests/renders/graincloud_libpippi_speed_modulated.wav')
+
"""
def test_libpippi_pulsed_graincloud(self):