summaryrefslogtreecommitdiff
path: root/plugins/dumb/dumb-kode54/src/sigtypes/combine.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/dumb/dumb-kode54/src/sigtypes/combine.c')
-rw-r--r--plugins/dumb/dumb-kode54/src/sigtypes/combine.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/plugins/dumb/dumb-kode54/src/sigtypes/combine.c b/plugins/dumb/dumb-kode54/src/sigtypes/combine.c
new file mode 100644
index 00000000..497f085c
--- /dev/null
+++ b/plugins/dumb/dumb-kode54/src/sigtypes/combine.c
@@ -0,0 +1,243 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * combine.c - The combining (COMB) signal type. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * This takes multiple monaural signals and | \ / /
+ * combines them into a single multichannel | ' /
+ * signal. It assumes the correct number of \__/
+ * channels is passed. An ASSERT() is in place
+ * to check the number of channels when you
+ * compile with -DDEBUGMODE. As an exception, if one channel is passed the
+ * signals are all mixed together.
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+
+
+
+#define SIGTYPE_COMBINING DUMB_ID('C','O','M','B')
+
+
+
+typedef struct COMBINING_SIGNAL
+{
+ int n_signals;
+ int sig[ZERO_SIZE];
+}
+COMBINING_SIGNAL;
+
+
+
+typedef struct COMBINING_SAMPINFO
+{
+ int n_signals;
+ int downmix;
+ DUH_SIGNAL_SAMPINFO *csampinfo[ZERO_SIZE];
+}
+COMBINING_SAMPINFO;
+
+
+
+static void *combining_load_signal(DUH *duh, DUMBFILE *file)
+{
+ COMBINING_SIGNAL *signal;
+ int n_signals;
+
+ (void)duh;
+
+ n_signals = dumbfile_getc(file);
+
+ /* No point in combining only one signal! */
+ if (dumbfile_error(file) || n_signals <= 1)
+ return NULL;
+
+ signal = malloc(sizeof(*signal) + n_signals * sizeof(*signal->sig));
+ if (!signal)
+ return NULL;
+
+ signal->n_signals = n_signals;
+
+ {
+ int n;
+ for (n = 0; n < signal->n_signals; n++) {
+ signal->sig[n] = dumbfile_igetl(file);
+ if (dumbfile_error(file)) {
+ free(signal);
+ return NULL;
+ }
+ }
+ }
+
+ return signal;
+}
+
+
+
+static void *combining_start_samples(DUH *duh, void *signal, int n_channels, long pos)
+{
+#define signal ((COMBINING_SIGNAL *)signal)
+
+ COMBINING_SAMPINFO *sampinfo;
+
+ sampinfo = malloc(sizeof(*sampinfo) + signal->n_signals * sizeof(*sampinfo->csampinfo));
+ if (!sampinfo)
+ return NULL;
+
+ sampinfo->n_signals = signal->n_signals;
+ if (n_channels == 1)
+ sampinfo->downmix = 1;
+ else if (n_channels == signal->n_signals)
+ sampinfo->downmix = 0;
+ else {
+ TRACE("Combining signal discrepancy: %d signals, %d channels.\n", signal->n_signals, n_channels);
+ free(sampinfo);
+ return NULL;
+ }
+
+ {
+ int worthwhile = 0;
+
+ {
+ int n;
+ for (n = 0; n < signal->n_signals; n++) {
+ sampinfo->csampinfo[n] = duh_signal_start_samples(duh, signal->sig[n], 1, pos);
+ if (sampinfo->csampinfo[n])
+ worthwhile = 1;
+ }
+ }
+
+ if (!worthwhile) {
+ free(sampinfo);
+ return NULL;
+ }
+ }
+
+ return sampinfo;
+
+#undef signal
+}
+
+
+
+static long combining_render_samples(
+ void *sampinfo,
+ float volume, float delta,
+ long size, sample_t **samples
+)
+{
+#define sampinfo ((COMBINING_SAMPINFO *)sampinfo)
+
+ long max_size;
+
+ int n;
+
+ if (sampinfo->downmix)
+ volume /= sampinfo->n_signals;
+
+ max_size = duh_signal_render_samples(sampinfo->csampinfo[0], volume, delta, size, samples);
+
+ if (sampinfo->downmix) {
+
+ long s;
+ long sz;
+
+ sample_t *sampbuf = malloc(size * sizeof(sample_t));
+
+ if (!sampbuf)
+ return 0;
+
+ for (n = 1; n < sampinfo->n_signals; n++) {
+ sz = duh_signal_render_samples(sampinfo->csampinfo[n], volume, delta, size, &sampbuf);
+ if (sz > max_size) {
+ for (s = max_size; s < sz; s++)
+ samples[0][s] = sampbuf[s];
+ sz = max_size;
+ max_size = s;
+ }
+ for (s = 0; s < sz; s++)
+ samples[0][s] += sampbuf[s];
+ }
+
+ free(sampbuf);
+
+ } else {
+
+ long *sz = malloc(size * sizeof(*sz));
+ long s;
+
+ if (!sz)
+ return 0;
+
+ sz[0] = max_size;
+
+ for (n = 1; n < sampinfo->n_signals; n++) {
+ sz[n] = duh_signal_render_samples(sampinfo->csampinfo[n], volume, delta, size, samples + n);
+ if (sz[n] > max_size)
+ max_size = sz[n];
+ }
+
+ for (n = 0; n < sampinfo->n_signals; n++)
+ for (s = sz[n]; s < max_size; s++)
+ samples[n][s] = 0;
+
+ free(sz);
+
+ }
+
+ return max_size;
+
+#undef sampinfo
+}
+
+
+
+static void combining_end_samples(void *sampinfo)
+{
+#define sampinfo ((COMBINING_SAMPINFO *)sampinfo)
+
+ int n;
+
+ for (n = 0; n < sampinfo->n_signals; n++)
+ duh_signal_end_samples(sampinfo->csampinfo[n]);
+
+ free(sampinfo);
+
+#undef sampinfo
+}
+
+
+
+static void combining_unload_signal(void *signal)
+{
+ free(signal);
+}
+
+
+
+static DUH_SIGTYPE_DESC sigtype_combining = {
+ SIGTYPE_COMBINING,
+ &combining_load_signal,
+ &combining_start_samples,
+ NULL,
+ &combining_render_samples,
+ &combining_end_samples,
+ &combining_unload_signal
+};
+
+
+void dumb_register_sigtype_combining(void)
+{
+ dumb_register_sigtype(&sigtype_combining);
+}