ref: 7de74a9d01cbb87b74def34099ce2f30a0fb6e6e
dir: /modules/prop.c/
/* * Tinyprop * By Paul Batchelor * * A tiny C implementation of prop, a proportional rhythmic notation system * */ #include <stdlib.h> #include <math.h> #include "soundpipe.h" typedef struct { uint32_t size; prop_list **ar; } prop_slice; static int prop_create(prop_data **pd); static int prop_parse(prop_data *pd, const char *str); static prop_event prop_next(sp_data *sp, prop_data *pd); static float prop_time(prop_data *pd, prop_event evt); static int prop_destroy(prop_data **pd); static int prop_val_free(prop_val val); static int prop_list_init(prop_list *lst); static int prop_list_destroy(prop_list *lst); static int prop_list_append(prop_list *lst, prop_val val); static void prop_list_reset(prop_list *lst); static int prop_list_copy(prop_list *src, prop_list **dst); static void mode_insert_event(prop_data *pd, char type); static void mode_insert_slice(prop_data *pd); static void mode_list_start(prop_data *pd); static void mode_list_end(prop_data *pd); static void prop_slice_encap(prop_data *pd); static void prop_slice_append(prop_data *pd); static void reset(prop_data *pd); static void back_to_top(prop_data *pd); enum { PTYPE_SLICE, PTYPE_LIST, PTYPE_EVENT, PTYPE_OFF, PTYPE_ON, PTYPE_MAYBE, PMODE_INSERT, PMODE_SETDIV, PMODE_SETMUL, PMODE_UNSETMUL, PMODE_INIT, PSTATUS_NOTOK, PSTATUS_OK, PTYPE_NULL }; int sp_prop_create(sp_prop **p) { *p = malloc(sizeof(sp_prop)); return SP_OK; } int sp_prop_destroy(sp_prop **p) { sp_prop *pp = *p; prop_destroy(&pp->prp); free(*p); return SP_OK; } int sp_prop_init(sp_data *sp, sp_prop *p, const char *str) { p->count = 0; prop_create(&p->prp); if (prop_parse(p->prp, str) == PSTATUS_NOTOK) { fprintf(stderr,"There was an error parsing the string.\n"); return SP_NOT_OK; } p->bpm = 60; p->lbpm = 60; return SP_OK; } int sp_prop_compute(sp_data *sp, sp_prop *p, SPFLOAT *in, SPFLOAT *out) { if (p->count == 0) { if (p->bpm != p->lbpm) { p->prp->scale = (SPFLOAT) 60.0 / p->bpm; p->lbpm = p->bpm; } p->evt = prop_next(sp, p->prp); p->count = prop_time(p->prp, p->evt) * sp->sr; switch (p->evt.type) { case PTYPE_ON: *out = 1.0; break; case PTYPE_MAYBE: if (((SPFLOAT) sp_rand(sp) / SP_RANDMAX) > 0.5) *out = 1.0; else *out = 0.0; break; default: *out = 0.0; break; } return SP_OK; } *out = 0; p->count--; return SP_OK; } static int stack_push(prop_stack *ps, uint32_t val) { if (ps->pos++ < 16) { ps->stack[ps->pos] = val; } return SP_OK; } static void stack_init(prop_stack *ps) { int n; ps->pos = -1; for (n = 0; n < 16; n++) ps->stack[n] = 1; } static uint32_t stack_pop(prop_stack *ps) { if (ps->pos >= 0) { return ps->stack[ps->pos--]; } return 1; } static void mode_insert_event(prop_data *pd, char type) { prop_val val; prop_event *evt; #ifdef DEBUG_PROP if (type == PTYPE_ON) { printf("mode_insert: PTYPE_ON\n"); } else { printf("mode_insert: PTYPE_OFF\n"); } printf("\tval/mul = %d, pos = %d, cons = %d, div = %d\n", pd->mul, pd->num, pd->cons_mul, pd->div); #endif val.type = PTYPE_EVENT; evt = malloc(sizeof(prop_event)); evt->type = type; evt->val = pd->mul; evt->cons = pd->cons_mul; val.ud = evt; prop_list_append(pd->main, val); } static void mode_setdiv(prop_data *pd, char n) { if (pd->tmp == 0 && n == 0) n = 1; pd->tmp *= 10; pd->tmp += n; } static void mode_setmul(prop_data *pd) { pd->mul *= pd->tmp; pd->div = pd->tmp; stack_push(&pd->mstack, pd->tmp); pd->tmp = 0; } static void mode_unsetmul(prop_data *pd) { uint32_t div = stack_pop(&pd->mstack); #ifdef DEBUG_PROP printf("mul / div = %d / %d\n", pd->mul, div); #endif pd->mul /= div; } static void mode_setcons(prop_data *pd) { pd->cons_mul *= pd->tmp; pd->cons_div = pd->tmp; stack_push(&pd->cstack, pd->tmp); pd->tmp = 0; } static void mode_unsetcons(prop_data *pd) { uint32_t div = stack_pop(&pd->cstack); #ifdef DEBUG_PROP printf("mul / div = %d / %d\n", pd->cons_mul, div); #endif pd->cons_mul /= div; } static int prop_create(prop_data **pd) { prop_data *pdp; *pd = malloc(sizeof(prop_data)); pdp = *pd; pdp->mul = 1; pdp->div = 0; pdp->scale = 1; pdp->cons_mul = 1; pdp->cons_div = 0; pdp->mode = PMODE_INIT; pdp->pos = 1; pdp->main = &pdp->top; pdp->main->lvl = 0; pdp->tmp = 0; stack_init(&pdp->mstack); stack_init(&pdp->cstack); prop_list_init(pdp->main); return PSTATUS_OK; } static int prop_parse(prop_data *pd, const char *str) { char c; while (*str != 0) { c = str[0]; switch(c) { case '+': mode_insert_event(pd, PTYPE_ON); break; case '?': mode_insert_event(pd, PTYPE_MAYBE); break; case '-': mode_insert_event(pd, PTYPE_OFF); break; case '0': mode_setdiv(pd, 0); break; case '1': mode_setdiv(pd, 1); break; case '2': mode_setdiv(pd, 2); break; case '3': mode_setdiv(pd, 3); break; case '4': mode_setdiv(pd, 4); break; case '5': mode_setdiv(pd, 5); break; case '6': mode_setdiv(pd, 6); break; case '7': mode_setdiv(pd, 7); break; case '8': mode_setdiv(pd, 8); break; case '9': mode_setdiv(pd, 9); break; case '(': mode_setmul(pd); break; case ')': mode_unsetmul(pd); break; case '[': mode_setcons(pd); break; case ']': mode_unsetcons(pd); break; case '|': mode_insert_slice(pd); break; case '{': mode_list_start(pd); break; case '}': mode_list_end(pd); break; case ' ': break; case '\n': break; case '\t': break; default: return PSTATUS_NOTOK; } pd->pos++; str++; } prop_list_reset(&pd->top); pd->main = &pd->top; return PSTATUS_OK; } prop_val prop_list_iterate(prop_list *lst) { prop_val val; if (lst->pos >= lst->size) { prop_list_reset(lst); } val = lst->last->val; lst->last = lst->last->next; lst->pos++; return val; } static void back_to_top(prop_data *pd) { prop_list *lst = pd->main; prop_list_reset(lst); pd->main = lst->top; reset(pd); } static void reset(prop_data *pd) { prop_list *lst = pd->main; if (lst->pos >= lst->size) { back_to_top(pd); } } prop_event prop_next(sp_data *sp, prop_data *pd) { /* prop_list *lst = pd->main; if(lst->pos >= lst->size) { //prop_list_reset(lst); pd->main = lst->top; } */ prop_list *lst; prop_event *p; prop_val val; reset(pd); lst = pd->main; val = lst->last->val; lst->last = lst->last->next; lst->pos++; switch (val.type) { case PTYPE_SLICE: { prop_slice *slice = (prop_slice *)val.ud; uint32_t pos = floor( ((SPFLOAT)sp_rand(sp) / SP_RANDMAX) * slice->size); pd->main = slice->ar[pos]; prop_list_reset(pd->main); return prop_next(sp, pd); break; } case PTYPE_LIST: { prop_list *lst = (prop_list *)val.ud; pd->main = lst; prop_list_reset(pd->main); return prop_next(sp, pd); break; } default: break; } p = (prop_event *)val.ud; return *p; } static float prop_time(prop_data *pd, prop_event evt) { float val = evt.cons * (pd->scale / evt.val); return val; } static int prop_destroy(prop_data **pd) { prop_data *pdp = *pd; prop_list_destroy(&pdp->top); free(*pd); return PSTATUS_OK; } static int prop_list_init(prop_list *lst) { lst->last = &lst->root; lst->size = 0; lst->pos = 0; lst->root.val.type = PTYPE_NULL; lst->top = lst; return PSTATUS_OK; } static int prop_list_append(prop_list *lst, prop_val val) { prop_entry *new; new = malloc(sizeof(prop_entry)); new->val = val; lst->last->next = new; lst->last = new; lst->size++; return PSTATUS_OK; } static int prop_slice_free(prop_slice *slice) { uint32_t i; for (i = 0; i < slice->size; i++) { prop_list_destroy(slice->ar[i]); free(slice->ar[i]); } free(slice->ar); return PSTATUS_OK; } static int prop_val_free(prop_val val) { switch (val.type) { case PTYPE_SLICE: prop_slice_free((prop_slice *)val.ud); free(val.ud); break; case PTYPE_LIST: prop_list_destroy((prop_list *)val.ud); free(val.ud); break; default: free(val.ud); break; } return PSTATUS_OK; } static int prop_list_destroy(prop_list *lst) { prop_entry *entry = lst->root.next; prop_entry *next; uint32_t i; for (i = 0; i < lst->size; i++) { next = entry->next; prop_val_free(entry->val); free(entry); entry = next; } return PSTATUS_OK; } static void prop_list_reset(prop_list *lst) { lst->last = lst->root.next; lst->pos = 0; } static void mode_insert_slice(prop_data *pd) { prop_entry *entry; entry = pd->main->top->last; if (entry->val.type != PTYPE_SLICE) { prop_slice_encap(pd); } else { prop_slice_append(pd); } } static void prop_slice_encap(prop_data *pd) { prop_val val; prop_list *lst, *new; prop_list *top; prop_slice *slice; top = pd->main->top; val.type = PTYPE_SLICE; slice = malloc(sizeof(prop_slice)); val.ud = slice; prop_list_copy(pd->main, &lst); new = malloc(sizeof(prop_list)); new->lvl = pd->main->lvl; slice->size = 2; slice->ar = (prop_list **)malloc(sizeof(prop_list *) * slice->size); slice->ar[0] = lst; /* reinit main list */ prop_list_init(pd->main); prop_list_append(pd->main, val); slice->ar[1] = new; prop_list_init(slice->ar[1]); pd->main = slice->ar[1]; slice->ar[0]->top = top; slice->ar[1]->top = top; } static void prop_slice_append(prop_data *pd) { prop_entry *entry; prop_slice *slice; prop_list *new; entry = pd->main->top->last; slice = (prop_slice *)entry->val.ud; new = malloc(sizeof(prop_list)); prop_list_init(new); slice->size++; slice->ar = (prop_list **) realloc(slice->ar, sizeof(prop_list *) * slice->size); slice->ar[slice->size - 1] = new; new->top = pd->main->top; pd->main = new; } static int prop_list_copy(prop_list *src, prop_list **dst) { prop_list *pdst; *dst = malloc(sizeof(prop_list)); pdst = *dst; pdst->root = src->root; pdst->last = src->last; pdst->size = src->size; pdst->pos = src->pos; pdst->lvl = src->lvl; return PSTATUS_OK; } static void mode_list_start(prop_data *pd) { prop_val val; prop_list *new; val.type = PTYPE_LIST; new = malloc(sizeof(prop_list)); prop_list_init(new); new->lvl = pd->main->lvl + 1; val.ud = new; prop_list_append(pd->main, val); new->top = pd->main; pd->main = new; } static void mode_list_end(prop_data *pd) { pd->main = pd->main->top; } int sp_prop_reset(sp_data *sp, sp_prop *p) { back_to_top(p->prp); p->count = 0; return SP_OK; }