#include #include #include #include "noise.h" #include "random.h" #include "builtins.h" #include "blocktype.h" typedef struct priv PRIV; typedef struct sb SB; struct priv { int bits; int kind; unsigned int mask; unsigned int cur; unsigned int mul; unsigned int count; int shift; } ; struct sb { void (*cont)(void *, void *); void *contarg; PRIV p; } ; static int x_noise = -1; static int x_type; static int w_type; static int x_bits; static int w_bits; static int x_out; static int my_w; static int my_h; static BLOCKDIMS size(BLOCK_SIZE_ARGS) { int noise; int white; int pink; int brown; int nbits; int bits; int bit_total; int out; int col; int total; if (x_noise < 0) { noise = widthof("Noise",5); white = widthof("White",5); pink = widthof("Pink",4); brown = widthof("Brown",5); nbits = widthof("00",2); bits = widthof(" bits",5); out = widthof("Out",3); bit_total = nbits + bits; col = noise; if (white > col) col = white; if (pink > col) col = pink; if (brown > col) col = brown; if (bit_total > col) col = bit_total; total = col + out + (3 * font_space); x_noise = font_space + ((col - noise) / 2); x_type = font_space; w_type = col; x_bits = font_space + ((col - bit_total) / 2); w_bits = col; x_out = total - out - font_space; my_w = total; my_h = 4 * font_baselineskip; } return((BLOCKDIMS){.w=my_w,.h=my_h}); } static void setup_done(int ok, void *sbv) { SB sb; PRIV *p; sb = *(SB *)sbv; free(sbv); if (ok) { p = malloc(sizeof(PRIV)); *p = sb.p; } else { p = 0; } (*sb.cont)(p,sb.contarg); } static void setup_bits(int ok, void *sbv) { SB sb; if (ok) { setup_getarg("Bits",&setup_done,sbv,&((SB *)sbv)->p.bits,PAR_IRANGE,1,16); } else { sb = *(SB *)sbv; free(sbv); (*sb.cont)(0,sb.contarg); } } static void setup(BLOCK_SETUP_ARGS) { SB *sb; sb = malloc(sizeof(SB)); sb->cont = cont; sb->contarg = contarg; setup_getarg("Type",&setup_bits,sb,&sb->p.kind,PAR_CHOICE,3,"White",NOISE_WHITE,"Pink",NOISE_PINK,"Brown",NOISE_BROWN); } static void destroy(BLOCK_DESTROY_ARGS) { free(priv); } static void render(BLOCK_RENDER_ARGS) { PRIV *p; int y; const char *s; int l; int w; char bs[16]; int bsl; p = priv; XFillRectangle(disp,d,gc_bg,0,0,my_w,my_h); XDrawLine(disp,d,gc_fg,0,0,my_w-2,0); XDrawLine(disp,d,gc_fg,my_w-1,0,my_w-1,my_h-2); XDrawLine(disp,d,gc_fg,my_w-1,my_h-1,1,my_h-1); XDrawLine(disp,d,gc_fg,0,my_h-1,0,1); y = font_baseline + (font_baselineskip / 2); XDrawString(disp,d,gc_fg,x_noise,y,"Noise",5); y += font_baselineskip; switch (p->kind) { case NOISE_WHITE: s = "White"; l = 5; break; case NOISE_PINK: s = "Pink"; l = 4; break; case NOISE_BROWN: s = "Brown"; l = 5; break; default: panic(); break; } w = widthof(s,l); XDrawString(disp,d,gc_fg,x_type+((w_type-w)/2),y,s,l); XDrawString(disp,d,gc_fg,x_out,y,"Out",3); bsl = sprintf(&bs[0],"%d %s",p->bits,(p->bits==1)?"bit":"bits"); w = widthof(&bs[0],bsl); y += font_baselineskip; XDrawString(disp,d,gc_fg,x_bits+((w_bits-w)/2),y,&bs[0],bsl); } static int outy(BLOCK_OUTPUT_Y_ARGS) { return(2*font_baselineskip); } static void rinit(BLOCK_RUN_INIT_ARGS) { PRIV *p; unsigned int m; unsigned int v; int s; p = priv; p->mask = (1 << p->bits) - 1; m = 0x8000; v = 0; while (m) { v |= m; m >>= p->bits; } s = p->bits - 1; while (! (v & 1)) { v >>= 1; s --; } p->mul = v; p->shift = s; p->cur = (rnd_16() & p->mask) * p->mul; p->count = 0; } static void rstep(BLOCK_RUN_STEP_ARGS) { PRIV *p; unsigned int m; double prob; int up; p = priv; switch (p->kind) { case NOISE_WHITE: p->cur = (rnd_16() & p->mask) * p->mul; break; case NOISE_PINK: m = (p->count ^ (p->count + 1)); p->cur = ((p->cur & p->mask & ~m) | (rnd_16() & m)) * p->mul; p->count ++; break; case NOISE_BROWN: if (p->cur > 0xc000) { prob = (0xffff - p->cur) / (double)0x7ffe; up = (rnd_unit() < prob); } else if (p->cur < 0x3fff) { prob = (0x7ffe - p->cur) / (double)0x7ffe; up = (rnd_unit() < prob); } else { up = rnd_16() & 1; } if (up) { p->cur += p->mul; } else { p->cur -= p->mul; } break; } } static double out(BLOCK_RUN_OUT_ARGS) { PRIV *p; p = priv; return(((p->cur >> p->shift) - 32767.5) / 32767.5); } static const char *outs[] = { "Out" }; static const char *typenames[] = { "White", "Pink", "Brown" }; static const int typevals[] = { NOISE_WHITE, NOISE_PINK, NOISE_BROWN }; static BLOCKPARAM params[] = { { .name = "Bits", .type = PAR_IRANGE, .u = { .irange = { .min = 1, .max = 16 } } }, { .name = "Type", .type = PAR_CHOICE, .u = { .choice = { .n = 3, .names = &typenames[0], .values = &typevals[0] } } } }; BLOCKTYPE block_noise = BLOCKTYPE_O_P("Noise",outs,params,size,setup,destroy,render,outy,rinit,rstep,out);