summaryrefslogtreecommitdiff
path: root/apps/codecs/dumb/src/core
diff options
context:
space:
mode:
authorMichiel Van Der Kolk <not.valid@email.address>2005-03-17 20:50:03 +0000
committerMichiel Van Der Kolk <not.valid@email.address>2005-03-17 20:50:03 +0000
commit27be5bc72855a0fbbdae230bc144624c9eb85f5e (patch)
treeb553f1321df924c4b744ffcab48dce5f4f081f7d /apps/codecs/dumb/src/core
parent7e7662bb716917ca431204f0113d400c1014f2e8 (diff)
downloadrockbox-27be5bc72855a0fbbdae230bc144624c9eb85f5e.zip
rockbox-27be5bc72855a0fbbdae230bc144624c9eb85f5e.tar.gz
rockbox-27be5bc72855a0fbbdae230bc144624c9eb85f5e.tar.bz2
rockbox-27be5bc72855a0fbbdae230bc144624c9eb85f5e.tar.xz
Initial check in dumb 0.9.2 - has a few usages of floating point that should
be rewritten to fixed point. seems to compile cleanly for iriver. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6197 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/dumb/src/core')
-rw-r--r--apps/codecs/dumb/src/core/atexit.c71
-rw-r--r--apps/codecs/dumb/src/core/duhlen.c34
-rw-r--r--apps/codecs/dumb/src/core/dumbfile.c401
-rw-r--r--apps/codecs/dumb/src/core/loadduh.c42
-rw-r--r--apps/codecs/dumb/src/core/makeduh.c92
-rw-r--r--apps/codecs/dumb/src/core/rawsig.c44
-rw-r--r--apps/codecs/dumb/src/core/readduh.c107
-rw-r--r--apps/codecs/dumb/src/core/register.c104
-rw-r--r--apps/codecs/dumb/src/core/rendduh.c202
-rw-r--r--apps/codecs/dumb/src/core/rendsig.c299
-rw-r--r--apps/codecs/dumb/src/core/unload.c58
11 files changed, 1454 insertions, 0 deletions
diff --git a/apps/codecs/dumb/src/core/atexit.c b/apps/codecs/dumb/src/core/atexit.c
new file mode 100644
index 0000000..16c6abd
--- /dev/null
+++ b/apps/codecs/dumb/src/core/atexit.c
@@ -0,0 +1,71 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * atexit.c - Library Clean-up Management. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+typedef struct DUMB_ATEXIT_PROC
+{
+ struct DUMB_ATEXIT_PROC *next;
+ void (*proc)(void);
+}
+DUMB_ATEXIT_PROC;
+
+
+
+static DUMB_ATEXIT_PROC *dumb_atexit_proc = NULL;
+
+
+
+int dumb_atexit(void (*proc)(void))
+{
+ DUMB_ATEXIT_PROC *dap = dumb_atexit_proc;
+
+ while (dap) {
+ if (dap->proc == proc) return 0;
+ dap = dap->next;
+ }
+
+ dap = malloc(sizeof(*dap));
+
+ if (!dap)
+ return -1;
+
+ dap->next = dumb_atexit_proc;
+ dap->proc = proc;
+ dumb_atexit_proc = dap;
+
+ return 0;
+}
+
+
+
+void dumb_exit(void)
+{
+ while (dumb_atexit_proc) {
+ DUMB_ATEXIT_PROC *next = dumb_atexit_proc->next;
+ (*dumb_atexit_proc->proc)();
+ free(dumb_atexit_proc);
+ dumb_atexit_proc = next;
+ }
+}
diff --git a/apps/codecs/dumb/src/core/duhlen.c b/apps/codecs/dumb/src/core/duhlen.c
new file mode 100644
index 0000000..4500d0a
--- /dev/null
+++ b/apps/codecs/dumb/src/core/duhlen.c
@@ -0,0 +1,34 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * duhlen.c - Function to return the length of / / \ \
+ * a DUH. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * Note that the length of a DUH is a constant | ' /
+ * stored in the DUH struct and in the DUH disk \__/
+ * format. It will be calculated on loading for
+ * other formats in which the length is not explicitly stored. Also note that
+ * it does not necessarily correspond to the length of time for which the DUH
+ * will generate samples. Rather it represents a suitable point for a player
+ * such as Winamp to stop, and in any good DUH it will allow for any final
+ * flourish to fade out and be appreciated.
+ */
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+long duh_get_length(DUH *duh)
+{
+ return duh ? duh->length : 0;
+}
diff --git a/apps/codecs/dumb/src/core/dumbfile.c b/apps/codecs/dumb/src/core/dumbfile.c
new file mode 100644
index 0000000..71108c0
--- /dev/null
+++ b/apps/codecs/dumb/src/core/dumbfile.c
@@ -0,0 +1,401 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * dumbfile.c - Hookable, strictly sequential / / \ \
+ * file input functions. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+
+
+
+static DUMBFILE_SYSTEM *the_dfs = NULL;
+
+
+
+void register_dumbfile_system(DUMBFILE_SYSTEM *dfs)
+{
+ ASSERT(dfs);
+ ASSERT(dfs->open);
+ ASSERT(dfs->getc);
+ ASSERT(dfs->close);
+ the_dfs = dfs;
+}
+
+
+
+struct DUMBFILE
+{
+ DUMBFILE_SYSTEM *dfs;
+ void *file;
+ long pos;
+};
+
+
+
+DUMBFILE *dumbfile_open(const char *filename)
+{
+ DUMBFILE *f;
+
+ ASSERT(the_dfs);
+
+ f = malloc(sizeof(*f));
+
+ if (!f)
+ return NULL;
+
+ f->dfs = the_dfs;
+
+ f->file = (*the_dfs->open)(filename);
+
+ if (!f->file) {
+ free(f);
+ return NULL;
+ }
+
+ f->pos = 0;
+
+ return f;
+}
+
+
+
+DUMBFILE *dumbfile_open_ex(void *file, DUMBFILE_SYSTEM *dfs)
+{
+ DUMBFILE *f;
+
+ ASSERT(dfs);
+ ASSERT(dfs->getc);
+ ASSERT(file);
+
+ f = malloc(sizeof(*f));
+
+ if (!f) {
+ if (dfs->close)
+ (*dfs->close)(file);
+ return NULL;
+ }
+
+ f->dfs = dfs;
+ f->file = file;
+
+ f->pos = 0;
+
+ return f;
+}
+
+
+
+long dumbfile_pos(DUMBFILE *f)
+{
+ ASSERT(f);
+
+ return f->pos;
+}
+
+
+
+int dumbfile_skip(DUMBFILE *f, long n)
+{
+ int rv;
+
+ ASSERT(f);
+ ASSERT(n >= 0);
+
+ if (f->pos < 0)
+ return -1;
+
+ f->pos += n;
+
+ if (f->dfs->skip) {
+ rv = (*f->dfs->skip)(f->file, n);
+ if (rv) {
+ f->pos = -1;
+ return rv;
+ }
+ } else {
+ while (n) {
+ rv = (*f->dfs->getc)(f->file);
+ if (rv < 0) {
+ f->pos = -1;
+ return rv;
+ }
+ n--;
+ }
+ }
+
+ return 0;
+}
+
+
+
+int dumbfile_getc(DUMBFILE *f)
+{
+ int rv;
+
+ ASSERT(f);
+
+ if (f->pos < 0)
+ return -1;
+
+ rv = (*f->dfs->getc)(f->file);
+
+ if (rv < 0) {
+ f->pos = -1;
+ return rv;
+ }
+
+ f->pos++;
+
+ return rv;
+}
+
+
+
+int dumbfile_igetw(DUMBFILE *f)
+{
+ int l, h;
+
+ ASSERT(f);
+
+ if (f->pos < 0)
+ return -1;
+
+ l = (*f->dfs->getc)(f->file);
+ if (l < 0) {
+ f->pos = -1;
+ return l;
+ }
+
+ h = (*f->dfs->getc)(f->file);
+ if (h < 0) {
+ f->pos = -1;
+ return h;
+ }
+
+ f->pos += 2;
+
+ return l | (h << 8);
+}
+
+
+
+int dumbfile_mgetw(DUMBFILE *f)
+{
+ int l, h;
+
+ ASSERT(f);
+
+ if (f->pos < 0)
+ return -1;
+
+ h = (*f->dfs->getc)(f->file);
+ if (h < 0) {
+ f->pos = -1;
+ return h;
+ }
+
+ l = (*f->dfs->getc)(f->file);
+ if (l < 0) {
+ f->pos = -1;
+ return l;
+ }
+
+ f->pos += 2;
+
+ return l | (h << 8);
+}
+
+
+
+long dumbfile_igetl(DUMBFILE *f)
+{
+ unsigned long rv, b;
+
+ ASSERT(f);
+
+ if (f->pos < 0)
+ return -1;
+
+ rv = (*f->dfs->getc)(f->file);
+ if ((signed long)rv < 0) {
+ f->pos = -1;
+ return rv;
+ }
+
+ b = (*f->dfs->getc)(f->file);
+ if ((signed long)b < 0) {
+ f->pos = -1;
+ return b;
+ }
+ rv |= b << 8;
+
+ b = (*f->dfs->getc)(f->file);
+ if ((signed long)b < 0) {
+ f->pos = -1;
+ return b;
+ }
+ rv |= b << 16;
+
+ b = (*f->dfs->getc)(f->file);
+ if ((signed long)b < 0) {
+ f->pos = -1;
+ return b;
+ }
+ rv |= b << 24;
+
+ f->pos += 4;
+
+ return rv;
+}
+
+
+
+long dumbfile_mgetl(DUMBFILE *f)
+{
+ unsigned long rv, b;
+
+ ASSERT(f);
+
+ if (f->pos < 0)
+ return -1;
+
+ rv = (*f->dfs->getc)(f->file);
+ if ((signed long)rv < 0) {
+ f->pos = -1;
+ return rv;
+ }
+ rv <<= 24;
+
+ b = (*f->dfs->getc)(f->file);
+ if ((signed long)b < 0) {
+ f->pos = -1;
+ return b;
+ }
+ rv |= b << 16;
+
+ b = (*f->dfs->getc)(f->file);
+ if ((signed long)b < 0) {
+ f->pos = -1;
+ return b;
+ }
+ rv |= b << 8;
+
+ b = (*f->dfs->getc)(f->file);
+ if ((signed long)b < 0) {
+ f->pos = -1;
+ return b;
+ }
+ rv |= b;
+
+ f->pos += 4;
+
+ return rv;
+}
+
+
+
+unsigned long dumbfile_cgetul(DUMBFILE *f)
+{
+ unsigned long rv = 0;
+ int v;
+
+ do {
+ v = dumbfile_getc(f);
+
+ if (v < 0)
+ return v;
+
+ rv <<= 7;
+ rv |= v & 0x7F;
+ } while (v & 0x80);
+
+ return rv;
+}
+
+
+
+signed long dumbfile_cgetsl(DUMBFILE *f)
+{
+ unsigned long rv = dumbfile_cgetul(f);
+
+ if (f->pos < 0)
+ return rv;
+
+ return (rv >> 1) | (rv << 31);
+}
+
+
+
+long dumbfile_getnc(char *ptr, long n, DUMBFILE *f)
+{
+ long rv;
+
+ ASSERT(f);
+ ASSERT(n >= 0);
+
+ if (f->pos < 0)
+ return -1;
+
+ if (f->dfs->getnc) {
+ rv = (*f->dfs->getnc)(ptr, n, f->file);
+ if (rv < n) {
+ f->pos = -1;
+ return MAX(rv, 0);
+ }
+ } else {
+ for (rv = 0; rv < n; rv++) {
+ int c = (*f->dfs->getc)(f->file);
+ if (c < 0) {
+ f->pos = -1;
+ return rv;
+ }
+ *ptr++ = c;
+ }
+ }
+
+ f->pos += rv;
+
+ return rv;
+}
+
+
+
+int dumbfile_error(DUMBFILE *f)
+{
+ ASSERT(f);
+
+ return f->pos < 0;
+}
+
+
+
+int dumbfile_close(DUMBFILE *f)
+{
+ int rv;
+
+ ASSERT(f);
+
+ rv = f->pos < 0;
+
+ if (f->dfs->close)
+ (*f->dfs->close)(f->file);
+
+ free(f);
+
+ return rv;
+}
diff --git a/apps/codecs/dumb/src/core/loadduh.c b/apps/codecs/dumb/src/core/loadduh.c
new file mode 100644
index 0000000..7dfe5cc
--- /dev/null
+++ b/apps/codecs/dumb/src/core/loadduh.c
@@ -0,0 +1,42 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadduh.c - Code to read a DUH from a file, / / \ \
+ * opening and closing the file for | < / \_
+ * you. | \/ /\ /
+ * \_ / > /
+ * By entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+/* load_duh(): loads a .duh file, returning a pointer to a DUH struct.
+ * When you have finished with it, you must pass the pointer to unload_duh()
+ * so that the memory can be freed.
+ */
+DUH *load_duh(const char *filename)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = read_duh(f);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/apps/codecs/dumb/src/core/makeduh.c b/apps/codecs/dumb/src/core/makeduh.c
new file mode 100644
index 0000000..1e422fb
--- /dev/null
+++ b/apps/codecs/dumb/src/core/makeduh.c
@@ -0,0 +1,92 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * makeduh.c - Function to construct a DUH from / / \ \
+ * its components. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+static DUH_SIGNAL *make_signal(DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata)
+{
+ DUH_SIGNAL *signal;
+
+ ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
+ ASSERT(desc->sigrenderer_get_samples && desc->sigrenderer_get_current_sample);
+
+ signal = malloc(sizeof(*signal));
+
+ if (!signal) {
+ if (desc->unload_sigdata)
+ if (sigdata)
+ (*desc->unload_sigdata)(sigdata);
+ return NULL;
+ }
+
+ signal->desc = desc;
+ signal->sigdata = sigdata;
+
+ return signal;
+}
+
+
+
+DUH *make_duh(long length, int n_signals, DUH_SIGTYPE_DESC *desc[], sigdata_t *sigdata[])
+{
+ DUH *duh = malloc(sizeof(*duh));
+ int i;
+ int fail;
+
+ if (duh) {
+ duh->n_signals = n_signals;
+
+ duh->signal = malloc(n_signals * sizeof(*duh->signal));
+
+ if (!duh->signal) {
+ free(duh);
+ duh = NULL;
+ }
+ }
+
+ if (!duh) {
+ for (i = 0; i < n_signals; i++)
+ if (desc[i]->unload_sigdata)
+ if (sigdata[i])
+ (*desc[i]->unload_sigdata)(sigdata[i]);
+ return NULL;
+ }
+
+ fail = 0;
+
+ for (i = 0; i < n_signals; i++) {
+ duh->signal[i] = make_signal(desc[i], sigdata[i]);
+ if (!duh->signal[i])
+ fail = 1;
+ }
+
+ if (fail) {
+ unload_duh(duh);
+ return NULL;
+ }
+
+ duh->length = length;
+
+ return duh;
+}
diff --git a/apps/codecs/dumb/src/core/rawsig.c b/apps/codecs/dumb/src/core/rawsig.c
new file mode 100644
index 0000000..926c990
--- /dev/null
+++ b/apps/codecs/dumb/src/core/rawsig.c
@@ -0,0 +1,44 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * rawsig.c - Function to retrieve raw signal / / \ \
+ * data from a DUH provided you know | < / \_
+ * what type of signal it is. | \/ /\ /
+ * \_ / > /
+ * By entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+/* You have to specify the type of sigdata, proving you know what to do with
+ * the pointer. If you get it wrong, you can expect NULL back.
+ */
+sigdata_t *duh_get_raw_sigdata(DUH *duh, int sig, long type)
+{
+ DUH_SIGNAL *signal;
+
+ if (!duh) return NULL;
+
+ if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL;
+
+ signal = duh->signal[sig];
+
+ if (signal && signal->desc->type == type)
+ return signal->sigdata;
+
+ return NULL;
+}
diff --git a/apps/codecs/dumb/src/core/readduh.c b/apps/codecs/dumb/src/core/readduh.c
new file mode 100644
index 0000000..514b04a
--- /dev/null
+++ b/apps/codecs/dumb/src/core/readduh.c
@@ -0,0 +1,107 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readduh.c - Code to read a DUH from an open / / \ \
+ * file. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+static DUH_SIGNAL *read_signal(DUH *duh, DUMBFILE *f)
+{
+ DUH_SIGNAL *signal;
+ long type;
+
+ signal = malloc(sizeof(*signal));
+
+ if (!signal)
+ return NULL;
+
+ type = dumbfile_mgetl(f);
+ if (dumbfile_error(f)) {
+ free(signal);
+ return NULL;
+ }
+
+ signal->desc = _dumb_get_sigtype_desc(type);
+ if (!signal->desc) {
+ free(signal);
+ return NULL;
+ }
+
+ if (signal->desc->load_sigdata) {
+ signal->sigdata = (*signal->desc->load_sigdata)(duh, f);
+ if (!signal->sigdata) {
+ free(signal);
+ return NULL;
+ }
+ } else
+ signal->sigdata = NULL;
+
+ return signal;
+}
+
+
+
+/* read_duh(): reads a DUH from an already open DUMBFILE, and returns its
+ * pointer, or null on error. The file is not closed.
+ */
+DUH *read_duh(DUMBFILE *f)
+{
+ DUH *duh;
+ int i;
+
+ if (dumbfile_mgetl(f) != DUH_SIGNATURE)
+ return NULL;
+
+ duh = malloc(sizeof(*duh));
+ if (!duh)
+ return NULL;
+
+ duh->length = dumbfile_igetl(f);
+ if (dumbfile_error(f) || duh->length <= 0) {
+ free(duh);
+ return NULL;
+ }
+
+ duh->n_signals = dumbfile_igetl(f);
+ if (dumbfile_error(f) || duh->n_signals <= 0) {
+ free(duh);
+ return NULL;
+ }
+
+ duh->signal = malloc(sizeof(*duh->signal) * duh->n_signals);
+ if (!duh->signal) {
+ free(duh);
+ return NULL;
+ }
+
+ for (i = 0; i < duh->n_signals; i++)
+ duh->signal[i] = NULL;
+
+ for (i = 0; i < duh->n_signals; i++) {
+ if (!(duh->signal[i] = read_signal(duh, f))) {
+ unload_duh(duh);
+ return NULL;
+ }
+ }
+
+ return duh;
+}
diff --git a/apps/codecs/dumb/src/core/register.c b/apps/codecs/dumb/src/core/register.c
new file mode 100644
index 0000000..9eed45f
--- /dev/null
+++ b/apps/codecs/dumb/src/core/register.c
@@ -0,0 +1,104 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * register.c - Signal type registration. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+static DUH_SIGTYPE_DESC_LINK *sigtype_desc = NULL;
+static DUH_SIGTYPE_DESC_LINK **sigtype_desc_tail = &sigtype_desc;
+
+
+
+/* destroy_sigtypes(): frees all memory allocated while registering signal
+ * types. This function is set up to be called by dumb_exit().
+ */
+static void destroy_sigtypes(void)
+{
+ DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc, *next;
+ sigtype_desc = NULL;
+ sigtype_desc_tail = &sigtype_desc;
+
+ while (desc_link) {
+ next = desc_link->next;
+ free(desc_link);
+ desc_link = next;
+ }
+}
+
+
+
+/* dumb_register_sigtype(): registers a new signal type with DUMB. The signal
+ * type is identified by a four-character string (e.g. "WAVE"), which you can
+ * encode using the the DUMB_ID() macro (e.g. DUMB_ID('W','A','V','E')). The
+ * signal's behaviour is defined by four functions, whose pointers you pass
+ * here. See the documentation for details.
+ *
+ * If a DUH tries to use a signal that has not been registered using this
+ * function, then the library will fail to load the DUH.
+ */
+void dumb_register_sigtype(DUH_SIGTYPE_DESC *desc)
+{
+ DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
+
+ ASSERT((desc->load_sigdata && desc->unload_sigdata) || (!desc->load_sigdata && !desc->unload_sigdata));
+ ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
+ ASSERT(desc->sigrenderer_get_samples && desc->sigrenderer_get_current_sample);
+
+ if (desc_link) {
+ do {
+ if (desc_link->desc->type == desc->type) {
+ desc_link->desc = desc;
+ return;
+ }
+ desc_link = desc_link->next;
+ } while (desc_link);
+ } else
+ dumb_atexit(&destroy_sigtypes);
+
+ desc_link = *sigtype_desc_tail = malloc(sizeof(DUH_SIGTYPE_DESC_LINK));
+
+ if (!desc_link)
+ return;
+
+ desc_link->next = NULL;
+ sigtype_desc_tail = &desc_link->next;
+
+ desc_link->desc = desc;
+}
+
+
+
+/* _dumb_get_sigtype_desc(): searches the registered functions for a signal
+ * type matching the parameter. If such a sigtype is found, it returns a
+ * pointer to a sigtype descriptor containing the necessary functions to
+ * manage the signal. If none is found, it returns NULL.
+ */
+DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(long type)
+{
+ DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
+
+ while (desc_link && desc_link->desc->type != type)
+ desc_link = desc_link->next;
+
+ return desc_link->desc;
+}
diff --git a/apps/codecs/dumb/src/core/rendduh.c b/apps/codecs/dumb/src/core/rendduh.c
new file mode 100644
index 0000000..39db8ab
--- /dev/null
+++ b/apps/codecs/dumb/src/core/rendduh.c
@@ -0,0 +1,202 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * rendduh.c - Functions for rendering a DUH into / / \ \
+ * an end-user sample format. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+/* On the x86, we can use some tricks to speed stuff up */
+#if (defined _MSC_VER) || (defined __DJGPP__) || (defined __MINGW__)
+// Can't we detect Linux and other x86 platforms here? :/
+
+#define FAST_MID(var, min, max) { \
+ var -= (min); \
+ var &= (~var) >> (sizeof(var) * CHAR_BIT - 1); \
+ var += (min); \
+ var -= (max); \
+ var &= var >> (sizeof(var) * CHAR_BIT - 1); \
+ var += (max); \
+}
+
+#define CONVERT8(src, pos, signconv) { \
+ signed int f = (src + 0x8000) >> 16; \
+ FAST_MID(f, -128, 127); \
+ ((char*)sptr)[pos] = (char)f ^ signconv; \
+}
+
+#define CONVERT16(src, pos, signconv) { \
+ signed int f = (src + 0x80) >> 8; \
+ FAST_MID(f, -32768, 32767); \
+ ((short*)sptr)[pos] = (short)(f ^ signconv); \
+}
+
+#else
+
+#define CONVERT8(src, pos, signconv) \
+{ \
+ signed int f = (src + 0x8000) >> 16; \
+ f = MID(-128, f, 127); \
+ ((char *)sptr)[pos] = (char)f ^ signconv; \
+}
+
+
+
+#define CONVERT16(src, pos, signconv) \
+{ \
+ signed int f = (src + 0x80) >> 8; \
+ f = MID(-32768, f, 32767); \
+ ((short *)sptr)[pos] = (short)(f ^ signconv); \
+}
+
+#endif
+
+
+
+/* DEPRECATED */
+DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos)
+{
+ return duh_start_sigrenderer(duh, 0, n_channels, pos);
+}
+
+
+
+long duh_render(
+ DUH_SIGRENDERER *sigrenderer,
+ int bits, int unsign,
+ float volume, float delta,
+ long size, void *sptr
+)
+{
+ long n;
+
+ sample_t **sampptr;
+
+ int n_channels;
+
+ ASSERT(bits == 8 || bits == 16);
+ ASSERT(sptr);
+
+ if (!sigrenderer)
+ return 0;
+
+ n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
+
+ ASSERT(n_channels > 0);
+ /* This restriction will be removed when need be. At the moment, tightly
+ * optimised loops exist for exactly one or two channels.
+ */
+ ASSERT(n_channels <= 2);
+
+ sampptr = create_sample_buffer(n_channels, size);
+
+ if (!sampptr)
+ return 0;
+
+ dumb_silence(sampptr[0], n_channels * size);
+
+ size = duh_sigrenderer_get_samples(sigrenderer, volume, delta, size, sampptr);
+
+ if (bits == 16) {
+ int signconv = unsign ? 0x8000 : 0x0000;
+
+ if (n_channels == 2) {
+ for (n = 0; n < size; n++) {
+ CONVERT16(sampptr[0][n], n << 1, signconv);
+ }
+ for (n = 0; n < size; n++) {
+ CONVERT16(sampptr[1][n], (n << 1) + 1, signconv);
+ }
+ } else {
+ for (n = 0; n < size; n++) {
+ CONVERT16(sampptr[0][n], n, signconv);
+ }
+ }
+ } else {
+ char signconv = unsign ? 0x80 : 0x00;
+
+ if (n_channels == 2) {
+ for (n = 0; n < size; n++) {
+ CONVERT8(sampptr[0][n], n << 1, signconv);
+ }
+ for (n = 0; n < size; n++) {
+ CONVERT8(sampptr[1][n], (n << 1) + 1, signconv);
+ }
+ } else {
+ for (n = 0; n < size; n++) {
+ CONVERT8(sampptr[0][n], n, signconv);
+ }
+ }
+ }
+
+ destroy_sample_buffer(sampptr);
+
+ return size;
+}
+
+
+
+/* DEPRECATED */
+int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr)
+{
+ return duh_sigrenderer_get_n_channels(dr);
+}
+
+
+
+/* DEPRECATED */
+long duh_renderer_get_position(DUH_SIGRENDERER *dr)
+{
+ return duh_sigrenderer_get_position(dr);
+}
+
+
+
+/* DEPRECATED */
+void duh_end_renderer(DUH_SIGRENDERER *dr)
+{
+ duh_end_sigrenderer(dr);
+}
+
+
+
+/* DEPRECATED */
+DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer)
+{
+ return sigrenderer;
+}
+
+
+
+/* DEPRECATED */
+DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr)
+{
+ return dr;
+}
+
+
+
+/* DEPRECATED */
+DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr)
+{
+ return dr;
+}
diff --git a/apps/codecs/dumb/src/core/rendsig.c b/apps/codecs/dumb/src/core/rendsig.c
new file mode 100644
index 0000000..a36ceb4
--- /dev/null
+++ b/apps/codecs/dumb/src/core/rendsig.c
@@ -0,0 +1,299 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * rendsig.c - Wrappers to render samples from / / \ \
+ * the signals in a DUH. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+struct DUH_SIGRENDERER
+{
+ DUH_SIGTYPE_DESC *desc;
+
+ sigrenderer_t *sigrenderer;
+
+ int n_channels;
+
+ long pos;
+ int subpos;
+
+ DUH_SIGRENDERER_ANALYSER_CALLBACK callback;
+ void *callback_data;
+};
+
+
+
+DUH_SIGRENDERER *duh_start_sigrenderer(DUH *duh, int sig, int n_channels, long pos)
+{
+ DUH_SIGRENDERER *sigrenderer;
+
+ DUH_SIGNAL *signal;
+ DUH_START_SIGRENDERER proc;
+
+ if ((unsigned int)sig >= (unsigned int)duh->n_signals)
+ return NULL;
+
+ signal = duh->signal[sig];
+ if (!signal)
+ return NULL;
+
+ sigrenderer = malloc(sizeof(*sigrenderer));
+ if (!sigrenderer)
+ return NULL;
+
+ sigrenderer->desc = signal->desc;
+
+ proc = sigrenderer->desc->start_sigrenderer;
+
+ if (proc) {
+ duh->signal[sig] = NULL;
+ sigrenderer->sigrenderer = (*proc)(duh, signal->sigdata, n_channels, pos);
+ duh->signal[sig] = signal;
+
+ if (!sigrenderer->sigrenderer) {
+ free(sigrenderer);
+ return NULL;
+ }
+ } else
+ sigrenderer->sigrenderer = NULL;
+
+ sigrenderer->n_channels = n_channels;
+
+ sigrenderer->pos = pos;
+ sigrenderer->subpos = 0;
+
+ sigrenderer->callback = NULL;
+
+ return sigrenderer;
+}
+
+
+
+#include <stdio.h>
+void duh_sigrenderer_set_callback(
+ DUH_SIGRENDERER *sigrenderer,
+ DUH_SIGRENDERER_CALLBACK callback, void *data
+)
+{
+ (void)sigrenderer;
+ (void)callback;
+ (void)data;
+/* FIXME
+ fprintf(stderr,
+ "Call to deprecated function duh_sigrenderer_set_callback(). The callback\n"
+ "was not installed. See dumb/docs/deprec.txt for how to fix this.\n");*/
+}
+
+
+
+void duh_sigrenderer_set_analyser_callback(
+ DUH_SIGRENDERER *sigrenderer,
+ DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data
+)
+{
+ if (sigrenderer) {
+ sigrenderer->callback = callback;
+ sigrenderer->callback_data = data;
+ }
+}
+
+
+
+int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer)
+{
+ return sigrenderer ? sigrenderer->n_channels : 0;
+}
+
+
+
+long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer)
+{
+ return sigrenderer ? sigrenderer->pos : -1;
+}
+
+
+
+void duh_sigrenderer_set_sigparam(
+ DUH_SIGRENDERER *sigrenderer,
+ unsigned char id, long value
+)
+{
+ DUH_SIGRENDERER_SET_SIGPARAM proc;
+
+ if (!sigrenderer) return;
+
+ proc = sigrenderer->desc->sigrenderer_set_sigparam;
+ if (proc)
+ (*proc)(sigrenderer->sigrenderer, id, value);
+ else
+ TRACE("Parameter #%d = %ld for signal %c%c%c%c, which does not take parameters.\n",
+ (int)id,
+ value,
+ (int)(sigrenderer->desc->type >> 24),
+ (int)(sigrenderer->desc->type >> 16),
+ (int)(sigrenderer->desc->type >> 8),
+ (int)(sigrenderer->desc->type));
+}
+
+
+
+long duh_sigrenderer_get_samples(
+ DUH_SIGRENDERER *sigrenderer,
+ float volume, float delta,
+ long size, sample_t **samples
+)
+{
+ long rendered;
+ LONG_LONG t;
+
+ if (!sigrenderer) return 0;
+
+ rendered = (*sigrenderer->desc->sigrenderer_get_samples)
+ (sigrenderer->sigrenderer, volume, delta, size, samples);
+
+ if (rendered) {
+ if (sigrenderer->callback)
+ (*sigrenderer->callback)(sigrenderer->callback_data,
+ (const sample_t *const *)samples, sigrenderer->n_channels, rendered);
+
+ t = sigrenderer->subpos + (LONG_LONG)(delta * 65536.0 + 0.5) * rendered;
+
+ sigrenderer->pos += (long)(t >> 16);
+ sigrenderer->subpos = (int)t & 65535;
+ }
+
+ return rendered;
+}
+
+
+
+/* DEPRECATED */
+long duh_render_signal(
+ DUH_SIGRENDERER *sigrenderer,
+ float volume, float delta,
+ long size, sample_t **samples
+)
+{
+ sample_t **s = create_sample_buffer(sigrenderer->n_channels, size);
+ long rendered;
+ long i;
+ int j;
+ if (!s) return 0;
+ rendered = duh_sigrenderer_get_samples(sigrenderer, volume, delta, size, s);
+ for (j = 0; j < sigrenderer->n_channels; j++)
+ for (i = 0; i < rendered; i++)
+ samples[j][i] += s[j][i] >> 8;
+ destroy_sample_buffer(s);
+ return rendered;
+}
+
+
+
+void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples)
+{
+ if (sigrenderer)
+ (*sigrenderer->desc->sigrenderer_get_current_sample)(sigrenderer->sigrenderer, volume, samples);
+}
+
+
+
+void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer)
+{
+ if (sigrenderer) {
+ if (sigrenderer->desc->end_sigrenderer)
+ if (sigrenderer->sigrenderer)
+ (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
+
+ free(sigrenderer);
+ }
+}
+
+
+
+DUH_SIGRENDERER *duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, long pos)
+{
+ DUH_SIGRENDERER *sigrenderer;
+
+ if (desc->start_sigrenderer && !vsigrenderer) return NULL;
+
+ sigrenderer = malloc(sizeof(*sigrenderer));
+ if (!sigrenderer) {
+ if (desc->end_sigrenderer)
+ if (vsigrenderer)
+ (*desc->end_sigrenderer)(vsigrenderer);
+ return NULL;
+ }
+
+ sigrenderer->desc = desc;
+ sigrenderer->sigrenderer = vsigrenderer;
+
+ sigrenderer->n_channels = n_channels;
+
+ sigrenderer->pos = pos;
+ sigrenderer->subpos = 0;
+
+ sigrenderer->callback = NULL;
+
+ return sigrenderer;
+}
+
+
+
+sigrenderer_t *duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type)
+{
+ if (sigrenderer && sigrenderer->desc->type == type)
+ return sigrenderer->sigrenderer;
+
+ return NULL;
+}
+
+
+
+#if 0
+// This function is disabled because we don't know whether we want to destroy
+// the sigrenderer if the type doesn't match. We don't even know if we need
+// the function at all. Who would want to keep an IT_SIGRENDERER (for
+// instance) without keeping the DUH_SIGRENDERER?
+sigrenderer_t *duh_decompose_to_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type)
+{
+ if (sigrenderer && sigrenderer->desc->type == type) {
+
+
+
+ if (sigrenderer) {
+ if (sigrenderer->desc->end_sigrenderer)
+ if (sigrenderer->sigrenderer)
+ (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
+
+ free(sigrenderer);
+ }
+
+
+
+
+
+
+ return sigrenderer->sigrenderer;
+ }
+
+ return NULL;
+}
+#endif
diff --git a/apps/codecs/dumb/src/core/unload.c b/apps/codecs/dumb/src/core/unload.c
new file mode 100644
index 0000000..3bf0285
--- /dev/null
+++ b/apps/codecs/dumb/src/core/unload.c
@@ -0,0 +1,58 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * unload.c - Code to free a DUH from memory. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+static void destroy_signal(DUH_SIGNAL *signal)
+{
+ if (signal) {
+ if (signal->desc)
+ if (signal->desc->unload_sigdata)
+ if (signal->sigdata)
+ (*signal->desc->unload_sigdata)(signal->sigdata);
+
+ free(signal);
+ }
+}
+
+
+
+/* unload_duh(): destroys a DUH struct. You must call this for every DUH
+ * struct created, when you've finished with it.
+ */
+void unload_duh(DUH *duh)
+{
+ int i;
+
+ if (duh) {
+ if (duh->signal) {
+ for (i = 0; i < duh->n_signals; i++)
+ destroy_signal(duh->signal[i]);
+
+ free(duh->signal);
+ }
+
+ free(duh);
+ }
+}