summaryrefslogtreecommitdiff
path: root/dumb/dumb-kode54/docs/duhspecs.txt
diff options
context:
space:
mode:
Diffstat (limited to 'dumb/dumb-kode54/docs/duhspecs.txt')
-rw-r--r--dumb/dumb-kode54/docs/duhspecs.txt296
1 files changed, 296 insertions, 0 deletions
diff --git a/dumb/dumb-kode54/docs/duhspecs.txt b/dumb/dumb-kode54/docs/duhspecs.txt
new file mode 100644
index 00000000..43b3d39c
--- /dev/null
+++ b/dumb/dumb-kode54/docs/duhspecs.txt
@@ -0,0 +1,296 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * duhspecs.txt - DUH File Specifications. / / \ \
+ * | < / \_
+ * Written by entheh, one of the few programmers | \/ /\ /
+ * in existance who can spell correctly. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+Technical Details
+=================
+
+WARNING: until this warning disappears, the DUH file format could change at
+any moment. This should not be of great concern, since DUH files are not
+designed to be edited directly, but will always be generated from some other
+format. However, it is our intention that this warning be removed before the
+first release.
+
+This document is written chiefly in the context of writing a DUH file, since
+the library already contains the necessary functionality to read and play a
+DUH file.
+
+DUH files are currently saved using Allegro's file compression routines. See
+Allegro's documentation and source code for details on this system. If you
+wish to port DUMB away from Allegro and wish to preserve the file compression
+capabilities, you will have to borrow the packfile source code from Allegro.
+
+If you are happy to do away with file compression, please store the following
+four-byte signature before the rest of the file: "slh." Alternatively, write
+your DUH file writer with Allegro, and open the file with F_WRITE_NOPACK.
+This will enable versions of the library using Allegro's file compression
+routines to load the file. If you are reading a DUH file and you detect the
+signature "slh!", then the file is compressed (and is not necessarily a DUH
+file).
+
+All numbers are little-endian unless specified otherwise. Allegro's
+pack_iget*() and pack_iput*() functions can be used to read and write data in
+this format. However, the four-byte signatures can be encoded into long ints
+with AL_ID() and read and written with pack_m*().
+
+
+Overall Structure
+=================
+
+Size Type Value Example C code to save to PACKFILE *f
+
+ 4 ID "DUH!" pack_mputl(AL_ID('D','U','H','!'), f);
+ 4 Int Number of signals pack_iputl(n_signals, f);
+
+For each signal { for (i = 0; i < n_signals; i++) {
+ 4 ID Signal type pack_mputl(AL_ID('S','E','Q','U'), f);
+ * - Signal data write_sequence(f);
+} }
+
+* The size of the data for any signal must either be constant or somehow
+ encoded in the data themselves. The library contains functions to read
+ various standard signal types, including "SAMP" and "SEQU" (sample and
+ sequence respectively), and the formats for these types are laid out
+ further down. If you wish to create your own signals, you must provide your
+ own loading function for the signal. This will be described in more detail
+ in a separate file.
+
+In order to play a DUH file, we simply play the first signal. Signals can
+construct their sound from the samples of other signals, and they in turn can
+use other signals. Thus a recursive structure is built up. Recursive cycles
+are not permitted.
+
+
+Signal: SAMP (Sample)
+=====================
+
+Size Type Value Example C code to save to PACKFILE *f
+
+ 4 Int Size pack_iputl(size, f);
+ 1 Bits Flags pack_putc(flags, f);
+ 1 ID Compression type pack_putc(compress, f); /* NOT IMPLEMENTED YET */
+
+The flags are stored in a bit-field. Bit 0 indicates whether 16-bit samples
+(set) or 8-bit samples (clear) are stored in the file. In both cases, the
+samples are signed. NOTE: this bit might be replaced with a system allowing
+for various sample compression algorithms, or altered so there are different
+signal types for the purpose.
+
+If Bit 1 is set, the sample is a looping sample, and loops indefinitely. In
+this case the loop start point will be saved. The loop end point is not
+saved, and is assumed to be the end of the sample. (When creating DUH files
+from other formats which allow for the loop end to be earlier, you should
+truncate the sample.)
+
+If Bit 1 is not set, then Bit 2 may be set to indicate that the sample is
+looping but only loops a finite number of times before continuing to play
+normally. In this mode, both loop points (start and end) are saved in the
+file. The number of times to loop will be specified on an instance-by-
+instance basis using signal parameter #0, which should be set immediately
+(before any samples are rendered) if it is to be set at all. It defaults to 0
+(so the sample just plays through normally). In fact this parameter's value
+is added to the loop count, but this is immaterial since there is no reason
+to specify it more than once.
+
+If Bit 1 is set, you should make sure Bit 2 is clear to allow for the
+possibility of future expansion.
+
+If Bit 3 is set, a ping-pong loop is used. When the sample reaches the loop
+end point, it starts to play backwards until it reaches the loop start point,
+at which time it will resume forward playback. When using a finite loop,
+every change of direction counts as one iteration. That means an odd loop
+count will cause the sample to proceed backwards when the looping ends.
+
+If neither Bit 1 nor Bit 2 is set, then neither loop point will be saved. In
+this case, you should also make sure Bit 3 is clear for the same reason as
+above.
+
+You may find the following definitions useful:
+
+#define SAMPFLAG_16BIT 1
+#define SAMPFLAG_LOOP 2
+#define SAMPFLAG_XLOOP 4
+#define SAMPFLAG_PINGPONG 8
+
+#define SAMPPARAM_N_LOOPS 0
+
+Size Type Value Example C code to save to PACKFILE *f
+
+ 4 Int Loop start pack_iputl(loop_start, f);
+ 4 Int Loop end pack_iputl(loop_end, f);
+
+For a 16-bit sample: if (flags & SAMPFLAG_16BIT)
+ for (n = 0; n < size; n++)
+ x*2 Int Sample data pack_iputw(sample[n], f);
+For an 8-bit sample: else
+ for (n = 0; n < size; n++)
+ x*1 Int Sample data pack_putc(sample[n], f);
+
+/*
+Compression type is 0 for uncompressed PCM.
+*/
+
+
+Signal: SEQU (Sequence)
+=======================
+
+Size Type Value Example C code to save to PACKFILE *f
+
+ 4 Int Size size = pack_igetl(f);
+ x - Sequencing data pack_fwrite(data, size, f);
+
+The sequence signal provides a medium in which other signals can be played at
+specific times for specific lengths. You can control the pitch, volume and
+other parameters for a signal, and these can change during the signal.
+
+A sequence consists of a series of commands. Each command is preceded by a
+time, which measures how long to wait before executing this command. A time
+of zero indicates that this command is simultaneous with the previous. A time
+of -1 indicates the end of the sequence. Note that signals do not stop
+playing when the end is reached.
+
+All times are measured in units such that 65536 corresponds to one second.
+The timing in DUMB is accurate to the nearest sample, and cannot be offset in
+the way it can with much mixing software, so you can rely on timing to
+achieve certain effects. Resampling should be accurate enough to satisfy the
+most acute musician's ear, but juggling pitches at this level of accuracy
+requires knowledge of temperaments such as many musicians do not have. The
+vast majority of people are satisfied with the even temperament. More on this
+later.
+
+Size Type Value Example C code to save to PACKFILE *f
+
+ 4 Int Time pack_iputl(time, f);
+ 1 ID Command pack_putc(SEQUENCE_START_SIGNAL, f);
+
+/********************************
+ Proposed change:
+ Time is a short, encoded in 2 bytes.
+ The value of 'time' is actually an unsigned offset from the time of the
+ previous command. 0 means at the same time as the last command.
+ If the time in between this signal and the previous one is larger than
+ 65534 ticks, then the value 65535 is written, followed by 4 more bytes (uint)
+ indicating the time offset.
+**********************************/
+
+Here are definitions for the various commands:
+
+#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
+
+Below are the details of what to write after each command code. The various
+fields are explained afterwards.
+
+Size Type Value Example C code to save to PACKFILE *f
+
+SEQUENCE_START_SIGNAL:
+ 1 ID Reference pack_putc(ref, f);
+ 4 Int Signal pack_iputl(signal, f); /* --> Can we drop this to 2 bytes? (65536 signals) */
+ 4 Int Starting position pack_iputl(pos, f);
+ 2 Int Volume pack_iputw(volume, f);
+ 2 Int Pitch pack_iputw(pitch, f);
+
+SEQUENCE_SET_VOLUME:
+ 1 ID Reference pack_putc(ref, f);
+ 2 Int Volume pack_iputw(volume, f);
+
+SEQUENCE_SET_PITCH:
+ 1 ID Reference pack_putc(ref, f);
+ 2 Int Pitch pack_iputw(pitch, f);
+
+SEQUENCE_SET_PARAMETER:
+ 1 ID Reference pack_putc(ref, f);
+ 1 ID Parameter ID pack_putc(id, f);
+ 4 Int Value pack_iputl(value, f);
+
+SEQUENCE_STOP_SIGNAL:
+ 1 ID Reference pack_putc(ref, f);
+
+When you initiate a signal, you must choose a reference number. If you want
+to modify the signal's volume, pitch or parameters, or stop the signal later,
+you must use this reference number to do so. Need more than 256 reference
+numbers? Use two sequences, and get your brain seen to.
+
+If you initiate a new signal with the same reference number, the reference
+will belong to the new signal. The old signal becomes anonymous, and will
+either continue to play indefinitely or stop of its own accord. Even if the
+new signal stops, the old one remains anonymous. DUMB will safely ignore
+operations on reference numbers not used by any signal, or which were used by
+a signal which has now stopped.
+
+Of course all signals will stop if the sequence itself is stopped.
+
+To initiate a signal, you must index the signal. The index is 0-based, so to
+initiate the fifth signal in the file you must specify 4. Out-of-range values
+will be handled safely, as will the case where a signal tries to generate
+itself directly or indirectly from its own samples (a recursive cycle).
+
+When you initiate a signal, you can specify a starting position. This will be
+passed directly to the appropriate signal's start_samples function, so for a
+SAMP (sample) signal it represents the sample on which to start, after any
+loops have been expanded (so you can start on the backwards-playing part of
+a ping-pong loop for example by careful choice of the starting position).
+
+Volume is probably the simplest parameter. It is on a linear scale ranging
+from 0 to 65535. Note that most music sounds more dramatic if the volume
+rises and falls exponentially or on a greater curve. Linear fades are more
+suitable for fading in and out, and do not sound dramatic in the least.
+
+Pitch is specified on what is perceived as a linear scale. It is in fact
+logarithmic, but you will not need to worry about this for most purposes.
+Pitch 0 represents that the sample will be played at 65536 Hz. (This is not
+strictly true, and will be explained further later.) In the likely case that
+your sample is not recorded at 65536 Hz, you will first need to calculate the
+central pitch. Use the following formula:
+
+pitch_centre = 12 * 256 * log(sampling_frequency / 65536.0) / log(2);
+
+If your programming language does not have a log function, look for ln, or
+any function that calculates the logarithm (to any base) of the number you
+give it. If you are lucky enough to find a logarithm to base 2, you can omit
+the final division since the divisor evaluates to 1.
+
+Once you have calculated pitch_centre, you can use it to play the sample at
+the frequency at which it was recorded. Each time you add or subtract 256,
+the sample will increase or decrease respectively in pitch by one semitone in
+the even temperament. (The even temperament was noted further up as being
+suitable for most musical applications.) One octave is represented by an
+interval of 12 * 256.
+
+If you wish to use another temperament, you can calculate the appropriate
+intervals in pitch as follows:
+
+pitch_interval = 12 * 256 * log(ratio) / log(2);
+
+where, for example, ratio = 1.5 for a perfect fifth. An octave is, of course,
+still represented by 12 * 256.
+
+The SEQUENCE_SET_PARAMETER command needs little explanation. Quite simply,
+the parameter ID and value you specify are passed on to the set_parameter
+function of the signal to which this reference belongs. Exactly what this
+does depends on the signal in question.
+
+Remember, a sequence is a signal in itself. Like all signals, it is subject
+to changes in pitch. Increasing the pitch of a sequence will also speed it
+up. This capability is used to allow DUH files to be rendered at different
+sampling frequencies, and it is also available for use by the musician. This
+means that samples are only played at 65536 Hz if the pitch of the sequence
+itself has not been adjusted.