Last active
November 5, 2019 12:44
-
-
Save standarddeviant/28f9a49322265097fdbd92b5754fb04d to your computer and use it in GitHub Desktop.
Soundpipe ex_biquad only, embedded exercise
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <math.h> | |
#ifndef NO_LIBSNDFILE | |
#include <sndfile.h> | |
#endif | |
#include "soundpipe.h" | |
int sp_create(sp_data **spp) | |
{ | |
*spp = (sp_data *) malloc(sizeof(sp_data)); | |
sp_data *sp = *spp; | |
sprintf(sp->filename, "test.wav"); | |
sp->nchan = 1; | |
SPFLOAT *out = malloc(sizeof(SPFLOAT) * sp->nchan); | |
*out = 0; | |
sp->out = out; | |
sp->sr = 44100; | |
sp->len = 5 * sp->sr; | |
sp->pos = 0; | |
sp->rand = 0; | |
return 0; | |
} | |
int sp_createn(sp_data **spp, int nchan) | |
{ | |
*spp = (sp_data *) malloc(sizeof(sp_data)); | |
sp_data *sp = *spp; | |
sprintf(sp->filename, "test.wav"); | |
sp->nchan = nchan; | |
SPFLOAT *out = malloc(sizeof(SPFLOAT) * sp->nchan); | |
*out = 0; | |
sp->out = out; | |
sp->sr = 44100; | |
sp->len = 5 * sp->sr; | |
sp->pos = 0; | |
sp->rand = 0; | |
return 0; | |
} | |
int sp_destroy(sp_data **spp) | |
{ | |
sp_data *sp = *spp; | |
free(sp->out); | |
free(*spp); | |
return 0; | |
} | |
#ifndef NO_LIBSNDFILE | |
int sp_process(sp_data *sp, void *ud, void (*callback)(sp_data *, void *)) | |
{ | |
SNDFILE *sf[sp->nchan]; | |
char tmp[140]; | |
SF_INFO info; | |
memset(&info, 0, sizeof(SF_INFO)); | |
SPFLOAT buf[sp->nchan][SP_BUFSIZE]; | |
info.samplerate = sp->sr; | |
info.channels = 1; | |
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24; | |
int numsamps, i, chan; | |
if(sp->nchan == 1) { | |
sf[0] = sf_open(sp->filename, SFM_WRITE, &info); | |
} else { | |
for(chan = 0; chan < sp->nchan; chan++) { | |
sprintf(tmp, "%02d_%s", chan, sp->filename); | |
sf[chan] = sf_open(tmp, SFM_WRITE, &info); | |
} | |
} | |
while(sp->len > 0){ | |
if(sp->len < SP_BUFSIZE) { | |
numsamps = sp->len; | |
}else{ | |
numsamps = SP_BUFSIZE; | |
} | |
for(i = 0; i < numsamps; i++){ | |
callback(sp, ud); | |
for(chan = 0; chan < sp->nchan; chan++) { | |
buf[chan][i] = sp->out[chan]; | |
} | |
sp->pos++; | |
} | |
for(chan = 0; chan < sp->nchan; chan++) { | |
#ifdef USE_DOUBLE | |
sf_write_double(sf[chan], buf[chan], numsamps); | |
#else | |
sf_write_float(sf[chan], buf[chan], numsamps); | |
#endif | |
} | |
sp->len -= numsamps; | |
} | |
for(i = 0; i < sp->nchan; i++) { | |
sf_close(sf[i]); | |
} | |
return 0; | |
} | |
#endif | |
int sp_process_raw(sp_data *sp, void *ud, void (*callback)(sp_data *, void *)) | |
{ | |
int chan; | |
if(sp->len == 0) { | |
while(1) { | |
callback(sp, ud); | |
for (chan = 0; chan < sp->nchan; chan++) { | |
fwrite(&sp->out[chan], sizeof(SPFLOAT), 1, stdout); | |
} | |
sp->len--; | |
} | |
} else { | |
while(sp->len > 0) { | |
callback(sp, ud); | |
for (chan = 0; chan < sp->nchan; chan++) { | |
fwrite(&sp->out[chan], sizeof(SPFLOAT), 1, stdout); | |
} | |
sp->len--; | |
sp->pos++; | |
} | |
} | |
return SP_OK; | |
} | |
int sp_process_plot(sp_data *sp, void *ud, void (*callback)(sp_data *, void *)) | |
{ | |
int chan; | |
fprintf(stdout, "sp_out = [ ... \n"); | |
while(sp->len > 0) { | |
callback(sp, ud); | |
for (chan = 0; chan < sp->nchan; chan++) { | |
/* fwrite(&sp->out[chan], sizeof(SPFLOAT), 1, stdout); */ | |
fprintf(stdout, "%g ", sp->out[chan]); | |
} | |
fprintf(stdout, "; ...\n"); | |
sp->len--; | |
sp->pos++; | |
} | |
fprintf(stdout, "];\n"); | |
fprintf(stdout, "plot(sp_out);\n"); | |
fprintf(stdout, "title('Plot generated by Soundpipe');\n"); | |
fprintf(stdout, "xlabel('Time (samples)');\n"); | |
fprintf(stdout, "ylabel('Amplitude');\n"); | |
return SP_OK; | |
} | |
int sp_auxdata_alloc(sp_auxdata *aux, size_t size) | |
{ | |
aux->ptr = malloc(size); | |
aux->size = size; | |
memset(aux->ptr, 0, size); | |
return SP_OK; | |
} | |
int sp_auxdata_free(sp_auxdata *aux) | |
{ | |
free(aux->ptr); | |
return SP_OK; | |
} | |
SPFLOAT sp_midi2cps(SPFLOAT nn) | |
{ | |
return pow(2, (nn - 69.0) / 12.0) * 440.0; | |
} | |
int sp_set(sp_param *p, SPFLOAT val) { | |
p->state = 1; | |
p->val = val; | |
return SP_OK; | |
} | |
int sp_out(sp_data *sp, uint32_t chan, SPFLOAT val) | |
{ | |
if(chan > sp->nchan - 1) { | |
fprintf(stderr, "sp_out: Invalid channel\n"); | |
return SP_NOT_OK; | |
} | |
sp->out[chan] = val; | |
return SP_OK; | |
} | |
uint32_t sp_rand(sp_data *sp) | |
{ | |
uint32_t val = (1103515245 * sp->rand + 12345) % SP_RANDMAX; | |
sp->rand = val; | |
return val; | |
} | |
void sp_srand(sp_data *sp, uint32_t val) | |
{ | |
sp->rand = val; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Biquad | |
* | |
* This code has been extracted from the Csound opcode "biquad". | |
* It has been modified to work as a Soundpipe module. | |
* | |
* Original Author(s): Hans Mikelson | |
* Year: 1998 | |
* Location: Opcodes/biquad.c | |
* | |
*/ | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <math.h> | |
#include "soundpipe.h" | |
#ifndef M_PI | |
#define M_PI 3.14159265358979323846 | |
#endif | |
int sp_biquad_create(sp_biquad **p) | |
{ | |
*p = malloc(sizeof(sp_biquad)); | |
return SP_OK; | |
} | |
int sp_biquad_destroy(sp_biquad **p) | |
{ | |
free(*p); | |
return SP_OK; | |
} | |
int sp_biquad_init(sp_data *sp, sp_biquad *p) | |
{ | |
p->tpidsr = 2.0*M_PI / sp->sr; | |
p->sr = sp->sr; | |
p->cutoff = 500; | |
p->res = 0.7; | |
p->reinit = 0.0; | |
SPFLOAT fcon = p->cutoff * p->tpidsr; | |
SPFLOAT alpha = 1-2*p->res*cos(fcon)*cos(fcon)+p->res*p->res*cos(2*fcon); | |
SPFLOAT beta = p->res*p->res*sin(2*fcon)-2*p->res*cos(fcon)*sin(fcon); | |
SPFLOAT gamma = 1+cos(fcon); | |
SPFLOAT m1 = alpha*gamma+beta*sin(fcon); | |
SPFLOAT m2 = alpha*gamma-beta*sin(fcon); | |
SPFLOAT den = sqrt(m1*m1+m2*m2); | |
p->b0 = 1.5*(alpha*alpha+beta*beta)/den; | |
p->b1 = p->b0; | |
p->b2 = 0.0; | |
p->a0 = 1.0; | |
p->a1 = -2.0*p->res*cos(fcon); | |
p->a2 = p->res*p->res; | |
if(p->reinit == 0.0){ | |
p->xnm1 = p->xnm2 = p->ynm1 = p->ynm2 = 0.0; | |
} | |
return SP_OK; | |
} | |
int sp_biquad_compute(sp_data *sp, sp_biquad *p, SPFLOAT *in, SPFLOAT *out) | |
{ | |
SPFLOAT xn, yn; | |
SPFLOAT a0 = p->a0, a1 = p->a1, a2 = p->a2; | |
SPFLOAT b0 = p->b0, b1 = p->b1, b2 = p->b2; | |
SPFLOAT xnm1 = p->xnm1, xnm2 = p->xnm2, ynm1 = p->ynm1, ynm2 = p->ynm2; | |
xn = *in; | |
yn = ( b0 * xn + b1 * xnm1 + b2 * xnm2 - | |
a1 * ynm1 - a2 * ynm2) / a0; | |
xnm2 = xnm1; | |
xnm1 = xn; | |
ynm2 = ynm1; | |
ynm1 = yn; | |
*out = yn; | |
p->xnm1 = xnm1; p->xnm2 = xnm2; p->ynm1 = ynm1; p->ynm2 = ynm2; | |
return SP_OK; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typedef struct{ | |
SPFLOAT b0, b1, b2, a0, a1, a2, reinit, xnm1, xnm2, ynm1, ynm2, cutoff, res; | |
SPFLOAT sr; | |
SPFLOAT tpidsr; | |
}sp_biquad; | |
int sp_biquad_create(sp_biquad **p); | |
int sp_biquad_destroy(sp_biquad **p); | |
int sp_biquad_init(sp_data *sp, sp_biquad *p); | |
int sp_biquad_compute(sp_data *sp, sp_biquad *p, SPFLOAT *in, SPFLOAT *out); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
gcc base.c biquad.c noise.c ex_biquad.c -D NO_LIBSNDFILE -lm |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdio.h> | |
#include <time.h> | |
#include "soundpipe.h" | |
typedef struct { | |
sp_noise *ns; | |
sp_biquad *tn; | |
} UserData; | |
void write_noise(sp_data *sp, void *udata) { | |
UserData *ud = udata; | |
SPFLOAT in = 0; | |
SPFLOAT out = 0; | |
sp_noise_compute(sp, ud->ns, NULL, &in); | |
sp_biquad_compute(sp, ud->tn, &in, &sp->out[0]); | |
} | |
int main() { | |
srand(time(NULL)); | |
UserData ud; | |
sp_data *sp; | |
sp_create(&sp); | |
sp_noise_create(&ud.ns); | |
sp_biquad_create(&ud.tn); | |
sp_noise_init(sp, ud.ns); | |
sp_biquad_init(sp, ud.tn); | |
sp->len = 44100 * 5; | |
sp_process_raw(sp, &ud, write_noise); | |
sp_noise_destroy(&ud.ns); | |
sp_biquad_destroy(&ud.tn); | |
sp_destroy(&sp); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <math.h> | |
#include <stdlib.h> | |
#include "soundpipe.h" | |
int sp_noise_create(sp_noise **ns) | |
{ | |
*ns = malloc(sizeof(sp_noise)); | |
return SP_OK; | |
} | |
int sp_noise_init(sp_data *sp, sp_noise *ns) | |
{ | |
ns->amp = 1.0; | |
return SP_OK; | |
} | |
int sp_noise_compute(sp_data *sp, sp_noise *ns, SPFLOAT *in, SPFLOAT *out) | |
{ | |
*out = ((sp_rand(sp) % SP_RANDMAX) / (SP_RANDMAX * 1.0)); | |
*out = (*out * 2) - 1; | |
*out *= ns->amp; | |
return SP_OK; | |
} | |
int sp_noise_destroy(sp_noise **ns) | |
{ | |
free(*ns); | |
return SP_OK; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typedef struct{ | |
SPFLOAT amp; | |
}sp_noise; | |
int sp_noise_create(sp_noise **ns); | |
int sp_noise_init(sp_data *sp, sp_noise *ns); | |
int sp_noise_compute(sp_data *sp, sp_noise *ns, SPFLOAT *in, SPFLOAT *out); | |
int sp_noise_destroy(sp_noise **ns); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef SOUNDPIPE_H | |
#define SOUNDPIPE_H | |
#include <stdint.h> | |
#include <stdio.h> | |
#define SP_BUFSIZE 4096 | |
#ifndef SPFLOAT | |
#define SPFLOAT float | |
#endif | |
#define SP_OK 1 | |
#define SP_NOT_OK 0 | |
#define SP_RANDMAX 2147483648 | |
typedef unsigned long sp_frame; | |
typedef struct sp_auxdata { | |
size_t size; | |
void *ptr; | |
} sp_auxdata; | |
typedef struct sp_data { | |
SPFLOAT *out; | |
int sr; | |
int nchan; | |
unsigned long len; | |
unsigned long pos; | |
char filename[200]; | |
uint32_t rand; | |
} sp_data; | |
typedef struct { | |
char state; | |
SPFLOAT val; | |
} sp_param; | |
int sp_auxdata_alloc(sp_auxdata *aux, size_t size); | |
int sp_auxdata_free(sp_auxdata *aux); | |
int sp_create(sp_data **spp); | |
int sp_createn(sp_data **spp, int nchan); | |
int sp_destroy(sp_data **spp); | |
int sp_process(sp_data *sp, void *ud, void (*callback)(sp_data *, void *)); | |
int sp_process_raw(sp_data *sp, void *ud, void (*callback)(sp_data *, void *)); | |
int sp_process_plot(sp_data *sp, void *ud, void (*callback)(sp_data *, void *)); | |
int sp_process_spa(sp_data *sp, void *ud, void (*callback)(sp_data *, void *)); | |
SPFLOAT sp_midi2cps(SPFLOAT nn); | |
int sp_set(sp_param *p, SPFLOAT val); | |
int sp_out(sp_data *sp, uint32_t chan, SPFLOAT val); | |
uint32_t sp_rand(sp_data *sp); | |
void sp_srand(sp_data *sp, uint32_t val); | |
#include "biquad.h" | |
#include "noise.h" | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment