From faada59567f8cb252f4a909116595ce309ff5828 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Fri, 23 May 2003 12:29:55 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r647, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/miXed/; revision=648 --- shared/common/sq.c | 371 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 shared/common/sq.c (limited to 'shared/common/sq.c') diff --git a/shared/common/sq.c b/shared/common/sq.c new file mode 100644 index 0000000..d7b1ea5 --- /dev/null +++ b/shared/common/sq.c @@ -0,0 +1,371 @@ +/* Copyright (c) 2001-2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* squeak and squeal: sequencing utilities, a prototype version + (the main, 'sq' part of the library) */ + +#include +#include +#include "m_pd.h" +#include "shared.h" +#include "common/sq.h" + +#if 1 +#define SQ_VERBOSE +#if 0 +#define SQ_DEBUG +#endif +#endif + +/* #define SQUMPI_IGNORE */ + +#define SQUB_NALLOC 32 +#define SQUMPI_NALLOC (32 * sizeof(t_squmpo)) +#define SQUAX_NALLOC (32 * sizeof(t_squack)) + +#define SQUMPI_DEFAULT 500000 /* 120 bpm in microseconds per beat */ + +/* Arguments reqcount and elsize as in calloc, returns count */ +size_t squb_checksize(void *buf, size_t reqcount, size_t elsize) +{ + t_squb *x = buf; + size_t reqsize = reqcount * elsize; + size_t newsize = x->b_bufsize; + while (newsize < reqsize) newsize *= 2; + if (newsize == x->b_bufsize) + return (newsize); +#ifdef SQ_DEBUG + post("need to resize buffer %x from %d to %d (requested size %d)", + (int)x, x->b_bufsize, newsize, reqsize); +#endif + if (!(x->b_data = resizebytes(x->b_data, x->b_bufsize, newsize)) && + /* rather hopeless... */ + !(x->b_data = getbytes(newsize = SQUB_NALLOC * elsize))) + newsize = 0; + return ((x->b_bufsize = newsize) / elsize); /* LATER do it right */ +} + +/* generic event */ + +/* tempo map */ + +/* comparison function used by qsort */ +static int squmpi_compare(const void *tp1, const void *tp2) +{ + return (((t_squmpo *)tp1)->te_onset > ((t_squmpo *)tp2)->te_onset ? 1 : -1); +} + +void squmpi_sort(t_sq *x) +{ + int i; + t_squmpo *tp; + qsort(x->s_tempomap, x->s_ntempi, sizeof(t_squmpo), squmpi_compare); +#if defined SQ_VERBOSE && ! defined SQ_DEBUG + for (i = x->s_ntempi, tp = x->s_tempomap; i > 0 ; i--, tp++) + post("tempo %d at %d", tp->te_value, (int)tp->te_onset); +#endif +} + +t_squmpo *squmpi_add(t_sq *x) +{ + size_t count = x->s_ntempi + 1; + t_squmpo *tep; + if (squb_checksize(x->s_mytempi, count, sizeof(t_squmpo)) < count) + return (0); + tep = x->s_tempomap + x->s_ntempi++; + squmpo_reset(tep); + return (tep); +} + +void squmpo_reset(t_squmpo *x) +{ + x->te_onset = 0; + x->te_value = SQUMPI_DEFAULT; +} + +/* track map */ + +t_squack *squax_add(t_sq *x) +{ + size_t count = x->s_ntracks + 2; /* guard point */ + t_squack *trp; + if (squb_checksize(x->s_mytracks, count, sizeof(t_squack)) < count) + return (0); + trp = x->s_trackmap + x->s_ntracks++; + squack_reset(trp); + return (trp); +} + +void squack_reset(t_squack *x) +{ + x->tr_id = 0; /* this is no-id */ + x->tr_nevents = 0; + x->tr_name = 0; + x->tr_head = 0; +} + +/* generic iterator */ + +void *squiter_new(t_sq *x) +{ + if (x->s_myiter = getbytes(sizeof(*x->s_myiter))) + { + } + return (x->s_myiter); +} + +/* routines to access iterator hooks (setting hooks is explicit only) */ +t_squiter_seekhook squiter_seekhook(t_squiter *x) +{ + return (x ? (t_squiter_seekhook)x->i_hooks[SQUITER_SEEKHOOK] : 0); +} + +t_squiter_incrhook squiter_incrhook(t_squiter *x) +{ + return (x ? (t_squiter_incrhook)x->i_hooks[SQUITER_INCRHOOK] : 0); +} + +t_squiter_getevehook squiter_getevehook(t_squiter *x) +{ + return (x ? (t_squiter_getevehook)x->i_hooks[SQUITER_GETEVEHOOK] : 0); +} + +t_squiter_setevehook squiter_setevehook(t_squiter *x) +{ + return (x ? (t_squiter_setevehook)x->i_hooks[SQUITER_SETEVEHOOK] : 0); +} + +t_squiter_gettimhook squiter_gettimhook(t_squiter *x) +{ + return (x ? (t_squiter_gettimhook)x->i_hooks[SQUITER_GETTIMHOOK] : 0); +} + +t_squiter_settimhook squiter_settimhook(t_squiter *x) +{ + return (x ? (t_squiter_settimhook)x->i_hooks[SQUITER_SETTIMHOOK] : 0); +} + +t_squiter_gettarhook squiter_gettarhook(t_squiter *x) +{ + return (x ? (t_squiter_gettarhook)x->i_hooks[SQUITER_GETTARHOOK] : 0); +} + +t_squiter_settarhook squiter_settarhook(t_squiter *x) +{ + return (x ? (t_squiter_settarhook)x->i_hooks[SQUITER_SETTARHOOK] : 0); +} + +/* time conversion */ + +/* Compute reusable coefficient, rather then repeatedly apply the formula. + For smpte time: + d msecs == (d / 1000.) secs == ((d * nframes * nticks) / 1000.) ticks + or for metrical time: + d msecs == (d * 1000.) usecs == ((d * 1000.) / tempo) beats + == ((d * nticks * 1000.) / tempo) ticks +*/ +/* LATER ntsc */ +float sq_ticks2msecs(t_sq *x, uint32 tempo) +{ + if (x->s_nframes) + return (1000. / (x->s_nframes * x->s_nticks)); + if (tempo <= 0) + tempo = x->s_tempo; + if (tempo <= 0) + tempo = SQUMPI_DEFAULT; + return (tempo / (x->s_nticks * 1000.)); +} + +float sq_msecs2ticks(t_sq *x, uint32 tempo) +{ + if (x->s_nframes) + return (((x->s_nframes * x->s_nticks) / 1000.)); + if (!tempo) + tempo = x->s_tempo; + if (!tempo) + tempo = SQUMPI_DEFAULT; + return ((x->s_nticks * 1000.) / tempo); +} + +/* transform onset ticks into delta msecs */ +void sq_fold_time(t_sq *x) +{ + t_squiter *it = x->s_myiter; + t_squiter_seekhook seekhook = squiter_seekhook(it); + t_squiter_incrhook incrhook = squiter_incrhook(it); + t_squiter_gettimhook gethook = squiter_gettimhook(it); + t_squiter_settimhook sethook = squiter_settimhook(it); + int i, ret, nevents = x->s_nevents; + + if (!it || !seekhook(it, 0)) + return; + if (x->s_nframes) + { + float coef = sq_ticks2msecs(x, 0); + t_float lasttime = 0; + for (i = 0; i < nevents; i++) + { + if (ret = squiter_inrange(it)) + { + t_float thistime = gethook(it, &ret) * coef; + /* back to delta time */ + if (ret) sethook(it, thistime - lasttime, &ret); + lasttime = thistime; + } + if (ret) incrhook(it); + else + { + post("sequence folding error: bad iterator"); + break; + } + } + } + else /* apply tempomap */ + { + float coef = sq_ticks2msecs(x, SQUMPI_DEFAULT); + int ntempi = x->s_ntempi; + t_float lasttime = 0, thistime = 0; + t_float temposince = 0; + t_float tempoonset = 0; + int tempondx = 0; + for (i = 0; i < nevents; i++) + { + if (ret = squiter_inrange(it)) + { + t_float thisonset = gethook(it, &ret); + t_float nexttempoonset; +#ifdef SQUMPI_IGNORE + thistime = thisonset * coef; +#else + while (tempondx < ntempi /* LATER consider using guard point */ + && (nexttempoonset = x->s_tempo_onset(tempondx)) + < thisonset) + { + temposince += (nexttempoonset - tempoonset) * coef; + tempoonset = nexttempoonset; + coef = sq_ticks2msecs(x, x->s_tempo_value(tempondx)); + tempondx++; + } + thistime = temposince + (thisonset - tempoonset) * coef; +#endif + if (thistime < lasttime) + { +#ifdef SQ_DEBUG + /* FIXME under msvc -- horror! */ + if (thistime != lasttime) + post("ndx %d, this-last (%x-%x) %.15f, \ +tix %.9f, tsince %.9f, ttix %.9f, coef %.9f", + tempondx, (int)thistime, (int)lasttime, + thistime - lasttime, + thisonset, temposince, tempoonset, coef); +#endif + thistime = lasttime; + } + /* back to delta time */ + if (ret) sethook(it, thistime - lasttime, &ret); + lasttime = thistime; + } + if (ret) incrhook(it); + else + { + post("sequence folding error: bad iterator"); + break; + } + } + } +} + +/* transform delta msecs into onset msecs */ +/* LATER add an option (or a separate function) for obtaining ticks + (according to tempomap) */ +void sq_unfold_time(t_sq *x) +{ + t_squiter *it = x->s_myiter; + t_squiter_seekhook seekhook = squiter_seekhook(it); + t_squiter_incrhook incrhook = squiter_incrhook(it); + t_squiter_gettimhook gethook = squiter_gettimhook(it); + t_squiter_settimhook sethook = squiter_settimhook(it); + int i, ret, nevents = x->s_nevents; + t_float thisonset = 0; + + if (!it || !seekhook(it, 0)) + return; + for (i = 0; i < nevents; i++) + { + if (ret = squiter_inrange(it)) + { + thisonset += gethook(it, &ret); + if (ret) sethook(it, thisonset, &ret); + } + if (ret) incrhook(it); + else + { + post("sequence unfolding error: bad iterator"); + break; + } + } +} + +void sq_reset(t_sq *x) +{ + x->s_eof = 0; + x->s_newtrack = 0; + x->s_anapass = 1; + x->s_fp = 0; + x->s_time = 0; + x->s_tempo = SQUMPI_DEFAULT; + x->s_track = 0; +} + +t_sq *sq_new(void) +{ + t_sq *x = (t_sq *)getbytes(sizeof(*x)); + if (!x) + goto constructorfailure; + + /* these two are allocated in derived structure constructor */ + x->s_myiter = 0; + x->s_auxeve = 0; + + if (!(x->s_mytempi = getbytes(sizeof(t_squmpi)))) + goto constructorfailure; + if (!(x->s_tempomap = getbytes(x->s_mytempi->m_bufsize = SQUMPI_NALLOC))) + goto constructorfailure; + x->s_ntempi = 0; + if (!(x->s_mytracks = getbytes(sizeof(t_squax)))) + goto constructorfailure; + if (!(x->s_trackmap = getbytes(x->s_mytracks->m_bufsize = SQUAX_NALLOC))) + goto constructorfailure; + x->s_ntracks = 0; + + x->s_autoalloc = 0; + x->s_format = 0; + x->s_nticks = 192; /* LATER parametrize this somehow */ + x->s_nframes = 0; + + sq_reset(x); + return (x); +constructorfailure: + if (x) sq_free(x); + return (0); +} + +void sq_free(t_sq *x) +{ + if (x->s_mytempi) + { + if (x->s_tempomap) + freebytes(x->s_tempomap, x->s_mytempi->m_bufsize); + freebytes(x->s_mytempi, sizeof(t_squmpi)); + } + if (x->s_mytracks) + { + if (x->s_trackmap) + freebytes(x->s_trackmap, x->s_mytracks->m_bufsize); + freebytes(x->s_mytracks, sizeof(t_squax)); + } + if (x->s_myiter) + freebytes(x->s_myiter, sizeof(*x->s_myiter)); + freebytes(x, sizeof(*x)); +} -- cgit v1.2.1