diff options
author | Alexey Yakovenko <wakeroid@gmail.com> | 2010-05-27 22:51:35 +0200 |
---|---|---|
committer | Alexey Yakovenko <wakeroid@gmail.com> | 2010-05-27 22:51:35 +0200 |
commit | 4810f9a0af507bb405e6a3c58decfa9c9980b2ff (patch) | |
tree | 75ac9c06345b23528e6771bb1bae697ff5c29c1c /plugins/dumb/dumb-kode54/src/sigtypes/sequence.c | |
parent | ad71971955594ada4a0b14d176a192d050c9ee36 (diff) |
merged parts of DUMB-0.9.3
Diffstat (limited to 'plugins/dumb/dumb-kode54/src/sigtypes/sequence.c')
-rw-r--r-- | plugins/dumb/dumb-kode54/src/sigtypes/sequence.c | 1184 |
1 files changed, 592 insertions, 592 deletions
diff --git a/plugins/dumb/dumb-kode54/src/sigtypes/sequence.c b/plugins/dumb/dumb-kode54/src/sigtypes/sequence.c index cfade4d6..38cbe783 100644 --- a/plugins/dumb/dumb-kode54/src/sigtypes/sequence.c +++ b/plugins/dumb/dumb-kode54/src/sigtypes/sequence.c @@ -1,592 +1,592 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * sequence.c - The sequence (SEQU) signal type. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-
-
-
-#define SIGTYPE_SEQUENCE DUMB_ID('S','E','Q','U')
-
-
-
-/* We have 256 intervals per semitone, 12 * 256 per octave
- 2 ** (1 / (12 * 256)) = 1.000225659305069791926712241547647863626
-
- pow(DUMB_PITCH_BASE, x) = 1.5
- x = log2(1.5) / log2(DUMB_PITCH_BASE)
- x = log2(1.5) * 12 * 256
- x = 1797.004802
- cf.
- x = 7 * 256 = 1792
-
- so, for the perfect fifth temperament, use an interval of 1797.
-*/
-
-
-
-/* Sequencing format
- * -----------------
- *
- * NOTE: A LOT OF THIS IS NOW REDUNDANT. PLEASE REFER TO duhspecs.txt.
- *
- * When a signal is initiated, it claims a reference number. If any other
- * currently playing signal has the same number, that signal becomes
- * anonymous and inaccessible; that is, if multiple signals were initiated
- * with the same reference, the reference belongs to the most recent.
- *
- * Signals can be stopped, or have their pitch, volume or parameters changed,
- * using the reference number. A signal may stop prematurely if it runs out
- * of data, in which case the reference number becomes void, and operations
- * on it will be ignored. Such a situation will not flag any kind of warning,
- * since it may be the result of inaccuracies when resampling.
- *
- * The sequence consists of a series of commands. All commands begin with a
- * long int, which is the time to wait after the last command (or the
- * beginning of the sequence) before executing this command. 65536 represents
- * one second. A time of -1 (or in fact any negative time) terminates the
- * sequence, but any currently playing signals will continue until they run
- * out. Make sure no non-terminating signals are playing when the sequence
- * ends!
- *
- * The time, if nonnegative, is followed by one byte indicating the type of
- * command. This byte can have the following values:
- *
- * SEQUENCE_START_SIGNAL
- * unsigned char ref; - Reference. Need more than 256? Use two sequences,
- * and get your brain seen to.
- * int sig; - The index of the signal to initiate.
- * long pos; - The position at which to start. 65536 represents one second.
- * unsigned short volume; - Volume. 65535 represents the maximum volume, so
- * you will want to go lower than this if you are
- * playing more than one signal at once.
- * signed short pitch; - Pitch. 0 represents a frequency of 65536 Hz. Scale
- * is logarithmic. Add 256 to increase pitch by one
- * semitone in the even temperament, or add 12*256 to
- * increase pitch by one octave in any temperament
- * (i.e. double the frequency).
- *
- * SEQUENCE_SET_VOLUME
- * unsigned char ref;
- * unsigned short volume;
- *
- * SEQUENCE_SET_PITCH
- * unsigned char ref;
- * signed short pitch;
- *
- * SEQUENCE_SET_PARAMETER
- * unsigned char ref;
- * unsigned char id;
- * long value;
- * - see the description of the set_parameter function pointer for
- * information on 'id' and 'value'.
- *
- * SEQUENCE_STOP_SIGNAL
- * unsigned char ref;
- */
-
-
-
-#define SEQUENCE_START_SIGNAL 0
-#define SEQUENCE_SET_VOLUME 1
-#define SEQUENCE_SET_PITCH 2
-#define SEQUENCE_SET_PARAMETER 3
-#define SEQUENCE_STOP_SIGNAL 4
-
-
-
-typedef struct SEQUENCE_PLAYING
-{
- struct SEQUENCE_PLAYING *next;
-
- DUH_SIGNAL_SAMPINFO *sampinfo;
-
- int ref;
-
- int pitch;
- int volume;
-}
-SEQUENCE_PLAYING;
-
-
-
-typedef struct SEQUENCE_SAMPINFO
-{
- DUH *duh;
-
- int n_channels;
-
- unsigned char *signal;
-
- long time_left;
- int sub_time_left;
-
- SEQUENCE_PLAYING *playing;
-}
-SEQUENCE_SAMPINFO;
-
-
-
-#define sequence_c(signal) ((int)*((*(signal))++))
-
-
-static int sequence_w(unsigned char **signal)
-{
- int v = (*signal)[0] | ((*signal)[1] << 8);
- *signal += 2;
- return v;
-}
-
-
-static long sequence_l(unsigned char **signal)
-{
- long v = (*signal)[0] | ((*signal)[1] << 8) | ((*signal)[2] << 16) | ((*signal)[3] << 24);
- *signal += 4;
- return v;
-}
-
-
-static long sequence_cl(unsigned char **signal)
-{
- long v = sequence_c(signal);
- if (v & 0x80) {
- v &= 0x7F;
- v |= sequence_c(signal) << 7;
- if (v & 0x4000) {
- v &= 0x3FFF;
- v |= sequence_c(signal) << 14;
- if (v & 0x200000) {
- v &= 0x1FFFFF;
- v |= sequence_c(signal) << 21;
- if (v & 0x10000000) {
- v &= 0x0FFFFFFF;
- v |= sequence_c(signal) << 28;
- }
- }
- }
- }
- return v;
-}
-
-
-
-static void *sequence_load_signal(DUH *duh, DUMBFILE *file)
-{
- long size;
- unsigned char *signal;
-
- (void)duh;
-
- size = dumbfile_igetl(file);
- if (dumbfile_error(file) || size <= 0)
- return NULL;
-
- signal = malloc(size);
- if (!signal)
- return NULL;
-
- if (dumbfile_getnc((char *)signal, size, file) < size) {
- free(signal);
- return NULL;
- }
-
- return signal;
-}
-
-
-
-static long render(
- SEQUENCE_SAMPINFO *sampinfo,
- float volume, float delta,
- long pos, long size, sample_t **samples
-)
-{
- sample_t **splptr;
-
- SEQUENCE_PLAYING **playing_p = &sampinfo->playing;
-
- long max_size = 0;
- long part_size;
-
- int n;
- long i;
-
- for (n = 0; n < sampinfo->n_channels; n++)
- memset(samples[n] + pos, 0, size * sizeof(sample_t));
-
- splptr = malloc(sampinfo->n_channels * sizeof(*splptr));
- if (!splptr)
- return 0;
-
- splptr[0] = malloc(sampinfo->n_channels * size * sizeof(sample_t));
- if (!splptr[0]) {
- free(splptr);
- return 0;
- }
-
- for (n = 1; n < sampinfo->n_channels; n++)
- splptr[n] = splptr[n - 1] + size;
-
- while (*playing_p) {
- SEQUENCE_PLAYING *playing = *playing_p;
-
- part_size = duh_signal_render_samples(
- playing->sampinfo,
- volume * (float)playing->volume * (1.0f / 65535.0f),
- (float)(pow(DUMB_PITCH_BASE, playing->pitch) * delta),
- size, splptr
- );
-
- for (n = 0; n < sampinfo->n_channels; n++)
- for (i = 0; i < part_size; i++)
- samples[n][pos+i] += splptr[n][i];
-
- if (part_size > max_size)
- max_size = part_size;
-
- if (part_size < size) {
- *playing_p = playing->next;
- duh_signal_end_samples(playing->sampinfo);
- free(playing);
- } else
- playing_p = &playing->next;
- }
-
- free(splptr[0]);
- free(splptr);
-
- return max_size;
-}
-
-
-
-/* 'offset' is added to the position at which the signal should start. It is
- * currently assumed to be positive, and is currently only used when seeking
- * forwards in the sequence.
- */
-static void sequence_command(SEQUENCE_SAMPINFO *sampinfo, long offset)
-{
- int command = sequence_c(&sampinfo->signal);
-
- if (command == SEQUENCE_START_SIGNAL) {
-
- int ref = sequence_c(&sampinfo->signal);
- int sig = sequence_cl(&sampinfo->signal);
- long pos = sequence_cl(&sampinfo->signal);
- int volume = sequence_w(&sampinfo->signal);
- int pitch = (int)(signed short)sequence_w(&sampinfo->signal);
-
- SEQUENCE_PLAYING *playing = sampinfo->playing;
-
- while (playing) {
- if (playing->ref == ref)
- playing->ref = -1;
- playing = playing->next;
- }
-
- playing = malloc(sizeof(SEQUENCE_PLAYING));
-
- if (playing) {
- playing->sampinfo = duh_signal_start_samples(sampinfo->duh, sig, sampinfo->n_channels, pos + offset);
-
- if (playing->sampinfo) {
- playing->ref = ref;
- playing->pitch = pitch;
- playing->volume = volume;
-
- playing->next = sampinfo->playing;
- sampinfo->playing = playing;
- } else
- free(playing);
- }
-
- } else if (command == SEQUENCE_SET_VOLUME) {
-
- int ref = sequence_c(&sampinfo->signal);
- int volume = sequence_w(&sampinfo->signal);
-
- SEQUENCE_PLAYING *playing = sampinfo->playing;
-
- while (playing) {
- if (playing->ref == ref) {
- playing->volume = volume;
- break;
- }
- playing = playing->next;
- }
-
- } else if (command == SEQUENCE_SET_PITCH) {
-
- int ref = sequence_c(&sampinfo->signal);
- int pitch = (int)(signed short)sequence_w(&sampinfo->signal);
-
- SEQUENCE_PLAYING *playing = sampinfo->playing;
-
- while (playing) {
- if (playing->ref == ref) {
- playing->pitch = pitch;
- break;
- }
- playing = playing->next;
- }
-
- } else if (command == SEQUENCE_SET_PARAMETER) {
-
- int ref = sequence_c(&sampinfo->signal);
- unsigned char id = sequence_c(&sampinfo->signal);
- long value = sequence_l(&sampinfo->signal);
-
- SEQUENCE_PLAYING *playing = sampinfo->playing;
-
- while (playing) {
- if (playing->ref == ref) {
- duh_signal_set_parameter(playing->sampinfo, id, value);
- break;
- }
- playing = playing->next;
- }
-
- } else if (command == SEQUENCE_STOP_SIGNAL) {
-
- int ref = sequence_c(&sampinfo->signal);
-
- SEQUENCE_PLAYING **playing_p = &sampinfo->playing;
-
- while (*playing_p) {
- SEQUENCE_PLAYING *playing = *playing_p;
-
- if (playing->ref == ref) {
- duh_signal_end_samples(playing->sampinfo);
- *playing_p = playing->next;
- free(playing);
- break;
- }
-
- playing_p = &playing->next;
- }
-
- } else {
-
- TRACE("Error in sequence: unknown command %d.\n", command);
- sampinfo->signal = NULL;
-
- }
-}
-
-
-
-static void *sequence_start_samples(DUH *duh, void *signal, int n_channels, long pos)
-{
- SEQUENCE_SAMPINFO *sampinfo;
- long time = sequence_cl((unsigned char **)&signal);
-
- if (time < 0)
- return NULL;
-
- sampinfo = malloc(sizeof(SEQUENCE_SAMPINFO));
- if (!sampinfo)
- return NULL;
-
- sampinfo->duh = duh;
- sampinfo->n_channels = n_channels;
- sampinfo->signal = signal;
- sampinfo->playing = NULL;
-
- /* Seek to 'pos'. */
- while (time < pos) {
- pos -= time;
-
- sequence_command(sampinfo, pos);
-
- time = sequence_cl(&sampinfo->signal);
-
- if (time < 0) {
- sampinfo->signal = NULL;
- return sampinfo;
- }
- }
-
- sampinfo->time_left = time - pos;
- sampinfo->sub_time_left = 0;
-
- return sampinfo;
-}
-
-
-
-static long sequence_render_samples(
- void *sampinfo,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
-
-#define sampinfo ((SEQUENCE_SAMPINFO *)sampinfo)
-
- long pos = 0;
-
- int dt = (int)(delta * 65536.0f + 0.5f);
-
- long todo;
- LONG_LONG t;
-
- while (sampinfo->signal) {
- todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt);
-
- if (todo >= size)
- break;
-
- if (todo) {
- render(sampinfo, volume, delta, pos, todo, samples);
-
- pos += todo;
- size -= todo;
-
- todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt);
- t = sampinfo->sub_time_left - (LONG_LONG)todo * dt;
- sampinfo->sub_time_left = (long)t & 65535;
- sampinfo->time_left += (long)(t >> 16);
- }
-
- sequence_command(sampinfo, 0);
-
- todo = sequence_cl(&sampinfo->signal);
-
- if (todo >= 0)
- sampinfo->time_left += todo;
- else
- sampinfo->signal = NULL;
- }
-
- if (sampinfo->signal) {
- render(sampinfo, volume, delta, pos, size, samples);
-
- pos += size;
-
- t = sampinfo->sub_time_left - (LONG_LONG)size * dt;
- sampinfo->sub_time_left = (long)t & 65535;
- sampinfo->time_left += (long)(t >> 16);
- } else
- pos += render(sampinfo, volume, delta, pos, size, samples);
-
- return pos;
-
-
-/** WARNING - remove this... */
-#if 0
- float size_unified = size * delta;
-
- int n;
-
- sample_t **samples2 = malloc(sampinfo->n_channels * sizeof(*samples2));
- memcpy(samples2, samples, sampinfo->n_channels * sizeof(*samples2));
-
- while (sampinfo->signal && sampinfo->time < size_unified) {
-
- {
- long sz = (long)(sampinfo->time / delta);
-
- if (sz)
- render(sampinfo, volume, delta, sz, samples2);
-
- for (n = 0; n < sampinfo->n_channels; n++)
- samples2[n] += sz;
-
- size -= sz;
- pos += sz;
-
- sampinfo->time -= sz * delta;
- }
-
- sequence_command(sampinfo, 0);
-
- {
- long time = sequence_cl(&sampinfo->signal);
-
- if (time >= 0)
- sampinfo->time += (float)time;
- else
- sampinfo->signal = NULL;
- }
-
- size_unified = size * delta;
- }
-
- if (sampinfo->signal) {
- render(sampinfo, volume, delta, size, samples2);
- sampinfo->time -= size_unified;
- pos += size;
- } else
- pos += render(sampinfo, volume, delta, size, samples2);
-
- free(samples2);
-
- return pos;
-#endif
-
-#undef sampinfo
-
-}
-
-
-
-static void sequence_end_samples(void *sampinfo)
-{
- SEQUENCE_PLAYING *playing = ((SEQUENCE_SAMPINFO *)sampinfo)->playing;
-
- while (playing) {
- SEQUENCE_PLAYING *next = playing->next;
-
- duh_signal_end_samples(playing->sampinfo);
- free(playing);
-
- playing = next;
- }
-
- free(sampinfo);
-}
-
-
-
-static void sequence_unload_signal(void *signal)
-{
- free(signal);
-}
-
-
-
-static DUH_SIGTYPE_DESC sigtype_sequence = {
- SIGTYPE_SEQUENCE,
- &sequence_load_signal,
- &sequence_start_samples,
- NULL,
- &sequence_render_samples,
- &sequence_end_samples,
- &sequence_unload_signal
-};
-
-
-
-void dumb_register_sigtype_sequence(void)
-{
- dumb_register_sigtype(&sigtype_sequence);
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * sequence.c - The sequence (SEQU) signal type. / / \ \ + * | < / \_ + * By entheh. | \/ /\ / + * \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" + + + +#define SIGTYPE_SEQUENCE DUMB_ID('S','E','Q','U') + + + +/* We have 256 intervals per semitone, 12 * 256 per octave + 2 ** (1 / (12 * 256)) = 1.000225659305069791926712241547647863626 + + pow(DUMB_PITCH_BASE, x) = 1.5 + x = log2(1.5) / log2(DUMB_PITCH_BASE) + x = log2(1.5) * 12 * 256 + x = 1797.004802 + cf. + x = 7 * 256 = 1792 + + so, for the perfect fifth temperament, use an interval of 1797. +*/ + + + +/* Sequencing format + * ----------------- + * + * NOTE: A LOT OF THIS IS NOW REDUNDANT. PLEASE REFER TO duhspecs.txt. + * + * When a signal is initiated, it claims a reference number. If any other + * currently playing signal has the same number, that signal becomes + * anonymous and inaccessible; that is, if multiple signals were initiated + * with the same reference, the reference belongs to the most recent. + * + * Signals can be stopped, or have their pitch, volume or parameters changed, + * using the reference number. A signal may stop prematurely if it runs out + * of data, in which case the reference number becomes void, and operations + * on it will be ignored. Such a situation will not flag any kind of warning, + * since it may be the result of inaccuracies when resampling. + * + * The sequence consists of a series of commands. All commands begin with a + * long int, which is the time to wait after the last command (or the + * beginning of the sequence) before executing this command. 65536 represents + * one second. A time of -1 (or in fact any negative time) terminates the + * sequence, but any currently playing signals will continue until they run + * out. Make sure no non-terminating signals are playing when the sequence + * ends! + * + * The time, if nonnegative, is followed by one byte indicating the type of + * command. This byte can have the following values: + * + * SEQUENCE_START_SIGNAL + * unsigned char ref; - Reference. Need more than 256? Use two sequences, + * and get your brain seen to. + * int sig; - The index of the signal to initiate. + * long pos; - The position at which to start. 65536 represents one second. + * unsigned short volume; - Volume. 65535 represents the maximum volume, so + * you will want to go lower than this if you are + * playing more than one signal at once. + * signed short pitch; - Pitch. 0 represents a frequency of 65536 Hz. Scale + * is logarithmic. Add 256 to increase pitch by one + * semitone in the even temperament, or add 12*256 to + * increase pitch by one octave in any temperament + * (i.e. double the frequency). + * + * SEQUENCE_SET_VOLUME + * unsigned char ref; + * unsigned short volume; + * + * SEQUENCE_SET_PITCH + * unsigned char ref; + * signed short pitch; + * + * SEQUENCE_SET_PARAMETER + * unsigned char ref; + * unsigned char id; + * long value; + * - see the description of the set_parameter function pointer for + * information on 'id' and 'value'. + * + * SEQUENCE_STOP_SIGNAL + * unsigned char ref; + */ + + + +#define SEQUENCE_START_SIGNAL 0 +#define SEQUENCE_SET_VOLUME 1 +#define SEQUENCE_SET_PITCH 2 +#define SEQUENCE_SET_PARAMETER 3 +#define SEQUENCE_STOP_SIGNAL 4 + + + +typedef struct SEQUENCE_PLAYING +{ + struct SEQUENCE_PLAYING *next; + + DUH_SIGNAL_SAMPINFO *sampinfo; + + int ref; + + int pitch; + int volume; +} +SEQUENCE_PLAYING; + + + +typedef struct SEQUENCE_SAMPINFO +{ + DUH *duh; + + int n_channels; + + unsigned char *signal; + + long time_left; + int sub_time_left; + + SEQUENCE_PLAYING *playing; +} +SEQUENCE_SAMPINFO; + + + +#define sequence_c(signal) ((int)*((*(signal))++)) + + +static int sequence_w(unsigned char **signal) +{ + int v = (*signal)[0] | ((*signal)[1] << 8); + *signal += 2; + return v; +} + + +static long sequence_l(unsigned char **signal) +{ + long v = (*signal)[0] | ((*signal)[1] << 8) | ((*signal)[2] << 16) | ((*signal)[3] << 24); + *signal += 4; + return v; +} + + +static long sequence_cl(unsigned char **signal) +{ + long v = sequence_c(signal); + if (v & 0x80) { + v &= 0x7F; + v |= sequence_c(signal) << 7; + if (v & 0x4000) { + v &= 0x3FFF; + v |= sequence_c(signal) << 14; + if (v & 0x200000) { + v &= 0x1FFFFF; + v |= sequence_c(signal) << 21; + if (v & 0x10000000) { + v &= 0x0FFFFFFF; + v |= sequence_c(signal) << 28; + } + } + } + } + return v; +} + + + +static void *sequence_load_signal(DUH *duh, DUMBFILE *file) +{ + long size; + unsigned char *signal; + + (void)duh; + + size = dumbfile_igetl(file); + if (dumbfile_error(file) || size <= 0) + return NULL; + + signal = malloc(size); + if (!signal) + return NULL; + + if (dumbfile_getnc((char *)signal, size, file) < size) { + free(signal); + return NULL; + } + + return signal; +} + + + +static long render( + SEQUENCE_SAMPINFO *sampinfo, + float volume, float delta, + long pos, long size, sample_t **samples +) +{ + sample_t **splptr; + + SEQUENCE_PLAYING **playing_p = &sampinfo->playing; + + long max_size = 0; + long part_size; + + int n; + long i; + + for (n = 0; n < sampinfo->n_channels; n++) + memset(samples[n] + pos, 0, size * sizeof(sample_t)); + + splptr = malloc(sampinfo->n_channels * sizeof(*splptr)); + if (!splptr) + return 0; + + splptr[0] = malloc(sampinfo->n_channels * size * sizeof(sample_t)); + if (!splptr[0]) { + free(splptr); + return 0; + } + + for (n = 1; n < sampinfo->n_channels; n++) + splptr[n] = splptr[n - 1] + size; + + while (*playing_p) { + SEQUENCE_PLAYING *playing = *playing_p; + + part_size = duh_signal_render_samples( + playing->sampinfo, + volume * (float)playing->volume * (1.0f / 65535.0f), + (float)(pow(DUMB_PITCH_BASE, playing->pitch) * delta), + size, splptr + ); + + for (n = 0; n < sampinfo->n_channels; n++) + for (i = 0; i < part_size; i++) + samples[n][pos+i] += splptr[n][i]; + + if (part_size > max_size) + max_size = part_size; + + if (part_size < size) { + *playing_p = playing->next; + duh_signal_end_samples(playing->sampinfo); + free(playing); + } else + playing_p = &playing->next; + } + + free(splptr[0]); + free(splptr); + + return max_size; +} + + + +/* 'offset' is added to the position at which the signal should start. It is + * currently assumed to be positive, and is currently only used when seeking + * forwards in the sequence. + */ +static void sequence_command(SEQUENCE_SAMPINFO *sampinfo, long offset) +{ + int command = sequence_c(&sampinfo->signal); + + if (command == SEQUENCE_START_SIGNAL) { + + int ref = sequence_c(&sampinfo->signal); + int sig = sequence_cl(&sampinfo->signal); + long pos = sequence_cl(&sampinfo->signal); + int volume = sequence_w(&sampinfo->signal); + int pitch = (int)(signed short)sequence_w(&sampinfo->signal); + + SEQUENCE_PLAYING *playing = sampinfo->playing; + + while (playing) { + if (playing->ref == ref) + playing->ref = -1; + playing = playing->next; + } + + playing = malloc(sizeof(SEQUENCE_PLAYING)); + + if (playing) { + playing->sampinfo = duh_signal_start_samples(sampinfo->duh, sig, sampinfo->n_channels, pos + offset); + + if (playing->sampinfo) { + playing->ref = ref; + playing->pitch = pitch; + playing->volume = volume; + + playing->next = sampinfo->playing; + sampinfo->playing = playing; + } else + free(playing); + } + + } else if (command == SEQUENCE_SET_VOLUME) { + + int ref = sequence_c(&sampinfo->signal); + int volume = sequence_w(&sampinfo->signal); + + SEQUENCE_PLAYING *playing = sampinfo->playing; + + while (playing) { + if (playing->ref == ref) { + playing->volume = volume; + break; + } + playing = playing->next; + } + + } else if (command == SEQUENCE_SET_PITCH) { + + int ref = sequence_c(&sampinfo->signal); + int pitch = (int)(signed short)sequence_w(&sampinfo->signal); + + SEQUENCE_PLAYING *playing = sampinfo->playing; + + while (playing) { + if (playing->ref == ref) { + playing->pitch = pitch; + break; + } + playing = playing->next; + } + + } else if (command == SEQUENCE_SET_PARAMETER) { + + int ref = sequence_c(&sampinfo->signal); + unsigned char id = sequence_c(&sampinfo->signal); + long value = sequence_l(&sampinfo->signal); + + SEQUENCE_PLAYING *playing = sampinfo->playing; + + while (playing) { + if (playing->ref == ref) { + duh_signal_set_parameter(playing->sampinfo, id, value); + break; + } + playing = playing->next; + } + + } else if (command == SEQUENCE_STOP_SIGNAL) { + + int ref = sequence_c(&sampinfo->signal); + + SEQUENCE_PLAYING **playing_p = &sampinfo->playing; + + while (*playing_p) { + SEQUENCE_PLAYING *playing = *playing_p; + + if (playing->ref == ref) { + duh_signal_end_samples(playing->sampinfo); + *playing_p = playing->next; + free(playing); + break; + } + + playing_p = &playing->next; + } + + } else { + + TRACE("Error in sequence: unknown command %d.\n", command); + sampinfo->signal = NULL; + + } +} + + + +static void *sequence_start_samples(DUH *duh, void *signal, int n_channels, long pos) +{ + SEQUENCE_SAMPINFO *sampinfo; + long time = sequence_cl((unsigned char **)&signal); + + if (time < 0) + return NULL; + + sampinfo = malloc(sizeof(SEQUENCE_SAMPINFO)); + if (!sampinfo) + return NULL; + + sampinfo->duh = duh; + sampinfo->n_channels = n_channels; + sampinfo->signal = signal; + sampinfo->playing = NULL; + + /* Seek to 'pos'. */ + while (time < pos) { + pos -= time; + + sequence_command(sampinfo, pos); + + time = sequence_cl(&sampinfo->signal); + + if (time < 0) { + sampinfo->signal = NULL; + return sampinfo; + } + } + + sampinfo->time_left = time - pos; + sampinfo->sub_time_left = 0; + + return sampinfo; +} + + + +static long sequence_render_samples( + void *sampinfo, + float volume, float delta, + long size, sample_t **samples +) +{ + +#define sampinfo ((SEQUENCE_SAMPINFO *)sampinfo) + + long pos = 0; + + int dt = (int)(delta * 65536.0f + 0.5f); + + long todo; + LONG_LONG t; + + while (sampinfo->signal) { + todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt); + + if (todo >= size) + break; + + if (todo) { + render(sampinfo, volume, delta, pos, todo, samples); + + pos += todo; + size -= todo; + + todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt); + t = sampinfo->sub_time_left - (LONG_LONG)todo * dt; + sampinfo->sub_time_left = (long)t & 65535; + sampinfo->time_left += (long)(t >> 16); + } + + sequence_command(sampinfo, 0); + + todo = sequence_cl(&sampinfo->signal); + + if (todo >= 0) + sampinfo->time_left += todo; + else + sampinfo->signal = NULL; + } + + if (sampinfo->signal) { + render(sampinfo, volume, delta, pos, size, samples); + + pos += size; + + t = sampinfo->sub_time_left - (LONG_LONG)size * dt; + sampinfo->sub_time_left = (long)t & 65535; + sampinfo->time_left += (long)(t >> 16); + } else + pos += render(sampinfo, volume, delta, pos, size, samples); + + return pos; + + +/** WARNING - remove this... */ +#if 0 + float size_unified = size * delta; + + int n; + + sample_t **samples2 = malloc(sampinfo->n_channels * sizeof(*samples2)); + memcpy(samples2, samples, sampinfo->n_channels * sizeof(*samples2)); + + while (sampinfo->signal && sampinfo->time < size_unified) { + + { + long sz = (long)(sampinfo->time / delta); + + if (sz) + render(sampinfo, volume, delta, sz, samples2); + + for (n = 0; n < sampinfo->n_channels; n++) + samples2[n] += sz; + + size -= sz; + pos += sz; + + sampinfo->time -= sz * delta; + } + + sequence_command(sampinfo, 0); + + { + long time = sequence_cl(&sampinfo->signal); + + if (time >= 0) + sampinfo->time += (float)time; + else + sampinfo->signal = NULL; + } + + size_unified = size * delta; + } + + if (sampinfo->signal) { + render(sampinfo, volume, delta, size, samples2); + sampinfo->time -= size_unified; + pos += size; + } else + pos += render(sampinfo, volume, delta, size, samples2); + + free(samples2); + + return pos; +#endif + +#undef sampinfo + +} + + + +static void sequence_end_samples(void *sampinfo) +{ + SEQUENCE_PLAYING *playing = ((SEQUENCE_SAMPINFO *)sampinfo)->playing; + + while (playing) { + SEQUENCE_PLAYING *next = playing->next; + + duh_signal_end_samples(playing->sampinfo); + free(playing); + + playing = next; + } + + free(sampinfo); +} + + + +static void sequence_unload_signal(void *signal) +{ + free(signal); +} + + + +static DUH_SIGTYPE_DESC sigtype_sequence = { + SIGTYPE_SEQUENCE, + &sequence_load_signal, + &sequence_start_samples, + NULL, + &sequence_render_samples, + &sequence_end_samples, + &sequence_unload_signal +}; + + + +void dumb_register_sigtype_sequence(void) +{ + dumb_register_sigtype(&sigtype_sequence); +} |