summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Arver <martin.arver@gmail.com>2006-12-11 21:01:14 +0000
committerMartin Arver <martin.arver@gmail.com>2006-12-11 21:01:14 +0000
commit7d820556e95ce8837eaa5baf2f6b5215a4b129ce (patch)
tree686899f7652fcd3c43c321ca53d99bbdfca42847
parent440513ab6a51c5cc311ce8671180970279e4eaf9 (diff)
downloadrockbox-7d820556e95ce8837eaa5baf2f6b5215a4b129ce.tar.gz
rockbox-7d820556e95ce8837eaa5baf2f6b5215a4b129ce.zip
Remove the files
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11719 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs/dumb/Makefile306
-rw-r--r--apps/codecs/dumb/docs/deprec.txt281
-rw-r--r--apps/codecs/dumb/docs/dumb.txt1699
-rw-r--r--apps/codecs/dumb/docs/faq.txt263
-rw-r--r--apps/codecs/dumb/docs/fnptr.txt113
-rw-r--r--apps/codecs/dumb/docs/howto.txt845
-rw-r--r--apps/codecs/dumb/docs/modplug.txt137
-rw-r--r--apps/codecs/dumb/docs/ptr.txt129
-rw-r--r--apps/codecs/dumb/examples/dumb.ini44
-rw-r--r--apps/codecs/dumb/examples/dumbout.c335
-rw-r--r--apps/codecs/dumb/examples/dumbplay.c238
-rw-r--r--apps/codecs/dumb/include/aldumb.h93
-rw-r--r--apps/codecs/dumb/include/dumb.h577
-rw-r--r--apps/codecs/dumb/include/internal/aldumb.h27
-rw-r--r--apps/codecs/dumb/include/internal/dumb.h58
-rw-r--r--apps/codecs/dumb/include/internal/it.h710
-rw-r--r--apps/codecs/dumb/licence.txt54
-rw-r--r--apps/codecs/dumb/make/Makefile.inc40
-rw-r--r--apps/codecs/dumb/make/config.bat33
-rwxr-xr-xapps/codecs/dumb/make/config.sh35
-rw-r--r--apps/codecs/dumb/make/config.txt3
-rw-r--r--apps/codecs/dumb/make/djgpp.inc28
-rwxr-xr-xapps/codecs/dumb/make/dumbaskbin12700 -> 0 bytes
-rw-r--r--apps/codecs/dumb/make/dumbask.c30
-rw-r--r--apps/codecs/dumb/make/mingw.inc28
-rw-r--r--apps/codecs/dumb/make/unix.inc20
-rw-r--r--apps/codecs/dumb/readme.txt421
-rw-r--r--apps/codecs/dumb/release.txt406
-rw-r--r--apps/codecs/dumb/src/allegro/alplay.c270
-rw-r--r--apps/codecs/dumb/src/allegro/datduh.c60
-rw-r--r--apps/codecs/dumb/src/allegro/datit.c62
-rw-r--r--apps/codecs/dumb/src/allegro/datmod.c61
-rw-r--r--apps/codecs/dumb/src/allegro/dats3m.c61
-rw-r--r--apps/codecs/dumb/src/allegro/datunld.c31
-rw-r--r--apps/codecs/dumb/src/allegro/datxm.c62
-rw-r--r--apps/codecs/dumb/src/allegro/packfile.c98
-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.c301
-rw-r--r--apps/codecs/dumb/src/core/unload.c58
-rw-r--r--apps/codecs/dumb/src/helpers/clickrem.c270
-rw-r--r--apps/codecs/dumb/src/helpers/memfile.c96
-rw-r--r--apps/codecs/dumb/src/helpers/resample.c1177
-rw-r--r--apps/codecs/dumb/src/helpers/sampbuf.c47
-rw-r--r--apps/codecs/dumb/src/helpers/silence.c29
-rw-r--r--apps/codecs/dumb/src/helpers/stdfile.c93
-rw-r--r--apps/codecs/dumb/src/it/itload.c43
-rw-r--r--apps/codecs/dumb/src/it/itmisc.c175
-rw-r--r--apps/codecs/dumb/src/it/itorder.c63
-rw-r--r--apps/codecs/dumb/src/it/itread.c1181
-rw-r--r--apps/codecs/dumb/src/it/itrender.c3512
-rw-r--r--apps/codecs/dumb/src/it/itunload.c71
-rw-r--r--apps/codecs/dumb/src/it/loadmod.c42
-rw-r--r--apps/codecs/dumb/src/it/loads3m.c42
-rw-r--r--apps/codecs/dumb/src/it/loadxm.c42
-rw-r--r--apps/codecs/dumb/src/it/readmod.c594
-rw-r--r--apps/codecs/dumb/src/it/reads3m.c668
-rw-r--r--apps/codecs/dumb/src/it/readxm.c998
-rw-r--r--apps/codecs/dumb/src/it/xmeffect.c255
66 files changed, 0 insertions, 18512 deletions
diff --git a/apps/codecs/dumb/Makefile b/apps/codecs/dumb/Makefile
deleted file mode 100644
index d2a045285e..0000000000
--- a/apps/codecs/dumb/Makefile
+++ /dev/null
@@ -1,306 +0,0 @@
1# Main Makefile for DUMB.
2
3# In theory, this Makefile can be used without modifications on DOS, Windows,
4# Linux, BeOS and Mac OS X. Caveats are as follows:
5
6# - For DOS and Windows users, COMSPEC (or ComSpec) must be set to point to
7# command.com or cmd.exe. If they point to a Unix-style shell, this
8# Makefile will die horribly.
9
10# - Users of other platforms must NOT set COMSPEC or ComSpec. They must be
11# undefined.
12
13# Commands are as follows:
14
15# make - Build the library (does make config for you first time).
16# make install - Install the library and examples into the system.
17# make uninstall - Remove the above.
18# make config - Do or redo the configuration.
19# make clean - Delete all object files; examples and libraries remain.
20# make veryclean - Delete examples and libraries too.
21
22# TODO: consider whether to delete config.txt and/or dumbask(.exe)
23
24
25.PHONY: all install uninstall clean veryclean config config-if-necessary
26
27PHONY_TARGETS := core allegro core-examples allegro-examples core-headers allegro-headers
28
29.PHONY: $(PHONY_TARGETS)
30.PHONY: $(PHONY_TARGETS:%=install-%)
31.PHONY: $(PHONY_TARGETS:%=uninstall-%)
32
33
34COMMA := ,
35
36#CC := gcc
37#AR := ar
38
39
40# Configuration.
41# The configuration is done by an MS-DOS batch file if COMSPEC is set.
42# Otherwise it is done by a Unix shell script. A file called 'config.txt',
43# containing variables that control the build process, is created, and
44# included by this Makefile.
45
46
47ifeq "$(COMSPEC)" ""
48ifdef ComSpec
49COMSPEC := $(ComSpec)
50endif
51endif
52
53
54-include make/config.txt
55
56
57ifeq "$(OSTYPE)" "beos"
58
59INCLUDE_INSTALL_PATH := /boot/develop/headers
60LIB_INSTALL_PATH := /boot/develop/lib/x86
61BIN_INSTALL_PATH := /boot/home/config/bin
62# DEFAULT_PREFIX is not set, so config.sh will not prompt for PREFIX.
63LINK_MATH :=
64
65else
66
67ifdef PREFIX
68DEFAULT_PREFIX := $(PREFIX)
69else
70DEFAULT_PREFIX := /usr/local
71endif
72export DEFAULT_PREFIX
73INCLUDE_INSTALL_PATH := $(PREFIX)/include
74LIB_INSTALL_PATH := $(PREFIX)/lib
75BIN_INSTALL_PATH := $(PREFIX)/bin
76
77endif
78
79
80all: config-if-necessary
81 @$(MAKE) --no-print-directory $(ALL_TARGETS)
82
83install: config-if-necessary
84 @$(MAKE) --no-print-directory $(ALL_TARGETS:%=install-%)
85 $(call ECHO,DUMB has been installed.)
86 $(call ECHO,See readme.txt for details on the example programs.)
87 $(call ECHO,When you$(APOST)re ready to start using DUMB$(COMMA) see docs/howto.txt.)
88 $(call ECHO,Enjoy!)
89
90uninstall: config-if-necessary
91 @$(MAKE) --no-print-directory $(ALL_TARGETS:%=uninstall-%)
92 $(call ECHO,DUMB has been uninstalled.)
93
94
95# Assume a Unix-compatible system.
96CONFIG_COMMAND := make/config.sh
97DUMBASK_EXE := make/dumbask
98
99# This will always configure.
100config: $(DUMBASK_EXE)
101 $(CONFIG_COMMAND)
102
103# This will only configure if the configuration file is absent. We don't use
104# config.txt as the target name, because Make then runs the config initially,
105# and again when it sees the 'config' target, so an initial 'make config'
106# causes the configuration to be done twice.
107ifeq "$(wildcard make/config.txt)" ""
108config-if-necessary: config
109else
110config-if-necessary:
111endif
112
113$(DUMBASK_EXE): make/dumbask.c
114 $(CC) $< -o $@
115
116
117ifdef PLATFORM
118
119
120# Build.
121
122
123CORE_MODULES := \
124 core/atexit.c \
125 core/duhlen.c \
126 core/dumbfile.c \
127 core/loadduh.c \
128 core/makeduh.c \
129 core/rawsig.c \
130 core/readduh.c \
131 core/register.c \
132 core/rendduh.c \
133 core/rendsig.c \
134 core/unload.c \
135 helpers/clickrem.c \
136 helpers/memfile.c \
137 helpers/resample.c \
138 helpers/sampbuf.c \
139 helpers/silence.c \
140 it/itload.c \
141 it/itread.c \
142 it/itrender.c \
143 it/itunload.c \
144 it/loads3m.c \
145 it/reads3m.c \
146 it/loadxm.c \
147 it/readxm.c \
148 it/loadmod.c \
149 it/readmod.c \
150 it/xmeffect.c \
151 it/itorder.c \
152 it/itmisc.c
153# helpers/stdfile.c
154
155ALLEGRO_MODULES := \
156 allegro/alplay.c \
157 allegro/datduh.c \
158 allegro/datit.c \
159 allegro/datxm.c \
160 allegro/dats3m.c \
161 allegro/datmod.c \
162 allegro/datunld.c \
163 allegro/packfile.c
164
165CORE_EXAMPLES := examples/dumbout.c
166ALLEGRO_EXAMPLES := examples/dumbplay.c
167
168CORE_HEADERS := include/dumb.h
169ALLEGRO_HEADERS := include/aldumb.h
170
171
172LIBDIR := lib/$(PLATFORM)
173OBJDIR_BASE := obj/$(PLATFORM)
174
175
176WFLAGS := -Wall -W -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations -DDUMB_DECLARE_DEPRECATED
177WFLAGS_ALLEGRO := -Wno-missing-declarations
178OFLAGS := -O2 -ffast-math -fomit-frame-pointer
179DBGFLAGS := -DDEBUGMODE=1 -g3
180
181CFLAGS_RELEASE := -Iinclude $(WFLAGS) $(OFLAGS) $(PROFILE_OPTS)
182CFLAGS_DEBUG := -Iinclude $(WFLAGS) $(DBGFLAGS)
183
184LDFLAGS := -s
185
186
187CORE_EXAMPLES_OBJ := $(addprefix examples/, $(notdir $(patsubst %.c, %.o, $(CORE_EXAMPLES))))
188ALLEGRO_EXAMPLES_OBJ := $(addprefix examples/, $(notdir $(patsubst %.c, %.o, $(ALLEGRO_EXAMPLES))))
189
190CORE_EXAMPLES_EXE := $(addprefix examples/, $(notdir $(patsubst %.c, %$(EXE_SUFFIX), $(CORE_EXAMPLES))))
191ALLEGRO_EXAMPLES_EXE := $(addprefix examples/, $(notdir $(patsubst %.c, %$(EXE_SUFFIX), $(ALLEGRO_EXAMPLES))))
192
193
194CORE_LIB_FILE_RELEASE := $(LIBDIR)/libdumb.a
195ALLEGRO_LIB_FILE_RELEASE := $(LIBDIR)/libaldmb.a
196
197CORE_LIB_FILE_DEBUG := $(LIBDIR)/libdumbd.a
198ALLEGRO_LIB_FILE_DEBUG := $(LIBDIR)/libaldmd.a
199
200
201core: $(CORE_LIB_FILE_RELEASE) $(CORE_LIB_FILE_DEBUG)
202allegro: $(ALLEGRO_LIB_FILE_RELEASE) $(ALLEGRO_LIB_FILE_DEBUG)
203
204core-examples: $(CORE_EXAMPLES_EXE)
205allegro-examples: $(ALLEGRO_EXAMPLES_EXE)
206
207core-headers:
208
209allegro-headers:
210
211install-core: core
212 $(call COPY,$(CORE_LIB_FILE_RELEASE),$(LIB_INSTALL_PATH))
213 $(call COPY,$(CORE_LIB_FILE_DEBUG),$(LIB_INSTALL_PATH))
214
215install-allegro: allegro
216 $(call COPY,$(ALLEGRO_LIB_FILE_RELEASE),$(LIB_INSTALL_PATH))
217 $(call COPY,$(ALLEGRO_LIB_FILE_DEBUG),$(LIB_INSTALL_PATH))
218
219ifeq "$(COMSPEC)" ""
220install-core-examples: core-examples
221 $(call COPY,$(CORE_EXAMPLES_EXE),$(BIN_INSTALL_PATH))
222
223install-allegro-examples: allegro-examples
224 $(call COPY,$(ALLEGRO_EXAMPLES_EXE),$(BIN_INSTALL_PATH))
225else
226# Don't install the examples on a Windows system.
227install-core-examples:
228install-allegro-examples:
229endif
230
231install-core-headers:
232 $(call COPY,$(CORE_HEADERS),$(INCLUDE_INSTALL_PATH))
233
234install-allegro-headers:
235 $(call COPY,$(ALLEGRO_HEADERS),$(INCLUDE_INSTALL_PATH))
236
237
238uninstall-core:
239 $(call DELETE,$(LIB_INSTALL_PATH)/$(notdir $(CORE_LIB_FILE_RELEASE)))
240 $(call DELETE,$(LIB_INSTALL_PATH)/$(notdir $(CORE_LIB_FILE_DEBUG)))
241
242uninstall-allegro:
243 $(call DELETE,$(LIB_INSTALL_PATH)/$(notdir $(ALLEGRO_LIB_FILE_RELEASE)))
244 $(call DELETE,$(LIB_INSTALL_PATH)/$(notdir $(ALLEGRO_LIB_FILE_DEBUG)))
245
246ifeq "$COMSPEC" ""
247uninstall-core-examples:
248 $(call DELETE,$(patsubst %,$(BIN_INSTALL_PATH)/%,$(notdir $(CORE_EXAMPLES_EXE))))
249
250uninstall-allegro-examples:
251 $(call DELETE,$(patsubst %,$(BIN_INSTALL_PATH)/%,$(notdir $(ALLEGRO_EXAMPLES_EXE))))
252else
253# The examples wouldn't have been installed on a Windows system.
254uninstall-core-examples:
255uninstall-allegro-examples:
256endif
257
258uninstall-core-headers:
259 $(call DELETE,$(patsubst %,$(INCLUDE_INSTALL_PATH)/%,$(notdir $(CORE_HEADERS))))
260
261uninstall-allegro-headers:
262 $(call DELETE,$(patsubst %,$(INCLUDE_INSTALL_PATH)/%,$(notdir $(ALLEGRO_HEADERS))))
263
264
265OBJDIR := $(OBJDIR_BASE)/release
266CFLAGS := $(CFLAGS_RELEASE)
267CORE_LIB_FILE := $(LIBDIR)/libdumb.a
268ALLEGRO_LIB_FILE := $(LIBDIR)/libaldmb.a
269include make/Makefile.inc
270
271OBJDIR := $(OBJDIR_BASE)/debug
272CFLAGS := $(CFLAGS_DEBUG)
273CORE_LIB_FILE := $(LIBDIR)/libdumbd.a
274ALLEGRO_LIB_FILE := $(LIBDIR)/libaldmd.a
275include make/Makefile.inc
276
277
278$(CORE_EXAMPLES_EXE): examples/%$(EXE_SUFFIX): examples/%.o $(CORE_LIB_FILE_RELEASE)
279 @echo "(dumb) compiling $^"
280 @$(CC) $^ -o $@ $(LDFLAGS) $(LINK_MATH)
281
282$(ALLEGRO_EXAMPLES_EXE): examples/%$(EXE_SUFFIX): examples/%.o $(ALLEGRO_LIB_FILE_RELEASE) $(CORE_LIB_FILE_RELEASE)
283 @echo "(dumb) compiling $^"
284 @$(CC) $^ -o $@ $(LDFLAGS) $(LINK_ALLEGRO)
285
286$(CORE_EXAMPLES_OBJ): examples/%.o: examples/%.c include/dumb.h
287 @echo "(dumb) compiling $^"
288 @$(CC) -c $< -o $@ $(CFLAGS_RELEASE)
289
290$(ALLEGRO_EXAMPLES_OBJ): examples/%.o: examples/%.c include/dumb.h include/aldumb.h
291 @echo "(dumb) compiling $^"
292 @$(CC) -c $< -o $@ $(CFLAGS_RELEASE) -Wno-missing-declarations
293
294clean:
295 $(call DELETE,$(call FIX,$(OBJDIR_BASE)/release/*.o))
296 $(call DELETE,$(call FIX,$(OBJDIR_BASE)/debug/*.o))
297 $(call DELETE,$(call FIX,examples/*.o))
298
299veryclean: clean
300 $(call DELETE,$(call FIX,$(CORE_LIB_FILE)))
301 $(call DELETE,$(call FIX,$(ALLEGRO_LIB_FILE)))
302 $(call DELETE,$(call FIX,$(CORE_EXAMPLES_EXE)))
303 $(call DELETE,$(call FIX,$(ALLEGRO_EXAMPLES_EXE)))
304
305
306endif # ifdef PLATFORM
diff --git a/apps/codecs/dumb/docs/deprec.txt b/apps/codecs/dumb/docs/deprec.txt
deleted file mode 100644
index 88ca2e9fda..0000000000
--- a/apps/codecs/dumb/docs/deprec.txt
+++ /dev/null
@@ -1,281 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * deprec.txt - Deprecated functions, why they / / \ \
12 * were deprecated, and what to do | < / \_
13 * instead. | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20
21**********************************************
22*** How the functions have been deprecated ***
23**********************************************
24
25
26 GCC 3.1 and later provide a very useful attribute. The following:
27
28 __attribute__((__deprecated__))
29
30 when written alongside a function prototype, variable declaration or type
31 definition, will result in a warning from GCC if any such part of the API
32 is used. The warning will even tell you where the declaration is, and I
33 have inserted comments by all the deprecated declarations, telling you
34 what to do.
35
36 Unfortunately, GCC 2.x and 3.0.x and MSVC do not have any means to
37 deprecate things. The approach I have taken with these compilers is to
38 avoid prototyping the declared functions. This means you will get
39 warnings and errors, and they won't be very helpful. If your program
40 compiles, you may get strange crashes when you run it, since the compiler
41 needs the declarations in order to make sure function calls are carried
42 out correctly.
43
44 If you would like the deprecated parts of the API to be declared, you can
45 compile with the -DDUMB_DECLARE_DEPRECATED switch for GCC, or the
46 -D"DUMB_DECLARE_DEPRECATED" switch for MSVC. This will be accepted by
47 GCC 3.x but is unnecessary. Use this switch with other people's projects
48 if necessary, but please make the effort to update your own projects to
49 use the new API, as the deprecated parts may be removed in the future.
50
51 The rest of this file explains why some parts of the API were deprecated,
52 and how to adapt your code.
53
54
55**************************************
56*** What happened to DUH_RENDERER? ***
57**************************************
58
59
60 The DUH_RENDERER struct was designed for rendering audio to an end-user
61 format - 8-bit or 16-bit, signed or unsigned, with stereo samples
62 interleaved. In order for it to do this, it was built on top of the
63 hitherto undocumented DUH_SIGRENDERER struct, which rendered audio in
64 DUMB's internal 32-bit signed format with channels (left/right) stored
65 separately. The DUH_RENDERER struct contained a pointer to a
66 DUH_SIGRENDERER struct, along with some other data like the position and
67 number of channels.
68
69 There were then some developments in the API. The DUH_SIGRENDERER struct
70 also stored the position and the number of channels, so I decided to write
71 functions for returning these. Suddenly there was no need to store them in
72 the DUH_RENDERER struct. Before long, the DUH_RENDERER struct contained
73 nothing but a pointer to a DUH_SIGRENDERER.
74
75 I decided it would be a good idea to unify the structs. After all, there
76 really is no difference between the data stored in each, and it would be
77 easy to make duh_render(DUH_RENDERER *dr, ...) and
78 duh_render_signal(DUH_SIGRENDERER *sr, ...) work on the same type of
79 struct. (Note that duh_render_signal() is now deprecated too; see the next
80 section.) It took some deliberation, but I decided I didn't want functions
81 to be #defined (it prevents you from using these names for member
82 functions in C++ classes), and that meant they had to be defined
83 somewhere. Defining redundant functions is a source of bloat, inefficiency
84 and general inelegance. After weighing things up, I decided it was better
85 to deprecate the redundant functions and have people begin to use the more
86 efficient versions, and eventually the redundant functions will be able to
87 be removed.
88
89 So why did I choose to keep the more complicated name, DUH_SIGRENDERER?
90 The reason has to do with what DUMB will become in the future. Signals are
91 an inherent part of the DUH struct and how .duh files will be constructed.
92 It will be possible to have multiple signals in a single DUH struct, and
93 you will be able to choose which one you want to play (this is the 'sig'
94 parameter passed to duh_start_sigrenderer()). But don't hold your breath;
95 we still have a long way to go before .duh files will start to appear...
96
97
98typedef DUH_SIGRENDERER DUH_RENDERER;
99
100 Wherever you are using DUH_RENDERER in your program, simply replace it
101 with DUH_SIGRENDERER. An automated (case-sensitive!) search and replace
102 operation should get this done.
103
104
105DUH_RENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos);
106
107 Use duh_start_sigrenderer() instead. It takes an extra parameter, 'sig',
108 which comes after 'duh' and before 'n_channels'; pass 0 for this. So an
109 example would be, replace:
110
111 sr = duh_start_renderer(duh, 2, 0);
112
113 with:
114
115 sr = duh_start_sigrenderer(duh, 0, 2, 0);
116
117
118int duh_renderer_get_n_channels(DUH_RENDERER *dr);
119long duh_renderer_get_position(DUH_RENDERER *dr);
120void duh_end_renderer(DUH_RENDERER *dr);
121
122 These are easy enough to fix; all you have to do is replace 'renderer'
123 with 'sigrenderer'. So the new functions are:
124
125 int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);
126 long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer);
127 void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer);
128
129
130Note that duh_render() has NOT been deprecated. It now uses DUH_SIGRENDERER
131instead of DUH_RENDERER, but its functionality is unchanged. You do not have
132to change calls to this function in any way.
133
134
135DUH_RENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sr);
136DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_RENDERER *dr);
137DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_RENDERER *dr);
138
139 These functions did not exist in the last release of DUMB, so you are
140 probably not using them, but they are included here for completeness. All
141 you have to do here is unwrap the function, since the structs have been
142 unified. So, for instance, replace:
143
144 duh_renderer_encapsulate_sigrenderer(my_sigrenderer)
145
146 with:
147
148 my_sigrenderer
149
150 Simple!
151
152
153AL_DUH_PLAYER *al_duh_encapsulate_renderer(DUH_RENDERER *dr,
154 float volume, long bufsize, int freq);
155DUH_RENDERER *al_duh_get_renderer(AL_DUH_PLAYER *dp);
156DUH_RENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp);
157
158 Again, these functions were not in the last release, so you probably
159 aren't using them. Nevertheless, the fix is simple as always: simply
160 replace 'renderer' with 'sigrenderer'. So the new functions are:
161
162 AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer(DUH_SIGRENDERER *sr,
163 float volume, long bufsize, int freq);
164 DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp);
165 DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp);
166
167
168*********************
169*** Miscellaneous ***
170*********************
171
172
173long duh_render_signal(DUH_SIGRENDERER *sigrenderer,
174 float volume, float delta,
175 long size, sample_t **samples);
176
177 This function used to return samples in DUMB's internal format. This
178 format consisted of 32-bit integers whose 'normal range' was -0x8000 to
179 0x7FFF (any samples outside this range would have to be clipped when sent
180 to the sound card).
181
182 DUMB's internal format has changed. DUMB still uses 32-bit integers, but
183 now the normal range is -0x800000 to 0x7FFFFF. The lowest eight bits are
184 discarded at the final stage by duh_render() when you ask for 16-bit
185 output. A new function, duh_sigrenderer_get_samples(), will return samples
186 in DUMB's new internal format. It takes exactly the same parameters, so
187 all you have to do to the call itself is change the name; however, you
188 will most likely have to change your code to account for the new
189 normalised range.
190
191 duh_render_signal() will still be able to give you the samples in DUMB's
192 old internal format, but it is inefficient. You should change your code as
193 soon as possible.
194
195
196typedef void (*DUH_SIGRENDERER_CALLBACK)(void *data, sample_t **samples,
197 int n_channels, long length);
198
199void duh_sigrenderer_set_callback(DUH_SIGRENDERER *sigrenderer,
200 DUH_SIGRENDERER_CALLBACK callback, void *data);
201
202 This callback was intended to allow you to analyse the output. It was by
203 no means intended to let you modify the output. For this reason, the names
204 have been changed to DUH_SIGRENDERER_ANALYSER_CALLBACK and
205 duh_sigrenderer_set_analyser_callback, and the 'samples' parameter to your
206 callback should now be specified as follows:
207
208 const sample_t *const *samples
209
210 The first 'const' indicates that you must not modify the samples. The
211 second indicates that you must not modify the pointers to each channel.
212
213 There is a second reason why this change was necessary, and it is the one
214 described further up for duh_render_signal()'s entry: the format in which
215 the samples themselves are stored has changed. They are 256 times as
216 large, with a normal range from -0x800000 to 0x7FFFFF. You will most
217 likely need to change your code to account for this.
218
219 If you try to call the old function, it will print a message to stderr
220 directing you to this file, and it will not install the callback. You
221 shouldn't be able to get this far without a compiler warning (or, if you
222 don't have GCC 3.1 or later, some compiler errors).
223
224 If you wanted to use this callback to apply a DSP effect, don't worry;
225 there is a better way of doing this. It is undocumented, so contact me
226 and I shall try to help. Contact details are at the bottom of this file.
227
228 For reference, here are the new definitions:
229
230 typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data,
231 const sample_t *const *samples, int n_channels, long length);
232
233 void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer,
234 DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data);
235
236
237int dumb_resampling_quality;
238
239 This variable has changed meaning. It used to hold a value from 0 to 4,
240 whose meaning was as follows:
241
242 0 - aliasing
243 1,2 - linear interpolation
244 3 - quadratic interpolation
245 4 - cubic interpolation
246
247 0,1 - always use a straightforward interpolation algorithm
248 2,3,4 - when decimating (increasing the pitch), use a linear average
249 algorithm designed to reduce frequencies that would otherwise
250 reflect off the Nyquist
251
252 Now the variable only holds values from 0 to 2, and these values have
253 preprocessor constants associated with them. The somewhat inappropriate
254 quadratic interpolation has been removed. The linear average algorithm has
255 also been removed, and may or may not come back; there are probably more
256 efficient ways of achieving the same effect, which I shall be
257 investigating in the future.
258
259 This change will have hardly any noticeable effect on existing programs.
260 Levels 2, 3 and 4 used considerably more processor time because of the
261 linear average algorithm. Likewise, Level 2 in the new scheme (cubic) uses
262 considerably more processor time than Levels 1 and 0, and Levels 3 and 4
263 will behave identically to Level 2.
264
265
266******************
267*** Conclusion ***
268******************
269
270
271"I conclude that... DUMB is the bestest music player in the world because...
272Complete this sentence in fifteen words or fewer... D'OH!"
273
274The preceding conclusion formerly appeared in dumb.txt, and is deprecated
275because it's lame.
276
277
278Ben Davis
279entheh@users.sf.net
280IRC EFnet #dumb
281See readme.txt for details on using IRC.
diff --git a/apps/codecs/dumb/docs/dumb.txt b/apps/codecs/dumb/docs/dumb.txt
deleted file mode 100644
index 86b2cc3374..0000000000
--- a/apps/codecs/dumb/docs/dumb.txt
+++ /dev/null
@@ -1,1699 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * dumb.txt - DUMB library reference. / / \ \
12 * | < / \_
13 * See readme.txt for general information on | \/ /\ /
14 * DUMB and how to set it up. \_ / > /
15 * | \ / /
16 * If you are new to DUMB, see howto.txt. | ' /
17 * \__/
18 */
19
20
21***********************************
22*** Include Files and Libraries ***
23***********************************
24
25
26dumb.h
27
28 Include this if you only want the core DUMB library functions. You will
29 be able to load music files and render them into memory buffers at your
30 own pace. The core library is completely portable, and as such does not
31 access hardware; you must relay the sound data to the sound card yourself.
32 A stdio file input module is available, but you must actively register it
33 if you wish to use it (see dumb_register_stdfiles()); if you do not
34 register it, it will not be linked into your executable. You must register
35 it, or a DUMBFILE module of your own, in order to load stand-alone music
36 files.
37
38 Optimised: -ldumb or /link dumb.lib
39 Debugging: -ldumbd or /link dumbd.lib
40
41
42aldumb.h
43
44 Include this if you wish to use DUMB with Allegro. This will provide you
45 with functions to play DUHs back through Allegro's audio streams and embed
46 music files in Allegro datafiles. A file input module using Allegro's
47 packfiles is provided; you have a choice between this and the stdio
48 module (or provide one of your own). You will be able to load datafiles
49 containing music files no matter which file input module you register, or
50 even if you register no file input module. However, you must register a
51 file input module in order to load stand-alone files.
52
53 Optimised: -laldmb -ldumb -lalleg or /link aldmb.lib alleg.lib dumb.lib
54 Debugging: -laldmd -ldumbd -lalld or /link aldmd.lib alld.lib dumbd.lib
55
56 aldmb or aldmd must be linked in first, so the symbols can be resolved
57 when linking in the other two libraries.
58
59
60***************************
61*** Version Information ***
62***************************
63
64
65#define DUMB_MAJOR_VERSION
66#define DUMB_MINOR_VERSION
67#define DUMB_REVISION_VERSION
68
69 Numeric constants representing this version of DUMB. If this were version
70 1.0, DUMB_MAJOR_VERSION would be 1 and DUMB_MINOR_VERSION would be 0.
71 DUMB_REVISION_VERSION will be 0 on any significant releases, and will be
72 incremented as releases with bugfixes and minor features are made.
73
74 Typical usage:
75
76 #if DUMB_MAJOR_VERSION < 1
77 #error This add-on requires DUMB v1.0 or higher. Please upgrade.
78 #endif
79
80
81#define DUMB_VERSION
82
83 A numeric constant which appears in the format MMmmrr when displayed in
84 decimal (M for major, m for minor, r for revision). This is most useful
85 for comparing version numbers; it has little other practical use.
86
87 Typical usage:
88
89 #if DUMB_VERSION < 801
90 #error This game requires DUMB v0.8.1 or higher. Please upgrade.
91 #endif
92
93 #if DUMB_VERSION < 10002
94 #error This game requires DUMB v1.0.2 or higher. Please upgrade.
95 #endif
96
97
98#define DUMB_VERSION_STR
99
100 String constant representing this version of DUMB. If this were Version
101 1.0, DUMB_VERSION_STR would be "1.0". DUMB_REVISION_VERSION will only
102 appear on the end if it is nonzero; then DUMB_VERSION_STR might be
103 "1.0.1".
104
105
106#define DUMB_NAME
107
108 A string identifying DUMB and its version. If this were Version 1.0,
109 DUMB_NAME might be "DUMB v1.0". This constant is suitable for use in your
110 Credits screen if you wish to acknowledge the use of DUMB there.
111
112
113#define DUMB_YEAR
114#define DUMB_MONTH
115#define DUMB_DAY
116
117 Numeric constants representing the year, month and day of this release of
118 DUMB. All four digits are included in the year. Please note that
119 DUMB_MONTH and DUMB_DAY were inadvertently swapped in the v0.8 release.
120
121
122#define DUMB_YEAR_STR4
123#define DUMB_YEAR_STR2
124#define DUMB_MONTH_STR2
125#define DUMB_MONTH_STR1
126#define DUMB_DAY_STR2
127#define DUMB_DAY_STR1
128
129 String constants representing the year, month and day of this release of
130 DUMB. DUMB_MONTH_STR2 and DUMB_DAY_STR2 include a leading zero if the
131 month or day respectively are less than ten; the STR1 variations do not.
132 DUMB_YEAR_STR2 contains only the two rightmost digits of the year, while
133 DUMB_YEAR_STR4 contains all four. I recommend using DUMB_YEAR_STR4,
134 especially so soon after the turn of the century (indeed the millennium).
135 However, it is a matter of personal preference which you use.
136
137 Please note that the month and day were inadvertently swapped in the v0.8
138 release.
139
140
141#define DUMB_DATE
142
143 A numeric constant that appears in the form yyyymmdd when displayed in
144 decimal. This is most useful for comparing release dates; it has little
145 other practical use.
146
147 WARNING: The month and day were inadvertently swapped in the v0.8 release.
148 Please do not compare this constant against any date in 2002. In
149 any case, DUMB_VERSION is probably more useful for this purpose.
150
151
152#define DUMB_DATE_STR
153
154 The date as a string. The format is "d.m.yyyy", with dots used as
155 separators, the day written first, four digits for the year, and no
156 leading zeros on the day or month. This is my preferred format. If you
157 don't like it, you can construct your own format using the other
158 constants. For example, "mm/dd/yy" could be constructed as follows:
159
160 DUMB_MONTH_STR2 "/" DUMB_DAY_STR2 "/" DUMB_YEAR_STR2
161
162 Please note that the month and day were inadvertently swapped in the v0.8
163 release.
164
165
166*************************
167*** Basic Sample Type ***
168*************************
169
170
171typedef int sample_t;
172
173 DUMB works internally with 32-bit integer samples, with a 'normal range'
174 from -0x800000 to 0x7FFFFF (as of DUMB v0.9.2; previously they ranged from
175 -0x8000 to 0x7FFF). Any samples that exceed this range will eventually be
176 clipped, and could cause integer overflow in extreme cases.
177
178
179***********************************
180*** Library Clean-up Management ***
181***********************************
182
183
184int dumb_atexit(void (*proc)(void));
185
186 Registers a function to be called at the end of your program. You can
187 register multiple functions to be called, and the one you register last
188 will be called first. If you try to register the same function twice, the
189 second attempt will have no effect.
190
191 See fnptr.txt for help with function pointers.
192
193 You must call dumb_exit() before exiting your program for this to work
194 properly. The library itself registers functions with dumb_atexit(), so it
195 is important to call dumb_exit() even if you do not use dumb_atexit()
196 yourself.
197
198 This function will return zero on success. It will return zero when
199 trying to install the same function twice. If it fails through lack of
200 memory, it will return nonzero. Generally you can ignore the return code;
201 in the worst case some memory will not be freed at the end. If it is
202 crucial that your function be called (e.g. to shut down some hardware or
203 save critical data), then you should call your function manually at the
204 end of the program instead of registering it here - or use the stdlib
205 function atexit(), guaranteed under ANSI C to succeed for at least 32
206 functions.
207
208
209void dumb_exit(void);
210
211 You should call this before exiting your program if you have used any part
212 of DUMB in the program. Some parts of DUMB will allocate memory, and this
213 function will free it all up.
214
215 More specifically, this function will call any functions that have been
216 registered with dumb_atexit(). If a part of DUMB needs shutting down, the
217 shutdown procedure will have been registered in this way.
218
219 dumb_exit() will, of course, also call any functions you registered with
220 dumb_atexit() yourself.
221
222 After a call to dumb_exit(), the list of functions is erased. If you are
223 not ready to exit your program, you can start using DUMB anew as if your
224 program had just started. (Note that not everything will be reset in
225 practice - dumb_resampling_quality will retain whatever you set it to, for
226 example, though you should not assume it will.)
227
228 If you only need to call dumb_exit() once at the end of the program, you
229 can use the following to register dumb_exit() with stdlib.h atexit():
230
231 #include <stdlib.h>
232
233 atexit(&dumb_exit);
234
235 Then dumb_exit() will be called for you when your program exits. This is
236 the recommended method, since it will ensure clean-up even if your program
237 aborts. You should only call dumb_exit() manually if you need to shut DUMB
238 down prematurely, or if atexit() is unavailable for one reason or another.
239
240
241*****************************
242*** Sequential File Input ***
243*****************************
244
245
246 DUMB provides a strictly sequential file input system which uses the
247 DUMBFILE struct. "Strictly sequential" means you cannot seek backwards.
248 However, the system will keep track of how many bytes you have read,
249 enabling you to seek forwards. DUMBFILEs provide a convenient error
250 detection system, so you do not have to check the return value from every
251 function call in the way you do with the ANSI C functions.
252
253 Note that DUMBFILEs cannot be used for output, nor can they be used
254 portably for text files.
255
256 If an error occurs when reading data from a DUMBFILE, the DUMBFILE will
257 become inoperative. All subsequent activities on the DUMBFILE will return
258 error codes without attempting to read from the file. The position in the
259 file will also be forgotten. You can find out if this has happened at any
260 stage with the dumbfile_error() function. You are still required to close
261 the DUMBFILE, and the return value from dumbfile_close() will tell you if
262 an error has occurred.
263
264 This system allows you to input large chunks of your file, neither
265 checking every return value nor wasting time accessing a file that has
266 already experienced an error. However, before you allocate an amount of
267 memory or read in a quantity of data depending on previous input from the
268 file, you should always check that such input was valid. In particular you
269 should avoid passing zero or negative numbers to malloc(), and avoid
270 passing negative numbers to dumbfile_skip() and dumbfile_getnc().
271
272 DUMBFILEs can be hooked. In other words, you can specify your own
273 functions to do the work of reading from a file. While DUMB contains two
274 modules for this purpose, it does not set them up for you automatically.
275 In most cases you must register one of these modules yourself, or provide
276 your own module. See register_dumbfile_system(), dumb_register_stdfiles()
277 and dumb_register_packfiles().
278
279
280void register_dumbfile_system(DUMBFILE_SYSTEM *dfs);
281
282 Use this function to register a set of functions for use by the DUMBFILEs
283 (a DUMBFILE system). The DUMBFILE_SYSTEM struct contains the following
284 fields:
285
286 void *(*open)(const char *filename);
287 int (*skip)(void *f, long n);
288 int (*getc)(void *f);
289 long (*getnc)(char *ptr, long n, void *f);
290 void (*close)(void *f);
291
292 See fnptr.txt for help with function pointers such as these.
293
294 Your 'open' function should open the file specified and return a pointer
295 to a struct representing the open file. This pointer will be passed to
296 your other functions as 'f'. Your 'close' function should close the file
297 and free all memory pointed to by 'f'. Note that the 'close' operation
298 should never be able to fail; if you are calling a function with a return
299 value, you can generally ignore it.
300
301 Your 'getc' function should read one byte from the file and return its
302 value in the range 0 to 255. If an error occurs, you should return -1. Do
303 not worry about remembering that an error has occurred; DUMB will do that
304 for you.
305
306 'skip' is for skipping parts of the file, and should skip n bytes,
307 returning 0 on success or any other number on failure. 'getnc' should read
308 n bytes from the file, store them at 'ptr', and return the number of bytes
309 read (n on success, fewer on failure). However, these two functions are
310 optional, and you should only provide them if the operations can be done
311 more efficiently than with repeated calls to your 'getc' function. If this
312 is not the case, specify NULL for 'skip', 'getnc' or both, and DUMB will
313 use your 'getc' function to do the work.
314
315 Once you have written all your functions, you need to create a
316 DUMBFILE_SYSTEM struct to hold them, and pass its pointer to
317 register_dumbfile_system().
318
319 The DUMBFILE_SYSTEM struct must be permanent. In other words, it must be
320 either global or static, and you should not modify it later. DUMB will not
321 make its own copy.
322
323 You will most likely create your own struct to represent the open file,
324 but do not be tempted to specify that struct in the function prototypes
325 and pacify the compiler warnings by casting your function pointers. There
326 exist computer systems where a (void *) pointer and a (MY_STRUCT *)
327 pointer are represented differently in memory, and a cast of such a
328 pointer causes a tangible conversion to take place. If you cast the
329 function pointers, the computer cannot know when such a conversion is
330 necessary. Instead, use the following structure:
331
332 int myskip(void *f, long n)
333 {
334 FILE *file = f;
335 /* Do some stuff with 'file' */
336 return something;
337 }
338
339 If you need examples, have a look at the two existing DUMBFILE systems in
340 dumb/src/core/stdfile.c and dumb/src/allegro/packfile.c.
341
342
343DUMBFILE *dumbfile_open(const char *filename);
344
345 Open the specified file for input. You must pass the DUMBFILE pointer
346 whenever you wish to operate on this file. When you have finished with the
347 file, you must pass it to dumbfile_close().
348
349 Before you use this function, make sure you have registered a DUMBFILE
350 system. See register_dumbfile_system(), dumb_register_stdfiles() and
351 dumb_register_packfiles().
352
353 You must check the return value from this function. If it is NULL, the
354 file could not be opened, and you must not pass the DUMBFILE to any other
355 function. The debugging library will abort if you get this wrong; the
356 optimised library will act weird.
357
358
359DUMBFILE *dumbfile_open_ex(void *file, DUMBFILE_SYSTEM *dfs);
360
361 This function is provided for more specialised use. You should create a
362 DUMBFILE_SYSTEM specially for the purpose. Its 'open' field is irrelevant;
363 for neatness, set it to NULL, unless you are using this DUMBFILE_SYSTEM
364 with register_dumbfile_system() as well.
365
366 When you have called this function, the DUMBFILE struct it returned can be
367 used as normal. The specified DUMBFILE_SYSTEM will be used for all input,
368 with 'file' passed to your 'skip', 'getc' and 'getnc' functions as 'f'.
369 This can be used, for example, to read from an already open file.
370
371 Note that the position will always be initialised to 0 for this DUMBFILE.
372 This means for example that offsets in the file do not need adjusting when
373 embedding data in a larger file.
374
375 There are two ways to use this function. If you want 'file' to persist
376 after using a DUMBFILE returned by this function, you should make sure the
377 'close' field in the DUMBFILE is set to NULL. When the DUMBFILE is closed,
378 'file' will be left alone, and you can and should deal with it yourself
379 when the DUMBFILE has been closed.
380
381 Alternatively, you can provide a 'close' function to get rid of 'file' for
382 you when the DUMBFILE is closed. If you do this, you should not otherwise
383 use 'file' after a call to this function.
384
385 If dumbfile_open_ex() has to return NULL, owing to lack of memory, then
386 your 'close' function will be called if provided. In other words, if you
387 have provided a 'close' function, then you no longer need to worry about
388 'file' whether this function succeeds or not.
389
390 See dumb/src/helpers/stdfile.c and dumb/src/allegro/packfile.c for
391 examples of how to use this function. Neither provides a 'close' function,
392 so I hope my explanation here will suffice. If not, please feel free to
393 contact me so I can make the explanation clearer and help you do what you
394 want to do. Contact details are at the end of this file.
395
396
397long dumbfile_pos(DUMBFILE *f);
398
399 Returns the number of bytes read from the DUMBFILE (or skipped) since it
400 was opened, or -1 if an error has occurred while reading.
401
402
403int dumbfile_skip(DUMBFILE *f, long n);
404
405 Skips n bytes of the specified DUMBFILE. Returns zero on success.
406
407
408int dumbfile_getc(DUMBFILE *f);
409
410 Reads one byte from the DUMBFILE and returns it in unsigned format (from 0
411 to 255). If an error occurs, or occurred before, this function returns -1.
412
413
414int dumbfile_igetw(DUMBFILE *f);
415
416 Reads two bytes from the DUMBFILE and combines them into a word ranging
417 from 0 to 65535. The first byte read is the least significant byte, as
418 with Intel processors. This function returns -1 on error.
419
420
421int dumbfile_mgetw(DUMBFILE *f);
422
423 Reads two bytes from the DUMBFILE and combines them into a word ranging
424 from 0 to 65535. The first byte read is the most significant byte, as
425 with the Apple Macintosh. This function returns -1 on error.
426
427
428long dumbfile_igetl(DUMBFILE *f);
429
430 Reads four bytes from the DUMBFILE and combines them into a long integer
431 ranging from -2147483648 to 2147483647. The first byte read is the least
432 significant byte, as with Intel processors. This function returns -1 on
433 error, but -1 is also a valid return value. After a call to this function,
434 you can use dumbfile_error() to find out if an error occurred.
435
436
437long dumbfile_mgetl(DUMBFILE *f);
438
439 Reads four bytes from the DUMBFILE and combines them into a long integer
440 ranging from -2147483648 to 2147483647. The first byte read is the most
441 significant byte, as with the Apple Macintosh. This function returns -1 on
442 error, but -1 is also a valid return value. After a call to this function,
443 you can use dumbfile_error() to find out if an error occurred.
444
445
446unsigned long dumbfile_cgetul(DUMBFILE *f);
447
448 Reads an unsigned (nonnegative) integer from the DUMBFILE. The integer is
449 stored in a condensed format where smaller numbers use less space:
450
451 0 to 127 1 byte
452 128 to 16383 2 bytes
453 16384 to 2097151 3 bytes
454 2097152 to 268435455 4 bytes
455 268435456 to 4294967295 5 bytes
456
457 This format is the same as that used for the times between notes in MIDI
458 files.
459
460 If an error occurs, this function returns (unsigned long)(-1), but that
461 may be a valid return value. After a call to this function, you can use
462 dumbfile_error() to find out if an error occurred.
463
464
465signed long dumbfile_cgetsl(DUMBFILE *f);
466
467 Reads a signed integer from the DUMBFILE. The integer is stored in a
468 condensed format where numbers closer to zero use less space:
469
470 -64 to 63 1 byte
471 -8192 to 8191 2 bytes
472 -1048576 to 1048575 3 bytes
473 -134217728 to 134217727 4 bytes
474 -2147483648 to 2147483647 5 bytes
475
476 If an error occurs, this function returns -1, but -1 is also a valid
477 return value. After a call to this function, you can use dumbfile_error()
478 to find out if an error occurred.
479
480
481long dumbfile_getnc(char *ptr, long n, DUMBFILE *f);
482
483 Reads n bytes from the DUMBFILE and stores them at 'ptr'. Note that the
484 pointer is to a series of chars. You may also use this function to read in
485 a series of signed chars or unsigned chars (which are both officially
486 distinct types from char), but do not use this to read ints, structs or
487 any other data type from the file. Integers must be read one at a time
488 using dumbfile_igetl(), dumbfile_cgetul(), etc. To load a struct in, you
489 must read each field separately using an appropriate function for each
490 one. For complicated data types, you can simplify this process by writing
491 a function for each struct.
492
493 dumbfile_getnc() returns the number of bytes successfully read, which will
494 be less than n if an error occurs, and may be as low as zero. If
495 dumbfile_getnc() returns -1, that means an error occurred on this DUMBFILE
496 earlier, before this function was called.
497
498
499int dumbfile_error(DUMBFILE *f);
500
501 This function returns -1 if an error has occurred with the specified
502 DUMBFILE, or 0 if all is well.
503
504
505int dumbfile_close(DUMBFILE *f);
506
507 This function closes the DUMBFILE, after which the pointer will be
508 invalid. dumbfile_close() returns the value that dumbfile_error() would
509 have returned, which is -1 if an error occurred while reading or 0
510 otherwise. Regardless of the return value, the file will always be closed
511 properly.
512
513
514*******************************
515*** stdio File Input Module ***
516*******************************
517
518
519void dumb_register_stdfiles(void);
520
521 This function registers the stdio file input module for use by DUMBFILEs.
522 FILE structs and their corresponding functions, as defined by the ANSI C
523 header stdio.h, will be used internally for all DUMBFILE input (unless
524 opened with dumbfile_open_ex()).
525
526 This must be called before dumbfile_open() is used, or else an alternative
527 system must be registered (see register_dumbfile_system() and
528 dumb_register_packfiles()).
529
530
531DUMBFILE *dumbfile_open_stdfile(FILE *p);
532
533 If you have a stdio FILE struct representing an open file, you can call
534 this if you wish to read from it using a DUMBFILE. This is useful when you
535 need to pass a DUMBFILE struct to a library function, to read an embedded
536 music file for example. When you close the DUMBFILE, you can continue
537 using the FILE struct to read what follows the embedded data.
538
539
540********************************
541*** Memory File Input Module ***
542********************************
543
544
545DUMBFILE *dumbfile_open_memory(const char *data, long size);
546
547 This function is useful if you have an image of a music file in memory.
548 You might have such an image if you use dat2s to encode a datafile
549 directly into the executable. Pass a pointer to the start of the memory,
550 and the size of the image to make sure DUMB doesn't overrun the buffer.
551 The resulting DUMBFILE will feed the contents of the image to you.
552
553 Note that the pointer is of type 'char *'. Files are series of chars, and
554 interpreting them directly as anything else isn't portable.
555
556
557**********************
558*** DUH Management ***
559**********************
560
561
562void unload_duh(DUH *duh);
563
564 Removes a DUH from memory. You must call this for all DUHs you load,
565 making sure they're not playing at the time.
566
567
568long duh_get_length(DUH *duh);
569
570 Returns the length of a DUH; 65536 represents one second. This value is
571 calculated when the DUH is created, and this function simply lifts it from
572 the struct. It may not truly correspond to the time for which the DUH will
573 generate sound. For module files, it will represent the point at which the
574 module first loops (or, in the case of some XM and MOD files, freezes).
575 Any add-ons to DUMB will provide their own code for calculating this.
576
577 The algorithm for calculating the length of a module file can be fooled,
578 but only by very deliberate methods. In the early days, when modules could
579 only be played by their editors and had to be exported to .wav or similar
580 in order to be used elsewhere, musicians would sometimes make the player
581 think it was looping when it wasn't in order to prevent their music from
582 being exported properly. If the length of a module seems a lot less than
583 it should be, the module is probably protected in this way.
584
585 Getting around this protection reliably would be extremely difficult, but
586 after considering it for a while I decided it would be better not to. The
587 musician has a right to protect his or her music in this way, and I have
588 no interest in actively breaking that protection.
589
590 (On the other hand, some musicians were just showing off!)
591
592
593***********************************
594*** IT, XM, S3M and MOD Support ***
595***********************************
596
597
598int dumb_it_max_to_mix;
599
600 Specifies the maximum number of samples DUMB will mix at any one time. The
601 default number is 64. Regardless of this value, all samples will continue
602 to be processed up to an internal maximum of 256 (roughly speaking; in
603 fact it will process one sample for each channel plus up to 192 extra
604 samples that are continuing to play owing to Impulse Tracker's New Note
605 Actions), and samples that have been cut will sound again as soon as the
606 congestion clears. Samples are given priority according to their final
607 volume after all factors affecting the volume of a sample have been
608 considered.
609
610 If you play two or more modules at once, this value represents the
611 maximum number of samples for each one. You will have to reduce it further
612 if your computer cannot keep up.
613
614 Despite the name, this variable controls XM, S3M and MOD files as well as
615 IT files.
616
617
618DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh);
619
620 This function attempts to retrieve the DUMB_IT_SIGDATA struct from a DUH.
621 This struct will exist for any IT, XM, S3M or MOD file, and you can use it
622 to obtain or override module-specific information. If 'duh' is NULL, or if
623 the DUH you pass contains something other than a music module, then this
624 function will return NULL (which can safely be passed to any other
625 function).
626
627
628DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer);
629
630 This function attempts to retrieve the DUMB_IT_SIGRENDERER struct from a
631 DUH_SIGRENDERER. This struct will exist for any currently playing IT, XM,
632 S3M or MOD file, and you can use it to obtain or override information
633 specific to module playback. If 'sigrenderer' is NULL, or if the
634 DUH_SIGRENDERER you pass is rendering something other than a music module,
635 then this function will return NULL (which can safely be passed to any
636 other function).
637
638
639DUH_SIGRENDERER *dumb_it_start_at_order
640 (DUH *duh, int n_channels, int startorder);
641
642 This function, given a DUH containing an IT, XM, S3M or MOD file, will
643 start playing it at the specified order. If the DUH does not contain a
644 module, this function will fail and return NULL.
645
646 Note that starting at an arbitrary order may result in missing notes or
647 other playback oddities. It should be used primarily for modules that
648 contain multiple songs that start on different orders. If you wish just to
649 start some music in the middle, consider using duh_start_sigrenderer() or
650 al_start_duh() with the pos parameter set appropriately.
651
652
653void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer,
654 int (*callback)(void *data), void *data);
655
656 Installs a callback which will be called every time the module loops. You
657 can pass any data pointer you like, and it will be passed to the callback
658 for you. DUMB considers a file to loop when it reaches the end, or when a
659 'Jump to order' effect (Bxx in both IT/S3M and XM/MOD) jumps to the same
660 order or a preceding order. This can result in the loop callback being
661 called when the module isn't really looping, but this only happens if the
662 module has a very deliberate design. See duh_get_length() for further
663 musings on this subject.
664
665 If your callback returns nonzero, the music will stop abruptly. Samples
666 will be cut, and the main program will be notified that the
667 DUH_SIGRENDERER has ended.
668
669 Alternatively, if you pass the DUMB_IT_SIGRENDERER for 'data', or
670 otherwise arrange for it to be available to the callback, then you can
671 call:
672
673 dumb_it_sr_set_speed(sigrenderer, 0);
674
675 from inside the callback, and this will cause the music to freeze but
676 samples will be able to continue playing. The xm_speed_zero callback will
677 NOT be called in this case (see below for information on this callback).
678 Note also that setting the speed in this way will work equally for IT and
679 S3M files, even though a 'speed zero' effect can only exist in XM and MOD
680 files. Beware when using this method; samples might not fade at all!
681
682 A helper callback, dumb_it_callback_terminate(), is provided; installing
683 this will cause the music to terminate when it tries to loop for the first
684 time.
685
686 Pass NULL to remove the callback function; the module will then loop as
687 normal.
688
689
690void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer,
691 int (*callback)(void *data), void *data);
692
693 Installs a callback which is in many ways similar to the loop callback
694 (see dumb_it_set_loop_callback()). This callback will be called whenever
695 an F00 effect is encountered in a MOD or XM file, setting the speed to
696 zero. If the callback returns nonzero, the music will terminate. If not,
697 any currently playing samples will continue to play. You can pass any data
698 pointer you like to this function, and it will be passed to your callback
699 for you.
700
701 The helper callback, dumb_it_callback_terminate(), will also work here;
702 installing it will cause the music to terminate as soon as an F00 effect
703 is encountered.
704
705 Pass NULL to remove the callback function.
706
707
708void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer,
709 int (*callback)(void *data, int channel, unsigned char byte),
710 void *data);
711
712 Installs a callback function which will be called whenever MIDI data are
713 generated by an IT file. (No other module formats are capable of
714 generating MIDI data, so your callback will never be called.)
715
716 Zxx macros will generate MIDI data. These are most often used to set the
717 parameters for IT's low-pass resonant filters, and DUMB will handle these
718 messages by itself by default. See Impulse Tracker's documentation for
719 the MIDI messages that control filters. However, Zxx macros can be used
720 to send any kind of MIDI data.
721
722 If you wish to interpret MIDI messages yourself, you can use this
723 callback. Note that the only MIDI messages generated by DUMB at present
724 are from Zxx macros; there are no messages for note start, stop, or
725 anything else.
726
727 If you return 1 from this callback, DUMB will subsequently ignore the byte
728 of MIDI data. You can use this to prevent Zxx macros from controlling the
729 filters, useful if they were intended to do something else. Note that this
730 is NOT an effective way to disable filters, since instruments can have
731 filter envelopes and initial filter parameters. DUMB provides no means to
732 disable filters, as any IT file that uses them will sound wrong without
733 them. If you want lower processor consumption, use a different piece of
734 music.
735
736 A helper callback, dumb_it_callback_midi_block(), is provided for blocking
737 all MIDI messages and making Zxx macros do nothing.
738
739 Pass NULL to remove the callback.
740
741
742int dumb_it_callback_terminate(void *data);
743
744 This is a helper callback that can be installed with both
745 dumb_it_set_loop_callback() and dumb_it_set_xm_speed_zero_callback(). In
746 each case it will cause the music to terminate abruptly.
747
748
749int dumb_it_callback_midi_block(void *data, int channel, unsigned char byte);
750
751 This helper callback, for use with dumb_it_set_midi_callback(), will
752 absorb all MIDI messages, returning 1 to prevent DUMB from interpreting
753 them itself.
754
755
756DUH *dumb_load_it(const char *filename);
757
758 Loads the specified Impulse Tracker file, encapsulating it in a DUH
759 struct. Once the file is loaded, it can be treated exactly the same as any
760 other DUH in memory. If this fails it will return NULL, but you can safely
761 pass this NULL value to DUMB's other functions, so you do not need to
762 check the return value explicitly.
763
764
765DUH *dumb_read_it(DUMBFILE *f);
766
767 Reads an Impulse Tracker file from an already open DUMBFILE. This leaves
768 the DUMBFILE open, but the DUMBFILE may not be positioned at the end of
769 the IT data. If you are embedding an IT in another file, you are advised
770 to store the size of the IT file and make up for it at the end using
771 dumbfile_pos().
772
773 Otherwise, this function is identical to dumb_load_it().
774
775 WARNING: The behaviour of this function is undefined if you pass a
776 DUMBFILE from which data have already been read; it is likely not
777 to work. This oversight will be fixed in future releases.
778
779
780DUH *dumb_load_xm(const char *filename);
781
782 Loads the specified Fast Tracker II file, encapsulating it in a DUH
783 struct. Once the file is loaded, it can be treated exactly the same as any
784 other DUH in memory. If this fails it will return NULL, but you can safely
785 pass this NULL value to DUMB's other functions, so you do not need to
786 check the return value explicitly.
787
788
789DUH *dumb_read_xm(DUMBFILE *f);
790
791 Reads a Fast Tracker II file from an already open DUMBFILE. This leaves
792 the DUMBFILE open, but the DUMBFILE may not be positioned at the end of
793 the XM data. If you are embedding an XM in another file, you are advised
794 to store the size of the XM file and make up for it at the end using
795 dumbfile_pos().
796
797 Otherwise, this function is identical to dumb_load_xm().
798
799 WARNING: The behaviour of this function is undefined if you pass a
800 DUMBFILE from which data have already been read; it is likely not
801 to work. This oversight will be fixed in future releases.
802
803
804DUH *dumb_load_s3m(const char *filename);
805
806 Loads the specified Scream Tracker 3 file, encapsulating it in a DUH
807 struct. Once the file is loaded, it can be treated exactly the same as any
808 other DUH in memory. If this fails it will return NULL, but you can safely
809 pass this NULL value to DUMB's other functions, so you do not need to
810 check the return value explicitly.
811
812
813DUH *dumb_read_s3m(DUMBFILE *f);
814
815 Reads a Scream Tracker 3 file from an already open DUMBFILE. This leaves
816 the DUMBFILE open, but the DUMBFILE may not be positioned at the end of
817 the S3M data. If you are embedding an S3M in another file, you are advised
818 to store the size of the S3M file and make up for it at the end using
819 dumbfile_pos().
820
821 Otherwise, this function is identical to dumb_load_s3m().
822
823 WARNING: The behaviour of this function is undefined if you pass a
824 DUMBFILE from which data have already been read; it is likely not
825 to work. This oversight will be fixed in future releases.
826
827
828DUH *dumb_load_mod(const char *filename);
829
830 Loads the specified Amiga module file, encapsulating it in a DUH struct.
831 Once the file is loaded, it can be treated exactly the same as any other
832 DUH in memory. If this fails it will return NULL, but you can safely pass
833 this NULL value to DUMB's other functions, so you do not need to check the
834 return value explicitly.
835
836
837DUH *dumb_read_mod(DUMBFILE *f);
838
839 Reads an Amiga module file from an already open DUMBFILE. This leaves the
840 DUMBFILE open, but the DUMBFILE may not be positioned at the end of the
841 MOD data. If you are embedding a MOD in another file, you are advised to
842 store the size of the MOD file and make up for it at the end using
843 dumbfile_pos().
844
845 Otherwise, this function is identical to dumb_load_mod().
846
847 WARNING: The behaviour of this function is undefined if you pass a
848 DUMBFILE from which data have already been read; it is likely not
849 to work. This oversight will be fixed in future releases.
850
851
852int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd);
853
854 This function returns the number of orders in the module.
855
856
857int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd);
858void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv);
859
860 These functions obtain and set the initial global volume for the module.
861 This value ranges from 0 to 128 inclusive. The module can set the global
862 volume itself during playback, so your change may not last throughout the
863 playback.
864
865
866int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd);
867void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv);
868
869 These functions obtain and set the mixing volume for the module. This
870 value ranges from 0 to 128 inclusive, and does not change during playback.
871 IT files have the mixing volume stored in them; for other formats it is
872 set to 48 on loading.
873
874
875int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd);
876void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed);
877int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd);
878void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo);
879
880 These functions obtain and set the initial speed and tempo for the module.
881 During module playback, everything happens on a tick. If a beat is 24
882 ticks, then the tempo is measured in beats per second. The speed is then
883 the number of ticks per row. With a speed of 6, a beat is then four rows.
884
885 Modules can set these values during playback, so your change may not last
886 throughout the playback. MOD files have to set the speed and tempo on the
887 first row if they want anything other than the default 6/125, so your
888 change may not be noticed at all!
889
890
891int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel);
892void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel,
893 int volume);
894
895 These functions obtain and set the initial volume for the specified
896 channel. The channel parameter is 0-based (contrary to the display in most
897 trackers so be careful), and can range from 0 to DUMB_IT_N_CHANNELS - 1,
898 i.e. from 0 to 63.
899
900 Modules can set their channel volumes during playback, so your changes may
901 not last throughout the playback.
902
903
904int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr);
905int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr);
906
907 These functions return the current order and row of playback. Both are
908 0-based. If the DUMB_IT_SIGRENDERER is invalid, or has been terminated
909 by a callback (see dumb_it_set_loop_callback() and
910 dumb_it_set_xm_speed_zero_callback()), these functions will both return
911 -1.
912
913
914int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr);
915void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv);
916
917 These functions obtain and set the current global volume for the module.
918 This value ranges from 0 to 128 inclusive. The module can set the global
919 volume itself during playback, so your change may not last.
920
921
922int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr);
923void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo);
924int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr);
925void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed);
926
927 These functions obtain and set the current speed and tempo of the module.
928 See the dumb_it_sd_*() equivalents of these functions for details on what
929 the speed and tempo mean.
930
931 Modules can set these values during playback, so your change may not last.
932
933
934int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel);
935void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel,
936 int volume);
937
938 These functions obtain and set the current volume for the specified
939 channel. The channel parameter is 0-based (contrary to the display in most
940 trackers so be careful), and can range from 0 to DUMB_IT_N_CHANNELS - 1,
941 i.e. from 0 to 63.
942
943 Modules can set their channel volumes during playback, so your changes may
944 not last.
945
946
947void dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel,
948 DUMB_IT_CHANNEL_STATE *state);
949
950 Returns the current playback state of the given channel. If you pass a
951 channel in the range 0 to DUMB_IT_N_CHANNELS-1 (0 to 63), you will get the
952 state of the most recently played note on that physical channel, if it is
953 still playing. For MOD, S3M and XM files, that's all there is to it.
954
955 IT files can have more than one note playing on a single channel, courtesy
956 of New Note Actions. This function also lets you query all the notes that
957 have been forced into the background and are still playing. For this, set
958 'channel' to a value from DUMB_IT_N_CHANNELS to DUMB_IT_TOTAL_CHANNELS-1.
959 DUMB_IT_TOTAL_CHANNELS is defined as follows:
960
961 #define DUMB_IT_TOTAL_CHANNELS \
962 (DUMB_IT_N_CHANNELS + DUMB_IT_N_NNA_CHANNELS)
963
964 Querying these background channels for MOD, S3M and XM files will not do
965 any harm; the function will report that these channels are inactive. For
966 all files, be sure not to query any channel numbers greater than or equal
967 to DUMB_IT_TOTAL_CHANNELS.
968
969 You must provide a pointer to a preallocated DUMB_IT_CHANNEL_STATE struct.
970 The easiest way to do this is as follows:
971
972 DUMB_IT_CHANNEL_STATE state;
973 dumb_it_sr_get_channel_state(sr, channel, &state);
974
975 or:
976
977 DUMB_IT_CHANNEL_STATE state[IT_TOTAL_CHANNELS];
978 dumb_it_sr_get_channel_state(sr, channel, &state[channel]);
979
980 This struct contains the following fields:
981
982 int channel;
983 int sample;
984 int freq;
985 float volume;
986 unsigned char pan;
987 signed char subpan;
988 unsigned char filter_cutoff;
989 unsigned char filter_subcutoff;
990 unsigned char filter_resonance;
991
992 The first field to check is 'sample'; if this is 0, then the channel is
993 inactive and the other fields are undefined. Otherwise, it is the index of
994 the currently playing sample, and is 1-based.
995
996 The channel number is returned, 0-based. This will be the same as the
997 channel number you passed, unless you are querying a background channel in
998 which case it will represent the channel the note originated on.
999
1000 The freq field is the current playback frequency, taking into account all
1001 phenomena such as slides, vibrato and arpeggio.
1002
1003 The volume field ranges from 0.0f to 1.0f. In practical terms, it will
1004 rarely reach 1.0f; if it does, the module is probably clipping a lot. This
1005 takes mixing volume into account, along with all the other volume
1006 phenomena in the IT file. The only one it doesn't take into account is the
1007 one you pass to duh_render() or duh_sigrenderer_get_samples(), or the one
1008 you passed to al_start_duh() (these are in fact the same thing).
1009
1010 The pan field ranges from 0 to 64 for a normally panned sample, but will
1011 be 100 if the sample is playing using IT's surround mode where the right-
1012 hand channel is inverted. If you want a more accurate pan reading, use one
1013 of the following to get one:
1014
1015 int scaled_pan = ((int)state.pan << 8) + state.subpan;
1016 float float_pan = state.pan + state.subpan / 256.0f;
1017
1018 The first will give a scaled value ranging (strictly) from 0 to 64*256.
1019 The second will give a floating-point value whose scale corresponds to
1020 that of the pan field. These results will only be valid if surround mode
1021 is off, so you should check that pan <= 64 before using the above
1022 expressions. At the time of writing, pitch-pan separation and panning
1023 envelopes take advantage of the extra accuracy offered by subpan.
1024
1025 Note that subpan is signed. This means applications that only look at the
1026 pan field will get an unbiased reading.
1027
1028 The filter cut-off and resonance both range from 0 to 127. If the cut-off
1029 is 127 and the resonance is 0, then no filters are applied. These
1030 parameters only ever change from the default values for IT files.
1031
1032 While IT allows you to set 127 different filter cut-off levels in the
1033 patterns and as a default value per instrument, it also allows you to
1034 create a filter envelope, which will result in an actual cut-off somewhere
1035 between 0 and the first-mentioned value. By the time this has been
1036 calculated, the actual cut-off may lie in between two levels on the
1037 original scale. If this is the case, filter_subcutoff will be nonzero and
1038 you can combine it with filter_cutoff. Typically you will want to use one
1039 of the following:
1040
1041 int scaled_cutoff = ((int)state.filter_cutoff << 8) +
1042 state.filter_subcutoff;
1043
1044 float float_cutoff = state.filter_cutoff +
1045 state.filter_subcutoff / 256.0f;
1046
1047 The first will give you a scaled value whose maximum is 127*256. The
1048 second will give you a floating-point value whose scale corresponds to the
1049 scale used by filter_cutoff. These match the expressions given further up
1050 for pan and subpan, but in this case, filter_subcutoff is unsigned.
1051
1052 Note that filter_subcutoff will always be zero if filter_cutoff is 127, so
1053 you need not check it if you simply wish to determine whether filters are
1054 being applied.
1055
1056
1057*******************************
1058*** DUH Rendering Functions ***
1059*******************************
1060
1061
1062 Use these functions to generate samples from a DUH. First you call
1063 duh_start_sigrenderer() with the DUH, the number of channels you want and
1064 the position at which you want to start. Then you use duh_render() or
1065 duh_sigrenderer_get_samples() to generate the samples. You can call these
1066 functions as many times as you like, and they will generate as many or as
1067 few samples as you require. When you have finished, call
1068 duh_end_sigrenderer().
1069
1070
1071DUH_SIGRENDERER *duh_start_sigrenderer
1072 (DUH *duh, int sig, int n_channels, long pos);
1073
1074 Starts a DUH_SIGRENDERER off. This is the struct you can use to get
1075 samples from a DUH. This function does not generate any samples; you must
1076 pass the struct to duh_render() or duh_sigrenderer_get_samples() for that.
1077 When you have finished with it, you must pass it to duh_end_sigrenderer().
1078 You can use as many DUH_SIGRENDERER structs as you like at the same time.
1079
1080 Set sig to 0 for now. Currently, n_channels can only be 1 or 2, for
1081 monaural and stereo sound respectively. The debugging library will cause
1082 your program to abort if you pass anything else. Future versions will be
1083 enhanced to support more channels as soon as someone needs them.
1084
1085 When specifying the position, 0 represents the start of the DUH, and 65536
1086 represents one second. Unlike most other music systems, DUMB will always
1087 make sure every note is there right from the start (assuming you aren't
1088 using any broken add-ons). In other words, you can start a DUH at a point
1089 halfway through a long note, and you will still hear the long note.
1090
1091
1092void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer,
1093 DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data);
1094
1095 Installs a callback function which will be called every time the given
1096 sigrenderer is used to generate some samples. This can be used to create
1097 an oscilloscope or spectrum analyser. DUH_SIGRENDERER_ANALYSER_CALLBACK is
1098 defined as follows:
1099
1100 typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data,
1101 const sample_t *const *samples, int n_channels, long length);
1102
1103 If the above confuses you, see fnptr.txt. As for the 'samples' parameter,
1104 the first 'const' says that the samples are read-only; the second says
1105 that each channel's sample pointer is also read-only. If you don't
1106 understand this, don't worry about it.
1107
1108 Beware: your callback function may occasionally be called with
1109 samples == NULL. This means the main program has decided to skip through
1110 the music without generating any data (see duh_sigrenderer_get_samples()).
1111 You should handle this case elegantly, typically by returning immediately,
1112 but you may wish to make a note of the fact that the music is being
1113 skipped, for whatever reason.
1114
1115 Beware again: if the main program ever calls duh_sigrenderer_get_samples()
1116 on a buffer that isn't all silence, this callback function will be passed
1117 the existing buffer after mixing, and thus it will include the original
1118 data. This will not be an issue if you stick to duh_render(), which always
1119 starts with a buffer filled with silence.
1120
1121 The samples array is two-dimensional. Refer to it as follows:
1122
1123 samples[channel_number][sample_position]
1124
1125 where 0 <= channel_number < n_channels,
1126 and 0 <= sample_position < length.
1127
1128 In addition you can pass any 'data' pointer you like to
1129 duh_sigrenderer_set_analyser_callback(), and this pointer will be relayed
1130 to your callback function each time.
1131
1132 To remove the callback function, pass NULL to
1133 duh_sigrenderer_set_analyser_callback().
1134
1135
1136int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);
1137
1138 Tells you how many channels a DUH_SIGRENDERER is set up to generate, or 0
1139 if it is invalid (perhaps owing to lack of memory). This will be 1 for
1140 monaural sound or 2 for stereo, in this release.
1141
1142
1143long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer);
1144
1145 Tells you what position a DUH_SIGRENDERER is up to, or -1 if it is invalid
1146 (perhaps owing to lack of memory). As usual, 65536 is one second.
1147
1148
1149long duh_sigrenderer_get_samples(DUH_SIGRENDERER *sigrenderer,
1150 float volume, float delta,
1151 long size, sample_t **samples);
1152
1153 Generates some samples in DUMB's internal 32-bit format (see sample_t; see
1154 also duh_render()). The samples buffer is a two-dimensional array, and can
1155 be allocated with create_sample_buffer(); see
1156 duh_sigrenderer_set_analyser_callback() for details.
1157 duh_sigrenderer_get_samples() mixes sample data with what's already in the
1158 buffer, so you have to call dumb_silence() first.
1159
1160 The volume is a float. 1.0f is the pseudo-maximum. If you pass 1.0f, any
1161 properly designed DUH will play nice and loud, but will not clip. You can
1162 pass a greater volume if you like, but be prepared for the possibility of
1163 distortion due to integer overflow. Of course you can pass smaller values
1164 to play the DUH more quietly, and this will also resolve clipping issues
1165 in badly designed DUHs.
1166
1167 Use delta to control the speed of the output signal. If you pass 1.0f, the
1168 resultant signal will be suitable for a 65536-Hz sampling rate (which
1169 isn't a commonly used rate). The most common sampling rates are 11025 Hz,
1170 22050 Hz, 44100 Hz and 48000 Hz. You can work out the required delta value
1171 as follows:
1172
1173 delta = 65536.0f / sampling_rate;
1174
1175 If you then increase this value, the DUH will speed up and increase in
1176 pitch. If you decrease it, the DUH will slow down and decrease in pitch.
1177
1178 This function will attempt to render 'size' samples. In most cases it will
1179 succeed. However, if the end of the DUH is reached, it may render fewer.
1180 The number of samples rendered will be returned. Therefore, if the return
1181 value is less than the value of 'size' passed, you know the DUH has
1182 finished. It is safe to continue calling duh_sigrenderer_get_samples() if
1183 you wish, and it will continually return 0.
1184
1185 If the DUH_SIGRENDERER is a null pointer, this function will generate
1186 precisely 0 samples. If you pass NULL for 'samples', the function will
1187 behave exactly the same as if you provided a sample buffer, except the
1188 samples won't be stored anywhere and the function will execute very
1189 quickly. This can be used to skip ahead in the audio.
1190
1191
1192long duh_render(DUH_SIGRENDERER *sigrenderer,
1193 int bits, int unsign,
1194 float volume, float delta,
1195 long size, void *sptr);
1196
1197 Generates some samples and converts them to an 8-bit or 16-bit format (see
1198 also duh_sigrenderer_get_samples()). Pass the DUH_SIGRENDERER as returned
1199 by duh_start_sigrenderer(). Pass the number of bits, which should be 8 or
1200 16. If unsign is nonzero, the samples will be unsigned (centred on 0x80 or
1201 0x8000 for 8 bits and 16 bits respectively). If unsign is zero, the
1202 samples will be signed.
1203
1204 Allegro's audio streams always take unsigned samples. 8-bit .wav files
1205 always take unsigned samples. 16-bit .wav files always take signed
1206 samples.
1207
1208 The volume and delta parameters work the same as for
1209 duh_sigrenderer_get_samples().
1210
1211 This function will attempt to render 'size' samples. In most cases it will
1212 succeed. However, if the end of the DUH is reached, it may render fewer.
1213 The number of samples rendered will be returned. Therefore, if the return
1214 value is less than the value of 'size' passed, you know the DUH has
1215 finished. It is safe to continue calling duh_render() if you wish, and it
1216 will continually return 0. However, if you wish to do this, you will
1217 probably have to fill the rest of the buffer with silence, which is 0 for
1218 signed, 0x80 for 8-bit unsigned or 0x8000 for 16-bit unsigned.
1219
1220 The samples will be placed at sptr. Use an array of chars for 8 bits or an
1221 array of shorts for 16 bits. Stereo samples will be interleaved, left
1222 first. Your array should contain at least (size * n_channels) elements of
1223 the appropriate bit resolution.
1224
1225 From an aesthetic standpoint if nothing else, it is wise to use the C
1226 qualifiers 'signed' or 'unsigned' depending on whether the samples are
1227 signed or unsigned. This is also convenient if you wish to process the
1228 samples further yourself.
1229
1230 If the DUH_SIGRENDERER is a null pointer, this function will generate
1231 precisely 0 samples. Unlike with duh_sigrenderer_get_samples(), you must
1232 specify a sample buffer.
1233
1234
1235void duh_end_sigrenderer(DUH_SIGRENDERER *dr);
1236
1237 Terminates a DUH_SIGRENDERER. Be sure to call this when you've finished
1238 with one. You can safely pass a null pointer.
1239
1240
1241********************************
1242*** Allegro Packfile Support ***
1243********************************
1244
1245
1246void dumb_register_packfiles(void);
1247
1248 This function registers the Allegro PACKFILE input module for use by
1249 DUMBFILEs. PACKFILE structs and their corresponding functions, as defined
1250 by Allegro's header file allegro.h, will be used internally for all
1251 DUMBFILE input (unless opened with dumbfile_open_ex()).
1252
1253 This must be called before dumbfile_open() is used, or else an alternative
1254 system must be registered (see register_dumbfile_system() and
1255 dumb_register_stdfiles()). Note that you don't have to call this function
1256 in order to load datafiles that contain music.
1257
1258
1259DUMBFILE *dumbfile_open_packfile(PACKFILE *p);
1260
1261 If you have an Allegro PACKFILE struct representing an open file, you can
1262 call this if you wish to read from it using a DUMBFILE. This is useful
1263 when you need to pass a DUMBFILE struct to a library function, to read an
1264 embedded music file for example. When you close the DUMBFILE, you can
1265 continue using the PACKFILE struct to read what follows the embedded data.
1266
1267
1268DUMBFILE *dumbfile_from_packfile(PACKFILE *p);
1269
1270 This function is the same as dumbfile_open_packfile(), except it will
1271 check if p is NULL, and arrange for pack_fclose() to be called on the
1272 PACKFILE when you close the DUMBFILE. It can be seen as a function for
1273 converting a PACKFILE to a DUMBFILE, but it will only work for a PACKFILE
1274 you obtained with pack_fopen(), not pack_fopen_chunk(). If this function
1275 fails, which may happen if memory is short, then the PACKFILE will be
1276 closed immediately, so you need not worry about potential memory leaks or
1277 files being left open when this happens.
1278
1279 The following is typical usage, and will open the compressed file foo.bin:
1280
1281 DUMBFILE *f = dumbfile_from_packfile(pack_fopen("foo.bin",
1282 F_READ_PACKED));
1283
1284 This differs from calling dumb_register_packfiles() and dumbfile_open() in
1285 that the latter will only read uncompressed files (and is thus a method
1286 suitable for reading music modules).
1287
1288
1289***********************************************
1290*** Allegro Datafile Registration Functions ***
1291***********************************************
1292
1293
1294void dumb_register_dat_it(long type);
1295
1296 If you wish to embed an IT file in an Allegro datafile, it is recommended
1297 that you use "IT " for the type. The grabber will have a box for the type
1298 when you insert a new object. The grabber will treat the IT file as binary
1299 data, which means the datafile will contain an exact copy of the IT file
1300 on disk.
1301
1302 You must then call dumb_register_dat_it(DUMB_DAT_IT) in your program
1303 before you load the datafile. Once you've done this, you'll be able to
1304 access the DUH using the usual datafile[n].dat notation. You do not need
1305 to call unload_duh() on this DUH; unload_datafile() will do that for you.
1306
1307 If you are using a different type for whatever reason, you can use
1308 Allegro's DAT_ID() macro for encoding it and passing it to this function.
1309 For example:
1310
1311 dumb_register_dat_it(DAT_ID('B','L','A','H'));
1312
1313 Assuming you used the recommended type, the following example iterates
1314 through all the ITs in disan.dat:
1315
1316 DATAFILE *dat;
1317 int n;
1318
1319 dumb_register_dat_it();
1320 dat = load_datafile("disan.dat");
1321
1322 for (n = 0; dat[n].type != DAT_END; n++) {
1323 if (dat[n].type == DUMB_DAT_IT) {
1324 DUH *duh = dat[n].dat;
1325 /* Insert code here to play 'duh' or whatever you want to do. */
1326 }
1327 }
1328
1329 unload_datafile(dat);
1330
1331
1332void dumb_register_dat_xm(long type);
1333
1334 Inserting an XM file in an Allegro datafile is the same as inserting an IT
1335 file, except that the recommended type is "XM ", the registration
1336 function is dumb_register_dat_xm(), and the macro DUMB_DAT_XM is provided
1337 for the type. The intuitive process of substituting XM for IT in the above
1338 method will work.
1339
1340
1341void dumb_register_dat_s3m(long type);
1342
1343 Inserting an S3M file in an Allegro datafile is the same as inserting an
1344 IT file, except that the recommended type is "S3M ", the registration
1345 function is dumb_register_dat_s3m(), and the macro DUMB_DAT_S3M is
1346 provided for the type. The intuitive process of substituting S3M for IT in
1347 the above method will work.
1348
1349
1350void dumb_register_dat_mod(long type);
1351
1352 Inserting a MOD file in an Allegro datafile is the same as inserting an IT
1353 file, except that the recommended type is "MOD ", the registration
1354 function is dumb_register_dat_mod(), and the macro DUMB_DAT_MOD is
1355 provided for the type. The intuitive process of substituting MOD for IT in
1356 the above method will work.
1357
1358
1359****************************************
1360*** Sample Buffer Allocation Helpers ***
1361****************************************
1362
1363
1364 Many parts of DUMB require sample buffers allocated in a special way. A
1365 pointer to one looks like this:
1366
1367 sample_t **samples;
1368
1369 and it can be indexed as follows:
1370
1371 samples[channel_number][sample_position]
1372
1373 where 0 <= channel_number < n_channels
1374 and 0 <= sample_position < length.
1375
1376 The following helpers will allocate and deallocate such buffers for you.
1377 They will not initialise them, and DUMB always writes into these buffers
1378 by adding to what's already there, so you will generally have to call
1379 dumb_silence() too.
1380
1381
1382sample_t **create_sample_buffer(int n_channels, long length);
1383
1384 This will allocate a sample buffer to hold the specified number of samples
1385 for the specified number of channels. Don't forget to check the return
1386 value!
1387
1388 You will generally have to initialise the buffer by calling
1389 dumb_silence(); the channels will be stored consecutively in memory, so
1390 the following technique is officially supported:
1391
1392 dumb_silence(samples[0], n_channels * length);
1393
1394 See dumb_silence() for general information on what this function does.
1395
1396
1397void destroy_sample_buffer(sample_t **samples);
1398
1399 This function does the obvious: it frees up a sample buffer when you've
1400 finished with it. It is safe to pass a null pointer to this function.
1401
1402
1403************************
1404*** Silencing Helper ***
1405************************
1406
1407
1408void dumb_silence(sample_t *samples, long length);
1409
1410 This function simply stores 'length' samples' worth of silence in the
1411 array. It is typically used straight after allocating a sample buffer with
1412 create_sample_buffer().
1413
1414
1415**************************
1416*** Resampling Helpers ***
1417**************************
1418
1419
1420 Please forgive the odd section name; it has to do with DUMB's internal
1421 structure and the fact that the resampling algorithm is there not just for
1422 use in rendering module files but for use anywhere that a waveform needs
1423 resampling. Unfortunately DUMB's resampling algorithm is not ready to be
1424 documented and used yet. However, one thing can be documented, and that's
1425 the global variable controlling the resampling quality.
1426
1427 (Ironically, even this variable has changed! See deprec.txt for
1428 information on what it used to do.)
1429
1430
1431int dumb_resampling_quality;
1432
1433 Allows you to control the quality of all resampling that takes place. This
1434 may be set to any DUMB_RQ_* constant (except DUMB_RQ_N_LEVELS). Higher
1435 values will sound better, but lower values will use up less processor
1436 time. You may compare any two DUMB_RQ_* constants or values using the
1437 integer inequalities <, <=, > and >=; higher numbers represent higher-
1438 quality algorithms.
1439
1440 #define DUMB_RQ_ALIASING
1441
1442 | --___ 'Aliasing' has very noticeable and usually unwanted
1443 |__--- __ overtones. It will occasionally produce acceptable
1444 | ___-- results for noisy (impure) samples (or for cheap
1445 speakers!), but usually you will want to pay for
1446 the extra processor time, which isn't much, and go for linear
1447 interpolation.
1448
1449 #define DUMB_RQ_LINEAR
1450
1451 | __ Linear interpolation is a pretty good algorithm in most
1452 | / \ /\ cases. When resampling down a few octaves, however, you
1453 |/ \/ \__ may begin to notice unwanted high frequencies. You can
1454 reduce these by switching to cubic interpolation, but it
1455 will cost you some processor time.
1456
1457 #define DUMB_RQ_CUBIC
1458
1459 Cubic interpolation looks like a smooth curve to the eye, and will
1460 produce good results in most cases. At present this is the highest
1461 quality offered by DUMB, and also the default. While this may seem
1462 extravagant, GCC 3.x and an AthlonXP handle it quite well - and the
1463 general trend is for processors to get better!
1464
1465 #define DUMB_RQ_N_LEVELS
1466
1467 This represents the number of resampling quality levels DUMB provides.
1468 Values of dumb_resampling_quality from 0 to DUMB_RQ_N_LEVELS - 1 are
1469 valid. You can use this constant if you wish to offer the resampling
1470 quality as an option for the user.
1471
1472
1473*************************************
1474*** Allegro DUH Playing Functions ***
1475*************************************
1476
1477
1478 The functions in this section allow you to play back a DUH through
1479 Allegro's sound system. You must call Allegro's install_sound() function
1480 before you use them.
1481
1482
1483AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos,
1484 float volume, long bufsize, int freq);
1485
1486 Starts playing the specified DUH.
1487
1488 An AL_DUH_PLAYER represents one instance of the DUH playing. If you wish,
1489 you can have two or more AL_DUH_PLAYERs going at the same time, for the
1490 same DUH or for different ones. Each uses one of Allegro's audio streams
1491 and hence one voice. The voice will be given priority 255 initially, so a
1492 build-up of sound effects will not cause your music streams to cut off (as
1493 long as you don't give all your sound effects priority 255!). You can
1494 change the priority of a stream with al_duh_set_priority(). See Allegro's
1495 documentation for more information on how voice priorities work.
1496
1497 At present, n_channels can either be 1 or 2 for monaural or stereo
1498 respectively. If you use the debugging library, your program will abort if
1499 other values are passed; otherwise weird things will happen.
1500
1501 The DUH will start playing from position 'pos'. 0 represents the start of
1502 the DUH, and 65536 represents one second. Unlike other music systems, DUMB
1503 will always make sure every note is there right from the start. In other
1504 words, you can start a DUH at a point halfway through a long note, and you
1505 will still hear the long note.
1506
1507 The volume is a float. 1.0f is the pseudo-maximum. If you pass 1.0f, any
1508 properly designed DUH file will play nice and loud, but will not clip. You
1509 can pass a greater volume if you like, but be prepared for clipping to
1510 occur. Of course you can pass smaller values to play the DUH more quietly,
1511 and this will also resolve clipping issues in badly designed DUH files.
1512
1513 You will need to pass the AL_DUH_PLAYER to other functions when you need
1514 to stop or pause the DUH, change its volume, or otherwise modify the way
1515 it is playing. You will also need to pass it to al_poll_duh() at regular
1516 intervals; if the sound is choppy, try calling al_poll_duh() more often.
1517
1518 'bufsize' is the number of samples that will be rendered at once. 1024 is
1519 a suitable value for most purposes. The greater this is, the less often
1520 you will have to call al_poll_duh() - but when al_poll_duh() decides to
1521 fill the buffer, it will take longer doing so. If your game exhibits
1522 regular brief freezes, try reducing the buffer size. If the sound is
1523 choppy, however, you may have to increase it.
1524
1525 'freq' specifies the sampling frequency at which the DUH should be
1526 rendered. At present there is no (official and portable) way of knowing
1527 the frequency at which Allegro is mixing - but if you do know that
1528 frequency, passing it here will give the highest quality sound. If you
1529 reduce it, the DUH will sound less crisp but use less processor time.
1530
1531 When you have finished, you must pass the AL_DUH_PLAYER to al_stop_duh()
1532 to free up memory. Do not destroy the DUH beforehand.
1533
1534 There is no real need to check the return value from this function. The
1535 other functions can be called safely with null pointers, so if there is a
1536 problem, your music will simply not play.
1537
1538
1539void al_stop_duh(AL_DUH_PLAYER *dp);
1540
1541 This will stop an AL_DUH_PLAYER. You must call this when you have finished
1542 with it, before destroying the DUH. The pointer will no longer be valid on
1543 return from this function.
1544
1545
1546void al_pause_duh(AL_DUH_PLAYER *dp);
1547
1548 This will pause an AL_DUH_PLAYER. Use al_resume_duh() when you want it to
1549 continue. You can safely call al_poll_duh() while the music is paused, and
1550 it will do nothing.
1551
1552
1553void al_resume_duh(AL_DUH_PLAYER *dp);
1554
1555 Causes a paused AL_DUH_PLAYER to resume playing (see al_pause_duh()).
1556
1557
1558void al_duh_set_priority(AL_DUH_PLAYER *dp, int priority);
1559
1560 This will set the priority of the audio stream underlying an
1561 AL_DUH_PLAYER. The priority is an integer ranging from 0 to 255. When
1562 too many samples play at the same time, those with lower priorities will
1563 be cut. 128 is the usual default with Allegro, but DUMB overrides the
1564 default for all AL_DUH_PLAYER structs: they will be set up initially with
1565 priority 255, so your music won't be cut (unless you play too many other
1566 streams or samples with priority 255). See Allegro's documentation for
1567 more information on priorities.
1568
1569
1570void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume);
1571
1572 This will set the volume of an AL_DUH_PLAYER. See al_start_duh() for
1573 details on the volume parameter.
1574
1575
1576int al_poll_duh(AL_DUH_PLAYER *dp);
1577
1578 An AL_DUH_PLAYER is not interrupt-driven. That means it will not play by
1579 itself. You must keep it alive from your main program. Call this function
1580 at regular intervals. If the sound crackles, try calling it more often.
1581 (There is nothing you can do if Windows decides to play with the hard
1582 disk; that will make your sound crackle no matter what you do.)
1583
1584 Normally this function will return zero. However, if it returns nonzero,
1585 that means the AL_DUH_PLAYER will not generate any more sound. Indeed the
1586 underlying audio stream and DUH_SIGRENDERER have been destroyed. When this
1587 happens, you can call al_stop_duh() whenever you wish - but you do not
1588 have to. Note that this function will wait two buffers' worth of samples
1589 before taking this action, allowing Allegro to mix the trailing sound
1590 before the audio stream is destroyed. This is an attempt to make sure your
1591 music does not get cut off prematurely, and it should work when using
1592 Allegro's mixer (the only option on DOS, the default on Linux as far as I
1593 know, but not the default on Windows). That said, if you immediately call
1594 Allegro's remove_sound() or exit your program, the music may get cut off.
1595 If you are using another mixer and experience problems, let me know (but I
1596 don't guarantee to be able to come up with an elegant solution, i.e. it
1597 might not get fixed).
1598
1599 In case you were wondering, it is not safe on all platforms to call
1600 al_poll_duh() from an interrupt context (that means an Allegro timer
1601 handler). Not only is no part of DUMB locked in memory, but many parts of
1602 DUMB allocate and free their memory on a call-by-call basis! Remember that
1603 any disk access that occurs in interrupt context is likely to crash the
1604 machine; this is explained more fully in howto.txt. This limitation only
1605 applies to DOS at present, and is due to the fact that the DOS file access
1606 functions are not re-entrant.
1607
1608 Multitasking systems are generally safe. If you are sure you don't want to
1609 target DOS, you can call al_poll_duh() from inside a timer handler, but I
1610 recommend including a construction like the following!
1611
1612 #ifdef ALLEGRO_DOS
1613 #error calling al_poll_duh() from a timer handler will not work in DOS!
1614 #endif
1615
1616 Furthermore, if you call al_poll_duh() from inside a timer handler, you
1617 must use a semaphore or other threading mechanism to make sure it is not
1618 executing when you call al_stop_duh(). If you don't know what a semaphore
1619 is, for Heaven's sake follow my advice and call al_poll_duh() from your
1620 main loop!
1621
1622
1623long al_duh_get_position(AL_DUH_PLAYER *dp);
1624
1625 Tells you what position an AL_DUH_PLAYER is up to, or -1 if it is invalid
1626 (perhaps owing to lack of memory). As usual, 65536 is one second. Note
1627 that this is a whole number, whereas a fractional part is stored
1628 internally; the sample will not be continuous if you terminate the
1629 AL_DUH_PLAYER and then reinitiate it with the same position. Furthermore,
1630 note that Allegro will not have mixed in all the sound up to this point;
1631 if you wait for this to reach a certain position and then terminate the
1632 AL_DUH_PLAYER, the sound will cut off too early. Please contact me if you
1633 need to get around this.
1634
1635
1636AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer
1637 (DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq);
1638
1639 If you have a DUH_SIGRENDERER, and would like to start playing music from
1640 it through an Allegro audio stream, use this function. Beware that it may
1641 return NULL, in which case you will have to call duh_end_sigrenderer()
1642 yourself instead of relying on the encapsulating AL_DUH_PLAYER to do it
1643 for you.
1644
1645
1646DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp);
1647
1648 This returns the DUH_SIGRENDERER contained in an AL_DUH_PLAYER, useful for
1649 controlling playback, installing callbacks, etc.
1650
1651
1652DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp);
1653
1654 This destroys an AL_DUH_PLAYER, but preserves the DUH_SIGRENDERER it
1655 contains, and returns it to you. You can then continue rendering samples
1656 from the DUH_SIGRENDERER and do whatever you like with them.
1657
1658
1659*********************
1660*** Thread Safety ***
1661*********************
1662
1663
1664The following points should pretty much sum up the essence of DUMB's thread
1665safety. If I haven't covered the one thing you'd like to do, please don't
1666hesitate to ask about it.
1667
1668DOs:
1669
1670- You may load and use multiple DUHs in separate threads.
1671
1672- You may change dumb_resampling_quality and dumb_it_max_to_mix while another
1673 thread is generating samples.
1674
1675DON'Ts:
1676
1677- You may not generate samples from the same DUH in multiple threads, even if
1678 you are using separate DUH_RENDERERs (separate AL_DUH_PLAYERS).
1679
1680
1681******************
1682*** Conclusion ***
1683******************
1684
1685
1686"DUMB is the bestest music player in the world because ..."
1687
1688Complete this sentence in fifteen words or fewer and receive a free copy of
1689DUMB! (Your Internet Service Provider may issue charges for your connection,
1690required for download of the Product. Your electricity supplier may issue
1691charges for the electricity consumed in writing the Product to a Permanent
1692Storage Device. You may have been charged for a Permanent Storage Device on
1693which to store the Product.)
1694
1695
1696Ben Davis
1697entheh@users.sf.net
1698IRC EFnet #dumb
1699See readme.txt for details on using IRC.
diff --git a/apps/codecs/dumb/docs/faq.txt b/apps/codecs/dumb/docs/faq.txt
deleted file mode 100644
index 48b5ef3fff..0000000000
--- a/apps/codecs/dumb/docs/faq.txt
+++ /dev/null
@@ -1,263 +0,0 @@
1TO DO: add question regarding set_close_button_callback vs set_window_close_hook
2
3/* _______ ____ __ ___ ___
4 * \ _ \ \ / \ / \ \ / / ' ' '
5 * | | \ \ | | || | \/ | . .
6 * | | | | | | || ||\ /| |
7 * | | | | | | || || \/ | | ' ' '
8 * | | | | | | || || | | . .
9 * | |_/ / \ \__// || | |
10 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
11 * / \
12 * / . \
13 * faq.txt - Frequently Asked Questions. / / \ \
14 * | < / \_
15 * This file covers some of the common problems | \/ /\ /
16 * and misconceptions people have with DUMB. If \_ / > /
17 * your problem is not covered here, please | \ / /
18 * contact me. I'll do my best to help - but | ' /
19 * don't be offended if I just direct you to the \__/
20 * manual!
21 */
22
23
24*****************************************************************************
25* I get a lot of strange warnings and errors when I compile my projects *
26* with this release of DUMB. They work with older versions! What happened? *
27*****************************************************************************
28
29 Some parts of DUMB's API have been deprecated. See docs/deprec.txt for
30 full details, including an explanation as to why your compiler warnings
31 and errors are so unfriendly, and information on how to fix each warning
32 or error.
33
34
35*****************************************************************************
36* When I try to compile DUMB with Allegro, it complains that it cannot find *
37* 'internal/alconfig.h'! What's wrong? *
38*****************************************************************************
39
40 In Allegro 4.0.1, and quite likely some other versions of Allegro, the
41 msvcmake batch file does not install Allegro properly. I believe this was
42 fixed in Allegro 4.0.2, but don't take my word for it. Some include files
43 are neglected, including alconfig.h. The fix is quite easy; you need to
44 copy all of Allegro's include files to your compiler's directory. The
45 following should do this for you (alter it accordingly depending on where
46 MSVC and Allegro are installed):
47
48 cd\progra~1\msvc\include
49 xcopy/s \allegro\include\*.*
50
51 You can safely tell it to overwrite all files.
52
53
54*****************************************************************************
55* When I build a project that uses DUMB, I get an error that it doesn't *
56* find -laldmbd! What's wrong? *
57*****************************************************************************
58
59 See the notes for DUMB v0.8 in release.txt; the existence of libaldmbd.a
60 in DUMB v0.7 was due to a mistake in the makefiles. It should be
61 libaldmd.a, in order to maintain DOS compatibility. All subsequent
62 releases get it right, but you will have to change your project files to
63 allow for the change. If this is someone else's project, please let them
64 know that it needs changing.
65
66
67*****************************************************************************
68* When I build a project that uses DUMB, I get some linker errors about *
69* _free, _malloc, etc. already being defined in LIBC.lib! What's wrong? *
70*****************************************************************************
71
72 MSVC offers three different implementations of the standard libraries.
73 When you link statically with a library, you have to use the same
74 implementation that the library uses. You need the multithreaded DLL
75 implementation, which you can select by passing /MD when you compile (not
76 when you link). See howto.txt for details.
77
78
79*****************************************************************************
80* I created an IT file with Impulse Tracker, but DUMB won't play it! Why? *
81*****************************************************************************
82
83 You probably created some patterns but didn't give any information on the
84 order in which they should be played. Impulse Tracker will also fail to
85 play your music if you press F5. Press F11 and you will have an
86 opportunity to create an order list, required for playback.
87
88
89*****************************************************************************
90* I created an IT file with ModPlug Tracker and I have it fading out at the *
91* end. Why won't it loop when I play it with DUMB? *
92*****************************************************************************
93
94 It loops at zero volume. This is what Impulse Tracker itself does. Fix the
95 IT file by setting the global volume explicitly (Vxx in the effects
96 column), either at the start, or right at the end before looping. Also see
97 the next two questions.
98
99
100*****************************************************************************
101* My module plays too loud and distorts badly with DUMB! What can I do? *
102*****************************************************************************
103
104 This problem is most often caused by ModPlug Tracker, which has a complete
105 lack of regard for the playback volume of the original tracker. See the
106 next question for DUMB's official position with regard to ModPlug Tracker.
107 If you wrote your module with ModPlug Tracker, please try loading it with
108 the original tracker and see if it distorts there too. If it does, reduce
109 the volume. If not, then it's a problem with DUMB; please let me know.
110
111 If for whatever reason you cannot modify the module file itself, you can
112 make it sound better by reducing the volume passed to al_start_duh().
113
114
115*****************************************************************************
116* I created a music module with ModPlug Tracker, and DUMB doesn't play it *
117* right! *
118*****************************************************************************
119
120 DUMB cannot and will not support ModPlug Tracker. Please see
121 docs/modplug.txt for details. The original trackers, which DUMB is
122 designed to mimic as closely as possible, are listed in readme.txt.
123 If you find DUMB plays your module differently from the original tracker,
124 then please contact me.
125
126
127*****************************************************************************
128* My program crashes as soon as I try to load anything with DUMB! *
129*****************************************************************************
130
131 Please take my advice and use the debugging build of DUMB, not the
132 optimised build. Then you'll probably find it aborts instead of crashing.
133 In this case you probably forgot to register a DUMBFILE system; this is
134 necessary for loading stand-alone files, though not for loading Allegro
135 datafiles with embedded music. Follow the instructions in docs/howto.txt
136 carefully and you shouldn't have this problem.
137
138 If DUMB crashes with a specific music module, please let me know.
139
140
141*****************************************************************************
142* I want to use the stdio file access functions to load stand-alone music *
143* files, but I also want to load datafiles containing music files. The docs *
144* say I shouldn't call both dumb_register_stdfiles() and *
145* dumb_register_packfiles(). What shall I do? *
146*****************************************************************************
147
148 When you register a DUMBFILE system, it only applies to files opened with
149 dumbfile_open(), i.e. separate files. When a file is embedded in a
150 datafile, dumbfile_open_ex() is used to read it, enabling it to use
151 PACKFILEs regardless of which DUMBFILE system is registered. In short, you
152 do not need to call dumb_register_packfiles() in order to load datafiles
153 with embedded music. See the section on "Sequential File Input" in
154 docs/dumb.txt if you're interested in how all this works.
155
156
157*****************************************************************************
158* I want to read a specific object in a datafile using Allegro's *
159* "demo.dat#MY_MUSIC" syntax. Why won't it work? *
160*****************************************************************************
161
162 Did you call dumb_register_packfiles(), or did you call
163 dumb_register_stdfiles()? It will only work if you use the former.
164
165
166*****************************************************************************
167* My program runs, but no music plays! What am I doing wrong? *
168*****************************************************************************
169
170 There are a number of possible causes for this. The most likely reason is
171 that you aren't calling al_poll_duh(); see docs/howto.txt for further
172 information.
173
174 Other possible causes are as follows:
175
176 - The speakers are turned down (duh)
177 - The volume of some system mixer is turned down
178 - Another program is using the sound card (not a problem for most modern
179 systems)
180 - You didn't initialise Allegro's sound system; see install_sound() in
181 Allegro's docs
182 - Allegro's drivers don't work on your system and chosen platform
183
184 In order to narrow down the cause, consider the following:
185
186 - Do you get any other sound from your program?
187 - Do other Allegro+DUMB programs generate sound?
188 - Do other Allegro programs generate sound?
189 - Do other non-Allegro programs generate sound?
190 - Does your program fail only on a specific platform (e.g. DOS but not
191 Windows)?
192
193 This problem is highly system-specific; please try hard to solve it by
194 yourself before contacting me. However, if you think this problem could
195 affect other people, please let me know what the problem is and how you
196 fixed it, if you did. Be as specific as possible.
197
198
199*****************************************************************************
200* The music stutters! What can I do? *
201*****************************************************************************
202
203 If you have an older computer, it may not be able to cope with the load.
204 Try reducing quality options; look up dumb_resampling_quality and
205 dumb_it_max_to_mix in docs/dumb.txt, and consider changing the frequency
206 you pass to al_start_duh().
207
208 Stuttering may not be caused by excessive load. To find out, try
209 increasing the buffer size passed to al_start_duh(). Beware of making it
210 too big though; older systems will freeze periodically if it's too big,
211 because they render larger chunks less frequently. The timing of callbacks
212 will also be less accurate, if you are using those.
213
214 If you're using the 'dumbplay' example, you can control these parameters
215 by editing dumb.ini.
216
217
218*****************************************************************************
219* Why does DUMB use so much processor time compared with other players? *
220*****************************************************************************
221
222 This should be less so in this release than in previous releases; the
223 resampling and filtering algorithms have been optimised.
224
225 By default, DUMB uses the most expensive resampling quality option. I've
226 found on an AthlonXP 1800+ and on a Pentium 233 that it typically uses
227 about twice as much processor time as the least expensive option.
228
229 Try setting dumb_resampling_quality to DUMB_RQ_ALIASING or DUMB_RQ_LINEAR.
230 See dumb.txt for more information. If you're using the example programs,
231 you can control this variable by editing dumb.ini.
232
233 DUMB uses 32-bit ints for mixing. Some players use 16-bit ints, and are
234 therefore marginally faster (not much!) and lower quality. So you can't
235 expect DUMB to beat these players. Furthermore, DUMB is currently written
236 entirely in C. GCC does an impressive job on the C code, but that's not to
237 say some custom-written assembly language couldn't beat it ...
238
239
240*****************************************************************************
241* Why does DUMB generate so much background noise? *
242*****************************************************************************
243
244 You're probably using the DOS build on a system with bad Sound Blaster
245 compatibility (most Windows XP systems fall in this category). This would
246 mean DUMB could only access an 8-bit driver. The Windows build will almost
247 certainly give better results. Your DOS binary will still give good
248 results on systems with better compatibility (like my Windows 98 system).
249
250
251*****************************************************************************
252* I e-mailed you and you replied with "RTFM"! What does that mean? *
253*****************************************************************************
254
255 Read The Manual. If it's a specific problem, I'll probably be kind and
256 tell you where to look in the manual. However, if I get the impression you
257 haven't even looked for a solution in the manual, expect no mercy ...
258
259
260Ben Davis
261entheh@users.sf.net
262IRC EFnet #dumb
263See readme.txt for details on using IRC.
diff --git a/apps/codecs/dumb/docs/fnptr.txt b/apps/codecs/dumb/docs/fnptr.txt
deleted file mode 100644
index a5fb216822..0000000000
--- a/apps/codecs/dumb/docs/fnptr.txt
+++ /dev/null
@@ -1,113 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * fnptr.txt - Function pointer explanation. / / \ \
12 * | < / \_
13 * | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20
21C allows you to create and use function pointers. A function pointer is a
22variable that points to a function, and you can use it to call that function.
23Why is this useful?
24
25Function pointers can be passed as parameters. As an example, here's a
26function from Allegro:
27
28 void create_light_table(COLOR_MAP *table, const PALETTE pal, int r, g, b,
29 void (*callback)(int pos));
30
31Don't worry about the syntax just yet, but the last parameter, 'callback', is
32a pointer to a function that takes an int parameter. create_light_table() can
33take some time to complete its work, and you may want to display a progress
34indicator. So you write a function to draw the progress indicator, and then,
35for 'callback', you specify a pointer to your function. This will enable
36create_light_table() to call your function at intervals during its
37processing. (If you don't want to use the callback, you can pass NULL, but
38this only works because create_light_table() checks actively for NULL. You
39can't always specify NULL when you want nothing to happen.)
40
41There are many other uses. In addition to using function pointers as
42parameters, Allegro has some global function pointers you can set to point to
43your functions. Function pointers can also be used in structs, and this is
44where DUMB makes the most use of them.
45
46So how are they used?
47
48 void bar(void) { ... } /* Here's a function */
49 void (*foo)(void) = &bar; /* Take a pointer */
50 (*foo)(); /* Call the function */
51
52 char *baz(float a) { ... } /* Here's another function */
53 char *(*foobarbaz)(float a) = &baz; /* Take a pointer */
54 char *rv = (*foobarbaz)(0.1); /* Call the function */
55
56In both these cases, note how the statement for calling the pointed-to
57function (third line) resembles the definition of the function pointer
58(second line). This is true of any variable in C, and can lead to some truly
59obfuscated definitions if you are that way inclined. Such definitions can be
60clarified with typedefs, but before you use those, it is important you
61understand how the above statements work. I speak from experience: function
62pointer notation looks random and scary, until you understand why it's the
63way it is; then it makes perfect sense.
64
65(It is actually permissible to omit the & when taking a pointer and to write
66e.g. foobarbaz(0.1) instead of (*foobarbaz)(0.1). However, I recommend not
67doing this, since the syntax for using the pointer no longer resembles the
68definition. Writing e.g. (*foobarbaz)(0.1) also makes a clear distinction
69between function pointer calls and ordinary function calls, which makes code
70more readable.)
71
72Note that function pointers have the return value and parameter list
73specified. A function pointer can only point to a function with a matching
74return value and matching parameters. (You can break this rule by casting the
75pointer explicitly, but there is no situation where doing so is portable to
76all computers, and I strongly advise against it unless you're writing system
77code. If you're not sure whether you're writing system code or not, then
78you're not.)
79
80The parameter names need not match (although the types must). If you wish to
81rename a parameter in your function, you do not have to change the function
82pointer accordingly. In fact, when you define a function pointer, you don't
83even have to specify the names of parameters if you don't want to. I normally
84do so for clarity.
85
86It is possible to typedef a function pointer. In order to typedef a function
87pointer, you start by declaring the pointer as a variable:
88
89 void (*myfunc)(void);
90
91Then you write 'typedef' before it and replace the variable name, which is
92myfunc, with the type name (this rule can be applied to any variable when you
93want to use typedef):
94
95 typedef void (*MYTYPE)(void);
96
97Now 'MYTYPE' represents a pointer to a function with no parameters and no
98return value. The following two lines are completely equivalent:
99
100 MYTYPE myfunc;
101 void (*myfunc)(void);
102
103Note that we use MYTYPE without an asterisk (*), since it is already a
104pointer.
105
106That's it. If you feel anything should be explained better here, or if you
107feel something should be added, please don't hesitate to let me know!
108
109
110Ben Davis
111entheh@users.sf.net
112IRC EFnet #dumb
113See readme.txt for details on using IRC.
diff --git a/apps/codecs/dumb/docs/howto.txt b/apps/codecs/dumb/docs/howto.txt
deleted file mode 100644
index 0e7057da2c..0000000000
--- a/apps/codecs/dumb/docs/howto.txt
+++ /dev/null
@@ -1,845 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * howto.txt - How To Use DUMB. / / \ \
12 * | < / \_
13 * See readme.txt for general information on | \/ /\ /
14 * DUMB and how to set it up. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20
21********************
22*** Introduction ***
23********************
24
25
26Welcome to the DUMB How-To! It is assumed here that you have already set DUMB
27up on your system, with or without Allegro. If not, please see readme.txt.
28
29
30*********************************
31*** Adding music to your game ***
32*********************************
33
34
35These instructions will help you add a piece of music to your game, assuming
36your music is stored in a stand-alone IT, XM, S3M or MOD file. If you wish to
37use a different method (such as putting the music file in an Allegro
38datafile), please follow these instructions first, test your program, and
39then follow the instructions further down for adapting your code.
40
41
421. You need to include DUMB's header file. If you have Allegro, add the
43 following line to the top of your source file (or at the top of each file
44 where you wish to use DUMB):
45
46 #include <aldumb.h>
47
48 If you do not have Allegro or do not wish to use it, use dumb.h instead.
49
50
512. You need to link with DUMB's library file or files. If you are compiling
52 with GCC from a command line on any platform, you need to add the
53 following to the command line:
54
55 If you are using Allegro: -laldmd -ldumbd
56 If you are not using Allegro: -ldumbd
57
58 If you are using MSVC from the command line:
59
60 If you are using Allegro: /link aldmd.lib dumbd.lib
61 If you are not using Allegro: /link dumbd.lib
62
63 With MSVC, you must also add /MD to the command line when compiling (not
64 when linking).
65
66 Note that -laldmd or aldmd.lib must PRECEDE alleg.lib, -lalleg_s,
67 `allegro-config --libs`, or whatever you are already using to link with
68 Allegro. For MSVC users, the /MD flag selects the multithreaded DLL
69 implementation of the standard libraries; since DUMB is statically linked,
70 you have to use the same library DUMB uses. You would also need this flag
71 to link statically with Allegro; if you already have it, there's no need
72 to put it twice.
73
74 (If anyone would like to contribute instructions for doing the above using
75 MSVC's IDE, please contact me. Contact details are at the end of this
76 file.)
77
78 If you are using RHIDE, go to Options -> Libraries. You will need to type
79 'aldmd' and 'dumbd' in two boxes, making sure 'aldmd' comes above whatever
80 you are using to link with Allegro (or just put 'dumbd' if you are not
81 using Allegro). Make sure the box next to each of these libraries is
82 checked.
83
84 The above are the debugging libraries. It is VERY HIGHLY RECOMMENDED that
85 you use the debugging libraries at first. The reason is as follows.
86 Although DUMB is supposedly robust against corrupt music files and things
87 like lack of memory, it will NOT tolerate programmer error. If you write
88 faulty code, DUMB will probably crash rather than returning an error code
89 for you. However, the debugging libraries will abort in many cases,
90 enabling you to find out what the cause is.
91
92 Once your program is up and running reliably, you can replace 'aldmd' with
93 'aldmb' and 'dumbd' with 'dumb'. Don't forget to do this, or DUMB will be
94 a lot slower than it should be!
95
96
973. As you use DUMB, it may claim system resources (memory in particular). You
98 will need to arrange for these resources to be freed at the end. Doing so
99 is very easy. Simply write the following line at the top of your main
100 function, but below allegro_init() if you are using Allegro:
101
102 atexit(&dumb_exit);
103
104 This arranges for the function dumb_exit() to be called when your program
105 exits; you do not need to call dumb_exit() yourself. This method is
106 preferable to calling dumb_exit() manually, as it will free resources even
107 if your program aborts unexpectedly.
108
109 If you are happy with this, please skip ahead to Step 4. If you are
110 interested in alternative methods, read on, but read on carefully.
111
112 In fact it mostly doesn't matter where you put the above atexit() line,
113 provided it gets called only once, and before you do anything with DUMB.
114 If you are using DUMB with Allegro, it is recommended that you write the
115 functions in this order:
116
117 allegro_init();
118 atexit(&dumb_exit);
119
120 And then you must NOT call allegro_exit() yourself (because it has to be
121 called after dumb_exit()). Alternatively, if you prefer not to use
122 atexit() (or you cannot), you will have to do the following before
123 exiting:
124
125 dumb_exit();
126 allegro_exit();
127
128
1294. DUMB does not automatically do any of its own file input. You have to tell
130 it how to read files. Don't worry, it's easy. Simply call the following
131 function near the beginning of your program, after your atexit() call:
132
133 dumb_register_stdfiles();
134
135 This tells DUMB to use ordinary stdio FILE structs for reading and writing
136 files. If you are using Allegro and would rather DUMB used PACKFILEs, call
137 the following function INSTEAD:
138
139 dumb_register_packfiles();
140
141 In the latter case, DUMB will be affected by any password you set with
142 packfile_password() in the same way that other PACKFILEs are.
143
144 Note that the procedure for loading datafiles with embedded music is
145 independent of these two functions; even if you will be loading datafiles,
146 you can use either of these functions. If you are loading datafiles, your
147 executable might be slightly smaller if you use dumb_register_packfiles().
148 On the other hand, dumb_register_stdfiles() will probably be faster. If
149 you are only ever going to load datafiles and never stand-alone files, you
150 can actually leave this step out; but I would recommend you put this in,
151 test your code with a stand-alone file, then follow the instructions in
152 the next section in order to adapt your code to use the datafile (you will
153 be reminded that you can remove the function call).
154
155
1565. If you are using Allegro, you'll have to initialise Allegro's sound
157 system. In most cases the following line will do the job:
158
159 install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL);
160
161 You may like to initialise a MIDI driver though; see Allegro's docs for
162 details. Put this line after allegro_init().
163
164
1656. All pieces of music are stored in memory in DUH structs. To handle these,
166 you must define pointers to them. Such pointers look like this:
167
168 DUH *myduh;
169
170 You can of course replace 'myduh' with anything you like. If you are
171 unfamiliar with pointers, please see ptr.txt. It is very important that
172 you understand these if you wish to use DUMB correctly.
173
174 You do not have direct access to the contents of a DUH struct, so do not
175 try. DUMB's functions provide everything you need; if you disagree, please
176 let me know and I shall see what I can do. Contact details are at the end
177 of this file.
178
179 Given the above definition, you can load a piece of music using one of the
180 following lines, depending on what file format you want to load:
181
182 myduh = dumb_load_it("a_one.it");
183 myduh = dumb_load_xm("a_two.xm");
184 myduh = dumb_load_s3m("a_one_two.s3m");
185 myduh = dumb_load_mod("three_four.mod");
186
187 Obviously you can use relative or absolute paths as normal. You should
188 always use forward slash (/), not backslash (\), when coding in C and
189 similar languages.
190
191 Every piece of music you load must be unloaded when you've finished with
192 it. When you type the above line in, it is good practice to type the
193 following line in at the same time, but put it at the end of the program:
194
195 unload_duh(myduh);
196
197 You will now be able to use the DUH struct anywhere in between the two
198 lines you just added. There is no need to check the return value; if the
199 DUH failed to load for one reason or another (this could be due to lack of
200 memory as well as the file not being there), then DUMB will do nothing -
201 safely.
202
203
2047. From this step onwards, it will be assumed you're using Allegro. If not,
205 please read these steps anyway, and then see the section entitled
206 "Rendering music into a buffer". You will have to write your own playback
207 code using whatever sound output system is available. Alternatively you
208 may like to write data to a file (especially if you have a file that
209 consumes a lot of processor time), but beware that any streaming audio
210 format is likely to be substantially larger than the module file you
211 generate it from, and formats like MP3 will be lower quality. You might
212 not be able to hear the difference between the MP3 and the original, but
213 many people can and don't like it, so please consider them. I'm one of
214 them. If you really want to use a lossy compression format, I highly
215 recommend Ogg Vorbis:
216
217 http://www.vorbis.com/
218
219 But I digress.
220
221 In order to play the DUH you loaded, you need to define a pointer to an
222 AL_DUH_PLAYER struct:
223
224 AL_DUH_PLAYER *dp;
225
226 Two of the functions you will need are prototyped as follows:
227
228 AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos,
229 float volume, long bufsize, int freq);
230
231 void al_stop_duh(AL_DUH_PLAYER *dp);
232
233 As you can see, al_start_duh() returns a pointer to an AL_DUH_PLAYER
234 struct when you call it. You then pass this pointer to all the other
235 functions. Again, if it is a NULL pointer for whatever reason (usually
236 lack of memory), DUMB will safely do nothing. When you call al_stop_duh(),
237 the pointer becomes invalid and you should not use it again; if there's
238 any risk of the pointer being used again, it is wise to set it to NULL at
239 this point. You can reassign the variable with a new call to
240 al_start_duh() of course.
241
242 Set 'n_channels' to 1 or 2 for mono or stereo respectively. Note that this
243 parameter has nothing to do with the number of samples that can play at
244 once in a music module. Set 'pos' to 0 to play from the beginning; each
245 time you add 65536, you will have advanced one second into the piece. As a
246 general rule, set the volume to 1.0f and adjust it later if the music is
247 too loud or too quiet - but see Allegro's set_volume_per_voice() function
248 first.
249
250 'bufsize' can generally be set to 4096. If your music stutters, try
251 increasing it; if your game freezes periodically, try reducing it. Find a
252 happy medium. Set 'freq' to 48000 for the best quality, though 44100 will
253 do in most cases. 22050 will be fine for a lot of music, though 11025 may
254 sound muffled. You can choose any other value, higher, lower or in
255 between. If your music stutters, and increasing 'bufsize' doesn't fix it,
256 try reducing this value.
257
258 Once you have put in a call to al_start_duh(), it is good practice to
259 insert the call to al_stop_duh() at the same time. You must call
260 al_stop_duh() before the DUH is unloaded (unload_duh(), Step 6 above).
261
262 Don't get impetuous, your program is not ready yet! Proceed to Step 8.
263
264
2658. DUMB does not play music in the background for you; if you were expecting
266 it to do so, please see the explanation at the end of this step. For your
267 music to be played, you have to call another function at regular
268 intervals. Here is its prototype:
269
270 int al_poll_duh(AL_DUH_PLAYER *dp);
271
272 Do NOT call this function from inside a timer function unless you really
273 know what you are doing. The reasons why this is bad are explained
274 further down. You should call it from your main program.
275
276 Simply writing the following line will be sufficient in general, if you
277 have a variable 'dp' that points to your AL_DUH_PLAYER struct.
278
279 al_poll_duh(dp);
280
281 As a general rule, calling this once for each logic update will do the
282 trick. If, however, you are executing time-consuming algorithms such as
283 software 3D rendering, you may wish to insert calls to this function in
284 the middle of those algorithms. You cannot call this function too often
285 (within reason); if it has nothing to do it will return immediately.
286
287 Exactly how often you need to call the function depends on the values for
288 'bufsize' and 'freq' that you passed to al_start_duh():
289
290 n = freq / bufsize;
291
292 You have to call al_poll_duh() at least n times a second. Do not hesitate
293 to call it more often for safety; if the sound stutters, you may need to
294 do just that. (Or you may need to increase the buffer size or reduce the
295 quality settings; the only way to find out is to try.)
296
297 For now, don't worry about al_poll_duh()'s return value. As soon as you
298 need it, it will be explained.
299
300 If you are happy, please skip to Step 9. If you were expecting DUMB to
301 play your music in the background, please read on.
302
303 The natural way to play music in the background on most operating systems
304 nowadays is to use threads. DOS was not built with multithreading in mind,
305 and its system operations (notably disk access) assume they will only be
306 used from a single thread.
307
308 Interrupts are the next best thing to threads. A DOS hardware interrupt
309 could be triggered at any moment, and a handler function will be called.
310 This is how Allegro's timer functions work. Unfortunately, what you can do
311 inside an interrupt handler is very limited. For one thing, all code and
312 data used by the handler must be locked in memory; if not, it could get
313 written to disk (virtual memory). If the main program was accessing the
314 disk when it got interrupted, the system would then die a horrible death.
315 This precludes the possibility of allocating extra memory inside the
316 handler, and DUMB does a lot of that in al_poll_duh().
317
318 Given DUMB's architecture, which cannot change for reasons which will
319 become apparent in future versions, this renders it impossible to come up
320 with a portable solution for making DUMB play music in the background.
321 Having said that, if you wish to write your own wrapper for al_poll_duh()
322 and use it in a thread, there is nothing stopping you. If you do do this,
323 you will have to be very careful when stopping the music; see the
324 description of al_poll_duh() in dumb.txt for more information.
325
326 So why not kill DOS? It is all too common a practice among programmers to
327 quote the phrase, "DOS is as dead as the dodo." Despite being a decidedly
328 derisible demonstation of the dreary device of alliteration, it shows a
329 distinct lack of experience. Many embedded systems still use DOS because
330 it provides hardware access capabilities and real-time possibilities
331 unparalleled by any current multitasking operating system. For an argument
332 closer to home, I used to use RHIDE for DOS before I switched to Linux,
333 and I have not found a single Freeware Windows IDE that measures up to
334 RHIDE. I'm sure many people are in the same boat, and really appreciate
335 DUMB's DOS port.
336
337 We will not be removing DOS support from DUMB. Any blind suggestions to do
338 so will be met with fiery flames. You have been warned.
339
340
3419. Test your program!
342
343 If you have trouble, check through the above steps to make sure you didn't
344 miss one out. Refer to faq.txt to see if your problem is addressed there.
345 If you still have trouble, contact me; details are at the end of this
346 file.
347
348
349**********************************
350*** Controlling music playback ***
351**********************************
352
353
354Here I describe some common operations you may wish to perform. The method
355for doing so will seem a bit strange sometimes, as will the names of the
356structs. However, there is a reason behind everything. If you would like to
357do more exotic things, or better understand some of the methods used here,
358then see dumb.txt, which covers everything from the ground up.
359
360
361To control playback quality:
362
363 #define DUMB_RQ_ALIASING
364 #define DUMB_RQ_LINEAR
365 #define DUMB_RQ_CUBIC
366 #define DUMB_RQ_N_LEVELS
367 extern int dumb_resampling_quality;
368 extern int dumb_it_max_to_mix;
369
370 Please note that dumb_resampling_quality has changed in DUMB v0.9.2. See
371 deprec.txt for more details on the change.
372
373 dumb_resampling_quality can be set to any of the DUMB_RQ_* constants
374 (except DUMB_RQ_N_LEVELS; see below). Resampling is the term given to the
375 process of adjusting a sample's pitch (in this context).
376 dumb_resampling_quality defaults to DUMB_RQ_CUBIC, which sounds nice but
377 takes a lot of processor power. Try reducing it if you have an older
378 computer or if you are trying to mix an insane number of samples (or
379 both!). See dumb.txt for details on what the different values actually do.
380
381 If you wish to give this option to your user, you can use
382 DUMB_RQ_N_LEVELS. All the values from 0 to DUMB_RQ_N_LEVELS - 1 will be
383 valid resampling levels. If a value outside this range is chosen, it is
384 not the end of the world; DUMB will behave as if you had chosen the value
385 at whichever extreme you went beyond.
386
387 dumb_it_max_to_mix, defaulting to 64, is the maximum number of samples
388 DUMB will ever mix together when playing an IT, XM, S3M or MOD file.
389 Unlike many other music systems, DUMB will still keep track of all samples
390 (up to a fixed maximum of 256 of them, roughly speaking), and then will
391 just render as many of them as this variable permits, starting with the
392 loudest ones. When samples are cut or come back in, the exact timings will
393 not generally be predictable - but nor will they be important.
394
395 dumb_it_max_to_mix applies to each currently playing module file
396 independently. So if you set it to 64, but render two modules
397 simultaneously, DUMB could end up mixing up to 128 samples.
398
399
400To pause and resume playback, set the volume, get the current playback
401position, or get the length of time a DUH will play for before either looping
402or freezing (effect F00 in XM and MOD files, which means no new notes will be
403played but any existing notes will continue):
404
405 void al_pause_duh(AL_DUH_PLAYER *dp);
406 void al_resume_duh(AL_DUH_PLAYER *dp);
407 void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume);
408 long al_duh_get_position(AL_DUH_PLAYER *dp);
409
410 long duh_get_length(DUH *duh);
411
412 These functions are pretty self-explanatory. The volume passed to
413 al_duh_set_volume() and the position returned by al_duh_get_position() are
414 in the same units as those you passed to al_start_duh(). The length
415 returned by duh_get_length() is in the same units as the aforementioned
416 position; see dumb.txt for more information on this function. Be careful
417 with al_duh_get_position(); it will return a position slightly ahead of
418 what you can hear, because the system has to keep ahead slightly to avoid
419 stuttering.
420
421
422To prevent the music from looping and/or freezing:
423
424 DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp);
425 DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer);
426
427 void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer,
428 int (*callback)(void *data), void *data);
429 void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer,
430 int (*callback)(void *data), void *data);
431
432 int dumb_it_callback_terminate(void *data);
433
434 If you are unfamiliar with function pointers, please see fnptr.txt.
435
436 Note that these functions apply to IT, XM, S3M and MOD files - not just to
437 IT files. This holds true throughout DUMB, for all functions with "it" in
438 the name. The xm_speed_zero event can only occur with XM and MOD files.
439
440 The first two functions will return a pointer to a struct contained by the
441 struct you pass. This system is necessary to ensure that these operations
442 are possible when not using Allegro. Typically you would write the
443 following code:
444
445 {
446 DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp);
447 DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sigrenderer);
448 dumb_it_set_loop_callback(itsr, &dumb_it_callback_terminate, NULL);
449 dumb_it_set_xm_speed_zero_callback
450 (itsr, &dumb_it_callback_terminate, NULL);
451 }
452
453 Once you have done this, the return value of al_poll_duh() becomes
454 significant. It will be 0 as long as the music is playing. When the music
455 stops, al_poll_duh() will return nonzero. You can call al_stop_duh() and
456 do something else as soon as you wish, but calling al_poll_duh() some more
457 will not do any harm.
458
459 al_poll_duh() will also return 1 if the music could not be loaded, or if
460 memory was short when trying to play it, or if it was a quirky music file
461 with no music in it (technically one with an empty order list). This
462 happens regardless of whether or not you execute the above code to disable
463 looping. Normally you shouldn't need to worry about this.
464
465 To undo the above and make DUMB loop or freeze again, pass NULL instead of
466 &dumb_it_callback_terminate. If you would like to fade on looping, or loop
467 a finite number of times, or display a message when looping, or whatever,
468 you will have to write your own callback function. In this case, please
469 see dumb.txt.
470
471 Note that the above code can safely be applied for a DUH that doesn't
472 contain a music module but contains some other kind of music.
473 duh_get_it_sigrenderer() will return NULL, and the code will do nothing.
474
475
476To analyse the audio as it's generated:
477
478 typedef int sample_t;
479
480 typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data,
481 const sample_t *const *samples, int n_channels, long length);
482
483 void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer,
484 DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data);
485
486 If the above confuses you, see fnptr.txt. These functions, along with
487 al_duh_get_sigrenderer() from the last section, enable you to register a
488 callback function. Every time some samples are generated, they will be
489 passed to this function. This enables you to display an oscilloscope or
490 spectrum analyser, for example.
491
492 Beware: your callback function may occasionally be called with
493 samples == NULL. This means the main program has decided to skip through
494 the music without generating any data. You should handle this case
495 elegantly, typically by returning immediately, but you may wish to make a
496 note of the fact that the music is being skipped, for whatever reason.
497
498 Beware again: if the main program ever calls duh_sigrenderer_get_samples()
499 on a buffer that isn't all silence, this callback function will be passed
500 the existing buffer after mixing, and thus it will include the original
501 data. This will not be an issue if you stick to duh_render(), which always
502 starts with a buffer filled with silence.
503
504 The samples array is two-dimensional. Refer to it as follows:
505
506 samples[channel_number][sample_position]
507
508 where 0 <= channel_number < n_channels,
509 and 0 <= sample_position < length.
510
511 In addition you can pass any 'data' pointer you like to
512 duh_sigrenderer_set_analyser_callback(), and this pointer will be relayed
513 to your callback function each time.
514
515 To remove the callback function, pass NULL to
516 duh_sigrenderer_set_analyser_callback().
517
518
519Everything below this point assumes some knowledge of how a music module is
520constructed. If you do not have this knowledge, talk to whoever is writing
521music for you, or download a tracking program and play with it (see
522readme.txt).
523
524
525To start playing an IT, XM, S3M or MOD from an arbitrary order number (the
526default being 0, the beginning of the song), use the following:
527
528 DUH_SIGRENDERER *dumb_it_start_at_order
529 (DUH *duh, int n_channels, int startorder);
530 AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer
531 (DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq);
532
533 The usage of these functions is as follows:
534
535 {
536 DUH_SIGRENDERER *sr = dumb_it_start_at_order
537 (duh, n_channels, startorder);
538 dp = al_duh_encapsulate_sigrenderer(sr, volume, bufsize, freq);
539 }
540
541 Replace 'dp' with whatever your AL_DUH_PLAYER pointer is. You also need
542 to insert suitable values for n_channels, startorder, volume, bufsize and
543 freq. These have the same meaning as those passed to al_start_duh().
544
545 WARNING: after passing a pointer to an "encapsulate" function, do not use
546 that pointer again. (More specifically, do not use it again if
547 the function returns NULL, because the function will have
548 destroyed the pointer if this happens, to help prevent memory
549 leaks.) There will be a "get" function with which you can obtain
550 the original pointer if it is still valid, or NULL otherwise.
551
552 The above functions will fail (safely) if you try to use them with a DUH
553 that contains a different type of music.
554
555 Notice that there is no 'pos' parameter. If you would like to skip through
556 the music, you can use this function:
557
558 long duh_sigrenderer_get_samples(
559 DUH_SIGRENDERER *sigrenderer,
560 float volume, float delta,
561 long size, sample_t **samples
562 );
563
564 Pass 0 for volume and NULL for samples, and this function will skip
565 through the music nice and quickly. So insert the following between the
566 two above statements:
567
568 duh_sigrenderer_get_samples(sr, 0, 65536.0f / freq, pos, NULL);
569
570 Substitute for 'freq' and 'pos'. An explanation of the 'delta' parameter
571 can be found further down in this file.
572
573 Finally, note that duh_get_length() is only meaningful when you start
574 playing music from order 0.
575
576
577If an IT file contains Zxx effects, DUMB will generate MIDI messages, which
578will control the low-pass resonant filters unless the IT file actively
579specifies something else. In rare cases this may not be what the Zxx effects
580were intended to do; if this is the case, you can block the MIDI messages as
581follows. Note that this does NOT mean filters are disabled; if an instrument
582specifies initial cut-off and resonance values, or has a filter envelope,
583then filters will be applied. It only makes sense to use this procedure at
584the beginning of playback.
585
586 void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer,
587 int (*callback)(void *data, int channel, unsigned char byte),
588 void *data);
589
590 int dumb_it_callback_midi_block(void *data, int channel,
591 unsigned char byte);
592
593 Using some functions described in the previous section, we arrive at the
594 following code:
595
596 {
597 DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp);
598 DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sigrenderer);
599 dumb_it_set_midi_callback(itsr, &dumb_it_callback_midi_block, NULL);
600 }
601
602DUMB offers no way of disabling filters completely. Disabling filters is not
603recommended as a means to reduce processor usage, as it will completely
604damage any piece of music that uses the filters. If you want lower processor
605consumption, use a piece of music that does not use filters.
606
607
608Finally, DUMB offers a myriad of functions for querying and adjusting
609module playback. Those beginning with "dumb_it_sd" operate on the
610DUMB_IT_SIGDATA struct, which represents the piece of music before it starts
611to play. Those beginning with "dumb_it_sr" operate on the DUMB_IT_SIGRENDERER
612struct, which represents a currently playing instance of the music. Note that
613duh_get_length(), described above, becomes meaningless after some of these
614functions are used.
615
616The method for getting a DUMB_IT_SIGRENDERER struct has already been given,
617but the function prototypes are repeated here for convenience:
618
619 DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp);
620 DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer);
621
622Getting a DUMB_IT_SIGDATA struct is simpler:
623
624 DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh);
625
626For a list of dumb_it_sd_*() and dumb_it_sr_*() functions, please see
627dumb.txt. These functions are new, and may not provide exactly what you need;
628if not, please let me know.
629
630
631**************************************************
632*** Embedding music files in Allegro datafiles ***
633**************************************************
634
635
636In this section it is assumed you are already reasonably familiar with how
637Allegro datafiles are used. If not, please refer to Allegro's documentation.
638At the time of writing, the documentation you need is off the beaten track,
639so to speak, in allegro/tools/grabber.txt.
640
641To add a piece of music to a datafile, you need to create an object of type
642"IT ", "XM ", "S3M " or "MOD " (note the spaces used as padding, although
643you do not need to type these into the grabber). Then grab the piece of music
644in. The grabber will treat it as a binary object. Save the datafile as usual.
645
646
647To use a piece of music you added to the datafile, follow these steps:
648
649
6501. Before loading the datafile, call one or more of these functions,
651 depending on which music format or formats you'd like to support:
652
653 dumb_register_dat_it(DUMB_DAT_IT);
654 dumb_register_dat_xm(DUMB_DAT_XM);
655 dumb_register_dat_s3m(DUMB_DAT_S3M);
656 dumb_register_dat_mod(DUMB_DAT_MOD);
657
658 Remember, do not call multiple functions unless you want to support
659 multiple formats. Calling more functions will add unused code to your
660 executable.
661
662 It is important that you make call these before loading the datafile,
663 since they tell Allegro how to load the respective files straight from
664 datafiles in the future. They will not help Allegro interpret any module
665 files that have already been loaded as binary objects (but if you really
666 need to interpret a module that has been loaded in this fashion, have a
667 look at dumbfile_open_memory() in dumb.txt).
668
669 If for whatever reason your music objects are identified by a different
670 type in the datafile, you can tell DUMB what that type is by changing the
671 parameter to the registration function above. Use Allegro's DAT_ID()
672 macro, e.g. DAT_ID('B','L','A','H'). This is not really recommended
673 though, since it would prevent a hypothetical grabber plug-in from being
674 able to play your music files. Use the above types if possible.
675
676
6772. Whenever you need a pointer to a DUH struct, simply use the 'dat' field.
678 Do this in the same way you would for a pointer to a BITMAP struct or
679 anything else. If it makes you feel more comfortable, you can extract the
680 pointer in advance:
681
682 DATAFILE *dat = load_datafile("smurf.dat");
683 if (!dat) abort(); /* There are much nicer ways of handling failure! */
684 DUH *myduh = (DUH *)dat[GAME_MUSIC].dat;
685
686 Note that the explicit (DUH *) cast is only necessary for C++, not for C.
687 However, it does no harm.
688
689 Be sure that you do NOT call unload_duh() for anything stored in the
690 datafile. These DUHs will be freed when you call unload_datafile(), and
691 freeing them twice is practically guaranteed to crash your program.
692
693
6943. If you only ever load music as part of a datafile, and you never load any
695 stand-alone music files, you do not need to register a file input system
696 for DUMB to use. If you followed the instructions for the first section
697 you will have one of these two lines in your program:
698
699 dumb_register_stdfiles();
700 dumb_register_packfiles();
701
702 You can safely delete this line - but only if you never load any
703 stand-alone music files. The debugging library will bale you out if you
704 delete it when you shouldn't; the optimised library won't.
705
706
707*************************************
708*** Rendering music into a buffer ***
709*************************************
710
711
712NOTE: much of the API formerly described in this section has been deprecated,
713 and you will need to alter your code. See deprec.txt for details. If
714 you are reading this section for the first time, you can ignore this
715 note.
716
717Rendering to a buffer is similar to playing using an AL_DUH_PLAYER. However,
718you must use a DUH_SIGRENDERER struct instead. Here are the functions:
719
720 DUH_SIGRENDERER *duh_start_sigrenderer
721 (DUH *duh, int sig, int n_channels, long pos);
722
723 int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);
724 long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer);
725
726 long duh_sigrenderer_get_samples(DUH_SIGRENDERER *sigrenderer,
727 float volume, float delta, long size, sample_t **samples);
728
729 long duh_render(DUH_SIGRENDERER *sigrenderer,
730 int bits, int unsign, float volume, float delta, long size, void *sptr);
731
732 void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer);
733
734The parameters to duh_start_sigrenderer() have the same meanings as those to
735al_start_duh(). However, note that the volume is not set at this stage. You
736pass the desired volume each time you want to render a block. The 'sig'
737parameter should be set to 0 for now.
738
739Notice that there are two rendering functions. duh_sigrenderer_get_samples()
740will generate samples in the internal 32-bit format, with a normal range from
741-0x800000 to 0x7FFFFF and with each channel in a separate array; duh_render()
742will convert to 8 or 16 bits, signed or unsigned, with stereo samples
743interleaved, left first.
744
745When you call duh_render(), pass 8 or 16 for 'bits'. If you pass 8, 'sptr' is
746expected to be an array of chars. If you pass 16, 'sptr' is expected to be an
747array of shorts. Endianness therefore depends on the platform, and you should
748not try to interpret 16-bit wave data as an array of chars (unless you're
749writing highly system-specific code anyway). Because DUMB renders internally
750with 32 bits, there is no significant speed increase in rendering an 8-bit
751stream.
752
753If you are rendering in stereo, make sure your 'sptr' array is twice as big!
754
755If you set 'unsign' to a nonzero value, then the samples generated will be
756centred on 0x80 or 0x8000, suitably stored in an array of unsigned chars or
757unsigned shorts. If 'unsign' is zero, the samples will be centred on 0,
758suitably stored in an array of signed chars or signed shorts. Note that 8-bit
759WAV files are unsigned while 16-bit WAV files are signed. This convention was
760used by the SoundBlaster 16 when receiving samples to be sent to the
761speakers. If you wish to write 16-bit sample data to a WAV file, don't use
762fwrite(); instead, take the shorts one at a time, split them up into chars as
763follows, and write the chars to the file.
764
765 short sptr[n];
766 char lsb = (char)sptr[n];
767 char msb = (char)(sptr[n] >> 8);
768
769For a 16-bit WAV file, write the LSB (less significant byte) first.
770
771The following applies equally to duh_render() and
772duh_sigrenderer_get_samples(), except where otherwise stated.
773
774If you set 'delta' to 1.0f, the sound generated will be suitable for playback
775at 65536 Hz. Increasing 'delta' causes the wave to speed up, given a constant
776sampling rate for playback. Supposing you want to vary the playback sampling
777rate but keep the pitch constant, here's the equation for 'delta':
778
779 delta = 65536.0f / sampling_rate;
780
781'size' is the number of samples you want rendered. For duh_render(), they
782will be rendered into an array which you pass as 'sptr'. Note that stereo
783samples count as one; so if you set n_channels to 2, your array must contain
784(2 * size) elements.
785
786For duh_sigrenderer_get_samples() you will have to use the following
787functions:
788
789 sample_t **create_sample_buffer(int n_channels, long length);
790 void destroy_sample_buffer(sample_t **samples);
791
792 void dumb_silence(sample_t *samples, long length);
793
794create_sample_buffer() allocates the channels sequentially in memory, so the
795following technique is valid:
796
797 sample_t **samples = create_sample_buffer(n_channels, length);
798 dumb_silence(samples[0], n_channels * length);
799
800It is necessary to fill the buffer with silence like this because
801duh_sigrenderer_get_samples() mixes what it renders with the existing
802contents of the buffer.
803
804The return values from duh_render() and duh_sigrenderer_get_samples() tell
805you how many samples were actually generated. In most cases, this will be the
806same as the 'size' parameter. However, if you reach the end of the DUH (which
807will happen if you disable looping or freezing as described further up), this
808function will return less. When that happens, you can assume the stream has
809finished. In the case of duh_render(), the remainder of the array will not
810have been initialised, so you either have to initialise it yourself or avoid
811using it.
812
813If for whatever reason duh_start_sigrenderer() returns NULL, then
814duh_render() and duh_sigrenderer_get_samples() will generate exactly 0
815samples, duh_sigrenderer_get_n_channels() will return 0,
816duh_sigrenderer_get_position() will return -1, and duh_end_sigrenderer() will
817safely do nothing.
818
819
820*********************
821*** Miscellaneous ***
822*********************
823
824
825Please see dumb.txt for an API reference and for information on thread safety
826with DUMB. The API reference has been stripped down, since some functions and
827variables are subject to change. If something does not appear in dumb.txt,
828please do not use it.
829
830
831******************
832*** Conclusion ***
833******************
834
835
836If you have any difficulties, or if you use DUMB successfully, please don't
837hesitate to contact me (see below).
838
839Enjoy!
840
841
842Ben Davis
843entheh@users.sf.net
844IRC EFnet #dumb
845See readme.txt for details on using IRC.
diff --git a/apps/codecs/dumb/docs/modplug.txt b/apps/codecs/dumb/docs/modplug.txt
deleted file mode 100644
index a02ddd8bdd..0000000000
--- a/apps/codecs/dumb/docs/modplug.txt
+++ /dev/null
@@ -1,137 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * modplug.txt - Our official position regarding / / \ \
12 * compatibility with ModPlug | < / \_
13 * Tracker. | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20
21********************
22*** Introduction ***
23********************
24
25ModPlug Tracker is a very popular tracker for Windows. Its popularity is due
26to the intuitive interface and its many advanced features. The author has
27done a good job with this piece of software, but sadly in doing so he has
28desecrated the IT file format.
29
30I am not against ModPlug Tracker being used to write music modules. As
31already stated, it has some very advanced and convenient features; I use it
32myself. However, I believe its users should be aware of the entire situation
33before using it for any serious work.
34
35 ModPlug Tracker - http://www.modplug.com/
36
37
38*************************
39*** Incompatibilities ***
40*************************
41
42There are a few situations in which ModPlug Tracker misinterprets the
43original module formats. I shall list the five I am most aware of, from least
44to most annoying:
45
465. Create a multisample instrument, for example a piano. Play a low note.
47 Then go up the scale, but in the pattern data, make sure the instrument
48 column is blank; put in only the notes. Play this with ModPlug Tracker,
49 and play it with Impulse Tracker. Impulse Tracker changes sample as you go
50 up the scale; ModPlug Tracker does not.
51
524. Arpeggio and Retrigger Note effects behave badly when combined with
53 Portamento, which can appear in the volume column. While Retrigger Note
54 isn't too bad, Arpeggio sounds completely wrong. Try it and see what
55 happens. Then repeat the experiment in Impulse Tracker.
56
573. The filter algorithm is incorrect, in more ways than one. When Jeffrey Lim
58 programmed the low-pass resonant filters into Impulse Tracker, he used a
59 standard filter algorithm with a slight modification to achieve greater
60 resonance. ModPlug Tracker does not incorporate this modification.
61 Furthermore, ModPlug Tracker uses integer arithmetic with nowhere near
62 enough precision; the wave output is really poor in some cases. I don't
63 doubt it damages the acoustic properties of the filters in subtle ways.
64
652. When looping, ModPlug Tracker resets all variables. The original trackers
66 do not do this.
67
681. Worst of all, ModPlug Tracker has no regard for playback volume, and
69 generally has a much lower output level than the original trackers.
70
71Cases 3, 2 and 1 lead people to write IT files that play badly in the
72original trackers. If some of these problems could be fixed, I'd be all for
73it - but these problems have been reported to the author and he had no
74motivation to fix them. ModPlug Tracker has been around long enough that
75fixing 3, 2 and 1 would be detrimental to too many people's music.
76
77
78******************
79*** Extensions ***
80******************
81
82Worse than the incompatibilities are the extensions ModPlug Tracker makes,
83mostly to the IT format. DUMB currently supports one of these extensions,
84namely stereo samples, but supporting the others is not high on my list of
85priorities.
86
87Other extensions ModPlug Tracker has provided mostly take the form of extra
88effects. For instance, S98 and S99 can be used to enable or disable reverb. I
89believe the latest versions of ModPlug Tracker offer alternative types of
90filter, such as high-pass and band-pass. As soon as an IT file uses any of
91these features, it will play incorrectly with Impulse Tracker.
92
93By far the most evil extension provided by ModPlug Tracker is the effect
94plug-ins. These enable IT files to use VST effects. I recently downloaded an
95IT file that uses some effects from a collection named "DirectX Media Audio
96Effects". When can we expect these effects to be ported to Linux?
97
98
99******************
100*** Conclusion ***
101******************
102
103ModPlug Tracker is trying to be two things at once. It wants to be an editor
104for the existing formats, but at the same time it wants to be proprietary,
105with all its own features and extensions. Unfortunately it is succeeding;
106there are many IT files out there that only play right in ModPlug Tracker. In
107my opinion, ModPlug Tracker should have come out with its own file format, in
108which all these extensions would have found a home.
109
110If you are going to use ModPlug Tracker's extensions, I recommend you
111ultimately convert your music to a streamed format such as Ogg Vorbis. (If
112you were thinking of using MP3, then don't - consider using Ogg Vorbis
113instead.) If you release IT files that use ModPlug Tracker's extensions,
114please state prominently that the files are designed to be played with
115ModPlug Tracker. Finally, don't ask me to support ModPlug Tracker's
116extensions; ModPlug Tracker's playback code is available for use in your
117games, so use that instead.
118
119 Ogg Vorbis - http://www.vorbis.com/
120
121Despite all the above problems, don't forget that ModPlug Tracker does have a
122lot of very useful features for editing files. These include a function for
123removing unused patterns, samples and instruments, drag-and-drop sample and
124instrument ripping, drop-down menus for selecting the effects by name without
125having to memorise the codes or refer to help, and lots of other nice things.
126I do recommend it as an editor, provided you make sure you are aware of the
127situation and do not use ModPlug Tracker's extensions or incompatibilities
128inadvertently.
129
130Oh, and by the way, save your final version with Impulse Tracker. Then the
131samples will be compressed for you!
132
133
134Ben Davis
135entheh@users.sf.net
136IRC EFnet #dumb
137See readme.txt for details on using IRC.
diff --git a/apps/codecs/dumb/docs/ptr.txt b/apps/codecs/dumb/docs/ptr.txt
deleted file mode 100644
index 0eb42ccf02..0000000000
--- a/apps/codecs/dumb/docs/ptr.txt
+++ /dev/null
@@ -1,129 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * ptr.txt - Pointer explanation. / / \ \
12 * | < / \_
13 * | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20
21A pointer is a small variable (often the same size as an int BUT NOT ALWAYS)
22that holds the address of something in memory. You create a pointer by adding
23a * to a variable, as follows:
24
25 int x, *y;
26
27 x = 5;
28 y = &x;
29
30The & means 'address of', so &x gives us a pointer to x. We are storing it in
31y.
32
33 (*y)++;
34
35The * here means 'value at'. It's known as the 'dereferencing' operator. When
36written before a pointer, as it is here, it allows you to treat the value
37like a normal variable. In this case we are incrementing the value. If we
38look at x, we'll find that it now contains 6, not 5.
39
40 y++;
41
42Here we are incrementing the pointer itself. This is useful for traversing
43through an array, but in this particular example it is not much use.
44
45 *y++;
46
47Beware; this will increment the pointer, not the value stored there. It will
48return the value stored at the pointer (before incrementing the pointer), so
49you can use this in a bigger expression. This is why we needed brackets in
50the first example.
51
52Note that you will not need these three examples when working with DUMB; they
53are simply to help illustrate the idea of pointers.
54
55Also be aware that when defining pointers you attach the * to the variable,
56not to the type. The following example will create a pointer and an int, not
57two pointers:
58
59 int *a, b;
60
61That is why I believe it's a good idea to put a space before the * and not
62after it, although programmers are divided on this.
63
64 y = 0;
65 y = NULL;
66
67These two statements are equivalent. 0, or NULL, is a special value that is
68guaranteed to have a different value from any valid pointer. This is most
69often used to indicate that something doesn't point anywhere. DUMB's
70functions may return it on occasion. However, in simple usage of DUMB, you
71will not actually need to check for it.
72
73Some of DUMB's functions return pointers to structs. (A struct is an
74aggregration of other variables, such as ints, pointers, or other structs.
75You can generally treat a struct as a single unit.) Here's an example of such
76a function:
77
78 DUH *dumb_load_it(const char *filename);
79
80You do not know what the DUH struct actually contains; dumb.h and aldumb.h
81only give the compiler enough information to deal with pointers to them. DUMB
82will take charge of everything that happens inside a DUH struct.
83
84The above function will create a DUH struct for you. First it allocates
85the memory it needs, then it fills the struct with data, then it returns a
86pointer. This DUH struct will contain the data necessary to play an IT file.
87You can define a suitable variable and store the pointer in it as follows:
88
89 DUH *duh = dumb_load_it("music.it");
90
91Or this can be split up:
92
93 DUH *duh;
94 duh = dumb_load_it("music.it");
95
96In order to use this DUH struct later, you must pass its pointer to other
97functions. To pass the pointer to a function, simply write 'duh' for the
98appropriate parameter.
99
100When you've finished with a DUH struct (this applies equally to the other
101structs DUMB deals with), you must pass it to an appropriate function for
102freeing up the memory:
103
104 unload_duh(duh);
105
106After you've done this, the memory will no longer be allocated, and the
107pointer will have no meaning. You may wish to set it to NULL at this point
108for safety. Alternatively just be sure not to use the present value of the
109pointer any more. You can of course assign a new value to the pointer, e.g.
110by calling dumb_load_it() again.
111
112Note the following:
113
114 DUH *duh2 = duh;
115
116This only duplicates the pointer, not the DUH itself. You still only have one
117copy of the DUH. There is no way of duplicating a DUH, short of loading it
118twice. This is not a problem, because DUMB can play it 'twice at the same
119time' anyway.
120
121That should be all you need to know about pointers in order to use DUMB. If
122there's anything you feel should be explained better here, or anything else
123that should be added, please don't hesitate to let me know!
124
125
126Ben Davis
127entheh@users.sf.net
128IRC EFnet #dumb
129See readme.txt for details on using IRC.
diff --git a/apps/codecs/dumb/examples/dumb.ini b/apps/codecs/dumb/examples/dumb.ini
deleted file mode 100644
index 6fea2ce50f..0000000000
--- a/apps/codecs/dumb/examples/dumb.ini
+++ /dev/null
@@ -1,44 +0,0 @@
1# Please edit this file to control the playback quality for 'dumbplay'. Note
2# that this does not affect DUMB when you use it in your own programs; you
3# need to borrow some code from the example program in order to get that to
4# happen.
5
6# dumb_resampling_quality can be 0 for aliasing, 1 for linear interpolation
7# or 2 for cubic interpolation. See docs/dumb.txt for details on what these
8# terms mean.
9
10# dumb_it_max_to_mix is the maximum number of samples DUMB will render at a
11# time. See docs/dumb.txt for a more detailed description.
12
13# Increase buffer_size to combat stuttering.
14
15# The music module will be rendered at the sampling frequency specified by
16# sound_freq. This variable is also used by Allegro for initialising the
17# sound hardware.
18
19# buffer_size and sound_freq are passed directly to al_start_duh(). See this
20# function's description in docs/dumb.txt for information about how to use
21# these variables.
22
23# You can ignore the quality variable. Allegro uses it when relaying the
24# audio stream to the sound card. Only a masochist would set it lower than 2;
25# if your computer is powerful enough to run DUMB, it is powerful enough to
26# use this setting with Allegro.
27
28# For best results, choose a value for sound_freq that your sound card can do
29# exactly. See Allegro's docs, "Standard config variables", for details. If
30# you do not choose an exact value, Allegro will round it to the nearest
31# value it can do; then when DUMB plays the stream at a sampling frequency of
32# sound_freq, Allegro will have to resample it. Allegro's 'quality = 2'
33# setting is only comparable with DUMB's 'dumb_resampling_quality = 1'
34# setting. Therefore, in order to appreciate DUMB's cubic resampler fully,
35# you will need to make sure Allegro doesn't do any resampling, by choosing
36# an exact value for sound_freq.
37
38[sound]
39dumb_resampling_quality = 2
40dumb_it_max_to_mix = 256
41buffer_size = 4096
42sound_freq = 44100
43
44quality = 2
diff --git a/apps/codecs/dumb/examples/dumbout.c b/apps/codecs/dumb/examples/dumbout.c
deleted file mode 100644
index b0ead3dd5e..0000000000
--- a/apps/codecs/dumb/examples/dumbout.c
+++ /dev/null
@@ -1,335 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * dumbout.c - Utility to stream music to a file. / / \ \
12 * | < / \_
13 * By entheh. | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <time.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <ctype.h>
24#include <math.h>
25#include <string.h>
26#include <dumb.h>
27
28
29union {
30 short s16[8192];
31 char s8[16384];
32} buffer;
33
34
35int main(int argc, const char *const *argv) /* I'm const-crazy! */
36{
37 DUH *duh;
38 DUH_SIGRENDERER *sr;
39
40 const char *fn = NULL;
41 const char *fn_out = NULL;
42 FILE *outf;
43
44 int depth = 16;
45 int bigendian = 0;
46 int unsign = 0;
47 int freq = 44100;
48 int n_channels = 2;
49 float volume = 1.0f;
50 float delay = 0.0f;
51 float delta;
52 int bufsize;
53 clock_t start, end;
54
55 int i = 1;
56
57 LONG_LONG length;
58 LONG_LONG done;
59 int dots;
60
61 while (i < argc) {
62 const char *arg = argv[i++];
63 if (*arg != '-') {
64 if (fn) {
65 fprintf(stderr,
66 "Cannot specify multiple filenames!\n"
67 "Second filename found: \"%s\"\n", arg);
68 return 1;
69 }
70 fn = arg;
71 continue;
72 }
73 arg++;
74 while (*arg) {
75 char *endptr;
76 switch (*arg++) {
77 case 'o':
78 case 'O':
79 if (i >= argc) {
80 fprintf(stderr, "Out of arguments; output filename expected!\n");
81 return 1;
82 }
83 fn_out = argv[i++];
84 break;
85 case 'd':
86 case 'D':
87 if (i >= argc) {
88 fprintf(stderr, "Out of arguments; delay expected!\n");
89 return 1;
90 }
91 delay = (float)strtod(argv[i++], &endptr);
92 if (*endptr != 0 || delay < 0.0f || delay > 64.0f) {
93 fprintf(stderr, "Invalid delay!\n");
94 return 1;
95 }
96 break;
97 case 'v':
98 case 'V':
99 if (i >= argc) {
100 fprintf(stderr, "Out of arguments; volume expected!\n");
101 return 1;
102 }
103 volume = (float)strtod(argv[i++], &endptr);
104 if (*endptr != 0 || volume < -8.0f || volume > 8.0f) {
105 fprintf(stderr, "Invalid volume!\n");
106 return 1;
107 }
108 break;
109 case 's':
110 case 'S':
111 if (i >= argc) {
112 fprintf(stderr, "Out of arguments; sampling rate expected!\n");
113 return 1;
114 }
115 freq = strtol(argv[i++], &endptr, 10);
116 if (*endptr != 0 || freq < 1 || freq > 960000) {
117 fprintf(stderr, "Invalid sampling rate!\n");
118 return 1;
119 }
120 break;
121 case '8':
122 depth = 8;
123 break;
124 case 'b':
125 case 'B':
126 bigendian = 1;
127 break;
128 case 'm':
129 case 'M':
130 n_channels = 1;
131 break;
132 case 'u':
133 case 'U':
134 unsign = 1;
135 break;
136 case 'r':
137 case 'R':
138 if (i >= argc) {
139 fprintf(stderr, "Out of arguments; resampling quality expected!\n");
140 return 1;
141 }
142 dumb_resampling_quality = strtol(argv[i++], &endptr, 10);
143 if (*endptr != 0 || dumb_resampling_quality < 0 || dumb_resampling_quality > 2) {
144 fprintf(stderr, "Invalid resampling quality!\n");
145 return 1;
146 }
147 break;
148 default:
149 fprintf(stderr, "Invalid switch - '%c'!\n", isprint(arg[-1]) ? arg[-1] : '?');
150 return 1;
151 }
152 }
153 }
154
155 if (!fn) {
156 fprintf(stderr,
157 "Usage: dumbout [options] module [more-options]\n"
158 "\n"
159 "The module can be any IT, XM, S3M or MOD file. It will be rendered to a .pcm\n"
160 "file of the same name, unless you specify otherwise with the -o option.\n"
161 "\n"
162 "The valid options are:\n"
163 "-o <file> specify the output filename (defaults to the input filename with\n"
164 " the extension replaced with .pcm); use - to write to standard\n"
165 " output or . to write nowhere (useful for measuring DUMB's\n"
166 " performance, and DOS and Windows don't have /dev/null!)\n"
167 "-d <delay> set the initial delay, in seconds (default 0.0)\n"
168 "-v <volume> adjust the volume (default 1.0)\n"
169 "-s <freq> set the sampling rate in Hz (default 44100)\n"
170 "-8 generate 8-bit instead of 16-bit\n"
171 "-b generate big-endian data instead of little-endian (meaningless when\n"
172 " using -8)\n"
173 "-m generate mono output instead of stereo left/right pairs\n"
174 "-u generated unsigned output instead of signed\n"
175 "-r <value> specify the resampling quality to use\n");
176 return 1;
177 }
178
179 atexit(&dumb_exit);
180 dumb_register_stdfiles();
181
182 dumb_it_max_to_mix = 256;
183
184 duh = load_duh(fn);
185 if (!duh) {
186 duh = dumb_load_it(fn);
187 if (!duh) {
188 duh = dumb_load_xm(fn);
189 if (!duh) {
190 duh = dumb_load_s3m(fn);
191 if (!duh) {
192 duh = dumb_load_mod(fn);
193 if (!duh) {
194 fprintf(stderr, "Unable to open %s!\n", fn);
195 return 1;
196 }
197 }
198 }
199 }
200 }
201
202 sr = duh_start_sigrenderer(duh, 0, n_channels, 0);
203 if (!sr) {
204 unload_duh(duh);
205 fprintf(stderr, "Unable to play file!\n");
206 return 1;
207 }
208
209 if (fn_out) {
210 if (fn_out[0] == '-' && fn_out[1] == 0)
211 outf = stdout;
212 else if (fn_out[0] == '.' && fn_out[1] == 0)
213 outf = NULL;
214 else {
215 outf = fopen(fn_out, "wb");
216 if (!outf) {
217 fprintf(stderr, "Unable to open %s for writing!\n", fn_out);
218 duh_end_sigrenderer(sr);
219 unload_duh(duh);
220 return 1;
221 }
222 }
223 } else {
224 char *extptr = NULL, *p;
225 char *fn_out = malloc(strlen(fn)+5);
226 if (!fn_out) {
227 fprintf(stderr, "Out of memory!\n");
228 duh_end_sigrenderer(sr);
229 unload_duh(duh);
230 return 1;
231 }
232 strcpy(fn_out, fn);
233 for (p = fn_out; *p; p++)
234 if (*p == '.') extptr = p;
235 if (!extptr) extptr = p;
236 strcpy(extptr, ".pcm");
237 outf = fopen(fn_out, "wb");
238 if (!outf) {
239 fprintf(stderr, "Unable to open %s for writing!\n", fn_out);
240 free(fn_out);
241 duh_end_sigrenderer(sr);
242 unload_duh(duh);
243 return 1;
244 }
245 free(fn_out);
246 }
247
248 {
249 DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr);
250 dumb_it_set_loop_callback(itsr, &dumb_it_callback_terminate, NULL);
251 dumb_it_set_xm_speed_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
252 }
253
254 length = (LONG_LONG)duh_get_length(duh) * freq >> 16;
255 done = 0;
256 dots = 0;
257 delta = 65536.0f / freq;
258 bufsize = depth == 16 ? 8192 : 16384;
259 bufsize /= n_channels;
260
261 {
262 long l = (long)floor(delay * freq + 0.5f);
263 l *= n_channels * (depth >> 3);
264 if (l) {
265 if (unsign) {
266 if (depth == 16) {
267 if (bigendian) {
268 for (i = 0; i < 8192; i++) {
269 buffer.s8[i*2] = 0x80;
270 buffer.s8[i*2+1] = 0x00;
271 }
272 } else {
273 for (i = 0; i < 8192; i++) {
274 buffer.s8[i*2] = 0x00;
275 buffer.s8[i*2+1] = 0x80;
276 }
277 }
278 } else
279 memset(buffer.s8, 0x80, 16384);
280 } else
281 memset(buffer.s8, 0, 16384);
282 while (l >= 16384) {
283 if (outf) fwrite(buffer.s8, 1, 16384, outf);
284 l -= 16384;
285 }
286 if (l && outf) fwrite(buffer.s8, 1, l, outf);
287 }
288 }
289
290 start = clock();
291
292 fprintf(stderr, "................................................................\n");
293 for (;;) {
294 int l = duh_render(sr, depth, unsign, volume, delta, bufsize, &buffer);
295 if (depth == 16) {
296 if (bigendian) {
297 for (i = 0; i < l * n_channels; i++) {
298 short val = buffer.s16[i];
299 buffer.s8[i*2] = val >> 8;
300 buffer.s8[i*2+1] = val;
301 }
302 } else {
303 for (i = 0; i < l * n_channels; i++) {
304 short val = buffer.s16[i];
305 buffer.s8[i*2] = val;
306 buffer.s8[i*2+1] = val >> 8;
307 }
308 }
309 }
310 if (outf) fwrite(buffer.s8, 1, l * n_channels * (depth >> 3), outf);
311 if (l < bufsize) break;
312 done += l;
313 l = done * 64 / length;
314 while (dots < 64 && l > dots) {
315 fprintf(stderr, "|");
316 dots++;
317 }
318 }
319
320 while (64 > dots) {
321 fprintf(stderr, "|");
322 dots++;
323 }
324 fprintf(stderr, "\n");
325
326 end = clock();
327
328 duh_end_sigrenderer(sr);
329 unload_duh(duh);
330 if (outf && outf != stdout) fclose(outf);
331
332 fprintf(stderr, "Elapsed time: %f seconds\n", (end - start) / (float)CLOCKS_PER_SEC);
333
334 return 0;
335}
diff --git a/apps/codecs/dumb/examples/dumbplay.c b/apps/codecs/dumb/examples/dumbplay.c
deleted file mode 100644
index 6421cfdf34..0000000000
--- a/apps/codecs/dumb/examples/dumbplay.c
+++ /dev/null
@@ -1,238 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * dumbplay.c - Not-so-simple program to play / / \ \
12 * music. It used to be simpler! | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * IMPORTANT NOTE: This file is not very friendly. | ' /
17 * I strongly recommend AGAINST using it as a \__/
18 * reference for writing your own code. If you would
19 * like to write a program that uses DUMB, or add DUMB to an existing
20 * project, please use docs/howto.txt. It will help you a lot more than this
21 * file can. (If you have difficulty reading documentation, you are lacking
22 * an important coding skill, and now is as good a time as any to learn.)
23 */
24
25#include <stdlib.h>
26#include <allegro.h>
27
28#ifndef ALLEGRO_DOS
29#include <string.h>
30#endif
31
32/* Note that your own programs should use <aldumb.h> not "aldumb.h". <> tells
33 * the compiler to look in the compiler's default header directory, which is
34 * where DUMB should be installed before you use it (make install does this).
35 * Use "" when it is your own header file. This example uses "" because DUMB
36 * might not have been installed yet when the makefile builds it.
37 */
38#include "aldumb.h"
39
40
41
42#ifndef ALLEGRO_DOS
43static volatile int closed = 0;
44static void closehook(void) { closed = 1; }
45#else
46#define closed 0
47#endif
48
49#ifdef ALLEGRO_WINDOWS
50#define GFX_DUMB_MODE GFX_GDI
51#include <winalleg.h>
52#define YIELD() Sleep(1)
53#else
54#define GFX_DUMB_MODE GFX_AUTODETECT_WINDOWED
55#ifdef ALLEGRO_UNIX
56#include <sys/time.h>
57static void YIELD(void)
58{
59 struct timeval tv;
60 tv.tv_sec = 0;
61 tv.tv_usec = 1;
62 select(0, NULL, NULL, NULL, &tv);
63}
64#else
65#define YIELD() yield_timeslice()
66#endif
67#endif
68
69
70
71#ifdef ALLEGRO_DOS
72static int loop_callback(void *data)
73{
74 (void)data;
75 printf("Music has looped.\n");
76 return 0;
77}
78
79static int xm_speed_zero_callback(void *data)
80{
81 (void)data;
82 printf("Music has stopped.\n");
83 return 0;
84}
85#else
86static int gfx_half_width;
87
88static int loop_callback(void *data)
89{
90 (void)data;
91 if (gfx_half_width) {
92 acquire_screen();
93 textout_centre(screen, font, "Music has looped.", gfx_half_width, 36, 10);
94 release_screen();
95 }
96 return 0;
97}
98
99static int xm_speed_zero_callback(void *data)
100{
101 (void)data;
102 if (gfx_half_width) {
103 text_mode(0); /* In case this is overwriting "Music has looped." */
104 acquire_screen();
105 textout_centre(screen, font, "Music has stopped.", gfx_half_width, 36, 10);
106 release_screen();
107 }
108 return 0;
109}
110#endif
111
112
113
114static void usage(const char *exename)
115{
116 allegro_message(
117#ifdef ALLEGRO_WINDOWS
118 "Usage:\n"
119 " At the command line: %s file\n"
120 " In Windows Explorer: drag a file on to this program's icon.\n"
121#else
122 "Usage: %s file\n"
123#endif
124 "This will play the music file specified.\n"
125 "File formats supported: IT XM S3M MOD.\n"
126 "You can control playback quality by editing dumb.ini.\n", exename);
127
128 exit(1);
129}
130
131
132
133int main(int argc, const char *const *argv) /* I'm const-crazy! */
134{
135 DUH *duh;
136 AL_DUH_PLAYER *dp;
137
138 if (allegro_init())
139 return 1;
140
141 if (argc != 2)
142 usage(argv[0]);
143
144 set_config_file("dumb.ini");
145
146 if (install_keyboard()) {
147 allegro_message("Failed to initialise keyboard driver!\n");
148 return 1;
149 }
150
151 set_volume_per_voice(0);
152
153 if (install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL)) {
154 allegro_message("Failed to initialise sound driver!\n%s\n", allegro_error);
155 return 1;
156 }
157
158 atexit(&dumb_exit);
159
160 dumb_register_packfiles();
161
162 duh = dumb_load_it(argv[1]);
163 if (!duh) {
164 duh = dumb_load_xm(argv[1]);
165 if (!duh) {
166 duh = dumb_load_s3m(argv[1]);
167 if (!duh) {
168 duh = dumb_load_mod(argv[1]);
169 if (!duh) {
170 allegro_message("Failed to load %s!\n", argv[1]);
171 return 1;
172 }
173 }
174 }
175 }
176
177 dumb_resampling_quality = get_config_int("sound", "dumb_resampling_quality", 4);
178 dumb_it_max_to_mix = get_config_int("sound", "dumb_it_max_to_mix", 128);
179
180#ifndef ALLEGRO_DOS
181 {
182 const char *fn = get_filename(argv[1]);
183 gfx_half_width = strlen(fn);
184 if (gfx_half_width < 22) gfx_half_width = 22;
185 gfx_half_width = (gfx_half_width + 2) * 4;
186
187 /* set_window_title() is not const-correct (yet). */
188 set_window_title((char *)"DUMB Music Player");
189
190 if (set_gfx_mode(GFX_DUMB_MODE, gfx_half_width*2, 80, 0, 0) == 0) {
191 acquire_screen();
192 textout_centre(screen, font, fn, gfx_half_width, 20, 14);
193 textout_centre(screen, font, "Press any key to exit.", gfx_half_width, 52, 11);
194 release_screen();
195 } else
196 gfx_half_width = 0;
197 }
198
199#if ALLEGRO_VERSION*10000 + ALLEGRO_SUB_VERSION*100 + ALLEGRO_WIP_VERSION >= 40105
200 set_close_button_callback(&closehook);
201#else
202 set_window_close_hook(&closehook);
203#endif
204
205#endif
206
207 set_display_switch_mode(SWITCH_BACKGROUND);
208
209 dp = al_start_duh(duh, 2, 0, 1.0f,
210 get_config_int("sound", "buffer_size", 4096),
211 get_config_int("sound", "sound_freq", 44100));
212
213 {
214 DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp);
215 DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr);
216 dumb_it_set_loop_callback(itsr, &loop_callback, NULL);
217 dumb_it_set_xm_speed_zero_callback(itsr, &xm_speed_zero_callback, NULL);
218 }
219
220 for (;;) {
221 if (keypressed()) {
222 readkey();
223 break;
224 }
225
226 if (al_poll_duh(dp) || closed)
227 break;
228
229 YIELD();
230 }
231
232 al_stop_duh(dp);
233
234 unload_duh(duh);
235
236 return 0;
237}
238END_OF_MAIN();
diff --git a/apps/codecs/dumb/include/aldumb.h b/apps/codecs/dumb/include/aldumb.h
deleted file mode 100644
index dae2029316..0000000000
--- a/apps/codecs/dumb/include/aldumb.h
+++ /dev/null
@@ -1,93 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * aldumb.h - The user header file for DUMB with / / \ \
12 * Allegro. | < / \_
13 * | \/ /\ /
14 * Include this file if you wish to use DUMB \_ / > /
15 * with Allegro. It will include dumb.h for you, | \ / /
16 * and provide extra functionality such as audio | ' /
17 * stream and datafile integration. \__/
18 */
19
20#ifndef ALDUMB_H
21#define ALDUMB_H
22
23
24#include <allegro.h>
25
26#include "dumb.h"
27
28
29#ifdef __cplusplus
30 extern "C" {
31#endif
32
33
34/* Packfile Support */
35
36void dumb_register_packfiles(void);
37
38DUMBFILE *dumbfile_open_packfile(PACKFILE *p);
39DUMBFILE *dumbfile_from_packfile(PACKFILE *p);
40
41
42/* Datafile Registration Functions */
43
44#define DUMB_DAT_DUH DAT_ID('D','U','H',' ')
45#define DUMB_DAT_IT DAT_ID('I','T',' ',' ')
46#define DUMB_DAT_XM DAT_ID('X','M',' ',' ')
47#define DUMB_DAT_S3M DAT_ID('S','3','M',' ')
48#define DUMB_DAT_MOD DAT_ID('M','O','D',' ')
49
50void dumb_register_dat_duh(long type);
51void dumb_register_dat_it(long type);
52void dumb_register_dat_xm(long type);
53void dumb_register_dat_s3m(long type);
54void dumb_register_dat_mod(long type);
55
56
57/* DUH Playing Functions */
58
59typedef struct AL_DUH_PLAYER AL_DUH_PLAYER;
60
61AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos, float volume, long bufsize, int freq);
62void al_stop_duh(AL_DUH_PLAYER *dp);
63void al_pause_duh(AL_DUH_PLAYER *dp);
64void al_resume_duh(AL_DUH_PLAYER *dp);
65void al_duh_set_priority(AL_DUH_PLAYER *dp, int priority);
66void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume);
67int al_poll_duh(AL_DUH_PLAYER *dp);
68long al_duh_get_position(AL_DUH_PLAYER *dp);
69
70AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq);
71DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp);
72
73/* IMPORTANT: This function will return NULL if the music has ended. */
74DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp);
75
76#ifdef DUMB_DECLARE_DEPRECATED
77
78AL_DUH_PLAYER *al_duh_encapsulate_renderer(DUH_SIGRENDERER *dr, float volume, long bufsize, int freq) DUMB_DEPRECATED;
79DUH_SIGRENDERER *al_duh_get_renderer(AL_DUH_PLAYER *dp) DUMB_DEPRECATED;
80DUH_SIGRENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp) DUMB_DEPRECATED;
81/* Replace 'renderer' with 'sigrenderer' in each case where you called one of
82 * these functions.
83 */
84
85#endif
86
87
88#ifdef __cplusplus
89 }
90#endif
91
92
93#endif /* ALDUMB_H */
diff --git a/apps/codecs/dumb/include/dumb.h b/apps/codecs/dumb/include/dumb.h
deleted file mode 100644
index 2aae95ccce..0000000000
--- a/apps/codecs/dumb/include/dumb.h
+++ /dev/null
@@ -1,577 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * dumb.h - The user header file for DUMB. / / \ \
12 * | < / \_
13 * Include this file in any of your files in | \/ /\ /
14 * which you wish to use the DUMB functions \_ / > /
15 * and variables. | \ / /
16 * | ' /
17 * \__/
18 */
19
20#ifndef DUMB_H
21#define DUMB_H
22
23
24#include <stdlib.h>
25#include <stdio.h>
26
27
28#ifdef __cplusplus
29 extern "C" {
30#endif
31
32
33#define DUMB_MAJOR_VERSION 0
34#define DUMB_MINOR_VERSION 9
35#define DUMB_REVISION_VERSION 2
36
37#define DUMB_VERSION (DUMB_MAJOR_VERSION*10000 + DUMB_MINOR_VERSION*100 + DUMB_REVISION_VERSION)
38
39#define DUMB_VERSION_STR "0.9.2"
40
41#define DUMB_NAME "DUMB v"DUMB_VERSION_STR
42
43#define DUMB_YEAR 2003
44#define DUMB_MONTH 4
45#define DUMB_DAY 2
46
47#define DUMB_YEAR_STR2 "03"
48#define DUMB_YEAR_STR4 "2003"
49#define DUMB_MONTH_STR1 "4"
50#define DUMB_DAY_STR1 "2"
51
52#if DUMB_MONTH < 10
53#define DUMB_MONTH_STR2 "0"DUMB_MONTH_STR1
54#else
55#define DUMB_MONTH_STR2 DUMB_MONTH_STR1
56#endif
57
58#if DUMB_DAY < 10
59#define DUMB_DAY_STR2 "0"DUMB_DAY_STR1
60#else
61#define DUMB_DAY_STR2 DUMB_DAY_STR1
62#endif
63
64
65/* WARNING: The month and day were inadvertently swapped in the v0.8 release.
66 * Please do not compare this constant against any date in 2002. In
67 * any case, DUMB_VERSION is probably more useful for this purpose.
68 */
69#define DUMB_DATE (DUMB_YEAR*10000 + DUMB_MONTH*100 + DUMB_DAY)
70
71#define DUMB_DATE_STR DUMB_DAY_STR1"."DUMB_MONTH_STR1"."DUMB_YEAR_STR4
72
73
74#undef MIN
75#undef MAX
76#undef MID
77
78#define MIN(x,y) (((x) < (y)) ? (x) : (y))
79#define MAX(x,y) (((x) > (y)) ? (x) : (y))
80#define MID(x,y,z) MAX((x), MIN((y), (z)))
81
82#undef ABS
83#define ABS(x) (((x) >= 0) ? (x) : (-(x)))
84
85
86#if 0 /* This code serves no useful purpose for Rockbox. Possibly the trace
87 thing could be defined for simulator... */
88
89#ifdef DEBUGMODE
90
91#ifndef ASSERT
92#include <assert.h>
93#define ASSERT(n) assert(n)
94#endif
95#ifndef TRACE
96// it would be nice if this did actually trace ...
97#define TRACE 1 ? (void)0 : (void)printf
98#endif
99
100#else
101
102#ifndef ASSERT
103#define ASSERT(n)
104#endif
105#ifndef TRACE
106#define TRACE 1 ? (void)0 : (void)printf
107#endif
108
109#endif
110
111#else /* 0 */
112/* disable TRACE() and ASSERT() calls */
113#define TRACE(...)
114#define ASSERT(...)
115
116/* now fake float function to hush the compiler */
117#define pow(x,y) ((x)+(y))
118#define floor(x) x
119#define log(x) (x)
120#define exp(x) (x)
121#endif /* 0 */
122
123#define DUMB_ID(a,b,c,d) (((unsigned int)(a) << 24) | \
124 ((unsigned int)(b) << 16) | \
125 ((unsigned int)(c) << 8) | \
126 ((unsigned int)(d) ))
127
128
129
130#ifndef LONG_LONG
131#ifdef __GNUC__
132#define LONG_LONG long long
133#elif defined _MSC_VER
134#define LONG_LONG __int64
135#else
136#error 64-bit integer type unknown
137#endif
138#endif
139
140#if __GNUC__ * 100 + __GNUC_MINOR__ >= 301 /* GCC 3.1+ */
141#ifndef DUMB_DECLARE_DEPRECATED
142#define DUMB_DECLARE_DEPRECATED
143#endif
144#define DUMB_DEPRECATED __attribute__((__deprecated__))
145#else
146#define DUMB_DEPRECATED
147#endif
148
149
150/* Basic Sample Type. Normal range is -0x800000 to 0x7FFFFF. */
151
152typedef int sample_t;
153
154
155/* Library Clean-up Management */
156
157int dumb_atexit(void (*proc)(void));
158
159void dumb_exit(void);
160
161
162/* File Input Functions */
163
164typedef struct DUMBFILE_SYSTEM
165{
166 void *(*open)(const char *filename);
167 int (*skip)(void *f, long n);
168 int (*getc)(void *f);
169 long (*getnc)(char *ptr, long n, void *f);
170 void (*close)(void *f);
171}
172DUMBFILE_SYSTEM;
173
174typedef struct DUMBFILE DUMBFILE;
175
176void register_dumbfile_system(DUMBFILE_SYSTEM *dfs);
177
178DUMBFILE *dumbfile_open(const char *filename);
179DUMBFILE *dumbfile_open_ex(void *file, DUMBFILE_SYSTEM *dfs);
180
181long dumbfile_pos(DUMBFILE *f);
182int dumbfile_skip(DUMBFILE *f, long n);
183
184int dumbfile_getc(DUMBFILE *f);
185
186int dumbfile_igetw(DUMBFILE *f);
187int dumbfile_mgetw(DUMBFILE *f);
188
189long dumbfile_igetl(DUMBFILE *f);
190long dumbfile_mgetl(DUMBFILE *f);
191
192unsigned long dumbfile_cgetul(DUMBFILE *f);
193signed long dumbfile_cgetsl(DUMBFILE *f);
194
195long dumbfile_getnc(char *ptr, long n, DUMBFILE *f);
196
197int dumbfile_error(DUMBFILE *f);
198int dumbfile_close(DUMBFILE *f);
199
200
201/* stdio File Input Module */
202
203/*void dumb_register_stdfiles(void);
204
205DUMBFILE *dumbfile_open_stdfile(int fd);*/
206
207
208/* Memory File Input Module */
209
210DUMBFILE *dumbfile_open_memory(const char *data, long size);
211
212
213/* DUH Management */
214
215typedef struct DUH DUH;
216
217#define DUH_SIGNATURE DUMB_ID('D','U','H','!')
218
219void unload_duh(DUH *duh);
220
221DUH *load_duh(const char *filename);
222DUH *read_duh(DUMBFILE *f);
223
224long duh_get_length(DUH *duh);
225
226
227/* Signal Rendering Functions */
228
229typedef struct DUH_SIGRENDERER DUH_SIGRENDERER;
230
231DUH_SIGRENDERER *duh_start_sigrenderer(DUH *duh, int sig, int n_channels, long pos);
232
233#ifdef DUMB_DECLARE_DEPRECATED
234typedef void (*DUH_SIGRENDERER_CALLBACK)(void *data, sample_t **samples, int n_channels, long length);
235/* This is deprecated, but is not marked as such because GCC tends to
236 * complain spuriously when the typedef is used later. See comments below.
237 */
238
239void duh_sigrenderer_set_callback(
240 DUH_SIGRENDERER *sigrenderer,
241 DUH_SIGRENDERER_CALLBACK callback, void *data
242) DUMB_DEPRECATED;
243/* The 'callback' argument's type has changed for const-correctness. See the
244 * DUH_SIGRENDERER_CALLBACK definition just above. Also note that the samples
245 * in the buffer are now 256 times as large; the normal range is -0x800000 to
246 * 0x7FFFFF. The function has been renamed partly because its functionality
247 * has changed slightly and partly so that its name is more meaningful. The
248 * new one is duh_sigrenderer_set_analyser_callback(), and the typedef for
249 * the function pointer has also changed, from DUH_SIGRENDERER_CALLBACK to
250 * DUH_SIGRENDERER_ANALYSER_CALLBACK. (If you wanted to use this callback to
251 * apply a DSP effect, don't worry; there is a better way of doing this. It
252 * is undocumented, so contact me and I shall try to help. Contact details
253 * are in readme.txt.)
254 */
255#endif
256
257typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, long length);
258
259void duh_sigrenderer_set_analyser_callback(
260 DUH_SIGRENDERER *sigrenderer,
261 DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data
262);
263
264int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);
265long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer);
266
267void duh_sigrenderer_set_sigparam(DUH_SIGRENDERER *sigrenderer, unsigned char id, long value);
268
269long duh_sigrenderer_get_samples(
270 DUH_SIGRENDERER *sigrenderer,
271 float volume, float delta,
272 long size, sample_t **samples
273);
274
275void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples);
276
277void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer);
278
279
280/* DUH Rendering Functions */
281
282long duh_render(
283 DUH_SIGRENDERER *sigrenderer,
284 int bits, int unsign,
285 float volume, float delta,
286 long size, void *sptr
287);
288
289#ifdef DUMB_DECLARE_DEPRECATED
290
291long duh_render_signal(
292 DUH_SIGRENDERER *sigrenderer,
293 float volume, float delta,
294 long size, sample_t **samples
295) DUMB_DEPRECATED;
296/* Please use duh_sigrenderer_get_samples(). Arguments and functionality are
297 * identical.
298 */
299
300typedef DUH_SIGRENDERER DUH_RENDERER DUMB_DEPRECATED;
301/* Please use DUH_SIGRENDERER instead of DUH_RENDERER. */
302
303DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos) DUMB_DEPRECATED;
304/* Please use duh_start_sigrenderer() instead. Pass 0 for 'sig'. */
305
306int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
307long duh_renderer_get_position(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
308/* Please use the duh_sigrenderer_*() equivalents of these two functions. */
309
310void duh_end_renderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
311/* Please use duh_end_sigrenderer() instead. */
312
313DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer) DUMB_DEPRECATED;
314DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
315DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
316/* These functions have become no-ops that just return the parameter.
317 * So, for instance, replace
318 * duh_renderer_encapsulate_sigrenderer(my_sigrenderer)
319 * with
320 * my_sigrenderer
321 */
322
323#endif
324
325
326/* Impulse Tracker Support */
327
328extern int dumb_it_max_to_mix;
329
330typedef struct DUMB_IT_SIGDATA DUMB_IT_SIGDATA;
331typedef struct DUMB_IT_SIGRENDERER DUMB_IT_SIGRENDERER;
332
333DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh);
334DUH_SIGRENDERER *duh_encapsulate_it_sigrenderer(DUMB_IT_SIGRENDERER *it_sigrenderer, int n_channels, long pos);
335DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer);
336
337DUH_SIGRENDERER *dumb_it_start_at_order(DUH *duh, int n_channels, int startorder);
338
339void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data);
340void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data);
341void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data, int channel, unsigned char byte), void *data);
342
343int dumb_it_callback_terminate(void *data);
344int dumb_it_callback_midi_block(void *data, int channel, unsigned char byte);
345
346DUH *dumb_load_it(const char *filename);
347DUH *dumb_load_xm(const char *filename);
348DUH *dumb_load_s3m(const char *filename);
349DUH *dumb_load_mod(const char *filename);
350
351DUH *dumb_read_it(DUMBFILE *f);
352DUH *dumb_read_xm(DUMBFILE *f);
353DUH *dumb_read_s3m(DUMBFILE *f);
354DUH *dumb_read_mod(DUMBFILE *f);
355
356int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd);
357
358int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd);
359void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv);
360
361int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd);
362void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv);
363
364int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd);
365void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed);
366
367int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd);
368void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo);
369
370int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel);
371void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, int volume);
372
373int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr);
374int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr);
375
376int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr);
377void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv);
378
379int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr);
380void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo);
381
382int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr);
383void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed);
384
385#define DUMB_IT_N_CHANNELS 64
386#define DUMB_IT_N_NNA_CHANNELS 192
387#define DUMB_IT_TOTAL_CHANNELS (DUMB_IT_N_CHANNELS + DUMB_IT_N_NNA_CHANNELS)
388
389/* Channels passed to any of these functions are 0-based */
390int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel);
391void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume);
392
393typedef struct DUMB_IT_CHANNEL_STATE DUMB_IT_CHANNEL_STATE;
394
395struct DUMB_IT_CHANNEL_STATE
396{
397 int channel; /* 0-based; meaningful for NNA channels */
398 int sample; /* 1-based; 0 if nothing playing, then other fields undef */
399 int freq; /* in Hz */
400 float volume; /* 1.0 maximum; affected by ALL factors, inc. mixing vol */
401 unsigned char pan; /* 0-64, 100 for surround */
402 signed char subpan; /* use (pan + subpan/256.0f) or ((pan<<8)+subpan) */
403 unsigned char filter_cutoff; /* 0-127 cutoff=127 AND resonance=0 */
404 unsigned char filter_subcutoff; /* 0-255 -> no filters (subcutoff */
405 unsigned char filter_resonance; /* 0-127 always 0 in this case) */
406 /* subcutoff only changes from zero if filter envelopes are in use. The
407 * calculation (filter_cutoff + filter_subcutoff/256.0f) gives a more
408 * accurate filter cutoff measurement as a float. It would often be more
409 * useful to use a scaled int such as ((cutoff<<8) + subcutoff).
410 */
411};
412
413/* Values of 64 or more will access NNA channels here. */
414void dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel, DUMB_IT_CHANNEL_STATE *state);
415
416
417/* Signal Design Helper Values */
418
419/* Use pow(DUMB_SEMITONE_BASE, n) to get the 'delta' value to transpose up by
420 * n semitones. To transpose down, use negative n.
421 */
422#define DUMB_SEMITONE_BASE 1.059463094359295309843105314939748495817
423
424/* Use pow(DUMB_QUARTERTONE_BASE, n) to get the 'delta' value to transpose up
425 * by n quartertones. To transpose down, use negative n.
426 */
427#define DUMB_QUARTERTONE_BASE 1.029302236643492074463779317738953977823
428
429/* Use pow(DUMB_PITCH_BASE, n) to get the 'delta' value to transpose up by n
430 * units. In this case, 256 units represent one semitone; 3072 units
431 * represent one octave. These units are used by the sequence signal (SEQU).
432 */
433#define DUMB_PITCH_BASE 1.000225659305069791926712241547647863626
434
435
436/* Signal Design Function Types */
437
438typedef void sigdata_t;
439typedef void sigrenderer_t;
440
441typedef sigdata_t *(*DUH_LOAD_SIGDATA)(DUH *duh, DUMBFILE *file);
442
443typedef sigrenderer_t *(*DUH_START_SIGRENDERER)(
444 DUH *duh,
445 sigdata_t *sigdata,
446 int n_channels,
447 long pos
448);
449
450typedef void (*DUH_SIGRENDERER_SET_SIGPARAM)(
451 sigrenderer_t *sigrenderer,
452 unsigned char id, long value
453);
454
455typedef long (*DUH_SIGRENDERER_GET_SAMPLES)(
456 sigrenderer_t *sigrenderer,
457 float volume, float delta,
458 long size, sample_t **samples
459);
460
461typedef void (*DUH_SIGRENDERER_GET_CURRENT_SAMPLE)(
462 sigrenderer_t *sigrenderer,
463 float volume,
464 sample_t *samples
465);
466
467typedef void (*DUH_END_SIGRENDERER)(sigrenderer_t *sigrenderer);
468
469typedef void (*DUH_UNLOAD_SIGDATA)(sigdata_t *sigdata);
470
471
472/* Signal Design Function Registration */
473
474typedef struct DUH_SIGTYPE_DESC
475{
476 long type;
477 DUH_LOAD_SIGDATA load_sigdata;
478 DUH_START_SIGRENDERER start_sigrenderer;
479 DUH_SIGRENDERER_SET_SIGPARAM sigrenderer_set_sigparam;
480 DUH_SIGRENDERER_GET_SAMPLES sigrenderer_get_samples;
481 DUH_SIGRENDERER_GET_CURRENT_SAMPLE sigrenderer_get_current_sample;
482 DUH_END_SIGRENDERER end_sigrenderer;
483 DUH_UNLOAD_SIGDATA unload_sigdata;
484}
485DUH_SIGTYPE_DESC;
486
487void dumb_register_sigtype(DUH_SIGTYPE_DESC *desc);
488
489
490// Decide where to put these functions; new heading?
491
492sigdata_t *duh_get_raw_sigdata(DUH *duh, int sig, long type);
493
494DUH_SIGRENDERER *duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, long pos);
495sigrenderer_t *duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type);
496
497
498/* Sample Buffer Allocation Helpers */
499
500sample_t **create_sample_buffer(int n_channels, long length);
501void destroy_sample_buffer(sample_t **samples);
502
503
504/* Silencing Helper */
505
506void dumb_silence(sample_t *samples, long length);
507
508
509/* Click Removal Helpers */
510
511typedef struct DUMB_CLICK_REMOVER DUMB_CLICK_REMOVER;
512
513DUMB_CLICK_REMOVER *dumb_create_click_remover(void);
514void dumb_record_click(DUMB_CLICK_REMOVER *cr, long pos, sample_t step);
515void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, float halflife);
516sample_t dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr);
517void dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr);
518
519DUMB_CLICK_REMOVER **dumb_create_click_remover_array(int n);
520void dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step);
521void dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step);
522void dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, long length, float halflife);
523void dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr, sample_t *offset);
524void dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr);
525
526
527/* Resampling Helpers */
528
529#define DUMB_RQ_ALIASING 0
530#define DUMB_RQ_LINEAR 1
531#define DUMB_RQ_CUBIC 2
532#define DUMB_RQ_N_LEVELS 3
533extern int dumb_resampling_quality;
534
535typedef struct DUMB_RESAMPLER DUMB_RESAMPLER;
536
537typedef void (*DUMB_RESAMPLE_PICKUP)(DUMB_RESAMPLER *resampler, void *data);
538
539struct DUMB_RESAMPLER
540{
541 sample_t *src;
542 long pos;
543 int subpos;
544 long start, end;
545 int dir;
546 DUMB_RESAMPLE_PICKUP pickup;
547 void *pickup_data;
548 int min_quality;
549 int max_quality;
550 /* Everything below this point is internal: do not use. */
551 sample_t x[3];
552 int overshot;
553};
554
555void dumb_reset_resampler(DUMB_RESAMPLER *resampler, sample_t *src, long pos, long start, long end);
556DUMB_RESAMPLER *dumb_start_resampler(sample_t *src, long pos, long start, long end);
557long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, float volume, float delta);
558sample_t dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, float volume);
559void dumb_end_resampler(DUMB_RESAMPLER *resampler);
560
561
562/* DUH Construction */
563
564DUH *make_duh(
565 long length,
566 int n_signals,
567 DUH_SIGTYPE_DESC *desc[],
568 sigdata_t *sigdata[]
569);
570
571
572#ifdef __cplusplus
573 }
574#endif
575
576
577#endif /* DUMB_H */
diff --git a/apps/codecs/dumb/include/internal/aldumb.h b/apps/codecs/dumb/include/internal/aldumb.h
deleted file mode 100644
index a0c6d63c07..0000000000
--- a/apps/codecs/dumb/include/internal/aldumb.h
+++ /dev/null
@@ -1,27 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * internal/aldumb.h - The internal header file / / \ \
12 * for DUMB with Allegro. | < / \_
13 * | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#ifndef INTERNAL_ALDUMB_H
21#define INTERNAL_ALDUMB_H
22
23
24void _dat_unload_duh(void *duh);
25
26
27#endif /* INTERNAL_DUMB_H */
diff --git a/apps/codecs/dumb/include/internal/dumb.h b/apps/codecs/dumb/include/internal/dumb.h
deleted file mode 100644
index b4cd0ab1c4..0000000000
--- a/apps/codecs/dumb/include/internal/dumb.h
+++ /dev/null
@@ -1,58 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * internal/dumb.h - DUMB's internal declarations. / / \ \
12 * | < / \_
13 * This header file provides access to the | \/ /\ /
14 * internal structure of DUMB, and is liable \_ / > /
15 * to change, mutate or cease to exist at any | \ / /
16 * moment. Include it at your own peril. | ' /
17 * \__/
18 * ...
19 *
20 * I mean it, people. You don't need access to anything in this file. If you
21 * disagree, contact the authors. In the unlikely event that you make a good
22 * case, we'll add what you need to dumb.h. Thanking you kindly.
23 */
24
25#ifndef INTERNAL_DUMB_H
26#define INTERNAL_DUMB_H
27
28
29typedef struct DUH_SIGTYPE_DESC_LINK
30{
31 struct DUH_SIGTYPE_DESC_LINK *next;
32 DUH_SIGTYPE_DESC *desc;
33}
34DUH_SIGTYPE_DESC_LINK;
35
36
37typedef struct DUH_SIGNAL
38{
39 sigdata_t *sigdata;
40 DUH_SIGTYPE_DESC *desc;
41}
42DUH_SIGNAL;
43
44
45struct DUH
46{
47 long length;
48
49 int n_signals;
50 DUH_SIGNAL **signal;
51};
52
53
54DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(long type);
55
56
57#endif /* INTERNAL_DUMB_H */
58
diff --git a/apps/codecs/dumb/include/internal/it.h b/apps/codecs/dumb/include/internal/it.h
deleted file mode 100644
index 7fffed6e6b..0000000000
--- a/apps/codecs/dumb/include/internal/it.h
+++ /dev/null
@@ -1,710 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * internal/it.h - Internal stuff for IT playback / / \ \
12 * and MOD/XM/S3M conversion. | < / \_
13 * | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#ifndef INTERNAL_IT_H
21#define INTERNAL_IT_H
22
23
24
25#include <stddef.h>
26
27
28
29/** TO DO: THINK ABOUT THE FOLLOWING:
30
31sigdata->flags & IT_COMPATIBLE_GXX
32
33 Bit 5: On = Link Effect G's memory with Effect E/F. Also
34 Gxx with an instrument present will cause the
35 envelopes to be retriggered. If you change a
36 sample on a row with Gxx, it'll adjust the
37 frequency of the current note according to:
38
39 NewFrequency = OldFrequency * NewC5 / OldC5;
40*/
41
42
43
44/* These #defines are TEMPORARY. They are used to write alternative code to
45 * handle ambiguities in the format specification. The correct code in each
46 * case will be determined most likely by experimentation.
47 */
48#define STEREO_SAMPLES_COUNT_AS_TWO
49#define INVALID_ORDERS_END_SONG
50#define INVALID_NOTES_CAUSE_NOTE_CUT
51#define SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP
52#define VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
53
54
55
56#define SIGTYPE_IT DUMB_ID('I', 'T', ' ', ' ')
57
58#define IT_SIGNATURE DUMB_ID('I', 'M', 'P', 'M')
59#define IT_INSTRUMENT_SIGNATURE DUMB_ID('I', 'M', 'P', 'I')
60#define IT_SAMPLE_SIGNATURE DUMB_ID('I', 'M', 'P', 'S')
61
62
63
64/* 1 minute per 4 rows, each row 6 ticks; this is divided by the tempo to get
65 * the interval between ticks.
66 */
67#define TICK_TIME_DIVIDEND ((65536 * 60) / (4 * 6))
68
69
70
71/* I'm not going to try to explain this, because I didn't derive it very
72 * formally ;)
73 */
74/* #define AMIGA_DIVISOR ((float)(4.0 * 14317056.0)) */
75/* I believe the following one to be more accurate. */
76#define AMIGA_DIVISOR ((float)(8.0 * 7159090.5))
77
78
79
80typedef struct IT_MIDI IT_MIDI;
81typedef struct IT_FILTER_STATE IT_FILTER_STATE;
82typedef struct IT_ENVELOPE IT_ENVELOPE;
83typedef struct IT_INSTRUMENT IT_INSTRUMENT;
84typedef struct IT_SAMPLE IT_SAMPLE;
85typedef struct IT_ENTRY IT_ENTRY;
86typedef struct IT_PATTERN IT_PATTERN;
87typedef struct IT_PLAYING_ENVELOPE IT_PLAYING_ENVELOPE;
88typedef struct IT_PLAYING IT_PLAYING;
89typedef struct IT_CHANNEL IT_CHANNEL;
90typedef struct IT_CHECKPOINT IT_CHECKPOINT;
91typedef struct IT_CALLBACKS IT_CALLBACKS;
92
93
94
95struct IT_MIDI
96{
97 unsigned char SFmacro[16][16]; // read these from 0x120
98 unsigned char SFmacrolen[16];
99 unsigned short SFmacroz[16]; /* Bitfield; bit 0 set = z in first position */
100 unsigned char Zmacro[128][16]; // read these from 0x320
101 unsigned char Zmacrolen[128];
102};
103
104
105
106struct IT_FILTER_STATE
107{
108 float currsample, prevsample;
109};
110
111
112
113#define IT_ENVELOPE_ON 1
114#define IT_ENVELOPE_LOOP_ON 2
115#define IT_ENVELOPE_SUSTAIN_LOOP 4
116#define IT_ENVELOPE_PITCH_IS_FILTER 128
117
118struct IT_ENVELOPE
119{
120 unsigned char flags;
121 unsigned char n_nodes;
122 unsigned char loop_start;
123 unsigned char loop_end;
124 unsigned char sus_loop_start;
125 unsigned char sus_loop_end;
126 signed char node_y[25];
127 unsigned short node_t[25];
128};
129
130
131
132#define NNA_NOTE_CUT 0
133#define NNA_NOTE_CONTINUE 1
134#define NNA_NOTE_OFF 2
135#define NNA_NOTE_FADE 3
136
137#define DCT_OFF 0
138#define DCT_NOTE 1
139#define DCT_SAMPLE 2
140#define DCT_INSTRUMENT 3
141
142#define DCA_NOTE_CUT 0
143#define DCA_NOTE_OFF 1
144#define DCA_NOTE_FADE 2
145
146struct IT_INSTRUMENT
147{
148 int fadeout;
149
150 IT_ENVELOPE volume_envelope;
151 IT_ENVELOPE pan_envelope;
152 IT_ENVELOPE pitch_envelope;
153
154 unsigned char new_note_action;
155 unsigned char dup_check_type;
156 unsigned char dup_check_action;
157 unsigned char pp_separation;
158 unsigned char pp_centre;
159 unsigned char global_volume;
160 unsigned char default_pan;
161 unsigned char random_volume;
162 unsigned char random_pan;
163
164 unsigned char filter_cutoff;
165 unsigned char filter_resonance;
166
167 unsigned char map_note[120];
168 unsigned short map_sample[120];
169};
170
171
172
173#define IT_SAMPLE_EXISTS 1
174#define IT_SAMPLE_16BIT 2
175#define IT_SAMPLE_STEREO 4
176#define IT_SAMPLE_LOOP 16
177#define IT_SAMPLE_SUS_LOOP 32
178#define IT_SAMPLE_PINGPONG_LOOP 64
179#define IT_SAMPLE_PINGPONG_SUS_LOOP 128
180
181#define IT_VIBRATO_SINE 0
182#define IT_VIBRATO_SAWTOOTH 1 /* Ramp down */
183#define IT_VIBRATO_SQUARE 2
184#define IT_VIBRATO_RANDOM 3
185
186struct IT_SAMPLE
187{
188 unsigned char flags;
189 unsigned char global_volume;
190 unsigned char default_volume;
191 unsigned char default_pan;
192
193 long length;
194 long loop_start;
195 long loop_end;
196 long C5_speed;
197 long sus_loop_start;
198 long sus_loop_end;
199
200 unsigned char vibrato_speed;
201 unsigned char vibrato_depth;
202 unsigned char vibrato_rate;
203 unsigned char vibrato_waveform;
204
205 sample_t *left;
206 sample_t *right;
207};
208
209
210
211#define IT_ENTRY_NOTE 1
212#define IT_ENTRY_INSTRUMENT 2
213#define IT_ENTRY_VOLPAN 4
214#define IT_ENTRY_EFFECT 8
215
216#define IT_SET_END_ROW(entry) ((entry)->channel = 255)
217#define IT_IS_END_ROW(entry) ((entry)->channel >= DUMB_IT_N_CHANNELS)
218
219#define IT_NOTE_OFF 255
220#define IT_NOTE_CUT 254
221
222#define IT_ENVELOPE_SHIFT 8
223
224#define IT_SURROUND 100
225#define IT_IS_SURROUND(pan) ((pan) > 64)
226#define IT_IS_SURROUND_SHIFTED(pan) ((pan) > 64 << IT_ENVELOPE_SHIFT)
227
228#define IT_SET_SPEED 1
229#define IT_JUMP_TO_ORDER 2
230#define IT_BREAK_TO_ROW 3
231#define IT_VOLUME_SLIDE 4
232#define IT_PORTAMENTO_DOWN 5
233#define IT_PORTAMENTO_UP 6
234#define IT_TONE_PORTAMENTO 7
235#define IT_VIBRATO 8
236#define IT_TREMOR 9
237#define IT_ARPEGGIO 10
238#define IT_VOLSLIDE_VIBRATO 11
239#define IT_VOLSLIDE_TONEPORTA 12
240#define IT_SET_CHANNEL_VOLUME 13
241#define IT_CHANNEL_VOLUME_SLIDE 14
242#define IT_SET_SAMPLE_OFFSET 15
243#define IT_PANNING_SLIDE 16
244#define IT_RETRIGGER_NOTE 17
245#define IT_TREMOLO 18
246#define IT_S 19
247#define IT_SET_SONG_TEMPO 20
248#define IT_FINE_VIBRATO 21
249#define IT_SET_GLOBAL_VOLUME 22
250#define IT_GLOBAL_VOLUME_SLIDE 23
251#define IT_SET_PANNING 24
252#define IT_PANBRELLO 25
253#define IT_MIDI_MACRO 26 //see MIDI.TXT
254
255/* Some effects needed for XM compatibility */
256#define IT_XM_PORTAMENTO_DOWN 27
257#define IT_XM_PORTAMENTO_UP 28
258#define IT_XM_FINE_VOLSLIDE_DOWN 29
259#define IT_XM_FINE_VOLSLIDE_UP 30
260#define IT_XM_RETRIGGER_NOTE 31
261
262#define IT_N_EFFECTS 32
263
264/* These represent the top nibble of the command value. */
265#define IT_S_SET_FILTER 0 /* Greyed out in IT... */
266#define IT_S_SET_GLISSANDO_CONTROL 1 /* Greyed out in IT... */
267#define IT_S_FINETUNE 2 /* Greyed out in IT... */
268#define IT_S_SET_VIBRATO_WAVEFORM 3
269#define IT_S_SET_TREMOLO_WAVEFORM 4
270#define IT_S_SET_PANBRELLO_WAVEFORM 5
271#define IT_S_FINE_PATTERN_DELAY 6
272#define IT_S7 7
273#define IT_S_SET_PAN 8
274#define IT_S_SET_SURROUND_SOUND 9
275#define IT_S_SET_HIGH_OFFSET 10
276#define IT_S_PATTERN_LOOP 11
277#define IT_S_DELAYED_NOTE_CUT 12
278#define IT_S_NOTE_DELAY 13
279#define IT_S_PATTERN_DELAY 14
280#define IT_S_SET_MIDI_MACRO 15
281
282/*
283S0x Set filter
284S1x Set glissando control
285S2x Set finetune
286
287
288S3x Set vibrato waveform to type x
289S4x Set tremelo waveform to type x
290S5x Set panbrello waveform to type x
291 Waveforms for commands S3x, S4x and S5x:
292 0: Sine wave
293 1: Ramp down
294 2: Square wave
295 3: Random wave
296S6x Pattern delay for x ticks
297S70 Past note cut
298S71 Past note off
299S72 Past note fade
300S73 Set NNA to note cut
301S74 Set NNA to continue
302S75 Set NNA to note off
303S76 Set NNA to note fade
304S77 Turn off volume envelope
305S78 Turn on volume envelope
306S79 Turn off panning envelope
307S7A Turn on panning envelope
308S7B Turn off pitch envelope
309S7C Turn on pitch envelope
310S8x Set panning position
311S91 Set surround sound
312SAy Set high value of sample offset yxx00h
313SB0 Set loopback point
314SBx Loop x times to loopback point
315SCx Note cut after x ticks
316SDx Note delay for x ticks
317SEx Pattern delay for x rows
318SFx Set parameterised MIDI Macro
319*/
320
321struct IT_ENTRY
322{
323 unsigned char channel; /* End of row if channel >= DUMB_IT_N_CHANNELS */
324 unsigned char mask;
325 unsigned char note;
326 unsigned char instrument;
327 unsigned char volpan;
328 unsigned char effect;
329 unsigned char effectvalue;
330};
331
332
333
334struct IT_PATTERN
335{
336 int n_rows;
337 int n_entries;
338 IT_ENTRY *entry;
339};
340
341
342
343#define IT_STEREO 1
344#define IT_USE_INSTRUMENTS 4
345#define IT_LINEAR_SLIDES 8 /* If not set, use Amiga slides */
346#define IT_OLD_EFFECTS 16
347#define IT_COMPATIBLE_GXX 32
348
349/* Make sure IT_WAS_AN_XM and IT_WAS_A_MOD aren't set accidentally */
350#define IT_REAL_FLAGS 63
351
352#define IT_WAS_AN_XM 64 /* Set for both XMs and MODs */
353#define IT_WAS_A_MOD 128
354
355#define IT_ORDER_END 255
356#define IT_ORDER_SKIP 254
357
358struct DUMB_IT_SIGDATA
359{
360 int n_orders;
361 int n_instruments;
362 int n_samples;
363 int n_patterns;
364
365 int flags;
366
367 int global_volume;
368 int mixing_volume;
369 int speed;
370 int tempo;
371 int pan_separation;
372
373 unsigned char channel_pan[DUMB_IT_N_CHANNELS];
374 unsigned char channel_volume[DUMB_IT_N_CHANNELS];
375
376 unsigned char *order;
377 unsigned char restart_position; /* for XM compatiblity */
378
379 IT_INSTRUMENT *instrument;
380 IT_SAMPLE *sample;
381 IT_PATTERN *pattern;
382
383 IT_MIDI *midi;
384
385 IT_CHECKPOINT *checkpoint;
386};
387
388
389
390struct IT_PLAYING_ENVELOPE
391{
392 int next_node;
393 int tick;
394};
395
396
397
398#define IT_PLAYING_BACKGROUND 1
399#define IT_PLAYING_SUSTAINOFF 2
400#define IT_PLAYING_FADING 4
401#define IT_PLAYING_DEAD 8
402
403struct IT_PLAYING
404{
405 int flags;
406
407 IT_CHANNEL *channel;
408 IT_SAMPLE *sample;
409 IT_INSTRUMENT *instrument;
410 IT_INSTRUMENT *env_instrument;
411
412 unsigned short sampnum;
413 unsigned char instnum;
414
415 unsigned char channel_volume;
416
417 unsigned char volume;
418 unsigned short pan;
419
420 unsigned char note;
421
422 unsigned char filter_cutoff;
423 unsigned char filter_resonance;
424
425 unsigned short true_filter_cutoff; /* These incorporate the filter envelope, and will not */
426 unsigned char true_filter_resonance; /* be changed if they would be set to 127<<8 and 0. */
427
428 unsigned char vibrato_speed;
429 unsigned char vibrato_depth;
430 unsigned char vibrato_n; /* May be specified twice: volpan & effect. */
431 unsigned char vibrato_time;
432
433 unsigned char tremolo_speed;
434 unsigned char tremolo_depth;
435 unsigned char tremolo_time;
436
437 unsigned char sample_vibrato_time;
438 int sample_vibrato_depth; /* Starts at rate?0:depth, increases by rate */
439
440 int slide;
441 float delta;
442
443 IT_PLAYING_ENVELOPE volume_envelope;
444 IT_PLAYING_ENVELOPE pan_envelope;
445 IT_PLAYING_ENVELOPE pitch_envelope;
446
447 int fadeoutcount;
448
449 IT_FILTER_STATE filter_state[2]; /* Left and right */
450
451 DUMB_RESAMPLER resampler[2];
452
453 /* time_lost is used to emulate Impulse Tracker's sample looping
454 * characteristics. When time_lost is added to pos, the result represents
455 * the position in the theoretical version of the sample where all loops
456 * have been expanded. If this is stored, the resampling helpers will
457 * safely convert it for use with new loop boundaries. The situation is
458 * slightly more complicated if dir == -1 when the change takes place; we
459 * must reflect pos off the loop end point and set dir to 1 before
460 * proceeding.
461 */
462 long time_lost;
463};
464
465
466
467#define IT_CHANNEL_MUTED 1
468
469struct IT_CHANNEL
470{
471 int flags;
472
473 unsigned char volume;
474 signed char volslide;
475 signed char xm_volslide;
476
477 /* xm_volslide is used for volume slides done in the volume column in an
478 * XM file, since it seems the volume column slide is applied first,
479 * followed by clamping, followed by the effects column slide. IT does
480 * not exhibit this behaviour, so xm_volslide is maintained at zero.
481 */
482
483 unsigned char pan;
484 unsigned short truepan;
485
486 unsigned char channelvolume;
487 signed char channelvolslide;
488
489 unsigned char instrument;
490 unsigned char note;
491
492 unsigned char SFmacro;
493
494 unsigned char filter_cutoff;
495 unsigned char filter_resonance;
496
497 unsigned char note_cut_count;
498 unsigned char note_delay_count;
499 IT_ENTRY *note_delay_entry;
500
501 int arpeggio;
502 unsigned char retrig;
503 unsigned char xm_retrig;
504 int retrig_tick;
505
506 unsigned char tremor;
507 unsigned char tremor_time; /* Bit 6 set if note on; bit 7 set if tremor active. */
508
509 int portamento;
510 int toneporta;
511 unsigned char destnote;
512
513 /** WARNING - for neatness, should one or both of these be in the IT_PLAYING struct? */
514 unsigned short sample;
515 unsigned char truenote;
516
517 unsigned char midi_state;
518
519 signed char lastvolslide;
520 unsigned char lastDKL;
521 unsigned char lastEF; /* Doubles as last portamento up for XM files */
522 unsigned char lastG;
523 unsigned char lastHspeed;
524 unsigned char lastHdepth;
525 unsigned char lastRspeed;
526 unsigned char lastRdepth;
527 unsigned char lastI;
528 unsigned char lastJ; /* Doubles as last portamento down for XM files */
529 unsigned char lastN;
530 unsigned char lastO;
531 unsigned char high_offset;
532 unsigned char lastQ;
533 unsigned char lastS;
534 unsigned char pat_loop_row;
535 unsigned char pat_loop_count;
536 unsigned char lastW;
537
538 unsigned char xm_lastE1;
539 unsigned char xm_lastE2;
540 unsigned char xm_lastEA;
541 unsigned char xm_lastEB;
542 unsigned char xm_lastX1;
543 unsigned char xm_lastX2;
544
545 IT_PLAYING *playing;
546};
547
548
549
550struct DUMB_IT_SIGRENDERER
551{
552 DUMB_IT_SIGDATA *sigdata;
553
554 int n_channels;
555
556 unsigned char globalvolume;
557 signed char globalvolslide;
558
559 unsigned char tempo;
560 signed char temposlide;
561
562 IT_CHANNEL channel[DUMB_IT_N_CHANNELS];
563
564 IT_PLAYING *playing[DUMB_IT_N_NNA_CHANNELS];
565
566 int tick;
567 int speed;
568 int rowcount;
569
570 int order; /* Set to -1 if the song is terminated by a callback. */
571 int row;
572 int processorder;
573 int processrow;
574 int breakrow;
575 int pat_loop_row;
576
577 int n_rows;
578
579 IT_ENTRY *entry_start;
580 IT_ENTRY *entry;
581 IT_ENTRY *entry_end;
582
583 long time_left; /* Time before the next tick is processed */
584 int sub_time_left;
585
586 DUMB_CLICK_REMOVER **click_remover;
587
588 IT_CALLBACKS *callbacks;
589};
590
591
592
593struct IT_CHECKPOINT
594{
595 IT_CHECKPOINT *next;
596 long time;
597 DUMB_IT_SIGRENDERER *sigrenderer;
598};
599
600
601
602struct IT_CALLBACKS
603{
604 int (*loop)(void *data);
605 void *loop_data;
606 /* Return 1 to prevent looping; the music will terminate abruptly. If you
607 * want to make the music stop but allow samples to fade (beware, as they
608 * might not fade at all!), use dumb_it_sr_set_speed() and set the speed
609 * to 0. Note that xm_speed_zero() will not be called if you set the
610 * speed manually, and also that this will work for IT and S3M files even
611 * though the music can't stop in this way by itself.
612 */
613
614 int (*xm_speed_zero)(void *data);
615 void *xm_speed_zero_data;
616 /* Return 1 to terminate the mod, without letting samples fade. */
617
618 int (*midi)(void *data, int channel, unsigned char byte);
619 void *midi_data;
620 /* Return 1 to prevent DUMB from subsequently interpreting the MIDI bytes
621 * itself. In other words, return 1 if the Zxx macros in an IT file are
622 * controlling filters and shouldn't be.
623 */
624};
625
626
627
628void _dumb_it_end_sigrenderer(sigrenderer_t *sigrenderer);
629void _dumb_it_unload_sigdata(sigdata_t *vsigdata);
630
631extern DUH_SIGTYPE_DESC _dumb_sigtype_it;
632
633
634
635long _dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata);
636
637
638
639#define XM_APPREGIO 0
640#define XM_PORTAMENTO_UP 1
641#define XM_PORTAMENTO_DOWN 2
642#define XM_TONE_PORTAMENTO 3
643#define XM_VIBRATO 4
644#define XM_VOLSLIDE_TONEPORTA 5
645#define XM_VOLSLIDE_VIBRATO 6
646#define XM_TREMOLO 7
647#define XM_SET_PANNING 8
648#define XM_SAMPLE_OFFSET 9
649#define XM_VOLUME_SLIDE 10 /* A */
650#define XM_POSITION_JUMP 11 /* B */
651#define XM_SET_CHANNEL_VOLUME 12 /* C */
652#define XM_PATTERN_BREAK 13 /* D */
653#define XM_E 14 /* E */
654#define XM_SET_TEMPO_BPM 15 /* F */
655#define XM_SET_GLOBAL_VOLUME 16 /* G */
656#define XM_GLOBAL_VOLUME_SLIDE 17 /* H */
657#define XM_KEY_OFF 20 /* K (undocumented) */
658#define XM_SET_ENVELOPE_POSITION 21 /* L */
659#define XM_PANNING_SLIDE 25 /* P */
660#define XM_MULTI_RETRIG 27 /* R */
661#define XM_TREMOR 29 /* T */
662#define XM_X 33 /* X */
663#define XM_N_EFFECTS (10+26)
664
665#define XM_E_SET_FILTER 0x0
666#define XM_E_FINE_PORTA_UP 0x1
667#define XM_E_FINE_PORTA_DOWN 0x2
668#define XM_E_SET_GLISSANDO_CONTROL 0x3
669#define XM_E_SET_VIBRATO_CONTROL 0x4
670#define XM_E_SET_FINETUNE 0x5
671#define XM_E_SET_LOOP 0x6
672#define XM_E_SET_TREMOLO_CONTROL 0x7
673#define XM_E_RETRIG_NOTE 0x9
674#define XM_E_FINE_VOLSLIDE_UP 0xA
675#define XM_E_FINE_VOLSLIDE_DOWN 0xB
676#define XM_E_NOTE_CUT 0xC
677#define XM_E_NOTE_DELAY 0xD
678#define XM_E_PATTERN_DELAY 0xE
679
680#define XM_X_EXTRAFINE_PORTA_UP 1
681#define XM_X_EXTRAFINE_PORTA_DOWN 2
682
683/* To make my life a bit simpler during conversion, effect E:xy is converted
684 * to effect number EBASE+x:y. The same applies to effect X, and IT's S. That
685 * way, these effects can be manipulated like regular effects.
686 */
687#define EBASE (XM_N_EFFECTS)
688#define XBASE (EBASE+16)
689#define SBASE (IT_N_EFFECTS)
690
691#define EFFECT_VALUE(x, y) (((x)<<4)|(y))
692#define HIGH(v) ((v)>>4)
693#define LOW(v) ((v)&0x0F)
694#define SET_HIGH(v, x) v = (((x)<<4)|((v)&0x0F))
695#define SET_LOW(v, y) v = (((v)&0xF0)|(y))
696#define BCD_TO_NORMAL(v) (HIGH(v)*10+LOW(v))
697
698
699
700#if 0
701unsigned char **_dumb_malloc2(int w, int h);
702void _dumb_free2(unsigned char **line);
703#endif
704
705void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry);
706int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata);
707
708
709
710#endif /* INTERNAL_IT_H */
diff --git a/apps/codecs/dumb/licence.txt b/apps/codecs/dumb/licence.txt
deleted file mode 100644
index 231bfa7f1d..0000000000
--- a/apps/codecs/dumb/licence.txt
+++ /dev/null
@@ -1,54 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * licence.txt - Conditions for use of DUMB. / / \ \
12 * | < / \_
13 * If you do not agree to these terms, please | \/ /\ /
14 * do not use DUMB. \_ / > /
15 * | \ / /
16 * Information in [brackets] is provided to aid | ' /
17 * interpretation of the licence. \__/
18 */
19
20
21Dynamic Universal Music Bibliotheque
22
23Copyright (C) 2001-2003 Ben Davis, Robert J Ohannessian and Julien Cugniere
24
25This software is provided 'as-is', without any express or implied warranty.
26In no event shall the authors be held liable for any damages arising from the
27use of this software.
28
29Permission is granted to anyone to use this software for any purpose,
30including commercial applications, and to alter it and redistribute it
31freely, subject to the following restrictions:
32
331. The origin of this software must not be misrepresented; you must not claim
34 that you wrote the original software. If you use this software in a
35 product, you are requested to acknowledge its use in the product
36 documentation, along with details on where to get an unmodified version of
37 this software, but this is not a strict requirement.
38
39 [Note that the above point asks for a link to DUMB, not just a mention.
40 Googling for DUMB doesn't help much! The URL is "http://dumb.sf.net/".]
41
42 [The only reason why the link is not strictly required is that such a
43 requirement prevents DUMB from being used in projects with certain other
44 licences, notably the GPL. See http://www.gnu.org/philosophy/bsd.html .]
45
462. Altered source versions must be plainly marked as such, and must not be
47 misrepresented as being the original software.
48
493. This notice may not be removed from or altered in any source distribution.
50
514. If you are using the Program in someone else's bedroom at any Monday
52 3:05 PM, you are not allowed to modify the Program for ten minutes. [This
53 clause provided by Inphernic; every licence should contain at least one
54 clause, the reasoning behind which is far from obvious.]
diff --git a/apps/codecs/dumb/make/Makefile.inc b/apps/codecs/dumb/make/Makefile.inc
deleted file mode 100644
index 9b213d8b76..0000000000
--- a/apps/codecs/dumb/make/Makefile.inc
+++ /dev/null
@@ -1,40 +0,0 @@
1# This file contains the main rules for compiling the library. It is included
2# twice with different values for CFLAGS and OBJDIR, so the optimised and
3# debugging libraries are both built.
4
5CORE_OBJECTS := $(addprefix $(OBJDIR)/, $(notdir $(patsubst %.c, %.o, $(CORE_MODULES))))
6ALLEGRO_OBJECTS := $(addprefix $(OBJDIR)/, $(notdir $(patsubst %.c, %.o, $(ALLEGRO_MODULES))))
7
8
9# Pass the current value of CFLAGS through to the commands. Or, more
10# accurately, create a local copy of the current CFLAGS variable. This is
11# necessary because Make doesn't expand variables in commands until they are
12# executed.
13$(CORE_LIB_FILE): CFLAGS := $(CFLAGS)
14$(ALLEGRO_LIB_FILE): CFLAGS := $(CFLAGS)
15
16
17$(OBJDIR)/%.o: src/core/%.c include/dumb.h include/internal/dumb.h
18 @echo "(dumb) CC $<"
19 @$(CC) -c -o $@ $< $(CFLAGS)
20
21$(OBJDIR)/%.o: src/helpers/%.c include/dumb.h
22 @echo "(dumb) CC $<"
23 @$(CC) -c -o $@ $< $(CFLAGS)
24
25$(OBJDIR)/%.o: src/it/%.c include/dumb.h include/internal/it.h
26 @echo "(dumb) CC $<"
27 @$(CC) -c -o $@ $< $(CFLAGS)
28
29$(OBJDIR)/%.o: src/allegro/%.c include/aldumb.h include/dumb.h \
30 include/internal/aldumb.h include/internal/dumb.h
31 @echo "(dumb) CC $<"
32 @$(CC) -c -o $@ $< $(CFLAGS) $(WFLAGS_ALLEGRO)
33
34$(CORE_LIB_FILE): $(CORE_OBJECTS)
35 @echo "(dumb) AR $<"
36 @$(AR) rs $@ $^
37
38$(ALLEGRO_LIB_FILE): $(ALLEGRO_OBJECTS)
39 @echo "(dumb) AR $<"
40 @$(AR) rs $@ $^
diff --git a/apps/codecs/dumb/make/config.bat b/apps/codecs/dumb/make/config.bat
deleted file mode 100644
index 2d33a61511..0000000000
--- a/apps/codecs/dumb/make/config.bat
+++ /dev/null
@@ -1,33 +0,0 @@
1@ECHO OFF
2
3REM This file does an interactive configuration for users of DOS and Windows.
4REM It creates a config.txt file for inclusion in the Makefile. This batch
5REM file should be run indirectly through the 'make config' target (or the
6REM 'make' target the first time).
7
8IF EXIST make\dumbask.exe GOTO dumbaskok
9ECHO You should not be running this directly! Use 'make' or 'make config'.
10GOTO end
11:dumbaskok
12
13make\dumbask.exe "Would you like to compile DUMB for DJGPP or MinGW (D/M)? " DM
14IF ERRORLEVEL 1 GOTO mingw
15ECHO include make/djgpp.inc>make\config.tmp
16GOTO djgpp
17:mingw
18ECHO include make/mingw.inc>make\config.tmp
19:djgpp
20
21ECHO ALL_TARGETS := core core-examples core-headers>>make\config.tmp
22
23make\dumbask.exe "Would you like support for Allegro (Y/N)? "
24IF NOT ERRORLEVEL 1 ECHO ALL_TARGETS += allegro allegro-examples allegro-headers>>make\config.tmp
25
26IF EXIST make\config.txt DEL make\config.txt
27REN make\config.tmp config.txt
28
29ECHO Configuration complete.
30ECHO Run 'make config' to change it in the future.
31PAUSE
32
33:end
diff --git a/apps/codecs/dumb/make/config.sh b/apps/codecs/dumb/make/config.sh
deleted file mode 100755
index f42e141176..0000000000
--- a/apps/codecs/dumb/make/config.sh
+++ /dev/null
@@ -1,35 +0,0 @@
1#!/bin/sh
2
3# This file does an interactive configuration for users of Unix-like systems.
4# It creates a config.txt file for inclusion in the Makefile. This script
5# should be run indirectly through the 'make config' target (or the 'make'
6# target the first time).
7
8if [ ! -e make/dumbask ]; then
9 echo "You should not be running this directly! Use 'make' or 'make config'."
10 exit
11fi
12
13echo 'include make/unix.inc' > make/config.tmp
14
15echo 'ALL_TARGETS := core core-examples core-headers' >> make/config.tmp
16
17if make/dumbask 'Would you like support for Allegro (Y/N)? ' YN; then
18 echo 'ALL_TARGETS += allegro allegro-examples allegro-headers' >> make/config.tmp
19fi
20
21
22if [ ! -z $DEFAULT_PREFIX ]; then
23echo "Please specify an installation prefix (default $DEFAULT_PREFIX)."
24echo -n '> '
25read PREFIX
26if [ -z $PREFIX ]; then PREFIX=$DEFAULT_PREFIX; fi
27echo "PREFIX := $PREFIX" >> make/config.tmp
28fi
29
30mv -f make/config.tmp make/config.txt
31
32echo 'Configuration complete.'
33echo "Run 'make config' to change it in the future."
34echo -n 'Press Enter to continue ... '
35read
diff --git a/apps/codecs/dumb/make/config.txt b/apps/codecs/dumb/make/config.txt
deleted file mode 100644
index abe4397216..0000000000
--- a/apps/codecs/dumb/make/config.txt
+++ /dev/null
@@ -1,3 +0,0 @@
1include make/unix.inc
2ALL_TARGETS := core
3PREFIX := /usr
diff --git a/apps/codecs/dumb/make/djgpp.inc b/apps/codecs/dumb/make/djgpp.inc
deleted file mode 100644
index 4147ab26a4..0000000000
--- a/apps/codecs/dumb/make/djgpp.inc
+++ /dev/null
@@ -1,28 +0,0 @@
1# This file contains DJGPP-specific definitions. It will be included by the
2# main Makefile when you compile with DJGPP.
3
4PLATFORM := djgpp
5
6APOST := \'
7
8# Macro for replacing / with \ where necessary. Usage: $(call FIX,path)
9FIX = $(subst /,\,$(subst /*,\\\*,$(1)))
10
11ECHO = @$(COMSPEC) /C ECHO $(1)
12# Note: the following two macros only work for single files!
13DELETE = $(COMSPEC) /C DEL $(call FIX,$(1))
14COPY = $(COMSPEC) /C COPY $(call FIX,$(1)) $(call FIX,$(2))
15
16EXE_SUFFIX := .exe
17
18LINK_MATH :=
19LINK_ALLEGRO := -lalleg
20
21ifndef DJDIR
22.PHONY: error
23error:
24 $(call ECHO,Your DJDIR environment variable is not set!)
25 $(call ECHO,Please refer to DJGPP's documentation and install it properly.)
26endif
27
28PREFIX := $(DJDIR)
diff --git a/apps/codecs/dumb/make/dumbask b/apps/codecs/dumb/make/dumbask
deleted file mode 100755
index ee6f5f7ecd..0000000000
--- a/apps/codecs/dumb/make/dumbask
+++ /dev/null
Binary files differ
diff --git a/apps/codecs/dumb/make/dumbask.c b/apps/codecs/dumb/make/dumbask.c
deleted file mode 100644
index da89fab97b..0000000000
--- a/apps/codecs/dumb/make/dumbask.c
+++ /dev/null
@@ -1,30 +0,0 @@
1#include <stdio.h>
2#include <ctype.h>
3
4
5int main(int argc, const char *const argv[])
6{
7 const char *message = argv[1];
8 const char *options;
9
10 if (!message) {
11 fprintf(stderr,
12 "dumbask: asks the user a question.\n"
13 "Specify a message as the first argument (quoted!).\n"
14 "You may optionally specify the choices as the second argument.\n"
15 "Default choices are YN. Exit code is 0 for first, 1 for second, etc.\n");
16 return 0;
17 }
18
19 options = argv[2] ? : "YN"; /* I _had_ to use a GNU Extension _somewhere_! */
20
21 printf("%s", argv[1]);
22
23 for (;;) {
24 char c = toupper(getchar());
25 int i;
26 for (i = 0; options[i]; i++)
27 if (c == toupper(options[i]))
28 return i;
29 }
30}
diff --git a/apps/codecs/dumb/make/mingw.inc b/apps/codecs/dumb/make/mingw.inc
deleted file mode 100644
index e58de58788..0000000000
--- a/apps/codecs/dumb/make/mingw.inc
+++ /dev/null
@@ -1,28 +0,0 @@
1# This file contains MinGW-specific definitions. It will be included by the
2# main Makefile when you compile with MinGW.
3
4PLATFORM := mingw
5
6APOST := \'
7
8# Macro for replacing / with \ where necessary. Usage: $(call FIX,path)
9FIX = $(subst /,\,$(subst /*,\\\*,$(1)))
10
11ECHO = @$(COMSPEC) /C ECHO $(1)
12# Note: the following two macros only work for single files!
13DELETE = $(COMSPEC) /C DEL $(call FIX,$(1))
14COPY = $(COMSPEC) /C COPY $(call FIX,$(1)) $(call FIX,$(2))
15
16EXE_SUFFIX := .exe
17
18LINK_MATH :=
19LINK_ALLEGRO := -lalleg
20
21ifndef MINGDIR
22.PHONY: error
23error:
24 $(call ECHO,Your MINGDIR environment variable is not set!)
25 $(call ECHO,Please set it to point to the directory containing your MinGW installation.)
26endif
27
28PREFIX := $(MINGDIR)
diff --git a/apps/codecs/dumb/make/unix.inc b/apps/codecs/dumb/make/unix.inc
deleted file mode 100644
index 89d47c0997..0000000000
--- a/apps/codecs/dumb/make/unix.inc
+++ /dev/null
@@ -1,20 +0,0 @@
1# This file contains definitions suitable for Unix-compatible systems. It will
2# be included by the main Makefile when you compile on such a system.
3
4PLATFORM := unix
5
6APOST := \'
7
8# Macro that on DOS and Windows would replace / with \. Usage: $(call FIX,path)
9FIX = $(1)
10
11ECHO = @echo $(1)
12DELETE = rm -f $(1)
13COPY = cp $(1) $(2)
14
15EXE_SUFFIX :=
16
17LINK_MATH := -lm
18LINK_ALLEGRO := `allegro-config --libs`
19
20# PREFIX is set by config.sh.
diff --git a/apps/codecs/dumb/readme.txt b/apps/codecs/dumb/readme.txt
deleted file mode 100644
index 45abd1a17a..0000000000
--- a/apps/codecs/dumb/readme.txt
+++ /dev/null
@@ -1,421 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * readme.txt - General information on DUMB. / / \ \
12 * | < / \_
13 * | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20
21********************
22*** Introduction ***
23********************
24
25
26Thank you for downloading DUMB! You should have the following documentation:
27
28 readme.txt - This file
29 licence.txt - Conditions for the use of this software
30 release.txt - Release notes and changes for this and past releases
31 docs/
32 howto.txt - Step-by-step instructions on adding DUMB to your project
33 faq.txt - Frequently asked questions and answers to them
34 dumb.txt - DUMB library reference
35 deprec.txt - Information about deprecated parts of the API
36 ptr.txt - Quick introduction to pointers for those who need it
37 fnptr.txt - Explanation of function pointers for those who need it
38 modplug.txt - Our official position regarding ModPlug Tracker
39
40This file will help you get DUMB set up. If you have not yet done so, please
41read licence.txt and release.txt before proceeding. After you've got DUMB set
42up, please refer to the files in the docs/ directory at your convenience. I
43recommend you start with howto.txt.
44
45
46****************
47*** Features ***
48****************
49
50
51Here is the statutory feature list:
52
53- Freeware
54
55- Supports playback of IT, XM, S3M and MOD files
56
57- Faithful to the original trackers, especially IT; if it plays your module
58 wrongly, please tell me so I can fix the bug! (But please don't complain
59 about differences between DUMB and ModPlug Tracker; see docs/modplug.txt)
60
61- Accurate support for low-pass resonant filters for IT files
62
63- Very accurate timing and pitching; completely deterministic playback
64
65- Click removal
66
67- Facility to embed music files in other files (e.g. Allegro datafiles)
68
69- Three resampling quality settings: aliasing, linear interpolation and cubic
70 interpolation
71
72- Number of samples playing at once can be limited to reduce processor usage,
73 but samples will come back in when other louder ones stop
74
75- All notes will be present and correct even if you start a piece of music in
76 the middle
77
78- Fast seeking to any point before the music first loops (seeking time
79 increases beyond this point)
80
81- Audio generated can be used in any way; DUMB does not necessarily send it
82 straight to a sound output system
83
84- Makefile provided for DJGPP, MinGW, Linux, BeOS and Mac OS X; project file
85 provided for MSVC 6 (please contact me if you'd like to submit or request
86 support for a new platform; the code itself should port anywhere that has a
87 32-bit C compiler)
88
89- Can be used with Allegro, can be used without (if you'd like to help make
90 DUMB more approachable to people who aren't using Allegro, please contact
91 me)
92
93
94*********************
95*** What you need ***
96*********************
97
98
99To use DUMB, you need a 32-bit C compiler (GCC and MSVC are fine). If you
100have Allegro, DUMB can integrate with its audio streams and datafiles, making
101your life easier. If you do not wish to use Allegro, you will have to do some
102work to get music playing back. The 'dumbplay' example program requires
103Allegro.
104
105 Allegro - http://alleg.sf.net/
106
107Neil Walker has kindly uploaded some DUMB binaries at
108http://retrospec.sgn.net/allegro/ . They may not always be up to date, so you
109should try to compile it yourself first.
110
111
112**********************************************
113*** How to set DUMB up with DJGPP or MinGW ***
114**********************************************
115
116
117You should have got the .zip version. If for some reason you got the .tar.gz
118version instead, you may have to convert make/config.bat to DOS text file
119format. WinZip does this automatically by default. Otherwise, loading it into
120MS EDIT and saving it again should do the trick. You will have to do the same
121for any files you want to view in Windows Notepad. If you have problems, just
122go and download the .zip instead.
123
124Make sure you preserved the directory structure when you extracted DUMB from
125the archive. Most unzipping programs will do this by default, but pkunzip
126requires you to pass -d. If not, please delete DUMB and extract it again
127properly.
128
129If you are using Windows, open an MS-DOS Prompt or a Windows Command Line.
130Change to the directory into which you unzipped DUMB.
131
132Type the following:
133
134 make
135
136DUMB will ask you whether you wish to compile for DJGPP or MinGW. Then it
137will ask you whether you want support for Allegro. (You have to have made and
138installed Allegro's optimised library for this to work.) Finally, it will
139compile optimised and debugging builds of DUMB, along with the example
140programs. When it has finished, run the following to install the libraries:
141
142 make install
143
144All done! If you ever need the configuration again (e.g. if you compiled for
145DJGPP before and you want to compile for MinGW now), run the following:
146
147 make config
148
149See the comments in the makefile for other targets.
150
151Note: the makefile will only work properly if you have COMSPEC or ComSpec set
152to point to command.com or cmd.exe. If you set it to point to a Unix-style
153shell, the makefile won't work.
154
155Please let me know if you have any trouble.
156
157Scroll down for information on the example programs. Refer to docs/howto.txt
158when you are ready to start programming with DUMB. If you use DUMB in a game,
159let me know - I might decide to place a link to your game on DUMB's website!
160
161
162******************************************************
163*** How to set DUMB up with Microsoft Visual C++ 6 ***
164******************************************************
165
166
167You should have got the .zip version. If for some reason you got the .tar.gz
168version instead, you may have to convert some files to DOS text file format.
169WinZip does this automatically by default. Otherwise, loading such files into
170MS EDIT and saving them again should do the trick. You will have to do this
171for any files you want to view in Windows Notepad. If you have problems, just
172go and download the .zip instead.
173
174Make sure you preserved the directory structure when you extracted DUMB from
175the archive. Most unzipping programs will do this by default, but pkunzip
176requires you to pass -d. If not, please delete DUMB and extract it again
177properly.
178
179DUMB now comes with a project file for Microsoft Visual C++ 6. To add DUMB to
180your project:
181
1821. Open your project in VC++.
1832. Select Project|Insert Project into Workspace...
1843. Navigate to the dumb\vc6 directory, and select dumb.dsp.
1854. Select Build|Set Active Configuration..., and reselect one of your
186 project's configurations.
1875. Select Project|Dependencies... and ensure your project is dependent on
188 DUMB.
1896. Select Project|Settings..., Settings for: All Configurations, C/C++ tab,
190 Preprocessor category. Add the DUMB include directory to the Additional
191 Include Directories box.
1927. Ensure that for all the projects in the workspace (or more likely just all
193 the projects in a particular dependency chain) the run-time libraries are
194 the same. That's in Project|Settings, C/C++ tab, Code generation category,
195 Use run-time library dropdown. The settings for Release and Debug are
196 separate, so you'll have to change them one at a time. Exactly which run-
197 time library you use will depend on what you need; it doesn't appear that
198 DUMB has any particular requirements, so set it to whatever you're using
199 now.
200
201Good thing you only have to do all that once ...
202
203If you have the Intel compiler installed, it will - well, should - be used to
204compile DUMB. The only setting I added is /QxiM. This allows the compiler to
205use PPro and MMX instructions, and so when compiling with Intel the resultant
206EXE will require a Pentium II or greater. I don't think this is unreasonable.
207After all, it is 2003 :)
208
209If you don't have the Intel compiler, VC will compile DUMB as normal.
210
211This project file and these instructions were provided by Tom Seddon (I hope
212I got his name right; I had to guess it from his e-mail address!). They are
213untested by me. If you have problems, check the download page at
214http://dumb.sf.net/ to see if they are addressed; failing that, direct
215queries to me and I'll try to figure them out.
216
217When you are ready to start using DUMB, refer to docs/howto.txt. If you use
218DUMB in a game, let me know - I might decide to place a link to your game on
219DUMB's website!
220
221
222********************************************************************
223*** How to set DUMB up on Linux, BeOS and possibly even Mac OS X ***
224********************************************************************
225
226
227You should have got the .tar.gz version. If for some reason you got the .zip
228version instead, you may have to use dtou on some or all of the text files.
229If you have problems, just go and download the .tar.gz instead.
230
231First, run the following command as a normal user:
232
233 make
234
235You will be asked whether you want Allegro support. Then, unless you are on
236BeOS, you will be asked where you'd like DUMB to install its headers,
237libraries and examples (which will go in the include/, lib/ and bin/
238subdirectories of the prefix you specify). BeOS has fixed locations for these
239files. Once you have specified these pieces of information, the optimised and
240debugging builds of DUMB will be compiled, along with the examples. When it
241has finished, you can install them with:
242
243 make install
244
245You may need to be root for this to work. It depends on the prefix you chose.
246
247Note: the makefile will only work if COMSPEC and ComSpec are both undefined.
248If either of these is defined, the makefile will try to build for a Windows
249system, and will fail.
250
251Please let me know if you have any trouble.
252
253Information on the example programs is just below. Refer to docs/howto.txt
254when you are ready to start programming with DUMB. If you use DUMB in a game,
255let me know - I might decide to place a link to your game on DUMB's website!
256
257
258****************************
259*** The example programs ***
260****************************
261
262
263Two example programs are provided. On DOS and Windows, you can find them in
264the examples subdirectory. On other systems they will be installed system-
265wide.
266
267dumbplay
268 This program will only be built if you have Allegro. Pass it the filename
269 of an IT, XM, S3M or MOD file, and it will play it. It's not a polished
270 player with real-time threading or anything - so don't complain about it
271 stuttering while you use other programs - but it does show DUMB's fidelity
272 nicely. You can control the playback quality by editing dumb.ini, which
273 must be in the current working directory. (This is a flaw for systems
274 where the program is installed system-wide, but it is non-fatal.) Have a
275 look at the examples/dumb.ini file for further information.
276
277dumbout
278 This program does not need Allegro. You can use it to stream an IT, XM,
279 S3M or MOD file to raw PCM. This can be used as input to an encoder like
280 oggenc (with appropriate command-line options), or it can be sent to a
281 .pcm file which can be read by any respectable waveform editor. No .wav
282 support yet, sorry. This program is also convenient for timing DUMB.
283 Compare the time it takes to render a module with the module's playing
284 time! dumbout doesn't try to read any configuration file; the options are
285 set on the command line.
286
287
288*********************************************
289*** Downloading music or writing your own ***
290*********************************************
291
292
293If you would like to compose your own music modules, then first I must offer
294a word of warning: not everyone is capable of composing music. Do not assume
295you will be able to learn the art. By all means have a go; if you can learn
296to play tunes on the computer keyboard, you're well on the way to being a
297composer!
298
299The best programs for the job are the trackers that pioneered the file
300formats:
301
302 Impulse Tracker - IT files - http://www.noisemusic.org/it/
303 Fast Tracker II - XM files - http://www.gwinternet.com/music/ft2/
304 Scream Tracker 3 - S3M files -
305 http://www.united-trackers.org/resources/software/screamtracker.htm
306
307MOD files come from the Amiga; I do not know what PC tracker to recommend for
308editing these. If you know of one, let me know! In the meantime, I would
309recommend using a more advanced file format. However, don't convert your
310existing MODs just for the sake of it.
311
312Note that Fast Tracker II is Shareware. It arguably offers the best
313interface, but the IT file format is more powerful and better defined.
314Impulse Tracker and Scream Tracker 3 are Freeware. DUMB is likely to be at
315its best with IT files.
316
317These editors are DOS programs. Users of DOS-incapable operating systems may
318like to try ModPlug Tracker, but should read docs/modplug.txt before using it
319for any serious work. If you use a different operating system, or if you know
320of any module editors for Windows that are more faithful to the original
321trackers' playback, please give me some links so I can put them here!
322
323 ModPlug Tracker - http://www.modplug.com/
324
325BEWARE OF WINAMP! Although it's excellent for MP3s, it is notorious for being
326one of the worst module players in existence; very few modules play correctly
327with it. There are plug-ins available to improve Winamp's module support, for
328example WSP.
329
330 Winamp - http://www.winamp.com/
331 WSP - http://www.spytech.cz/index.php?sec=demo
332
333Samples and instruments are the building blocks of music modules. You can
334download samples at:
335
336 http://www.tump.net/
337
338If you would like to download module files composed by other people, check
339the following sites:
340
341 http://www.modarchive.com/
342 http://www.scene.org/
343 http://www.tump.net/
344 http://www.homemusic.cc/main.php
345 http://www.modplug.com/
346
347Once again, if you know of more sites where samples or module files are
348available for download, please let me know.
349
350If you wish to use someone's music in your game, please respect the
351composer's wishes. In general, you should ask the composer. Music that has
352been placed in the Public Domain can be used by anyone for anything, but it
353wouldn't do any harm to ask anyway if you know who the author is. In most
354cases the author will be thrilled, so don't hesitate!
355
356A note about converting modules from one format to another: don't do it,
357unless you are a musician and are prepared to go through the file and make
358sure everything sounds the way it should! The module formats are all slightly
359different, and converting from one format to another will usually do some
360damage.
361
362Instead, it is recommended that you allow DUMB to interpret the original file
363as it sees fit. DUMB may make mistakes (it does a lot of conversion on
364loading), but future versions of DUMB will be able to rectify these mistakes.
365On the other hand, if you convert the file, the damage is permanent.
366
367
368***********************
369*** Contact details ***
370***********************
371
372
373If you have trouble with DUMB, or want to contact me for any other reason, my
374e-mail address is given below. However, I may be able to help more if you
375come on to IRC EFnet #dumb.
376
377IRC stands for Internet Relay Chat, and is a type of chat network. Several
378such networks exist, and EFnet is a popular one. In order to connect to an
379IRC network, you first need an IRC client. Here are some:
380
381 http://www.xchat.org/
382 http://www.visualirc.net/beta.php
383 http://www.mirc.com/
384
385Getting on to IRC can be a steep cliff, but it is not insurmountable, and
386it's well worth it. Once you have set up the client software, you need to
387connect to a server. Here is a list of EFnet servers I have had success with.
388Type "/server" (without quotes), then a space, then the name of a server.
389
390 irc.homelien.no
391 irc.webgiro.se
392 efnet.vuurwerk.nl
393 efnet.demon.co.uk
394 irc.isdnet.fr
395 irc.prison.net
396
397If these servers do not work, visit http://efnet.org/ircdb/servers.php for a
398huge list of other EFnet servers to try.
399
400Once you're connected, type the following:
401
402 /join #dumb
403
404A window will appear, and you can ask your question. It should be clear
405what's going on from this point onwards. I am 'entheh'. Note that unlike many
406other nerds I am not always at my computer, so if I don't answer your
407question, don't take it personally! I will usually be able to read your
408question when I come back.
409
410
411******************
412*** Conclusion ***
413******************
414
415
416This is the conclusion.
417
418
419Ben Davis
420entheh@users.sf.net
421IRC EFnet #dumb
diff --git a/apps/codecs/dumb/release.txt b/apps/codecs/dumb/release.txt
deleted file mode 100644
index eff4b8ded8..0000000000
--- a/apps/codecs/dumb/release.txt
+++ /dev/null
@@ -1,406 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * release.txt - Release notes for DUMB. / / \ \
12 * | < / \_
13 * | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20
21******************************************
22*** DUMB v0.9.2, released 2 April 2003 ***
23******************************************
24
25Yes, there really has been a release. This is not a day-late April fools'
26joke.
27
28DUMB's full name has changed! The old "Dedicated Universal Music
29Bastardisation" was rather silly, and not much more than a forced attempt at
30finding words beginning with D, U, M and B. I spent weeks and weeks browsing
31dictionaries and hopelessly asking others for bright ideas, until the
32brilliant Chris "Kitty Cat" Robinson came up with "Dynamic". I decided to
33keep the U as Universal, since a DUH struct can hold digital music in any
34format. Now all that remained was the B, but it didn't take me long to come
35up with Bibliotheque, which, despite looking French, is indeed considered an
36English word by Oxford English Dictionary Online, to which my university has
37a subscription. So there you have it - the name now makes sense.
38
39The two most significant additions to the project would have to be the new
40thread safety (with an important restriction, detailed in docs/dumb.txt), and
41the new build system. The silly 'makeall' and 'makecore' scripts are gone. If
42you are a GCC user, all you need do now is run 'make' and 'make install', as
43for other projects. You don't even have to run a 'fix' script any more! There
44are some caveats, which are covered in readme.txt. If you use Microsoft
45Visual C++ 6, you no longer need to obtain GCC and GNU Make - there is a
46project file just for you.
47
48Huge thanks go to Steve Terry for testing on Windows XP - about five times -
49and to lillo for testing on BeOS and Mac OS X. Thanks also to X-G for testing
50on a Windows system that has consistently posed problems for DUMB's old
51makefiles.
52
53There was a bug whereby al_poll_duh() would sometimes cause the music to
54resume playing if you called it after al_pause_duh(). Whether this was DUMB's
55fault for misusing Allegro's API, or a bug in Allegro, is unclear, but this
56release makes it work.
57
58In one of my projects, I found that my AL_DUH_PLAYER stopped playing when
59there were lots of other sound effects. In order to fix this, I programmed
60DUMB to set the priority of the stream's voice to 255, the maximum. I also
61added al_duh_set_priority(), so you can set the priority yourself if you need
62to.
63
64The resampling code has undergone a transformation. The bad news is that the
65linear average code is no longer in use. The good news is that where DUMB's
66resamplers used to require three extra samples' worth of memory to be
67allocated and initialised, it now copes with just the sample data. And it
68does a very good job at bouncing off loop points and otherwise hurtling
69around the sample. The resampling code is considerably more complicated, but
70the code that uses the resamplers is considerably simpler - and if you
71noticed a slight click in some bidirectionally looping samples, you'll be
72pleased to know that that click is gone!
73
74I have also devoted some effort to optimisation. It seemed hopeless for a
75while, but then I actually figured out a way of making it faster AND more
76accurate at the same time! DUMB is now quite a bit faster than it was, and it
77mixes not with 16-bit precision, but with 24-bit precision. (It used 32-bit
78integers all along, but the difference is that it now makes use of 256 times
79as much of the integer's range.)
80
81There have been the usual improvements to playback. The last release occurred
82rather too soon after I had fixed the XM effect memories; EAx and EBx, fine
83volume ramps, had been neglected. These are now handled properly.
84
85In previous versions of DUMB, muted channels in IT were actually played with
86surround sound panning (where the right-hand channel is inverted). This has
87been fixed, so muted channels will really be muted now.
88
89There were also some subtle problems with the way DUMB handled New Note
90Actions for IT files. It turned out that, in all releases of DUMB so far,
91pitch, filter and panning envelopes and sample vibrato were not being
92processed for any note that was forced into the background by a new note on
93the same channel! This only affected IT files. Not only has this been fixed,
94but envelope interpolation is much more accurate. Long trailing envelope-
95driven fade-outs sound a lot better now!
96
97Since panning and filter envelopes are more precise, extra fields have been
98added to the DUMB_IT_CHANNEL_STATE struct, used by
99dumb_it_sr_get_channel_state(). These fields hold the 'decimal' parts of the
100pan and filter cut-off. See dumb.txt for details.
101
102Mxx (set channel volume) now correctly only modifies the last note played on
103the channel, not any previous notes that have been forced into the background
104by New Note Actions, and filter effect processing is now closer to what
105Impulse Tracker does.
106
107The XM loader was slightly flawed and could crash on files containing samples
108with out-of-range loop points. One such file was given to me. This has been
109fixed.
110
111Finally, the legal stuff. Julien Cugniere has been added to the list of
112copyright owners. He deserves it, for all the work he did on the XM support!
113And the licence has been changed. You are no longer required to include a
114link to DUMB in a project that uses DUMB; the reasons for this relaxation are
115explained in licence.txt. However, the request is still there ...
116
117As usual, enjoy!
118
119
120**********************************************
121*** DUMB v0.9.1, released 19 December 2002 ***
122**********************************************
123
124Hi again! Lots to say this time, so I shall cut right to the chase.
125
126DUMB now supports Impulse Tracker's low-pass resonant filters! Huge thanks go
127to Jeffrey Lim, author of Impulse Tracker, for giving me what information he
128still had regarding the algorithm; to cut a long story short, modifying
129ModPlug Tracker's source code (which is in the Public Domain) led to an
130algorithm whose output matched Impulse Tracker's perfectly.
131
132Please note that ModPlug Tracker's filters as they stand do not match Impulse
133Tracker's, and I have no interest in supporting ModPlug Tracker's variant
134(especially not the integer rounding problems). Please see docs/modplug.txt,
135new in this release, for details.
136
137Thanks also go to Fatso Huuskonen for motivating me to add filter support,
138and providing me with several great IT files to test it with!
139
140The other important feature added for this release is click removal. Up until
141now, DUMB has generated clicks when cutting notes, starting samples in the
142middle, and so on. This version of DUMB will remove any such clicks. Note
143that DUMB does not use volume ramps to accomplish this; the algorithm will
144not take the bite out of the music!
145
146In other news, DUMB now supports sample vibrato for IT files, and instrument
147vibrato for XM files. A slight bug in New Note Action handling for IT files
148has been fixed; Note Fade will not break the sustain loops of the sample and
149envelope, as it did before. Tremor handling (Ixy) had a strange bug in it,
150which has been fixed.
151
152Support for XM files has been greatly enhanced. The XM envelope handling new
153in the last release contained a huge bug, resulting in notes seeming not to
154stop when they should; this has been fixed. Some XM files crashed DUMB, while
155others failed to load; these problems have been solved. Effect memories now
156work properly for XM and MOD files, to the best of my knowledge. Some other
157differences between IT and XM have been accounted for, most notably the
158Retrigger Note effects, Rxy and E9x.
159
160DUMB's sound quality and accuracy are not the only areas that have been
161enhanced. The API has been expanded, at last. You can now detect when a
162module loops, or make it play through just once. You can ask DUMB to inform
163you every time it generates some samples; this is useful for visualisation.
164For IT files, you can intercept the MIDI messages generated by Zxx macros,
165enabling you to synchronise your game with the music to some extent. (There
166is no such method for XM, S3M or MOD files yet; sorry. Also note that the
167function will be called before you actually hear the sound; I cannot improve
168this until DUMB has its own sound drivers, which won't be for a while.) You
169can query the current order and row. Finally, operations like changing the
170speed and tempo are now possible, and you can query the playback state on
171each channel.
172
173Some parts of DUMB's API have been deprecated. Simple programs that use
174Allegro will be unaffected, but if you get some compiler warnings or errors,
175please review docs/deprec.txt. This file explains why those parts of the API
176were deprecated, and tells you how to adapt your code; the changes you need
177to make are straightforward. Sorry for the inconvenience.
178
179For various reasons, I have made DUMB's makefiles use different compiler
180flags depending on your GCC version (unless you are using MSVC). There is no
181elegant way of getting the makefiles to detect when GCC is upgraded. If you
182upgrade GCC, you should execute 'make clean' in order to make DUMB detect the
183GCC version again. Otherwise you may get some annoying error messages. (It is
184wise to do this in any case, so that all the object files are built with the
185same GCC version.)
186
187DUMB's example players have been unified into a single player called
188'dumbplay'. The player has been enhanced to display messages when the music
189loops, and when XM and MOD files freeze (effect F00; more information on this
190in docs/howto.txt).
191
192Finally, as noted on DUMB's website, the release notes from the last release
193were inaccurate. It has been verified that DUMBOGG v0.5 does still work with
194that release, and still works with this release. The esoteric DUMBOGG v0.6
195has not been created yet, since DUMBOGG v0.5 still works.
196
197Please scroll down and read through the indented paragraphs in the notes for
198the last release; they are relevant for this release too.
199
200That's all folks! Until next time.
201
202
203*******************************************
204*** DUMB v0.9, released 16 October 2002 ***
205*******************************************
206
207MOD support is here! DUMB now supports all four of the common module formats.
208As usual, there have also been some improvements to the way modules are
209played back. Most notably, handling of tone portamento in IT files has been
210improved a lot, and XM envelopes are now processed correctly.
211
212The other major change is that DUMB now does a dummy run through each module
213on loading. It stores the playback state at thirty-second intervals. It stops
214when the module first loops, and then stores the playback time. This results
215in a slightly longer load time and a greater memory overhead, but seeking is
216faster (to any point before the module first loops) and the length is
217calculated! duh_get_length() will return this and is now documented in
218docs/howto.txt and docs/dumb.txt.
219
220DUMB's build process has been changed to use 'mingw' wherever it used
221'mingw32' before; some directories have been renamed, and the 'fix' command
222you had to run for MinGW has been changed from 'fix mingw32' to 'fix mingw'.
223
224Last time, I directed you to scroll down and read the notes from a past
225release, but ignore this point, and that point applies to something else, and
226so on. Did anyone do so? Well, if you're reading this at all, you probably
227did. Nevertheless, this time I shall be much less confusing and restate any
228relevant information. So the least you can do is read it!
229
230- If your program ever aborts with exit code 37 while loading an IT file,
231 PLEASE LET ME KNOW! The IT file in question has a stereo compressed sample
232 in it, and the format is unspecified for this case (Impulse Tracker itself
233 doesn't use stereo samples at all). I will need the IT file in question,
234 and any information you can give me about how the IT file was created (e.g.
235 what program). (If you don't get to see an exit code, let me know anyway.)
236
237- If your program ever outputs a line resembling "Inst 01 Env: 0,64 8,32
238 15,48" to stderr while loading an IT file, PLEASE LET ME KNOW! You have an
239 old IT file (saved by an Impulse Tracker version older than 2.00), and
240 support for such files is STILL untested.
241
242- Not all parts of DUMB's API are documented yet. You will find some
243 functions in dumb.h which are not listed in docs/dumb.txt; the reason is
244 that these functions still need work and will probably change. If you
245 really, really want to use them, talk to me first (IRC EFnet #dumb is a
246 good place for this; see readme.txt for details on using IRC). I intend to
247 finalise and document the whole of DUMB's API for Version 1.0.
248
249There have been some changes to the naming conventions in DUMB's undocumented
250API. DUMBOGG v0.5 will not work with this and subsequent releases of DUMB;
251please upgrade to DUMBOGG v0.6. These changes should not break anything in
252your own code, since you didn't use those parts of the API, did you ;)
253
254There is still a great deal of work to be done before DUMB's API can be
255finalised, and thus it will be a while before DUMB v1.0 comes out. It should
256be worth the wait. In the meantime, there will be 0.9.x releases with
257additional functionality, improved playback, and possibly support for some
258extra file formats.
259
260Finally I should like to offer an apology; there is a strong possibility that
261some of DUMB's official API will change in the near future. There will not be
262any drastic changes, and the corresponding changes to your source code will
263be simple enough. If I didn't make these changes, DUMB's API would start to
264become limited, or messy, or both, so it's for the better. I apologise in
265advance for this.
266
267Now scroll down and read the notes for the first r... oh wait, we already did
268that. I guess that's it then. You can stop reading now.
269
270Right after you've read this.
271
272And this.
273
274Off you go.
275
276Bye.
277
278
279********************************************
280*** DUMB v0.8.1, released 11 August 2002 ***
281********************************************
282
283This is a minor release that fixes a few bugs. One of these bugs, however,
284was pretty serious. dumb_register_dat_xm() was never coded! It was prototyped
285in aldumb.h, so code would compile, but there would be an unresolved symbol
286at the linking stage. This has been fixed.
287
288Platforms other than Unix did not have a working 'make veryclean' target;
289this has been fixed. In addition, the makefiles now use 'xcopy' instead of
290'copy', since on some systems GNU Make seems to have trouble calling commands
291built in to the shell.
292
293Contrary to the errata that was on the DUMB website, the makeall.sh and
294makecore.sh scripts actually DID install in /usr. This has now been
295corrected, and regardless of whether you use these scripts or call make
296directly, the files will now be installed to /usr/local by default.
297
298The XM loader used to treat stereo samples as mono samples with the data for
299the right channel positioned after the data for the left channel. This
300generally resulted in an unwanted echo effect. This has been fixed.
301
302When playing XM files, specifying an invalid instrument would cause an old
303note on that channel to come back (roughly speaking). Fast Tracker 2 does not
304exhibit this behaviour. This has been fixed.
305
306The GCC makefiles used -mpentium, which is deprecated in gcc 3.x. This was
307generating warnings, and has now been fixed.
308
309In XM files, the length of a sample is stored in bytes. DUMB was assuming
310that the length of a 16-bit sample would be even. I had two XM files where
311this was not the case, and DUMB was unable to load them. This has been fixed.
312
313In order to accommodate the extra part of the version number,
314DUMB_REVISION_VERSION has been added. DUMB_VERSION has also been added in
315order to facilitate checking if the version of DUMB installed is sufficient.
316See docs/dumb.txt for details.
317
318As a last-minute fix, the XM "Break to row" effect is now loaded properly. It
319was necessary to convert from binary-coded decimal to hexadecimal (those who
320have experience with Fast Tracker 2 will know what I mean). In short, this
321means the effect will now work properly when breaking to row 10 or greater.
322
323DUMB v0.8 had faulty release date constants; DUMB_MONTH and DUMB_DAY were
324swapped! For this reason, DUMB_DATE should not be compared against any date
325in 2002. This note has been added to docs/dumb.txt and also to dumb.h.
326
327Please scroll to the end and read the release notes for the first version,
328DUMB v0.7. Most of them apply equally to this release. However, the
329non-portable code was rewritten for DUMB v0.8, so that point does not apply.
330The point about length not being calculated also applies to XM files.
331
332Enjoy :)
333
334
335****************************************
336*** DUMB v0.8, released 14 June 2002 ***
337****************************************
338
339Welcome to the second release of DUMB!
340
341In addition to these notes, please read below the release notes for the
342previous version, DUMB v0.7. Most of them apply equally to this release.
343However, the non-portable code has been rewritten; DUMB should now port to
344big-endian platforms.
345
346The main improvement in this release of DUMB is the support for XM files.
347Enormous thanks go to Julien Cugniere for working on this while I had to
348revise for my exams!
349
350There was a mistake in the makefiles in the last release. The debugging
351Allegro interface library was mistakenly named libaldmbd.a instead of
352libaldmd.a, meaning you had to compile with -laldmbd, contrary to what the
353docs said. Apologies to everyone who lost sleep trying to work out what was
354wrong! The reason for using libaldmd.a is to maintain compatibility with
355plain DOS, where filenames are limited to eight characters (plus a three-
356letter extension). The makefiles have now been changed to match the
357information in the docs, so you may have to alter your project files
358accordingly.
359
360The example programs were faulty, and crashed on Windows if they were unable
361to load the file. It was also difficult to work out how to exit them (you had
362to click the taskbar button that didn't have a window, then press a key).
363They have been improved in both these respects.
364
365I have now added a docs/faq.txt file (Frequently Asked Questions), which is
366based on problems and misconceptions people have had with the first release.
367Please refer to it before contacting me with problems.
368
369Thanks to networm for touching up the Unix makefile and writing the
370instructions on using it.
371
372Incidentally, today (Friday 14 June) is the Robinson College May Ball at
373Cambridge Uni. God knows why it's called a May Ball if it's in June. I'm not
374going myself (72 GBP, and I'd have to wear a suit, ugh), but with all the
375noise outside I shall enjoy pumping up the speakers tonight!
376
377
378****************************************
379*** DUMB v0.7, released 2 March 2002 ***
380****************************************
381
382This is the first release of DUMB, and parts of the library are not
383crystallised. Don't let this put you off! Provided you don't try to use any
384features that aren't documented in docs/dumb.txt, the library should be rock
385solid and you should be able to upgrade more or less without problems.
386
387Here are some notes on this release:
388
389- There is some non-portable code in this release of DUMB. It is likely that
390 the library will fail to load IT files with compressed samples on
391 big-endian machines such as the Apple Macintosh.
392
393- If your program ever aborts with exit code 37 while loading an IT file,
394 PLEASE LET ME KNOW! The IT file in question has a stereo compressed sample
395 in it, and the format is unspecified for this case (Impulse Tracker itself
396 doesn't use stereo samples at all). I will need the IT file in question,
397 and any information you can give me about how the IT file was created (e.g.
398 what program). (If you don't get to see an exit code, let me know anyway.)
399
400- If your program ever outputs a line resembling "Inst 01 Env: 0,64 8,32
401 15,48" to stderr while loading an IT file, PLEASE LET ME KNOW! You have an
402 old IT file (saved by an Impulse Tracker version older than 2.00), and
403 support for such files is untested.
404
405- The length of IT and S3M files is not currently calculated. It is just set
406 to ten minutes.
diff --git a/apps/codecs/dumb/src/allegro/alplay.c b/apps/codecs/dumb/src/allegro/alplay.c
deleted file mode 100644
index 983bde105b..0000000000
--- a/apps/codecs/dumb/src/allegro/alplay.c
+++ /dev/null
@@ -1,270 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * alplay.c - Functions to play a DUH through / / \ \
12 * an Allegro audio stream. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21
22#include <allegro.h>
23
24#include "aldumb.h"
25
26
27
28#define ADP_PLAYING 1
29
30struct AL_DUH_PLAYER
31{
32 int flags;
33 long bufsize;
34 int freq;
35 AUDIOSTREAM *stream;
36 DUH_SIGRENDERER *sigrenderer; /* If this is NULL, stream is invalid. */
37 float volume;
38 int silentcount;
39};
40
41
42
43AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos, float volume, long bufsize, int freq)
44{
45 AL_DUH_PLAYER *dp;
46
47 /* This restriction is imposed by Allegro. */
48 ASSERT(n_channels > 0);
49 ASSERT(n_channels <= 2);
50
51 if (!duh)
52 return NULL;
53
54 dp = malloc(sizeof(*dp));
55 if (!dp)
56 return NULL;
57
58 dp->flags = ADP_PLAYING;
59 dp->bufsize = bufsize;
60 dp->freq = freq;
61
62 dp->stream = play_audio_stream(bufsize, 16, n_channels - 1, freq, 255, 128);
63
64 if (!dp->stream) {
65 free(dp);
66 return NULL;
67 }
68
69 voice_set_priority(dp->stream->voice, 255);
70
71 dp->sigrenderer = duh_start_sigrenderer(duh, 0, n_channels, pos);
72
73 if (!dp->sigrenderer) {
74 stop_audio_stream(dp->stream);
75 free(dp);
76 return NULL;
77 }
78
79 dp->volume = volume;
80 dp->silentcount = 0;
81
82 return dp;
83}
84
85
86
87void al_stop_duh(AL_DUH_PLAYER *dp)
88{
89 if (dp) {
90 if (dp->sigrenderer) {
91 duh_end_sigrenderer(dp->sigrenderer);
92 stop_audio_stream(dp->stream);
93 }
94 free(dp);
95 }
96}
97
98
99
100void al_pause_duh(AL_DUH_PLAYER *dp)
101{
102 if (dp && dp->sigrenderer && (dp->flags & ADP_PLAYING)) {
103 voice_stop(dp->stream->voice);
104 dp->flags &= ~ADP_PLAYING;
105 }
106}
107
108
109
110void al_resume_duh(AL_DUH_PLAYER *dp)
111{
112 if (dp && dp->sigrenderer && !(dp->flags & ADP_PLAYING)) {
113 voice_start(dp->stream->voice);
114 dp->flags |= ADP_PLAYING;
115 }
116}
117
118
119
120void al_duh_set_priority(AL_DUH_PLAYER *dp, int priority)
121{
122 if (dp && dp->sigrenderer)
123 voice_set_priority(dp->stream->voice, priority);
124}
125
126
127
128void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume)
129{
130 if (dp)
131 dp->volume = volume;
132}
133
134
135
136int al_poll_duh(AL_DUH_PLAYER *dp)
137{
138 unsigned short *sptr;
139 long n;
140 long size;
141 int n_channels;
142
143 if (!dp || !dp->sigrenderer)
144 return 1;
145
146 if (!(dp->flags & ADP_PLAYING))
147 return 0;
148
149 sptr = get_audio_stream_buffer(dp->stream);
150
151 if (!sptr)
152 return 0;
153
154 n = duh_render(dp->sigrenderer, 16, 1, dp->volume, 65536.0 / dp->freq, dp->bufsize, sptr);
155
156 if (n == 0) {
157 if (++dp->silentcount >= 2) {
158 duh_end_sigrenderer(dp->sigrenderer);
159 free_audio_stream_buffer(dp->stream);
160 stop_audio_stream(dp->stream);
161 dp->sigrenderer = NULL;
162 return 1;
163 }
164 }
165
166 n_channels = duh_sigrenderer_get_n_channels(dp->sigrenderer);
167 n *= n_channels;
168 size = dp->bufsize * n_channels;
169 for (; n < size; n++)
170 sptr[n] = 0x8000;
171
172 free_audio_stream_buffer(dp->stream);
173
174 return 0;
175}
176
177
178
179long al_duh_get_position(AL_DUH_PLAYER *dp)
180{
181 return dp ? duh_sigrenderer_get_position(dp->sigrenderer) : -1;
182}
183
184
185
186AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq)
187{
188 AL_DUH_PLAYER *dp;
189 int n_channels;
190
191 if (!sigrenderer)
192 return NULL;
193
194 dp = malloc(sizeof(*dp));
195 if (!dp)
196 return NULL;
197
198 n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
199
200 /* This restriction is imposed by Allegro. */
201 ASSERT(n_channels > 0);
202 ASSERT(n_channels <= 2);
203
204 dp->flags = ADP_PLAYING;
205 dp->bufsize = bufsize;
206 dp->freq = freq;
207
208 dp->stream = play_audio_stream(bufsize, 16, n_channels - 1, freq, 255, 128);
209
210 if (!dp->stream) {
211 free(dp);
212 return NULL;
213 }
214
215 voice_set_priority(dp->stream->voice, 255);
216
217 dp->sigrenderer = sigrenderer;
218
219 dp->volume = volume;
220 dp->silentcount = 0;
221
222 return dp;
223}
224
225
226
227DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp)
228{
229 return dp ? dp->sigrenderer : NULL;
230}
231
232
233
234/* IMPORTANT: This function will return NULL if the music has ended. */
235// Should this be changed? User might want to hack the underlying SIGRENDERER
236// and resurrect it (e.g. change pattern number), before it gets destroyed...
237DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp)
238{
239 if (dp) {
240 DUH_SIGRENDERER *sigrenderer = dp->sigrenderer;
241 if (sigrenderer) stop_audio_stream(dp->stream);
242 free(dp);
243 return sigrenderer;
244 }
245 return NULL;
246}
247
248
249
250/* DEPRECATED */
251AL_DUH_PLAYER *al_duh_encapsulate_renderer(DUH_SIGRENDERER *dr, float volume, long bufsize, int freq)
252{
253 return al_duh_encapsulate_sigrenderer(dr, volume, bufsize, freq);
254}
255
256
257
258/* DEPRECATED */
259DUH_SIGRENDERER *al_duh_get_renderer(AL_DUH_PLAYER *dp)
260{
261 return al_duh_get_sigrenderer(dp);
262}
263
264
265
266/* DEPRECATED */
267DUH_SIGRENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp)
268{
269 return al_duh_decompose_to_sigrenderer(dp);
270}
diff --git a/apps/codecs/dumb/src/allegro/datduh.c b/apps/codecs/dumb/src/allegro/datduh.c
deleted file mode 100644
index 672e3c820c..0000000000
--- a/apps/codecs/dumb/src/allegro/datduh.c
+++ /dev/null
@@ -1,60 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * datduh.c - Integration with Allegro's / / \ \
12 * datafiles. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <allegro.h>
21
22#include "aldumb.h"
23#include "internal/aldumb.h"
24
25
26
27static void *dat_read_duh(PACKFILE *f, long size)
28{
29 DUMBFILE *df;
30 DUH *duh;
31
32 (void)size;
33
34 df = dumbfile_open_packfile(f);
35
36 if (!df)
37 return NULL;
38
39 duh = read_duh(df);
40
41 dumbfile_close(df);
42
43 return duh;
44}
45
46
47
48/* dumb_register_dat_duh(): tells Allegro about the DUH datafile object. If
49 * you intend to load a datafile containing a DUH object, you must call this
50 * function first. It is recommended you pass DAT_DUH, but you may have a
51 * reason to use a different type (apart from pride, that doesn't count).
52 */
53void dumb_register_dat_duh(long type)
54{
55 register_datafile_object(
56 type,
57 &dat_read_duh,
58 &_dat_unload_duh
59 );
60}
diff --git a/apps/codecs/dumb/src/allegro/datit.c b/apps/codecs/dumb/src/allegro/datit.c
deleted file mode 100644
index 8f58f14234..0000000000
--- a/apps/codecs/dumb/src/allegro/datit.c
+++ /dev/null
@@ -1,62 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * datit.c - Integration of IT files with / / \ \
12 * Allegro's datafiles. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <allegro.h>
21
22#include "aldumb.h"
23#include "internal/aldumb.h"
24
25
26
27static void *dat_read_it(PACKFILE *f, long size)
28{
29 DUMBFILE *df;
30 DUH *duh;
31
32 (void)size;
33
34 df = dumbfile_open_packfile(f);
35
36 if (!df)
37 return NULL;
38
39 duh = dumb_read_it(df);
40
41 dumbfile_close(df);
42
43 return duh;
44}
45
46
47
48/* dumb_register_dat_it(): tells Allegro about the IT datafile object. If you
49 * intend to load a datafile containing an IT object, you must call this
50 * function first. It is recommended you pass DUMB_DAT_IT, but you may have a
51 * reason to use a different type (perhaps you already have a datafile with
52 * IT files in and they use a different type).
53 */
54void dumb_register_dat_it(long type)
55{
56 register_datafile_object(
57 type,
58 &dat_read_it,
59 &_dat_unload_duh
60 );
61}
62
diff --git a/apps/codecs/dumb/src/allegro/datmod.c b/apps/codecs/dumb/src/allegro/datmod.c
deleted file mode 100644
index 850b17b444..0000000000
--- a/apps/codecs/dumb/src/allegro/datmod.c
+++ /dev/null
@@ -1,61 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * datmod.c - Integration of MOD files with / / \ \
12 * Allegro's datafiles. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <allegro.h>
21
22#include "aldumb.h"
23#include "internal/aldumb.h"
24
25
26
27static void *dat_read_mod(PACKFILE *f, long size)
28{
29 DUMBFILE *df;
30 DUH *duh;
31
32 (void)size;
33
34 df = dumbfile_open_packfile(f);
35
36 if (!df)
37 return NULL;
38
39 duh = dumb_read_mod(df);
40
41 dumbfile_close(df);
42
43 return duh;
44}
45
46
47
48/* dumb_register_dat_mod(): tells Allegro about the MOD datafile object. If
49 * you intend to load a datafile containing a MOD object, you must call this
50 * function first. It is recommended you pass DUMB_DAT_MOD, but you may have
51 * a reason to use a different type (perhaps you already have a datafile with
52 * MOD files in and they use a different type).
53 */
54void dumb_register_dat_mod(long type)
55{
56 register_datafile_object(
57 type,
58 &dat_read_mod,
59 &_dat_unload_duh
60 );
61}
diff --git a/apps/codecs/dumb/src/allegro/dats3m.c b/apps/codecs/dumb/src/allegro/dats3m.c
deleted file mode 100644
index a0fc74420e..0000000000
--- a/apps/codecs/dumb/src/allegro/dats3m.c
+++ /dev/null
@@ -1,61 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * dats3m.c - Integration of S3M files with / / \ \
12 * Allegro's datafiles. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <allegro.h>
21
22#include "aldumb.h"
23#include "internal/aldumb.h"
24
25
26
27static void *dat_read_s3m(PACKFILE *f, long size)
28{
29 DUMBFILE *df;
30 DUH *duh;
31
32 (void)size;
33
34 df = dumbfile_open_packfile(f);
35
36 if (!df)
37 return NULL;
38
39 duh = dumb_read_s3m(df);
40
41 dumbfile_close(df);
42
43 return duh;
44}
45
46
47
48/* dumb_register_dat_s3m(): tells Allegro about the S3M datafile object. If
49 * you intend to load a datafile containing an S3M object, you must call this
50 * function first. It is recommended you pass DUMB_DAT_S3M, but you may have
51 * a reason to use a different type (perhaps you already have a datafile with
52 * S3M files in and they use a different type).
53 */
54void dumb_register_dat_s3m(long type)
55{
56 register_datafile_object(
57 type,
58 &dat_read_s3m,
59 &_dat_unload_duh
60 );
61}
diff --git a/apps/codecs/dumb/src/allegro/datunld.c b/apps/codecs/dumb/src/allegro/datunld.c
deleted file mode 100644
index 71906445e0..0000000000
--- a/apps/codecs/dumb/src/allegro/datunld.c
+++ /dev/null
@@ -1,31 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * datunld.c - Unload function for integration / / \ \
12 * with Allegro's datafiles. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <allegro.h>
21
22#include "aldumb.h"
23#include "internal/aldumb.h"
24
25
26
27void _dat_unload_duh(void *duh)
28{
29 unload_duh(duh);
30}
31
diff --git a/apps/codecs/dumb/src/allegro/datxm.c b/apps/codecs/dumb/src/allegro/datxm.c
deleted file mode 100644
index 6cb98d87c1..0000000000
--- a/apps/codecs/dumb/src/allegro/datxm.c
+++ /dev/null
@@ -1,62 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * datxm.c - Integration of XM files with / / \ \
12 * Allegro's datafiles. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <allegro.h>
21
22#include "aldumb.h"
23#include "internal/aldumb.h"
24
25
26
27static void *dat_read_xm(PACKFILE *f, long size)
28{
29 DUMBFILE *df;
30 DUH *duh;
31
32 (void)size;
33
34 df = dumbfile_open_packfile(f);
35
36 if (!df)
37 return NULL;
38
39 duh = dumb_read_xm(df);
40
41 dumbfile_close(df);
42
43 return duh;
44}
45
46
47
48/* dumb_register_dat_xm(): tells Allegro about the XM datafile object. If you
49 * intend to load a datafile containing an XM object, you must call this
50 * function first. It is recommended you pass DUMB_DAT_XM, but you may have a
51 * reason to use a different type (perhaps you already have a datafile with
52 * XM files in and they use a different type).
53 */
54void dumb_register_dat_xm(long type)
55{
56 register_datafile_object(
57 type,
58 &dat_read_xm,
59 &_dat_unload_duh
60 );
61}
62
diff --git a/apps/codecs/dumb/src/allegro/packfile.c b/apps/codecs/dumb/src/allegro/packfile.c
deleted file mode 100644
index 525baebd4e..0000000000
--- a/apps/codecs/dumb/src/allegro/packfile.c
+++ /dev/null
@@ -1,98 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * packfile.c - Packfile input module. / / \ \
12 * | < / \_
13 * By entheh. | \/ /\ /
14 * \_ / > /
15 * Note that this does not use file compression; | \ / /
16 * for that you must open the file yourself and | ' /
17 * then use dumbfile_open_packfile(). \__/
18 */
19
20#include <allegro.h>
21
22#include "aldumb.h"
23
24
25
26static void *dumb_packfile_open(const char *filename)
27{
28 return pack_fopen(filename, F_READ);
29}
30
31
32
33static int dumb_packfile_skip(void *f, long n)
34{
35 return pack_fseek(f, n);
36}
37
38
39
40static int dumb_packfile_getc(void *f)
41{
42 return pack_getc(f);
43}
44
45
46
47static long dumb_packfile_getnc(char *ptr, long n, void *f)
48{
49 return pack_fread(ptr, n, f);
50}
51
52
53
54static void dumb_packfile_close(void *f)
55{
56 pack_fclose(f);
57}
58
59
60
61static DUMBFILE_SYSTEM packfile_dfs = {
62 &dumb_packfile_open,
63 &dumb_packfile_skip,
64 &dumb_packfile_getc,
65 &dumb_packfile_getnc,
66 &dumb_packfile_close
67};
68
69
70
71void dumb_register_packfiles(void)
72{
73 register_dumbfile_system(&packfile_dfs);
74}
75
76
77
78static DUMBFILE_SYSTEM packfile_dfs_leave_open = {
79 NULL,
80 &dumb_packfile_skip,
81 &dumb_packfile_getc,
82 &dumb_packfile_getnc,
83 NULL
84};
85
86
87
88DUMBFILE *dumbfile_open_packfile(PACKFILE *p)
89{
90 return dumbfile_open_ex(p, &packfile_dfs_leave_open);
91}
92
93
94
95DUMBFILE *dumbfile_from_packfile(PACKFILE *p)
96{
97 return p ? dumbfile_open_ex(p, &packfile_dfs) : NULL;
98}
diff --git a/apps/codecs/dumb/src/core/atexit.c b/apps/codecs/dumb/src/core/atexit.c
deleted file mode 100644
index 16c6abdb2c..0000000000
--- a/apps/codecs/dumb/src/core/atexit.c
+++ /dev/null
@@ -1,71 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * atexit.c - Library Clean-up Management. / / \ \
12 * | < / \_
13 * By entheh. | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21
22#include "dumb.h"
23#include "internal/dumb.h"
24
25
26
27typedef struct DUMB_ATEXIT_PROC
28{
29 struct DUMB_ATEXIT_PROC *next;
30 void (*proc)(void);
31}
32DUMB_ATEXIT_PROC;
33
34
35
36static DUMB_ATEXIT_PROC *dumb_atexit_proc = NULL;
37
38
39
40int dumb_atexit(void (*proc)(void))
41{
42 DUMB_ATEXIT_PROC *dap = dumb_atexit_proc;
43
44 while (dap) {
45 if (dap->proc == proc) return 0;
46 dap = dap->next;
47 }
48
49 dap = malloc(sizeof(*dap));
50
51 if (!dap)
52 return -1;
53
54 dap->next = dumb_atexit_proc;
55 dap->proc = proc;
56 dumb_atexit_proc = dap;
57
58 return 0;
59}
60
61
62
63void dumb_exit(void)
64{
65 while (dumb_atexit_proc) {
66 DUMB_ATEXIT_PROC *next = dumb_atexit_proc->next;
67 (*dumb_atexit_proc->proc)();
68 free(dumb_atexit_proc);
69 dumb_atexit_proc = next;
70 }
71}
diff --git a/apps/codecs/dumb/src/core/duhlen.c b/apps/codecs/dumb/src/core/duhlen.c
deleted file mode 100644
index 4500d0a50f..0000000000
--- a/apps/codecs/dumb/src/core/duhlen.c
+++ /dev/null
@@ -1,34 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * duhlen.c - Function to return the length of / / \ \
12 * a DUH. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * Note that the length of a DUH is a constant | ' /
17 * stored in the DUH struct and in the DUH disk \__/
18 * format. It will be calculated on loading for
19 * other formats in which the length is not explicitly stored. Also note that
20 * it does not necessarily correspond to the length of time for which the DUH
21 * will generate samples. Rather it represents a suitable point for a player
22 * such as Winamp to stop, and in any good DUH it will allow for any final
23 * flourish to fade out and be appreciated.
24 */
25
26#include "dumb.h"
27#include "internal/dumb.h"
28
29
30
31long duh_get_length(DUH *duh)
32{
33 return duh ? duh->length : 0;
34}
diff --git a/apps/codecs/dumb/src/core/dumbfile.c b/apps/codecs/dumb/src/core/dumbfile.c
deleted file mode 100644
index 71108c0c3b..0000000000
--- a/apps/codecs/dumb/src/core/dumbfile.c
+++ /dev/null
@@ -1,401 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * dumbfile.c - Hookable, strictly sequential / / \ \
12 * file input functions. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21
22#include "dumb.h"
23
24
25
26static DUMBFILE_SYSTEM *the_dfs = NULL;
27
28
29
30void register_dumbfile_system(DUMBFILE_SYSTEM *dfs)
31{
32 ASSERT(dfs);
33 ASSERT(dfs->open);
34 ASSERT(dfs->getc);
35 ASSERT(dfs->close);
36 the_dfs = dfs;
37}
38
39
40
41struct DUMBFILE
42{
43 DUMBFILE_SYSTEM *dfs;
44 void *file;
45 long pos;
46};
47
48
49
50DUMBFILE *dumbfile_open(const char *filename)
51{
52 DUMBFILE *f;
53
54 ASSERT(the_dfs);
55
56 f = malloc(sizeof(*f));
57
58 if (!f)
59 return NULL;
60
61 f->dfs = the_dfs;
62
63 f->file = (*the_dfs->open)(filename);
64
65 if (!f->file) {
66 free(f);
67 return NULL;
68 }
69
70 f->pos = 0;
71
72 return f;
73}
74
75
76
77DUMBFILE *dumbfile_open_ex(void *file, DUMBFILE_SYSTEM *dfs)
78{
79 DUMBFILE *f;
80
81 ASSERT(dfs);
82 ASSERT(dfs->getc);
83 ASSERT(file);
84
85 f = malloc(sizeof(*f));
86
87 if (!f) {
88 if (dfs->close)
89 (*dfs->close)(file);
90 return NULL;
91 }
92
93 f->dfs = dfs;
94 f->file = file;
95
96 f->pos = 0;
97
98 return f;
99}
100
101
102
103long dumbfile_pos(DUMBFILE *f)
104{
105 ASSERT(f);
106
107 return f->pos;
108}
109
110
111
112int dumbfile_skip(DUMBFILE *f, long n)
113{
114 int rv;
115
116 ASSERT(f);
117 ASSERT(n >= 0);
118
119 if (f->pos < 0)
120 return -1;
121
122 f->pos += n;
123
124 if (f->dfs->skip) {
125 rv = (*f->dfs->skip)(f->file, n);
126 if (rv) {
127 f->pos = -1;
128 return rv;
129 }
130 } else {
131 while (n) {
132 rv = (*f->dfs->getc)(f->file);
133 if (rv < 0) {
134 f->pos = -1;
135 return rv;
136 }
137 n--;
138 }
139 }
140
141 return 0;
142}
143
144
145
146int dumbfile_getc(DUMBFILE *f)
147{
148 int rv;
149
150 ASSERT(f);
151
152 if (f->pos < 0)
153 return -1;
154
155 rv = (*f->dfs->getc)(f->file);
156
157 if (rv < 0) {
158 f->pos = -1;
159 return rv;
160 }
161
162 f->pos++;
163
164 return rv;
165}
166
167
168
169int dumbfile_igetw(DUMBFILE *f)
170{
171 int l, h;
172
173 ASSERT(f);
174
175 if (f->pos < 0)
176 return -1;
177
178 l = (*f->dfs->getc)(f->file);
179 if (l < 0) {
180 f->pos = -1;
181 return l;
182 }
183
184 h = (*f->dfs->getc)(f->file);
185 if (h < 0) {
186 f->pos = -1;
187 return h;
188 }
189
190 f->pos += 2;
191
192 return l | (h << 8);
193}
194
195
196
197int dumbfile_mgetw(DUMBFILE *f)
198{
199 int l, h;
200
201 ASSERT(f);
202
203 if (f->pos < 0)
204 return -1;
205
206 h = (*f->dfs->getc)(f->file);
207 if (h < 0) {
208 f->pos = -1;
209 return h;
210 }
211
212 l = (*f->dfs->getc)(f->file);
213 if (l < 0) {
214 f->pos = -1;
215 return l;
216 }
217
218 f->pos += 2;
219
220 return l | (h << 8);
221}
222
223
224
225long dumbfile_igetl(DUMBFILE *f)
226{
227 unsigned long rv, b;
228
229 ASSERT(f);
230
231 if (f->pos < 0)
232 return -1;
233
234 rv = (*f->dfs->getc)(f->file);
235 if ((signed long)rv < 0) {
236 f->pos = -1;
237 return rv;
238 }
239
240 b = (*f->dfs->getc)(f->file);
241 if ((signed long)b < 0) {
242 f->pos = -1;
243 return b;
244 }
245 rv |= b << 8;
246
247 b = (*f->dfs->getc)(f->file);
248 if ((signed long)b < 0) {
249 f->pos = -1;
250 return b;
251 }
252 rv |= b << 16;
253
254 b = (*f->dfs->getc)(f->file);
255 if ((signed long)b < 0) {
256 f->pos = -1;
257 return b;
258 }
259 rv |= b << 24;
260
261 f->pos += 4;
262
263 return rv;
264}
265
266
267
268long dumbfile_mgetl(DUMBFILE *f)
269{
270 unsigned long rv, b;
271
272 ASSERT(f);
273
274 if (f->pos < 0)
275 return -1;
276
277 rv = (*f->dfs->getc)(f->file);
278 if ((signed long)rv < 0) {
279 f->pos = -1;
280 return rv;
281 }
282 rv <<= 24;
283
284 b = (*f->dfs->getc)(f->file);
285 if ((signed long)b < 0) {
286 f->pos = -1;
287 return b;
288 }
289 rv |= b << 16;
290
291 b = (*f->dfs->getc)(f->file);
292 if ((signed long)b < 0) {
293 f->pos = -1;
294 return b;
295 }
296 rv |= b << 8;
297
298 b = (*f->dfs->getc)(f->file);
299 if ((signed long)b < 0) {
300 f->pos = -1;
301 return b;
302 }
303 rv |= b;
304
305 f->pos += 4;
306
307 return rv;
308}
309
310
311
312unsigned long dumbfile_cgetul(DUMBFILE *f)
313{
314 unsigned long rv = 0;
315 int v;
316
317 do {
318 v = dumbfile_getc(f);
319
320 if (v < 0)
321 return v;
322
323 rv <<= 7;
324 rv |= v & 0x7F;
325 } while (v & 0x80);
326
327 return rv;
328}
329
330
331
332signed long dumbfile_cgetsl(DUMBFILE *f)
333{
334 unsigned long rv = dumbfile_cgetul(f);
335
336 if (f->pos < 0)
337 return rv;
338
339 return (rv >> 1) | (rv << 31);
340}
341
342
343
344long dumbfile_getnc(char *ptr, long n, DUMBFILE *f)
345{
346 long rv;
347
348 ASSERT(f);
349 ASSERT(n >= 0);
350
351 if (f->pos < 0)
352 return -1;
353
354 if (f->dfs->getnc) {
355 rv = (*f->dfs->getnc)(ptr, n, f->file);
356 if (rv < n) {
357 f->pos = -1;
358 return MAX(rv, 0);
359 }
360 } else {
361 for (rv = 0; rv < n; rv++) {
362 int c = (*f->dfs->getc)(f->file);
363 if (c < 0) {
364 f->pos = -1;
365 return rv;
366 }
367 *ptr++ = c;
368 }
369 }
370
371 f->pos += rv;
372
373 return rv;
374}
375
376
377
378int dumbfile_error(DUMBFILE *f)
379{
380 ASSERT(f);
381
382 return f->pos < 0;
383}
384
385
386
387int dumbfile_close(DUMBFILE *f)
388{
389 int rv;
390
391 ASSERT(f);
392
393 rv = f->pos < 0;
394
395 if (f->dfs->close)
396 (*f->dfs->close)(f->file);
397
398 free(f);
399
400 return rv;
401}
diff --git a/apps/codecs/dumb/src/core/loadduh.c b/apps/codecs/dumb/src/core/loadduh.c
deleted file mode 100644
index 7dfe5cc100..0000000000
--- a/apps/codecs/dumb/src/core/loadduh.c
+++ /dev/null
@@ -1,42 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * loadduh.c - Code to read a DUH from a file, / / \ \
12 * opening and closing the file for | < / \_
13 * you. | \/ /\ /
14 * \_ / > /
15 * By entheh. | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include "dumb.h"
21#include "internal/dumb.h"
22
23
24
25/* load_duh(): loads a .duh file, returning a pointer to a DUH struct.
26 * When you have finished with it, you must pass the pointer to unload_duh()
27 * so that the memory can be freed.
28 */
29DUH *load_duh(const char *filename)
30{
31 DUH *duh;
32 DUMBFILE *f = dumbfile_open(filename);
33
34 if (!f)
35 return NULL;
36
37 duh = read_duh(f);
38
39 dumbfile_close(f);
40
41 return duh;
42}
diff --git a/apps/codecs/dumb/src/core/makeduh.c b/apps/codecs/dumb/src/core/makeduh.c
deleted file mode 100644
index 1e422fb502..0000000000
--- a/apps/codecs/dumb/src/core/makeduh.c
+++ /dev/null
@@ -1,92 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * makeduh.c - Function to construct a DUH from / / \ \
12 * its components. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21
22#include "dumb.h"
23#include "internal/dumb.h"
24
25
26
27static DUH_SIGNAL *make_signal(DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata)
28{
29 DUH_SIGNAL *signal;
30
31 ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
32 ASSERT(desc->sigrenderer_get_samples && desc->sigrenderer_get_current_sample);
33
34 signal = malloc(sizeof(*signal));
35
36 if (!signal) {
37 if (desc->unload_sigdata)
38 if (sigdata)
39 (*desc->unload_sigdata)(sigdata);
40 return NULL;
41 }
42
43 signal->desc = desc;
44 signal->sigdata = sigdata;
45
46 return signal;
47}
48
49
50
51DUH *make_duh(long length, int n_signals, DUH_SIGTYPE_DESC *desc[], sigdata_t *sigdata[])
52{
53 DUH *duh = malloc(sizeof(*duh));
54 int i;
55 int fail;
56
57 if (duh) {
58 duh->n_signals = n_signals;
59
60 duh->signal = malloc(n_signals * sizeof(*duh->signal));
61
62 if (!duh->signal) {
63 free(duh);
64 duh = NULL;
65 }
66 }
67
68 if (!duh) {
69 for (i = 0; i < n_signals; i++)
70 if (desc[i]->unload_sigdata)
71 if (sigdata[i])
72 (*desc[i]->unload_sigdata)(sigdata[i]);
73 return NULL;
74 }
75
76 fail = 0;
77
78 for (i = 0; i < n_signals; i++) {
79 duh->signal[i] = make_signal(desc[i], sigdata[i]);
80 if (!duh->signal[i])
81 fail = 1;
82 }
83
84 if (fail) {
85 unload_duh(duh);
86 return NULL;
87 }
88
89 duh->length = length;
90
91 return duh;
92}
diff --git a/apps/codecs/dumb/src/core/rawsig.c b/apps/codecs/dumb/src/core/rawsig.c
deleted file mode 100644
index 926c990655..0000000000
--- a/apps/codecs/dumb/src/core/rawsig.c
+++ /dev/null
@@ -1,44 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * rawsig.c - Function to retrieve raw signal / / \ \
12 * data from a DUH provided you know | < / \_
13 * what type of signal it is. | \/ /\ /
14 * \_ / > /
15 * By entheh. | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21
22#include "dumb.h"
23#include "internal/dumb.h"
24
25
26
27/* You have to specify the type of sigdata, proving you know what to do with
28 * the pointer. If you get it wrong, you can expect NULL back.
29 */
30sigdata_t *duh_get_raw_sigdata(DUH *duh, int sig, long type)
31{
32 DUH_SIGNAL *signal;
33
34 if (!duh) return NULL;
35
36 if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL;
37
38 signal = duh->signal[sig];
39
40 if (signal && signal->desc->type == type)
41 return signal->sigdata;
42
43 return NULL;
44}
diff --git a/apps/codecs/dumb/src/core/readduh.c b/apps/codecs/dumb/src/core/readduh.c
deleted file mode 100644
index 514b04a077..0000000000
--- a/apps/codecs/dumb/src/core/readduh.c
+++ /dev/null
@@ -1,107 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * readduh.c - Code to read a DUH from an open / / \ \
12 * file. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21
22#include "dumb.h"
23#include "internal/dumb.h"
24
25
26
27static DUH_SIGNAL *read_signal(DUH *duh, DUMBFILE *f)
28{
29 DUH_SIGNAL *signal;
30 long type;
31
32 signal = malloc(sizeof(*signal));
33
34 if (!signal)
35 return NULL;
36
37 type = dumbfile_mgetl(f);
38 if (dumbfile_error(f)) {
39 free(signal);
40 return NULL;
41 }
42
43 signal->desc = _dumb_get_sigtype_desc(type);
44 if (!signal->desc) {
45 free(signal);
46 return NULL;
47 }
48
49 if (signal->desc->load_sigdata) {
50 signal->sigdata = (*signal->desc->load_sigdata)(duh, f);
51 if (!signal->sigdata) {
52 free(signal);
53 return NULL;
54 }
55 } else
56 signal->sigdata = NULL;
57
58 return signal;
59}
60
61
62
63/* read_duh(): reads a DUH from an already open DUMBFILE, and returns its
64 * pointer, or null on error. The file is not closed.
65 */
66DUH *read_duh(DUMBFILE *f)
67{
68 DUH *duh;
69 int i;
70
71 if (dumbfile_mgetl(f) != DUH_SIGNATURE)
72 return NULL;
73
74 duh = malloc(sizeof(*duh));
75 if (!duh)
76 return NULL;
77
78 duh->length = dumbfile_igetl(f);
79 if (dumbfile_error(f) || duh->length <= 0) {
80 free(duh);
81 return NULL;
82 }
83
84 duh->n_signals = dumbfile_igetl(f);
85 if (dumbfile_error(f) || duh->n_signals <= 0) {
86 free(duh);
87 return NULL;
88 }
89
90 duh->signal = malloc(sizeof(*duh->signal) * duh->n_signals);
91 if (!duh->signal) {
92 free(duh);
93 return NULL;
94 }
95
96 for (i = 0; i < duh->n_signals; i++)
97 duh->signal[i] = NULL;
98
99 for (i = 0; i < duh->n_signals; i++) {
100 if (!(duh->signal[i] = read_signal(duh, f))) {
101 unload_duh(duh);
102 return NULL;
103 }
104 }
105
106 return duh;
107}
diff --git a/apps/codecs/dumb/src/core/register.c b/apps/codecs/dumb/src/core/register.c
deleted file mode 100644
index 9eed45f796..0000000000
--- a/apps/codecs/dumb/src/core/register.c
+++ /dev/null
@@ -1,104 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * register.c - Signal type registration. / / \ \
12 * | < / \_
13 * By entheh. | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21
22#include "dumb.h"
23#include "internal/dumb.h"
24
25
26
27static DUH_SIGTYPE_DESC_LINK *sigtype_desc = NULL;
28static DUH_SIGTYPE_DESC_LINK **sigtype_desc_tail = &sigtype_desc;
29
30
31
32/* destroy_sigtypes(): frees all memory allocated while registering signal
33 * types. This function is set up to be called by dumb_exit().
34 */
35static void destroy_sigtypes(void)
36{
37 DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc, *next;
38 sigtype_desc = NULL;
39 sigtype_desc_tail = &sigtype_desc;
40
41 while (desc_link) {
42 next = desc_link->next;
43 free(desc_link);
44 desc_link = next;
45 }
46}
47
48
49
50/* dumb_register_sigtype(): registers a new signal type with DUMB. The signal
51 * type is identified by a four-character string (e.g. "WAVE"), which you can
52 * encode using the the DUMB_ID() macro (e.g. DUMB_ID('W','A','V','E')). The
53 * signal's behaviour is defined by four functions, whose pointers you pass
54 * here. See the documentation for details.
55 *
56 * If a DUH tries to use a signal that has not been registered using this
57 * function, then the library will fail to load the DUH.
58 */
59void dumb_register_sigtype(DUH_SIGTYPE_DESC *desc)
60{
61 DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
62
63 ASSERT((desc->load_sigdata && desc->unload_sigdata) || (!desc->load_sigdata && !desc->unload_sigdata));
64 ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
65 ASSERT(desc->sigrenderer_get_samples && desc->sigrenderer_get_current_sample);
66
67 if (desc_link) {
68 do {
69 if (desc_link->desc->type == desc->type) {
70 desc_link->desc = desc;
71 return;
72 }
73 desc_link = desc_link->next;
74 } while (desc_link);
75 } else
76 dumb_atexit(&destroy_sigtypes);
77
78 desc_link = *sigtype_desc_tail = malloc(sizeof(DUH_SIGTYPE_DESC_LINK));
79
80 if (!desc_link)
81 return;
82
83 desc_link->next = NULL;
84 sigtype_desc_tail = &desc_link->next;
85
86 desc_link->desc = desc;
87}
88
89
90
91/* _dumb_get_sigtype_desc(): searches the registered functions for a signal
92 * type matching the parameter. If such a sigtype is found, it returns a
93 * pointer to a sigtype descriptor containing the necessary functions to
94 * manage the signal. If none is found, it returns NULL.
95 */
96DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(long type)
97{
98 DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
99
100 while (desc_link && desc_link->desc->type != type)
101 desc_link = desc_link->next;
102
103 return desc_link->desc;
104}
diff --git a/apps/codecs/dumb/src/core/rendduh.c b/apps/codecs/dumb/src/core/rendduh.c
deleted file mode 100644
index 39db8ab8a3..0000000000
--- a/apps/codecs/dumb/src/core/rendduh.c
+++ /dev/null
@@ -1,202 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * rendduh.c - Functions for rendering a DUH into / / \ \
12 * an end-user sample format. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21#include <limits.h>
22
23#include "dumb.h"
24#include "internal/dumb.h"
25
26
27
28/* On the x86, we can use some tricks to speed stuff up */
29#if (defined _MSC_VER) || (defined __DJGPP__) || (defined __MINGW__)
30// Can't we detect Linux and other x86 platforms here? :/
31
32#define FAST_MID(var, min, max) { \
33 var -= (min); \
34 var &= (~var) >> (sizeof(var) * CHAR_BIT - 1); \
35 var += (min); \
36 var -= (max); \
37 var &= var >> (sizeof(var) * CHAR_BIT - 1); \
38 var += (max); \
39}
40
41#define CONVERT8(src, pos, signconv) { \
42 signed int f = (src + 0x8000) >> 16; \
43 FAST_MID(f, -128, 127); \
44 ((char*)sptr)[pos] = (char)f ^ signconv; \
45}
46
47#define CONVERT16(src, pos, signconv) { \
48 signed int f = (src + 0x80) >> 8; \
49 FAST_MID(f, -32768, 32767); \
50 ((short*)sptr)[pos] = (short)(f ^ signconv); \
51}
52
53#else
54
55#define CONVERT8(src, pos, signconv) \
56{ \
57 signed int f = (src + 0x8000) >> 16; \
58 f = MID(-128, f, 127); \
59 ((char *)sptr)[pos] = (char)f ^ signconv; \
60}
61
62
63
64#define CONVERT16(src, pos, signconv) \
65{ \
66 signed int f = (src + 0x80) >> 8; \
67 f = MID(-32768, f, 32767); \
68 ((short *)sptr)[pos] = (short)(f ^ signconv); \
69}
70
71#endif
72
73
74
75/* DEPRECATED */
76DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos)
77{
78 return duh_start_sigrenderer(duh, 0, n_channels, pos);
79}
80
81
82
83long duh_render(
84 DUH_SIGRENDERER *sigrenderer,
85 int bits, int unsign,
86 float volume, float delta,
87 long size, void *sptr
88)
89{
90 long n;
91
92 sample_t **sampptr;
93
94 int n_channels;
95
96 ASSERT(bits == 8 || bits == 16);
97 ASSERT(sptr);
98
99 if (!sigrenderer)
100 return 0;
101
102 n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
103
104 ASSERT(n_channels > 0);
105 /* This restriction will be removed when need be. At the moment, tightly
106 * optimised loops exist for exactly one or two channels.
107 */
108 ASSERT(n_channels <= 2);
109
110 sampptr = create_sample_buffer(n_channels, size);
111
112 if (!sampptr)
113 return 0;
114
115 dumb_silence(sampptr[0], n_channels * size);
116
117 size = duh_sigrenderer_get_samples(sigrenderer, volume, delta, size, sampptr);
118
119 if (bits == 16) {
120 int signconv = unsign ? 0x8000 : 0x0000;
121
122 if (n_channels == 2) {
123 for (n = 0; n < size; n++) {
124 CONVERT16(sampptr[0][n], n << 1, signconv);
125 }
126 for (n = 0; n < size; n++) {
127 CONVERT16(sampptr[1][n], (n << 1) + 1, signconv);
128 }
129 } else {
130 for (n = 0; n < size; n++) {
131 CONVERT16(sampptr[0][n], n, signconv);
132 }
133 }
134 } else {
135 char signconv = unsign ? 0x80 : 0x00;
136
137 if (n_channels == 2) {
138 for (n = 0; n < size; n++) {
139 CONVERT8(sampptr[0][n], n << 1, signconv);
140 }
141 for (n = 0; n < size; n++) {
142 CONVERT8(sampptr[1][n], (n << 1) + 1, signconv);
143 }
144 } else {
145 for (n = 0; n < size; n++) {
146 CONVERT8(sampptr[0][n], n, signconv);
147 }
148 }
149 }
150
151 destroy_sample_buffer(sampptr);
152
153 return size;
154}
155
156
157
158/* DEPRECATED */
159int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr)
160{
161 return duh_sigrenderer_get_n_channels(dr);
162}
163
164
165
166/* DEPRECATED */
167long duh_renderer_get_position(DUH_SIGRENDERER *dr)
168{
169 return duh_sigrenderer_get_position(dr);
170}
171
172
173
174/* DEPRECATED */
175void duh_end_renderer(DUH_SIGRENDERER *dr)
176{
177 duh_end_sigrenderer(dr);
178}
179
180
181
182/* DEPRECATED */
183DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer)
184{
185 return sigrenderer;
186}
187
188
189
190/* DEPRECATED */
191DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr)
192{
193 return dr;
194}
195
196
197
198/* DEPRECATED */
199DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr)
200{
201 return dr;
202}
diff --git a/apps/codecs/dumb/src/core/rendsig.c b/apps/codecs/dumb/src/core/rendsig.c
deleted file mode 100644
index 6b39ce7de9..0000000000
--- a/apps/codecs/dumb/src/core/rendsig.c
+++ /dev/null
@@ -1,301 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * rendsig.c - Wrappers to render samples from / / \ \
12 * the signals in a DUH. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21
22#include "dumb.h"
23#include "internal/dumb.h"
24
25
26
27struct DUH_SIGRENDERER
28{
29 DUH_SIGTYPE_DESC *desc;
30
31 sigrenderer_t *sigrenderer;
32
33 int n_channels;
34
35 long pos;
36 int subpos;
37
38 DUH_SIGRENDERER_ANALYSER_CALLBACK callback;
39 void *callback_data;
40};
41
42
43
44DUH_SIGRENDERER *duh_start_sigrenderer(DUH *duh, int sig, int n_channels, long pos)
45{
46 DUH_SIGRENDERER *sigrenderer;
47
48 DUH_SIGNAL *signal;
49 DUH_START_SIGRENDERER proc;
50
51 if ((unsigned int)sig >= (unsigned int)duh->n_signals)
52 return NULL;
53
54 signal = duh->signal[sig];
55 if (!signal)
56 return NULL;
57
58 sigrenderer = malloc(sizeof(*sigrenderer));
59 if (!sigrenderer)
60 return NULL;
61
62 sigrenderer->desc = signal->desc;
63
64 proc = sigrenderer->desc->start_sigrenderer;
65
66 if (proc) {
67 duh->signal[sig] = NULL;
68 sigrenderer->sigrenderer = (*proc)(duh, signal->sigdata, n_channels, pos);
69 duh->signal[sig] = signal;
70
71 if (!sigrenderer->sigrenderer) {
72 free(sigrenderer);
73 return NULL;
74 }
75 } else
76 sigrenderer->sigrenderer = NULL;
77
78 sigrenderer->n_channels = n_channels;
79
80 sigrenderer->pos = pos;
81 sigrenderer->subpos = 0;
82
83 sigrenderer->callback = NULL;
84
85 return sigrenderer;
86}
87
88
89
90#include <stdio.h>
91void duh_sigrenderer_set_callback(
92 DUH_SIGRENDERER *sigrenderer,
93 DUH_SIGRENDERER_CALLBACK callback, void *data
94)
95{
96 (void)sigrenderer;
97 (void)callback;
98 (void)data;
99/* FIXME
100 fprintf(stderr,
101 "Call to deprecated function duh_sigrenderer_set_callback(). The callback\n"
102 "was not installed. See dumb/docs/deprec.txt for how to fix this.\n");*/
103}
104
105
106
107void duh_sigrenderer_set_analyser_callback(
108 DUH_SIGRENDERER *sigrenderer,
109 DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data
110)
111{
112 if (sigrenderer) {
113 sigrenderer->callback = callback;
114 sigrenderer->callback_data = data;
115 }
116}
117
118
119
120int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer)
121{
122 return sigrenderer ? sigrenderer->n_channels : 0;
123}
124
125
126
127long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer)
128{
129 return sigrenderer ? sigrenderer->pos : -1;
130}
131
132
133
134void duh_sigrenderer_set_sigparam(
135 DUH_SIGRENDERER *sigrenderer,
136 unsigned char id, long value
137)
138{
139 DUH_SIGRENDERER_SET_SIGPARAM proc;
140
141 if (!sigrenderer) return;
142
143 proc = sigrenderer->desc->sigrenderer_set_sigparam;
144 if (proc) {
145 (*proc)(sigrenderer->sigrenderer, id, value);
146 return;
147 }
148
149 TRACE("Parameter #%d = %ld for signal %c%c%c%c, which does not take parameters.\n",
150 (int)id,
151 value,
152 (int)(sigrenderer->desc->type >> 24),
153 (int)(sigrenderer->desc->type >> 16),
154 (int)(sigrenderer->desc->type >> 8),
155 (int)(sigrenderer->desc->type));
156}
157
158
159
160long duh_sigrenderer_get_samples(
161 DUH_SIGRENDERER *sigrenderer,
162 float volume, float delta,
163 long size, sample_t **samples
164)
165{
166 long rendered;
167 LONG_LONG t;
168
169 if (!sigrenderer) return 0;
170
171 rendered = (*sigrenderer->desc->sigrenderer_get_samples)
172 (sigrenderer->sigrenderer, volume, delta, size, samples);
173
174 if (rendered) {
175 if (sigrenderer->callback)
176 (*sigrenderer->callback)(sigrenderer->callback_data,
177 (const sample_t *const *)samples, sigrenderer->n_channels, rendered);
178
179 t = sigrenderer->subpos + (LONG_LONG)(delta * 65536.0 + 0.5) * rendered;
180
181 sigrenderer->pos += (long)(t >> 16);
182 sigrenderer->subpos = (int)t & 65535;
183 }
184
185 return rendered;
186}
187
188
189
190/* DEPRECATED */
191long duh_render_signal(
192 DUH_SIGRENDERER *sigrenderer,
193 float volume, float delta,
194 long size, sample_t **samples
195)
196{
197 sample_t **s = create_sample_buffer(sigrenderer->n_channels, size);
198 long rendered;
199 long i;
200 int j;
201 if (!s) return 0;
202 rendered = duh_sigrenderer_get_samples(sigrenderer, volume, delta, size, s);
203 for (j = 0; j < sigrenderer->n_channels; j++)
204 for (i = 0; i < rendered; i++)
205 samples[j][i] += s[j][i] >> 8;
206 destroy_sample_buffer(s);
207 return rendered;
208}
209
210
211
212void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples)
213{
214 if (sigrenderer)
215 (*sigrenderer->desc->sigrenderer_get_current_sample)(sigrenderer->sigrenderer, volume, samples);
216}
217
218
219
220void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer)
221{
222 if (sigrenderer) {
223 if (sigrenderer->desc->end_sigrenderer)
224 if (sigrenderer->sigrenderer)
225 (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
226
227 free(sigrenderer);
228 }
229}
230
231
232
233DUH_SIGRENDERER *duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, long pos)
234{
235 DUH_SIGRENDERER *sigrenderer;
236
237 if (desc->start_sigrenderer && !vsigrenderer) return NULL;
238
239 sigrenderer = malloc(sizeof(*sigrenderer));
240 if (!sigrenderer) {
241 if (desc->end_sigrenderer)
242 if (vsigrenderer)
243 (*desc->end_sigrenderer)(vsigrenderer);
244 return NULL;
245 }
246
247 sigrenderer->desc = desc;
248 sigrenderer->sigrenderer = vsigrenderer;
249
250 sigrenderer->n_channels = n_channels;
251
252 sigrenderer->pos = pos;
253 sigrenderer->subpos = 0;
254
255 sigrenderer->callback = NULL;
256
257 return sigrenderer;
258}
259
260
261
262sigrenderer_t *duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type)
263{
264 if (sigrenderer && sigrenderer->desc->type == type)
265 return sigrenderer->sigrenderer;
266
267 return NULL;
268}
269
270
271
272#if 0
273// This function is disabled because we don't know whether we want to destroy
274// the sigrenderer if the type doesn't match. We don't even know if we need
275// the function at all. Who would want to keep an IT_SIGRENDERER (for
276// instance) without keeping the DUH_SIGRENDERER?
277sigrenderer_t *duh_decompose_to_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type)
278{
279 if (sigrenderer && sigrenderer->desc->type == type) {
280
281
282
283 if (sigrenderer) {
284 if (sigrenderer->desc->end_sigrenderer)
285 if (sigrenderer->sigrenderer)
286 (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
287
288 free(sigrenderer);
289 }
290
291
292
293
294
295
296 return sigrenderer->sigrenderer;
297 }
298
299 return NULL;
300}
301#endif
diff --git a/apps/codecs/dumb/src/core/unload.c b/apps/codecs/dumb/src/core/unload.c
deleted file mode 100644
index 3bf0285cd1..0000000000
--- a/apps/codecs/dumb/src/core/unload.c
+++ /dev/null
@@ -1,58 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * unload.c - Code to free a DUH from memory. / / \ \
12 * | < / \_
13 * By entheh. | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21
22#include "dumb.h"
23#include "internal/dumb.h"
24
25
26
27static void destroy_signal(DUH_SIGNAL *signal)
28{
29 if (signal) {
30 if (signal->desc)
31 if (signal->desc->unload_sigdata)
32 if (signal->sigdata)
33 (*signal->desc->unload_sigdata)(signal->sigdata);
34
35 free(signal);
36 }
37}
38
39
40
41/* unload_duh(): destroys a DUH struct. You must call this for every DUH
42 * struct created, when you've finished with it.
43 */
44void unload_duh(DUH *duh)
45{
46 int i;
47
48 if (duh) {
49 if (duh->signal) {
50 for (i = 0; i < duh->n_signals; i++)
51 destroy_signal(duh->signal[i]);
52
53 free(duh->signal);
54 }
55
56 free(duh);
57 }
58}
diff --git a/apps/codecs/dumb/src/helpers/clickrem.c b/apps/codecs/dumb/src/helpers/clickrem.c
deleted file mode 100644
index ddc861d931..0000000000
--- a/apps/codecs/dumb/src/helpers/clickrem.c
+++ /dev/null
@@ -1,270 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * clickrem.c - Click removal helpers. / / \ \
12 * | < / \_
13 * By entheh. | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21#include <math.h>
22#include "dumb.h"
23
24
25
26typedef struct DUMB_CLICK DUMB_CLICK;
27
28
29struct DUMB_CLICK_REMOVER
30{
31 DUMB_CLICK *click;
32 int n_clicks;
33
34 int offset;
35};
36
37
38struct DUMB_CLICK
39{
40 DUMB_CLICK *next;
41 long pos;
42 sample_t step;
43};
44
45
46
47DUMB_CLICK_REMOVER *dumb_create_click_remover(void)
48{
49 DUMB_CLICK_REMOVER *cr = malloc(sizeof(*cr));
50 if (!cr) return NULL;
51
52 cr->click = NULL;
53 cr->n_clicks = 0;
54
55 cr->offset = 0;
56
57 return cr;
58}
59
60
61
62void dumb_record_click(DUMB_CLICK_REMOVER *cr, long pos, sample_t step)
63{
64 DUMB_CLICK *click;
65
66 ASSERT(pos >= 0);
67
68 if (!cr || !step) return;
69
70 if (pos == 0) {
71 cr->offset -= step;
72 return;
73 }
74
75 click = malloc(sizeof(*click));
76 if (!click) return;
77
78 click->pos = pos;
79 click->step = step;
80
81 click->next = cr->click;
82 cr->click = click;
83 cr->n_clicks++;
84}
85
86
87
88static DUMB_CLICK *dumb_click_mergesort(DUMB_CLICK *click, int n_clicks)
89{
90 int i;
91 DUMB_CLICK *c1, *c2, **cp;
92
93 if (n_clicks <= 1) return click;
94
95 /* Split the list into two */
96 c1 = click;
97 cp = &c1;
98 for (i = 0; i < n_clicks; i += 2) cp = &(*cp)->next;
99 c2 = *cp;
100 *cp = NULL;
101
102 /* Sort the sublists */
103 c1 = dumb_click_mergesort(c1, (n_clicks + 1) >> 1);
104 c2 = dumb_click_mergesort(c2, n_clicks >> 1);
105
106 /* Merge them */
107 cp = &click;
108 while (c1 && c2) {
109 if (c1->pos > c2->pos) {
110 *cp = c2;
111 c2 = c2->next;
112 } else {
113 *cp = c1;
114 c1 = c1->next;
115 }
116 cp = &(*cp)->next;
117 }
118 if (c2)
119 *cp = c2;
120 else
121 *cp = c1;
122
123 return click;
124}
125
126
127
128void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, float halflife)
129{
130 DUMB_CLICK *click;
131 long pos = 0;
132 int offset;
133 int factor;
134
135 if (!cr) return;
136
137 factor = (int)floor(pow(0.5, 1.0/halflife) * (1U << 31));
138
139 click = dumb_click_mergesort(cr->click, cr->n_clicks);
140 cr->click = NULL;
141 cr->n_clicks = 0;
142
143 while (click) {
144 DUMB_CLICK *next = click->next;
145 ASSERT(click->pos <= length);
146 offset = cr->offset;
147 if (offset < 0) {
148 offset = -offset;
149 while (pos < click->pos) {
150 samples[pos++] -= offset;
151 offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
152 }
153 offset = -offset;
154 } else {
155 while (pos < click->pos) {
156 samples[pos++] += offset;
157 offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
158 }
159 }
160 cr->offset = offset - click->step;
161 free(click);
162 click = next;
163 }
164
165 offset = cr->offset;
166 if (offset < 0) {
167 offset = -offset;
168 while (pos < length) {
169 samples[pos++] -= offset;
170 offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
171 }
172 offset = -offset;
173 } else {
174 while (pos < length) {
175 samples[pos++] += offset;
176 offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
177 }
178 }
179 cr->offset = offset;
180}
181
182
183
184sample_t dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr)
185{
186 return cr ? cr->offset : 0;
187}
188
189
190
191void dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr)
192{
193 if (cr) {
194 DUMB_CLICK *click = cr->click;
195 while (click) {
196 DUMB_CLICK *next = click->next;
197 free(click);
198 click = next;
199 }
200 free(cr);
201 }
202}
203
204
205
206DUMB_CLICK_REMOVER **dumb_create_click_remover_array(int n)
207{
208 int i;
209 DUMB_CLICK_REMOVER **cr;
210 if (n <= 0) return NULL;
211 cr = malloc(n * sizeof(*cr));
212 if (!cr) return NULL;
213 for (i = 0; i < n; i++) cr[i] = dumb_create_click_remover();
214 return cr;
215}
216
217
218
219void dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step)
220{
221 if (cr) {
222 int i;
223 for (i = 0; i < n; i++)
224 dumb_record_click(cr[i], pos, step[i]);
225 }
226}
227
228
229
230void dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step)
231{
232 if (cr) {
233 int i;
234 for (i = 0; i < n; i++)
235 dumb_record_click(cr[i], pos, -step[i]);
236 }
237}
238
239
240
241void dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, long length, float halflife)
242{
243 if (cr) {
244 int i;
245 for (i = 0; i < n; i++)
246 dumb_remove_clicks(cr[i], samples[i], length, halflife);
247 }
248}
249
250
251
252void dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr, sample_t *offset)
253{
254 if (cr) {
255 int i;
256 for (i = 0; i < n; i++)
257 if (cr[i]) offset[i] += cr[i]->offset;
258 }
259}
260
261
262
263void dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr)
264{
265 if (cr) {
266 int i;
267 for (i = 0; i < n; i++) dumb_destroy_click_remover(cr[i]);
268 free(cr);
269 }
270}
diff --git a/apps/codecs/dumb/src/helpers/memfile.c b/apps/codecs/dumb/src/helpers/memfile.c
deleted file mode 100644
index b65ab5f78d..0000000000
--- a/apps/codecs/dumb/src/helpers/memfile.c
+++ /dev/null
@@ -1,96 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * memfile.c - Module for reading data from / / \ \
12 * memory using a DUMBFILE. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21#include <string.h>
22
23#include "dumb.h"
24
25
26
27typedef struct MEMFILE MEMFILE;
28
29struct MEMFILE
30{
31 const char *ptr;
32 long left;
33};
34
35
36
37static int dumb_memfile_skip(void *f, long n)
38{
39 MEMFILE *m = f;
40 if (n > m->left) return -1;
41 m->ptr += n;
42 m->left -= n;
43 return 0;
44}
45
46
47
48static int dumb_memfile_getc(void *f)
49{
50 MEMFILE *m = f;
51 if (m->left <= 0) return -1;
52 m->left--;
53 return *(const unsigned char *)m->ptr++;
54}
55
56
57
58static long dumb_memfile_getnc(char *ptr, long n, void *f)
59{
60 MEMFILE *m = f;
61 if (n > m->left) n = m->left;
62 memcpy(ptr, m->ptr, n);
63 m->ptr += n;
64 m->left -= n;
65 return n;
66}
67
68
69
70static void dumb_memfile_close(void *f)
71{
72 free(f);
73}
74
75
76
77static DUMBFILE_SYSTEM memfile_dfs = {
78 NULL,
79 &dumb_memfile_skip,
80 &dumb_memfile_getc,
81 &dumb_memfile_getnc,
82 &dumb_memfile_close
83};
84
85
86
87DUMBFILE *dumbfile_open_memory(const char *data, long size)
88{
89 MEMFILE *m = malloc(sizeof(*m));
90 if (!m) return NULL;
91
92 m->ptr = data;
93 m->left = size;
94
95 return dumbfile_open_ex(m, &memfile_dfs);
96}
diff --git a/apps/codecs/dumb/src/helpers/resample.c b/apps/codecs/dumb/src/helpers/resample.c
deleted file mode 100644
index d8b238fc71..0000000000
--- a/apps/codecs/dumb/src/helpers/resample.c
+++ /dev/null
@@ -1,1177 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * resample.c - Resampling helper. / / \ \
12 * | < / \_
13 * By Bob and entheh. | \/ /\ /
14 * \_ / > /
15 * In order to find a good trade-off between | \ / /
16 * speed and accuracy in this code, some tests | ' /
17 * were carried out regarding the behaviour of \__/
18 * long long ints with gcc. The following code
19 * was tested:
20 *
21 * int a, b, c;
22 * c = ((long long)a * b) >> 16;
23 *
24 * DJGPP GCC Version 3.0.3 generated the following assembly language code for
25 * the multiplication and scaling, leaving the 32-bit result in EAX.
26 *
27 * movl -8(%ebp), %eax ; read one int into EAX
28 * imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX
29 * shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX
30 *
31 * Note that a 32*32->64 multiplication is performed, allowing for high
32 * accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally),
33 * so it is a minor concern when four multiplications are being performed
34 * (the cubic resampler). On the Pentium MMX and earlier, it takes four or
35 * more cycles, so this method is unsuitable for use in the low-quality
36 * resamplers.
37 *
38 * Since "long long" is a gcc-specific extension, we use LONG_LONG instead,
39 * defined in dumb.h. We may investigate later what code MSVC generates, but
40 * if it seems too slow then we suggest you use a good compiler.
41 *
42 * FIXME: these comments are somewhat out of date now.
43 */
44
45#include <math.h>
46#include "dumb.h"
47
48
49
50/* Compile with -DHEAVYDEBUG if you want to make sure the pick-up function is
51 * called when it should be. There will be a considerable performance hit,
52 * since at least one condition has to be tested for every sample generated.
53 */
54#ifdef HEAVYDEBUG
55#define HEAVYASSERT(cond) ASSERT(cond)
56#else
57#define HEAVYASSERT(cond)
58#endif
59
60
61
62//#define MULSC(a, b) ((int)((LONG_LONG)(a) * (b) >> 16))
63//#define MULSC(a, b) ((a) * ((b) >> 2) >> 14)
64#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32))
65
66
67
68/* A global variable for controlling resampling quality wherever a local
69 * specification doesn't override it. The following values are valid:
70 *
71 * 0 - DUMB_RQ_ALIASING - fastest
72 * 1 - DUMB_RQ_LINEAR
73 * 2 - DUMB_RQ_CUBIC - nicest
74 *
75 * Values outside the range 0-2 will behave the same as the nearest
76 * value within the range.
77 */
78int dumb_resampling_quality = 2;
79
80
81
82void dumb_reset_resampler(DUMB_RESAMPLER *resampler, sample_t *src, long pos, long start, long end)
83{
84 resampler->src = src;
85 resampler->pos = pos;
86 resampler->subpos = 0;
87 resampler->start = start;
88 resampler->end = end;
89 resampler->dir = 1;
90 resampler->pickup = NULL;
91 resampler->pickup_data = NULL;
92 resampler->min_quality = 0;
93 resampler->max_quality = DUMB_RQ_N_LEVELS - 1;
94 resampler->x[2] = resampler->x[1] = resampler->x[0] = 0;
95 resampler->overshot = -1;
96}
97
98
99
100DUMB_RESAMPLER *dumb_start_resampler(sample_t *src, long pos, long start, long end)
101{
102 DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler));
103 if (!resampler) return NULL;
104 dumb_reset_resampler(resampler, src, pos, start, end);
105 return resampler;
106}
107
108
109
110/* For convenience, returns nonzero on stop. */
111static int process_pickup(DUMB_RESAMPLER *resampler)
112{
113 if (resampler->overshot < 0) {
114 resampler->overshot = 0;
115 dumb_resample(resampler, NULL, 2, 0, 1.0f);
116 resampler->x[0] = resampler->x[1];
117 }
118
119 for (;;) {
120 if (resampler->dir < 0) {
121 if (resampler->overshot >= 3 && resampler->pos+3 >= resampler->start) resampler->x[0] = resampler->src[resampler->pos+3];
122 if (resampler->overshot >= 2 && resampler->pos+2 >= resampler->start) resampler->x[1] = resampler->src[resampler->pos+2];
123 if (resampler->overshot >= 1 && resampler->pos+1 >= resampler->start) resampler->x[2] = resampler->src[resampler->pos+1];
124 resampler->overshot = resampler->start - resampler->pos - 1;
125 } else {
126 if (resampler->overshot >= 3 && resampler->pos-3 < resampler->end) resampler->x[0] = resampler->src[resampler->pos-3];
127 if (resampler->overshot >= 2 && resampler->pos-2 < resampler->end) resampler->x[1] = resampler->src[resampler->pos-2];
128 if (resampler->overshot >= 1 && resampler->pos-1 < resampler->end) resampler->x[2] = resampler->src[resampler->pos-1];
129 resampler->overshot = resampler->pos - resampler->end;
130 }
131
132 if (resampler->overshot < 0) {
133 resampler->overshot = 0;
134 return 0;
135 }
136
137 if (!resampler->pickup) {
138 resampler->dir = 0;
139 return 1;
140 }
141 (*resampler->pickup)(resampler, resampler->pickup_data);
142 if (resampler->dir == 0) return 1;
143 ASSERT(resampler->dir == -1 || resampler->dir == 1);
144 }
145}
146
147
148
149/* Executes the content 'iterator' times.
150 * Clobbers the 'iterator' variable.
151 * The loop is unrolled by four.
152 */
153#define LOOP4(iterator, CONTENT) \
154{ \
155 if ((iterator) & 2) { \
156 CONTENT; \
157 CONTENT; \
158 } \
159 if ((iterator) & 1) { \
160 CONTENT; \
161 } \
162 (iterator) >>= 2; \
163 while (iterator) { \
164 CONTENT; \
165 CONTENT; \
166 CONTENT; \
167 CONTENT; \
168 (iterator)--; \
169 } \
170}
171
172
173
174long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, float volume, float delta)
175{
176 int dt;
177 int vol;
178 long done;
179 long todo;
180 int quality;
181
182 if (!resampler || resampler->dir == 0) return 0;
183 ASSERT(resampler->dir == -1 || resampler->dir == 1);
184
185 done = 0;
186 dt = (int)(delta * 65536.0 + 0.5);
187 vol = (int)floor(volume * 65536.0 + 0.5);
188
189 if (vol == 0) dst = NULL;
190
191 quality = dumb_resampling_quality;
192 if (quality > resampler->max_quality) quality = resampler->max_quality;
193 else if (quality < resampler->min_quality) quality = resampler->min_quality;
194
195 while (done < dst_size) {
196 if (process_pickup(resampler)) return done;
197
198 if ((resampler->dir ^ dt) < 0)
199 dt = -dt;
200
201 if (resampler->dir < 0)
202 todo = (long)((((LONG_LONG)(resampler->pos - resampler->start) << 16) + resampler->subpos - dt) / -dt);
203 else
204 todo = (long)((((LONG_LONG)(resampler->end - resampler->pos) << 16) - resampler->subpos - 1 + dt) / dt);
205
206 if (todo < 0)
207 todo = 0;
208 else if (todo > dst_size - done)
209 todo = dst_size - done;
210
211 done += todo;
212
213 {
214 sample_t *src = resampler->src;
215 long pos = resampler->pos;
216 int subpos = resampler->subpos;
217 long diff = pos;
218 long overshot;
219 if (resampler->dir < 0) {
220 if (!dst) {
221 /* Silence or simulation */
222 LONG_LONG new_subpos = subpos + dt * todo;
223 pos += (long)(new_subpos >> 16);
224 subpos = (long)new_subpos & 65535;
225 } else if (quality <= DUMB_RQ_ALIASING) {
226 /* Aliasing, backwards */
227 sample_t xbuf[2];
228 sample_t *x = &xbuf[0];
229 sample_t *xstart;
230 xbuf[0] = resampler->x[1];
231 xbuf[1] = resampler->x[2];
232 while (todo && x < &xbuf[2]) {
233 HEAVYASSERT(pos >= resampler->start);
234 *dst++ += MULSC(x[0], vol);
235 subpos += dt;
236 pos += subpos >> 16;
237 x -= subpos >> 16;
238 subpos &= 65535;
239 todo--;
240 }
241 x = xstart = &src[pos];
242 LOOP4(todo,
243 *dst++ += MULSC(x[2], vol);
244 subpos += dt;
245 x += subpos >> 16;
246 subpos &= 65535;
247 );
248 pos += x - xstart;
249 } else if (quality <= DUMB_RQ_LINEAR) {
250 /* Linear interpolation, backwards */
251 sample_t xbuf[3];
252 sample_t *x = &xbuf[1];
253 xbuf[0] = resampler->x[1];
254 xbuf[1] = resampler->x[2];
255 xbuf[2] = src[pos];
256 while (todo && x < &xbuf[3]) {
257 HEAVYASSERT(pos >= resampler->start);
258 *dst++ += MULSC(x[0] + MULSC(x[-1] - x[0], subpos), vol);
259 subpos += dt;
260 pos += subpos >> 16;
261 x -= subpos >> 16;
262 subpos &= 65535;
263 todo--;
264 }
265 x = &src[pos];
266 LOOP4(todo,
267 HEAVYASSERT(pos >= resampler->start);
268 *dst++ += MULSC(x[1] + MULSC(x[2] - x[1], subpos), vol);
269 subpos += dt;
270 pos += subpos >> 16;
271 x += subpos >> 16;
272 subpos &= 65535;
273 );
274 } else {
275 /* Cubic interpolation, backwards */
276 sample_t xbuf[6];
277 sample_t *x = &xbuf[3];
278 sample_t *lastx = NULL;
279 int a = 0, b = 0, c = 0;
280 xbuf[0] = resampler->x[0];
281 xbuf[1] = resampler->x[1];
282 xbuf[2] = resampler->x[2];
283 xbuf[3] = src[pos];
284 if (pos-1 >= resampler->start) xbuf[4] = src[pos-1];
285 if (pos-2 >= resampler->start) xbuf[5] = src[pos-2];
286 while (todo && x < &xbuf[6]) {
287 HEAVYASSERT(pos >= resampler->start);
288 if (lastx != x) {
289 lastx = x;
290 a = (((x[-1] - x[-2]) << 1) + (x[-1] - x[-2]) + (x[-3] - x[0])) >> 1;
291 b = (x[-2] << 1) + x[0] - ((5 * x[-1] + x[-3]) >> 1);
292 c = (x[-2] - x[0]) >> 1;
293 }
294 *dst++ += MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + x[-1], vol);
295 subpos += dt;
296 pos += subpos >> 16;
297 x -= subpos >> 16;
298 subpos &= 65535;
299 todo--;
300 }
301 x = &src[pos];
302 lastx = NULL;
303 LOOP4(todo,
304 HEAVYASSERT(pos >= resampler->start);
305 if (lastx != x) {
306 lastx = x;
307 a = (((x[1] - x[2]) << 1) + (x[1] - x[2]) + (x[3] - x[0])) >> 1;
308 b = (x[2] << 1) + x[0] - ((5 * x[1] + x[3]) >> 1);
309 c = (x[2] - x[0]) >> 1;
310 }
311 *dst++ += MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + x[1], vol);
312 subpos += dt;
313 pos += subpos >> 16;
314 x += subpos >> 16;
315 subpos &= 65535;
316 );
317 }
318 diff = diff - pos;
319 overshot = resampler->start - pos - 1;
320 if (diff >= 3) {
321 resampler->x[0] = overshot >= 3 ? 0 : src[pos+3];
322 resampler->x[1] = overshot >= 2 ? 0 : src[pos+2];
323 resampler->x[2] = overshot >= 1 ? 0 : src[pos+1];
324 } else if (diff >= 2) {
325 resampler->x[0] = resampler->x[2];
326 resampler->x[1] = overshot >= 2 ? 0 : src[pos+2];
327 resampler->x[2] = overshot >= 1 ? 0 : src[pos+1];
328 } else if (diff >= 1) {
329 resampler->x[0] = resampler->x[1];
330 resampler->x[1] = resampler->x[2];
331 resampler->x[2] = overshot >= 1 ? 0 : src[pos+1];
332 }
333 } else {
334 if (!dst) {
335 /* Silence or simulation */
336 LONG_LONG new_subpos = subpos + dt * todo;
337 pos += (long)(new_subpos >> 16);
338 subpos = (long)new_subpos & 65535;
339 } else if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
340 /* Aliasing, forwards */
341 sample_t xbuf[2];
342 sample_t *x = &xbuf[0];
343 sample_t *xstart;
344 xbuf[0] = resampler->x[1];
345 xbuf[1] = resampler->x[2];
346 while (todo && x < &xbuf[2]) {
347 HEAVYASSERT(pos < resampler->end);
348 *dst++ += MULSC(x[0], vol);
349 subpos += dt;
350 pos += subpos >> 16;
351 x += subpos >> 16;
352 subpos &= 65535;
353 todo--;
354 }
355 x = xstart = &src[pos];
356 LOOP4(todo,
357 *dst++ += MULSC(x[-2], vol);
358 subpos += dt;
359 x += subpos >> 16;
360 subpos &= 65535;
361 );
362 pos += x - xstart;
363 } else if (dumb_resampling_quality <= DUMB_RQ_LINEAR) {
364 /* Linear interpolation, forwards */
365 sample_t xbuf[3];
366 sample_t *x = &xbuf[1];
367 xbuf[0] = resampler->x[1];
368 xbuf[1] = resampler->x[2];
369 xbuf[2] = src[pos];
370 while (todo && x < &xbuf[3]) {
371 HEAVYASSERT(pos < resampler->end);
372 *dst++ += MULSC(x[-1] + MULSC(x[0] - x[-1], subpos), vol);
373 subpos += dt;
374 pos += subpos >> 16;
375 x += subpos >> 16;
376 subpos &= 65535;
377 todo--;
378 }
379 x = &src[pos];
380 LOOP4(todo,
381 HEAVYASSERT(pos < resampler->end);
382 *dst++ += MULSC(x[-2] + MULSC(x[-1] - x[-2], subpos), vol);
383 subpos += dt;
384 pos += subpos >> 16;
385 x += subpos >> 16;
386 subpos &= 65535;
387 );
388 } else {
389 /* Cubic interpolation, forwards */
390 sample_t xbuf[6];
391 sample_t *x = &xbuf[3];
392 sample_t *lastx = NULL;
393 int a = 0, b = 0, c = 0;
394 xbuf[0] = resampler->x[0];
395 xbuf[1] = resampler->x[1];
396 xbuf[2] = resampler->x[2];
397 xbuf[3] = src[pos];
398 if (pos+1 < resampler->end) xbuf[4] = src[pos+1];
399 if (pos+2 < resampler->end) xbuf[5] = src[pos+2];
400 while (todo && x < &xbuf[6]) {
401 HEAVYASSERT(pos < resampler->end);
402 if (lastx != x) {
403 lastx = x;
404 a = (((x[-2] - x[-1]) << 1) + (x[-2] - x[-1]) + (x[0] - x[-3])) >> 1;
405 b = (x[-1] << 1) + x[-3] - ((5 * x[-2] + x[0]) >> 1);
406 c = (x[-1] - x[-3]) >> 1;
407 }
408 *dst++ += MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + x[-2], vol);
409 subpos += dt;
410 pos += subpos >> 16;
411 x += subpos >> 16;
412 subpos &= 65535;
413 todo--;
414 }
415 x = &src[pos];
416 lastx = NULL;
417 LOOP4(todo,
418 HEAVYASSERT(pos < resampler->end);
419 if (lastx != x) {
420 lastx = x;
421 a = (((x[-2] - x[-1]) << 1) + (x[-2] - x[-1]) + (x[0] - x[-3])) >> 1;
422 b = (x[-1] << 1) + x[-3] - ((5 * x[-2] + x[0]) >> 1);
423 c = (x[-1] - x[-3]) >> 1;
424 }
425 *dst++ += MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + x[-2], vol);
426 subpos += dt;
427 pos += subpos >> 16;
428 x += subpos >> 16;
429 subpos &= 65535;
430 );
431 }
432 diff = pos - diff;
433 overshot = pos - resampler->end;
434 if (diff >= 3) {
435 resampler->x[0] = overshot >= 3 ? 0 : src[pos-3];
436 resampler->x[1] = overshot >= 2 ? 0 : src[pos-2];
437 resampler->x[2] = overshot >= 1 ? 0 : src[pos-1];
438 } else if (diff >= 2) {
439 resampler->x[0] = resampler->x[2];
440 resampler->x[1] = overshot >= 2 ? 0 : src[pos-2];
441 resampler->x[2] = overshot >= 1 ? 0 : src[pos-1];
442 } else if (diff >= 1) {
443 resampler->x[0] = resampler->x[1];
444 resampler->x[1] = resampler->x[2];
445 resampler->x[2] = overshot >= 1 ? 0 : src[pos-1];
446 }
447 }
448 resampler->pos = pos;
449 resampler->subpos = subpos;
450 }
451 }
452
453 return done;
454}
455
456
457
458sample_t dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, float volume)
459{
460 int vol;
461 sample_t *src;
462 long pos;
463 int subpos;
464 int quality;
465
466 if (!resampler || resampler->dir == 0) return 0;
467 ASSERT(resampler->dir == -1 || resampler->dir == 1);
468
469 if (process_pickup(resampler)) return 0;
470
471 vol = (int)floor(volume * 65536.0 + 0.5);
472 if (vol == 0) return 0;
473
474 quality = dumb_resampling_quality;
475 if (quality > resampler->max_quality) quality = resampler->max_quality;
476 else if (quality < resampler->min_quality) quality = resampler->min_quality;
477
478 src = resampler->src;
479 pos = resampler->pos;
480 subpos = resampler->subpos;
481
482 if (resampler->dir < 0) {
483 HEAVYASSERT(pos >= resampler->start);
484 if (dumb_resampling_quality <= 0) {
485 /* Aliasing, backwards */
486 return MULSC(src[pos], vol);
487 } else if (quality <= DUMB_RQ_LINEAR) {
488 /* Linear interpolation, backwards */
489 return MULSC(resampler->x[2] + MULSC(resampler->x[1] - resampler->x[2], subpos), vol);
490 } else {
491 /* Cubic interpolation, backwards */
492 sample_t *x = resampler->x;
493 int a, b, c;
494 a = (((x[2] - x[1]) << 1) + (x[2] - x[1]) + (x[0] - src[pos])) >> 1;
495 b = (x[1] << 1) + src[pos] - ((5 * x[2] + x[0]) >> 1);
496 c = (x[1] - src[pos]) >> 1;
497 return MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + x[2], vol);
498 }
499 } else {
500 HEAVYASSERT(pos < resampler->end);
501 if (dumb_resampling_quality <= 0) {
502 /* Aliasing */
503 return MULSC(src[pos], vol);
504 } else if (dumb_resampling_quality <= DUMB_RQ_LINEAR) {
505 /* Linear interpolation, forwards */
506 return MULSC(resampler->x[1] + MULSC(resampler->x[2] - resampler->x[1], subpos), vol);
507 } else {
508 /* Cubic interpolation, forwards */
509 sample_t *x = resampler->x;
510 int a, b, c;
511 a = (((x[1] - x[2]) << 1) + (x[1] - x[2]) + (src[pos] - x[0])) >> 1;
512 b = (x[2] << 1) + x[0] - ((5 * x[1] + src[pos]) >> 1);
513 c = (x[2] - x[0]) >> 1;
514 return MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + x[1], vol);
515 }
516 }
517}
518
519
520
521void dumb_end_resampler(DUMB_RESAMPLER *resampler)
522{
523 if (resampler)
524 free(resampler);
525}
526
527
528
529#if 0
530/* The following macro is used to overcome the fact that most C
531 * compilers (including gcc and MSVC) can't correctly multiply signed
532 * integers outside the range -32768 to 32767. i86 assembler versions
533 * don't need to use this method, since the processor does in fact
534 * have instructions to multiply large numbers correctly - which
535 * means using assembly language could make a significant difference
536 * to the speed.
537 *
538 * The basic method is as follows. We halve the subposition (how far
539 * we are between samples), so it never exceeds 32767. We also halve
540 * the delta, which is the amount to be added to the subposition each
541 * time. Then we unroll the loop twofold, so that we can add the lost
542 * one every other time if necessary (since the halving may have
543 * resulted in rounding down).
544 *
545 * This method doesn't incur any cumulative inaccuracies. There is a
546 * very slight loss of quality, which I challenge anyone to notice -
547 * but the position will advance at *exactly* the same rate as it
548 * would if we didn't use this method. This also means the pitch is
549 * exactly the same, which may even make a difference to trained
550 * musicians when resampling down a lot :)
551 *
552 * Each time this macro is invoked, DO_RESAMPLE(inc) must be defined
553 * to calculate the samples by the appropriate equation (linear,
554 * cubic, etc.). See the individual cases for examples of how this is
555 * done.
556 */
557#define MAKE_RESAMPLER() \
558{ \
559 if (dt & 1) { \
560 long todo2; \
561 \
562 dt >>= 1; \
563 \
564 if (src_subpos & 1) { \
565 src_subpos >>= 1; \
566 DO_RESAMPLE(1); \
567 todo--; \
568 } else \
569 src_subpos >>= 1; \
570 \
571 todo2 = todo >> 1; \
572 \
573 while (todo2) { \
574 DO_RESAMPLE(0); \
575 DO_RESAMPLE(1); \
576 todo2--; \
577 } \
578 \
579 if (todo & 1) { \
580 DO_RESAMPLE(0); \
581 src_subpos = (src_subpos << 1) | 1; \
582 } else \
583 src_subpos <<= 1; \
584 \
585 todo = 0; \
586 dt = (dt << 1) | 1; \
587 } else { \
588 long subposbit = src_subpos & 1; \
589 dt >>= 1; \
590 src_subpos >>= 1; \
591 \
592 if (todo & 1) { \
593 DO_RESAMPLE(0); \
594 } \
595 \
596 todo >>= 1; \
597 \
598 while (todo) { \
599 DO_RESAMPLE(0); \
600 DO_RESAMPLE(0); \
601 todo--; \
602 } \
603 \
604 src_subpos = (src_subpos << 1) | subposbit; \
605 dt <<= 1; \
606 } \
607}
608
609
610
611sample_t dumb_resample_get_current_sample(
612 sample_t *src, long *_src_pos, int *_src_subpos,
613 long src_start, long src_end,
614 float volume, int *_dir,
615 DUMB_RESAMPLE_PICKUP pickup, void *pickup_data
616)
617{
618 long src_pos = *_src_pos;
619 int src_subpos = *_src_subpos;
620 int dir = _dir ? *_dir : 1;
621
622 sample_t value = 0;
623
624 if (dir == 0)
625 return 0;
626
627 ASSERT(dir == 1 || dir == -1);
628
629 if (dir < 0 ? (src_pos < src_start) : (src_pos >= src_end)) {
630
631 /* If there's no pick-up function, we stop. */
632 if (!pickup) {
633 dir = 0;
634 goto end;
635 }
636
637 /* Process the pick-up. It may need invoking more than once. */
638 do {
639 dir = (*pickup)(src, &src_pos, &src_subpos, &src_start, &src_end, dir, pickup_data);
640
641 if (dir == 0)
642 goto end;
643
644 ASSERT(dir == 1 || dir == -1);
645 } while (dir < 0 ? (src_pos < src_start) : (src_pos >= src_end));
646 }
647
648 HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end));
649
650 if (dumb_resampling_quality == 0) {
651 /* Aliasing (coarse) */
652 int volume_fact = (int)(volume * 16384.0);
653 value = (src[src_pos] * volume_fact) >> 14;
654 } else if (dumb_resampling_quality <= 2) {
655 /* Linear interpolation */
656 int volume_fact = (int)(volume * 16384.0);
657 int subpos = src_subpos >> 1;
658 value = ((src[src_pos] + ((((src[src_pos + 1] - src[src_pos]) >> 1) * subpos) >> 14)) * volume_fact) >> 14;
659 } else if (dumb_resampling_quality == 3) {
660 /* Quadratic interpolation */
661 int volume_fact = (int)(volume * 16384.0);
662 int a, b;
663 sample_t *x;
664 int subpos = src_subpos >> 1;
665 x = &src[src_pos];
666 a = ((x[0] + x[2]) >> 1) - x[1];
667 b = ((x[2] - x[0]) >> 1) - (a << 1);
668 value = (((((((a * subpos) >> 15) + b) * subpos) >> 15) + x[0]) * volume_fact) >> 14;
669 } else {
670 /* Cubic interpolation */
671 int volume_fact = (int)(volume * 16384.0);
672 int a, b, c;
673 sample_t *x;
674 int subpos = src_subpos >> 1;
675 x = &src[src_pos];
676 a = (((x[1] - x[2]) << 1) + (x[1] - x[2]) + (x[3] - x[0])) >> 1;
677 b = (x[2] << 1) + x[0] - ((5 * x[1] + x[3]) >> 1);
678 c = (x[2] - x[0]) >> 1;
679 value = (((int)(((LONG_LONG)((int)(((LONG_LONG)((int)(((LONG_LONG)a * subpos) >> 15) + b) * subpos) >> 15) + c) * subpos) >> 15) + x[1]) * volume_fact) >> 14;
680 }
681
682 end:
683
684 *_src_pos = src_pos;
685 *_src_subpos = src_subpos;
686 if (_dir) *_dir = dir;
687
688 return value;
689}
690
691
692
693long dumb_resample(
694 sample_t *src, long *_src_pos, int *_src_subpos,
695 long src_start, long src_end,
696 sample_t *dst, long dst_size,
697 float volume, float delta, int *_dir,
698 DUMB_RESAMPLE_PICKUP pickup, void *pickup_data
699)
700{
701 int dt = (int)(delta * 65536.0 + 0.5);
702 long s = 0; /* Current position in the destination buffer */
703
704 long src_pos = *_src_pos;
705 int src_subpos = *_src_subpos;
706 int dir = _dir ? *_dir : 1;
707
708 int linear_average;
709
710 if (dir == 0)
711 return 0;
712
713 ASSERT(dir == 1 || dir == -1);
714
715 linear_average = dst && dumb_resampling_quality >= 2 && dt > 65536;
716
717 if (dir < 0) dt = -dt;
718
719 if (linear_average)
720 volume /= delta;
721
722 while (s < dst_size) {
723
724 long todo;
725
726 /* Process pick-ups first, just in case. */
727
728 if (linear_average) {
729
730 /* For linear average, the pick-up point could split a sum into
731 * two parts. We handle this by putting the pick-up code inside
732 * the summing loop. Note that this code is only executed when we
733 * know that a pick-up is necessary somewhere during this sum
734 * (although it is always executed once for the first sample).
735 * We use a separate loop further down when we know we won't have
736 * to do a pick-up, so the condition does not need testing inside
737 * the loop.
738 */
739
740 float sum;
741 long i;
742 int advance;
743 int x[3];
744
745 advance = src_subpos + dt;
746
747 /* Make these negative. Then they stay within the necessary
748 * range for integer multiplication, -32768 to 32767 ;)
749 */
750 x[0] = ~(src_subpos >> 1); /* = -1 - (src_subpos >> 1) */
751 x[2] = x[0] ^ 0x7FFF; /* = -32768 + (src_subpos >> 1) */
752
753 sum = (float)(-((src[src_pos] * (x+1)[dir]) >> 15));
754
755 i = src_pos + (advance >> 16);
756 src_pos += dir;
757 src_subpos = (dir >> 1) & 65535; /* changes 1,-1 to 0,65535 */
758
759 advance &= 65535;
760
761 /* i is the index of the first sample NOT to sum fully,
762 * regardless of the direction of resampling.
763 */
764
765 while (dir < 0 ? (i < src_start) : (i >= src_end)) {
766 if (dir < 0) {
767 while (src_pos >= src_start)
768 sum += src[src_pos--];
769 } else {
770 while (src_pos < src_end)
771 sum += src[src_pos++];
772 }
773
774 i -= src_pos;
775 /* i is now the number of samples left to sum fully, except
776 * it's negative if we're going backwards.
777 */
778
779 if (!pickup) {
780 dir = 0;
781 goto endsum;
782 }
783
784 dir = (*pickup)(src, &src_pos, &src_subpos, &src_start, &src_end, dir, pickup_data);
785
786 if (dir == 0)
787 goto endsum;
788
789 ASSERT(dir == 1 || dir == -1);
790
791 if ((dir ^ dt) < 0) {
792 dt = -dt;
793 advance ^= 65535;
794 i = -i;
795 }
796
797 i += src_pos;
798 /* There, i is back to normal. */
799 }
800
801 for (; src_pos != i; src_pos += dir)
802 sum += src[src_pos];
803
804 src_subpos = advance;
805
806 x[2] = src_subpos >> 1;
807 x[0] = x[2] ^ 0x7FFF; /* = 32767 - (src_subpos >> 1) */
808
809 sum += (src[src_pos] * (x+1)[dir]) >> 15;
810
811 endsum:
812
813 sum *= volume;
814 dst[s] += (int)sum;
815
816 s++;
817
818 if (dir == 0)
819 break;
820
821 } else if (dir < 0 ? (src_pos < src_start) : (src_pos >= src_end)) {
822
823 /* If there's no pick-up function, we stop. */
824 if (!pickup) {
825 dir = 0;
826 break;
827 }
828
829 /* Process the pick-up. It may need invoking more than once. */
830 do {
831 dir = (*pickup)(src, &src_pos, &src_subpos, &src_start, &src_end, dir, pickup_data);
832
833 if (dir == 0)
834 goto end;
835
836 ASSERT(dir == 1 || dir == -1);
837 } while (dir < 0 ? (src_pos < src_start) : (src_pos >= src_end));
838
839 /* Update sign of dt to match that of dir. */
840 if ((dir ^ dt) < 0)
841 dt = -dt;
842 }
843
844 /* Work out how many contiguous samples we can now render. */
845 if (dir < 0)
846 todo = (long)((((LONG_LONG)(src_pos - src_start) << 16) + src_subpos) / -dt);
847 else
848 todo = (long)((((LONG_LONG)(src_end - src_pos) << 16) - src_subpos - 1) / dt);
849
850 /* The above equations work out how many complete dt-sized
851 * intervals there are between the current position and the loop
852 * point (provided there is a little fractional extra). The linear
853 * average function needs complete intervals - but the other
854 * resamplers only read a sample from the beginning of each interval,
855 * so they can process one extra sample in their main loops (so we
856 * increment todo in a moment).
857 *
858 * The linear average function makes up the extra sample using the
859 * specialised pick-up code above.
860 *
861 * Note that our above pick-up process should have absolutely ensured
862 * that the result of this function will be nonnegative.
863 */
864
865 ASSERT(todo >= 0);
866
867 if (!linear_average)
868 todo++;
869
870 /* Of course we don't want to overrun the output buffer! */
871 if (todo > dst_size - s)
872 todo = dst_size - s;
873
874 if (!dst) {
875
876 LONG_LONG t = src_subpos + (LONG_LONG)dt * todo;
877 src_pos += (long)(t >> 16);
878 src_subpos = (int)t & 0xFFFFl;
879
880 s += todo;
881
882 } else if (linear_average) {
883
884 float sum;
885 long i;
886 int advance;
887 int x[3];
888
889 while (todo) {
890
891 advance = src_subpos + dt;
892
893 /* Make these negative. Then they stay within the necessary
894 * range for integer multiplication, -32768 to 32767 ;)
895 */
896 x[0] = ~(src_subpos >> 1); /* = -1 - (src_subpos >> 1) */
897 x[2] = x[0] ^ 0x7FFF; /* = -32768 + (src_subpos >> 1) */
898
899 sum = (float)(-((src[src_pos] * (x+1)[dir]) >> 15));
900
901 i = src_pos + (advance >> 16);
902 src_pos += dir;
903 src_subpos = (dir >> 1) & 65535; /* changes 1,-1 to 0,65535 */
904
905 advance &= 65535;
906
907 /* i is the index of the first sample NOT to sum fully,
908 * regardless of the direction of resampling.
909 */
910
911 HEAVYASSERT(dir < 0 ? (i >= src_start) : (i < src_end));
912
913 for (; src_pos != i; src_pos += dir)
914 sum += src[src_pos];
915
916 src_subpos = advance;
917
918 x[2] = src_subpos >> 1;
919 x[0] = x[2] ^ 0x7FFF; /* = 32767 - (src_subpos >> 1) */
920
921 sum += (src[src_pos] * (x+1)[dir]) >> 15;
922
923 sum *= volume;
924 dst[s] += (int)sum;
925
926 s++;
927 todo--;
928 }
929
930 } else if (dumb_resampling_quality == 0 || (dumb_resampling_quality == 1 && delta >= 1.0)) {
931
932 /* Aliasing (coarse) */
933 int volume_fact = (int)(volume * 16384.0);
934
935 do {
936 HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end));
937 dst[s] += ((src[src_pos] * volume_fact) >> 14);
938 src_subpos += dt;
939 src_pos += src_subpos >> 16;
940 src_subpos &= 0xFFFFl;
941 s++;
942 } while (--todo);
943
944 } else if (dumb_resampling_quality <= 2) {
945
946 /* Linear interpolation */
947 int volume_fact = (int)(volume * 16384.0);
948
949 #define DO_RESAMPLE(inc) \
950 { \
951 HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end)); \
952 \
953 dst[s] += (((src[src_pos] + ((((src[src_pos + 1] - src[src_pos]) >> 1) * src_subpos) >> 14)) * volume_fact) >> 14); \
954 \
955 src_subpos += dt + inc; \
956 src_pos += src_subpos >> 15; \
957 src_subpos &= 0x7FFFl; \
958 s++; \
959 }
960
961 MAKE_RESAMPLER();
962
963 #undef DO_RESAMPLE
964
965 } else if (dumb_resampling_quality == 3) {
966
967 /* Quadratic interpolation */
968
969 int volume_fact = (int)(volume * 16384.0);
970 int a = 0, b = 0;
971 sample_t *x = NULL;
972 int last_src_pos = -1;
973
974 /* AIM: no integer multiplicands must transcend the range -32768 to 32767.
975 * This limitation is imposed by most compilers, including gcc and MSVC.
976 *
977 * a = 0.5 * (s0 + s2) - s1
978 * b = -1.5 * s0 + 2 * s1 - 0.5 * s2
979 * c = s0
980 *
981 * s = (a * t + b) * t + c
982 *
983 * In fixed-point:
984 *
985 * a = ((s0 + s2) >> 1) - s1
986 * b = ((-3 * s0 - s2) >> 1) + (s1 << 1)
987 *
988 * s = (((((a * t) >> 16) + b) * t) >> 16) + s0
989 *
990 * With t halved (since t can reach 65535):
991 *
992 * s = (((((a * t) >> 15) + b) * t) >> 15) + s0
993 *
994 * a currently reaches 65536
995 * b currently reaches 131072
996 *
997 * So we must use aon2
998 *
999 * s = (((((aon2 * t) >> 14) + b) * t) >> 15) + s0
1000 *
1001 * ((aon2 * t) >> 14) + b is 5 times too big
1002 * so we must divide by 8
1003 *
1004 * s = (((((aon2 * t) >> 17) + bon8) * t) >> 12) + s0
1005 *
1006 * aon2 = ((s0 + s2) >> 2) - (s1 >> 1)
1007 * bon8 = ((-3 * s0 - s2) >> 4) + (s1 >> 2)
1008 * or:
1009 * bon8 = ((s2 - s0) >> 4) - (aon2 >> 1)
1010 */
1011
1012 /* Unh4x0r3d version:
1013 #define DO_RESAMPLE(inc) \
1014 { \
1015 HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end)); \
1016 \
1017 if (src_pos != last_src_pos) { \
1018 last_src_pos = src_pos; \
1019 x = &src[src_pos]; \
1020 a = ((x[0] + x[2]) >> 2) - (x[1] >> 1); \
1021 b = ((x[2] - x[0]) >> 4) - (a >> 1); \
1022 } \
1023 \
1024 dst[s] += ((((((((a * src_subpos) >> 17) + b) * src_subpos) >> 12) + x[0]) * volume_fact) >> 14); \
1025 \
1026 src_subpos += dt + inc; \
1027 src_pos += src_subpos >> 15; \
1028 src_subpos &= 0x7FFFl; \
1029 s++; \
1030 }
1031 */
1032
1033 /* H4x0r3d version: */
1034 #define DO_RESAMPLE(inc) \
1035 { \
1036 HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end)); \
1037 \
1038 if (src_pos != last_src_pos) { \
1039 last_src_pos = src_pos; \
1040 x = &src[src_pos]; \
1041 a = ((x[0] + x[2]) >> 1) - x[1]; \
1042 b = ((x[2] - x[0]) >> 1) - (a << 1); \
1043 } \
1044 \
1045 dst[s] += ((((((((a * src_subpos) >> 15) + b) * src_subpos) >> 15) + x[0]) * volume_fact) >> 14); \
1046 \
1047 src_subpos += dt + inc; \
1048 src_pos += src_subpos >> 15; \
1049 src_subpos &= 0x7FFFl; \
1050 s++; \
1051 }
1052
1053 MAKE_RESAMPLER();
1054
1055 #undef DO_RESAMPLE
1056
1057 } else {
1058
1059 /* Cubic interpolation */
1060
1061 int volume_fact = (int)(volume * 16384.0);
1062 int a = 0, b = 0, c = 0;
1063 sample_t *x = NULL;
1064 int last_src_pos = -1;
1065
1066 /* AIM: never multiply integers outside the range -32768 to 32767.
1067 *
1068 * a = 1.5f * (x[1] - x[2]) + (x[3] - x[0]) * 0.5f;
1069 * b = 2.0f * x[2] + x[0] - 2.5f * x[1] - x[3] * 0.5f;
1070 * c = (x[2] - x[0]) * 0.5f;
1071 *
1072 * s = ((a * t + b) * t + c) * t + x[1];
1073 *
1074 * Fixed-point version:
1075 *
1076 * a = (((x[1] - x[2]) << 1) + (x[1] - x[2]) + (x[3] - x[0])) >> 1;
1077 * b = (x[2] << 1) + x[0] - ((5 * x[1] + x[3]) >> 1);
1078 * c = (x[2] - x[0]) >> 1;
1079 *
1080 * s = ((((((((a * t) >> 15) + b) * t) >> 15) + c) * t) >> 15) + x[1];
1081 * (with t already halved, maximum 32767)
1082 *
1083 * a is in (((1+1)*2)+(1+1)+(1+1))/2 = 8 times the required range
1084 * b is in (1*2)+1+((5*1+1)/2) = 6 times
1085 * c is in the required range
1086 *
1087 * We must use aon8
1088 *
1089 * s = ((((((((aon8 * t) >> 12) + b) * t) >> 15) + c) * t) >> 15) + x[1];
1090 *
1091 * But ((aon8 * t) >> 12) is in 2^(15+15-12) = 2^18 = 8 times
1092 * b is in 6 times
1093 * so we divide both ((aon8 * t) >> 12) and b by 16
1094 *
1095 * s = ((((((((aon8 * t) >> 16) + bon16) * t) >> 11) + c) * t) >> 15) + x[1];
1096 *
1097 * ((... + bon16) * t) >> 11 is 16 times too big
1098 * c is in the correct range
1099 * we must divide both by 32
1100 *
1101 * s = ((((((((aon8 * t) >> 16) + bon16) * t) >> 16) + con32) * t) >> 10) + x[1];
1102 *
1103 * aon8 = (((x[1] - x[2]) << 1) + (x[1] - x[2]) + (x[3] - x[0])) >> 4;
1104 * bon16 = ((x[2] << 2) + (x[0] << 1) - (5 * x[1] + x[3])) >> 5;
1105 * con32 = (x[2] - x[0]) >> 6;
1106 *
1107 * A lot of accuracy is lost here. It is quite likely that some
1108 * of the above would cancel anyway, so the scaling down wouldn't
1109 * have to be so severe. However, I'm not in the mood to work it
1110 * out now :P
1111 *
1112 * It may also be worth investigating whether doing this stuff
1113 * in floats would be faster.
1114 */
1115
1116 /* Unh4x0r3d version:
1117 #define DO_RESAMPLE(inc) \
1118 { \
1119 HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end)); \
1120 \
1121 if (src_pos != last_src_pos) { \
1122 last_src_pos = src_pos; \
1123 x = &src[src_pos]; \
1124 a = (((x[1] - x[2]) << 1) + (x[1] - x[2]) + (x[3] - x[0])) >> 4; \
1125 b = ((x[2] << 2) + (x[0] << 1) - (5 * x[1] + x[3])) >> 5; \
1126 c = (x[2] - x[0]) >> 6; \
1127 } \
1128 \
1129 dst[s] += ((((((((((a * src_subpos) >> 16) + b) * src_subpos) >> 16) + c) * src_subpos) >> 10) + x[1]) * volume_fact) >> 14; \
1130 \
1131 src_subpos += dt + inc; \
1132 src_pos += src_subpos >> 15; \
1133 src_subpos &= 0x7FFFl; \
1134 s++; \
1135 }
1136 */
1137
1138 /* H4x0r3d version: */
1139 #define DO_RESAMPLE(inc) \
1140 { \
1141 HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end)); \
1142 \
1143 if (src_pos != last_src_pos) { \
1144 last_src_pos = src_pos; \
1145 x = &src[src_pos]; \
1146 a = (((x[1] - x[2]) << 1) + (x[1] - x[2]) + (x[3] - x[0])) >> 1; \
1147 b = (x[2] << 1) + x[0] - ((5 * x[1] + x[3]) >> 1); \
1148 c = (x[2] - x[0]) >> 1; \
1149 } \
1150 \
1151 dst[s] += (((int)(((LONG_LONG)((int)(((LONG_LONG)((int)(((LONG_LONG)a * src_subpos) >> 15) + b) * src_subpos) >> 15) + c) * src_subpos) >> 15) + x[1]) * volume_fact) >> 14; \
1152 \
1153 src_subpos += dt + inc; \
1154 src_pos += src_subpos >> 15; \
1155 src_subpos &= 0x7FFFl; \
1156 s++; \
1157 }
1158
1159 MAKE_RESAMPLER();
1160
1161 #undef DO_RESAMPLE
1162
1163 }
1164
1165 }
1166
1167 end:
1168
1169 ASSERT(s <= dst_size);
1170
1171 *_src_pos = src_pos;
1172 *_src_subpos = src_subpos;
1173 if (_dir) *_dir = dir;
1174
1175 return s;
1176}
1177#endif
diff --git a/apps/codecs/dumb/src/helpers/sampbuf.c b/apps/codecs/dumb/src/helpers/sampbuf.c
deleted file mode 100644
index 75510c729a..0000000000
--- a/apps/codecs/dumb/src/helpers/sampbuf.c
+++ /dev/null
@@ -1,47 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * sampbuf.c - Helper for allocating sample / / \ \
12 * buffers. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21#include "dumb.h"
22
23
24
25sample_t **create_sample_buffer(int n_channels, long length)
26{
27 int i;
28 sample_t **samples = malloc(n_channels * sizeof(*samples));
29 if (!samples) return NULL;
30 samples[0] = malloc(n_channels * length * sizeof(*samples[0]));
31 if (!samples[0]) {
32 free(samples);
33 return NULL;
34 }
35 for (i = 1; i < n_channels; i++) samples[i] = samples[i-1] + length;
36 return samples;
37}
38
39
40
41void destroy_sample_buffer(sample_t **samples)
42{
43 if (samples) {
44 free(samples[0]);
45 free(samples);
46 }
47}
diff --git a/apps/codecs/dumb/src/helpers/silence.c b/apps/codecs/dumb/src/helpers/silence.c
deleted file mode 100644
index 4d5fdcf4da..0000000000
--- a/apps/codecs/dumb/src/helpers/silence.c
+++ /dev/null
@@ -1,29 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * silence.c - Silencing helper. / / \ \
12 * | < / \_
13 * By entheh. | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <string.h>
21#include "dumb.h"
22
23
24
25void dumb_silence(sample_t *samples, long length)
26{
27 memset(samples, 0, length * sizeof(*samples));
28}
29
diff --git a/apps/codecs/dumb/src/helpers/stdfile.c b/apps/codecs/dumb/src/helpers/stdfile.c
deleted file mode 100644
index 2f02539a92..0000000000
--- a/apps/codecs/dumb/src/helpers/stdfile.c
+++ /dev/null
@@ -1,93 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * stdfile.c - stdio file input module. / / \ \
12 * | < / \_
13 * By entheh. | \/ /\ /
14 * \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdio.h>
21
22#include "dumb.h"
23
24
25
26static void *dumb_stdfile_open(const char *filename)
27{
28 return fopen(filename, "rb");
29}
30
31
32
33static int dumb_stdfile_skip(void *f, long n)
34{
35 return fseek(f, n, SEEK_CUR);
36}
37
38
39
40static int dumb_stdfile_getc(void *f)
41{
42 return fgetc(f);
43}
44
45
46
47static long dumb_stdfile_getnc(char *ptr, long n, void *f)
48{
49 return fread(ptr, 1, n, f);
50}
51
52
53
54static void dumb_stdfile_close(void *f)
55{
56 fclose(f);
57}
58
59
60
61static DUMBFILE_SYSTEM stdfile_dfs = {
62 &dumb_stdfile_open,
63 &dumb_stdfile_skip,
64 &dumb_stdfile_getc,
65 &dumb_stdfile_getnc,
66 &dumb_stdfile_close
67};
68
69
70
71void dumb_register_stdfiles(void)
72{
73 register_dumbfile_system(&stdfile_dfs);
74}
75
76
77
78static DUMBFILE_SYSTEM stdfile_dfs_leave_open = {
79 NULL,
80 &dumb_stdfile_skip,
81 &dumb_stdfile_getc,
82 &dumb_stdfile_getnc,
83 NULL
84};
85
86
87
88DUMBFILE *dumbfile_open_stdfile(FILE *p)
89{
90 DUMBFILE *d = dumbfile_open_ex(p, &stdfile_dfs_leave_open);
91
92 return d;
93}
diff --git a/apps/codecs/dumb/src/it/itload.c b/apps/codecs/dumb/src/it/itload.c
deleted file mode 100644
index a377619a88..0000000000
--- a/apps/codecs/dumb/src/it/itload.c
+++ /dev/null
@@ -1,43 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * itload.c - Code to read an Impulse Tracker / / \ \
12 * file, opening and closing it for | < / \_
13 * you. | \/ /\ /
14 * \_ / > /
15 * By entheh. Don't worry Bob, you're credited | \ / /
16 * in itread.c! | ' /
17 * \__/
18 */
19
20#include "dumb.h"
21#include "internal/it.h"
22
23
24
25/* dumb_load_it(): loads an IT file into a DUH struct, returning a pointer to
26 * the DUH struct. When you have finished with it, you must pass the pointer
27 * to unload_duh() so that the memory can be freed.
28 */
29DUH *dumb_load_it(const char *filename)
30{
31 DUH *duh;
32 DUMBFILE *f = dumbfile_open(filename);
33
34 if (!f)
35 return NULL;
36
37 duh = dumb_read_it(f);
38
39 dumbfile_close(f);
40
41 return duh;
42}
43
diff --git a/apps/codecs/dumb/src/it/itmisc.c b/apps/codecs/dumb/src/it/itmisc.c
deleted file mode 100644
index b69a64df10..0000000000
--- a/apps/codecs/dumb/src/it/itmisc.c
+++ /dev/null
@@ -1,175 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * itmisc.c - Miscellaneous functions relating / / \ \
12 * to module files. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include "dumb.h"
21#include "internal/it.h"
22
23
24
25DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh)
26{
27 return duh_get_raw_sigdata(duh, 0, SIGTYPE_IT);
28}
29
30
31
32int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd)
33{
34 return sd ? sd->n_orders : 0;
35}
36
37
38
39int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd)
40{
41 return sd ? sd->global_volume : 0;
42}
43
44
45
46void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv)
47{
48 if (sd) sd->global_volume = gv;
49}
50
51
52
53int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd)
54{
55 return sd ? sd->mixing_volume : 0;
56}
57
58
59
60void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv)
61{
62 if (sd) sd->mixing_volume = mv;
63}
64
65
66
67int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd)
68{
69 return sd ? sd->speed : 0;
70}
71
72
73
74void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed)
75{
76 if (sd) sd->speed = speed;
77}
78
79
80
81int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd)
82{
83 return sd ? sd->tempo : 0;
84}
85
86
87
88void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo)
89{
90 if (sd) sd->tempo = tempo;
91}
92
93
94
95int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel)
96{
97 ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS);
98 return sd ? sd->channel_volume[channel] : 0;
99}
100
101void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, int volume)
102{
103 ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS);
104 if (sd) sd->channel_volume[channel] = volume;
105}
106
107
108
109int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr)
110{
111 return sr ? sr->order : -1;
112}
113
114
115
116int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr)
117{
118 return sr ? sr->row : -1;
119}
120
121
122
123int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr)
124{
125 return sr ? sr->globalvolume : 0;
126}
127
128
129
130void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv)
131{
132 if (sr) sr->globalvolume = gv;
133}
134
135
136
137int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr)
138{
139 return sr ? sr->tempo : 0;
140}
141
142
143
144void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo)
145{
146 if (sr) sr->tempo = tempo;
147}
148
149
150
151int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr)
152{
153 return sr ? sr->speed : 0;
154}
155
156
157
158void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed)
159{
160 if (sr) sr->speed = speed;
161}
162
163
164
165int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel)
166{
167 return sr ? sr->channel[channel].channelvolume : 0;
168}
169
170
171
172void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume)
173{
174 if (sr) sr->channel[channel].channelvolume = volume;
175}
diff --git a/apps/codecs/dumb/src/it/itorder.c b/apps/codecs/dumb/src/it/itorder.c
deleted file mode 100644
index 6959f05443..0000000000
--- a/apps/codecs/dumb/src/it/itorder.c
+++ /dev/null
@@ -1,63 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * itorder.c - Code to fix invalid patterns in / / \ \
12 * the pattern table. | < / \_
13 * | \/ /\ /
14 * By Julien Cugniere. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20
21
22#include <stdlib.h>
23
24#include "dumb.h"
25#include "internal/it.h"
26
27
28
29/* This function ensures that any pattern mentioned in the order table but
30 * not present in the pattern table is treated as an empty 64 rows pattern.
31 * This is done by adding such a dummy pattern at the end of the pattern
32 * table, and redirect invalid orders to it.
33 * Patterns 254 and 255 are left untouched, unless the signal is an XM.
34 */
35int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata)
36{
37 int i;
38 int found_some = 0;
39
40 int first_invalid = sigdata->n_patterns;
41 int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253;
42
43 for (i = 0; i < sigdata->n_orders; i++) {
44 if (sigdata->order[i] >= first_invalid && sigdata->order[i] <= last_invalid) {
45 sigdata->order[i] = sigdata->n_patterns;
46 found_some = 1;
47 }
48 }
49
50 if (found_some) {
51 IT_PATTERN *new_pattern = realloc(sigdata->pattern, sizeof(*sigdata->pattern) * (sigdata->n_patterns + 1));
52 if (!new_pattern)
53 return -1;
54
55 new_pattern[sigdata->n_patterns].n_rows = 64;
56 new_pattern[sigdata->n_patterns].n_entries = 0;
57 new_pattern[sigdata->n_patterns].entry = NULL;
58 sigdata->pattern = new_pattern;
59 sigdata->n_patterns++;
60 }
61
62 return 0;
63}
diff --git a/apps/codecs/dumb/src/it/itread.c b/apps/codecs/dumb/src/it/itread.c
deleted file mode 100644
index 0e789436d2..0000000000
--- a/apps/codecs/dumb/src/it/itread.c
+++ /dev/null
@@ -1,1181 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * itread.c - Code to read an Impulse Tracker / / \ \
12 * module from an open file. | < / \_
13 * | \/ /\ /
14 * Based on the loader from an IT player by Bob. \_ / > /
15 * Adapted for DUMB by entheh. | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21#include <string.h>//might not be necessary later; required for memset
22
23#include "dumb.h"
24#include "internal/it.h"
25
26
27
28#define INVESTIGATE_OLD_INSTRUMENTS
29
30
31
32static int it_seek(DUMBFILE *f, long offset)
33{
34 long pos = dumbfile_pos(f);
35
36 if (pos > offset)
37 return -1;
38
39 if (pos < offset)
40 if (dumbfile_skip(f, offset - pos))
41 return -1;
42
43 return 0;
44}
45
46
47
48typedef unsigned char byte;
49typedef unsigned short word;
50typedef unsigned long dword;
51
52
53
54static unsigned char *sourcebuf = NULL;
55static unsigned char *sourcepos = NULL;
56static unsigned char *sourceend;
57static int rembits = 0;
58
59
60
61static int readblock(DUMBFILE *f)
62{
63 long size;
64 int c;
65
66 size = dumbfile_igetw(f);
67 if (size < 0)
68 return size;
69
70 sourcebuf = malloc(size);
71 if (!sourcebuf)
72 return -1;
73
74 c = dumbfile_getnc((char *)sourcebuf, size, f);
75 if (c < size) {
76 free(sourcebuf);
77 sourcebuf = NULL;
78 return -1;
79 }
80
81 sourcepos = sourcebuf;
82 sourceend = sourcebuf + size;
83 rembits = 8;
84 return 0;
85}
86
87
88
89static void freeblock(void)
90{
91 free(sourcebuf);
92 sourcebuf = NULL;
93}
94
95
96
97static int readbits(int bitwidth)
98{
99 int val = 0;
100 int b = 0;
101
102 if (sourcepos >= sourceend) return val;
103
104 while (bitwidth > rembits) {
105 val |= *sourcepos++ << b;
106 if (sourcepos >= sourceend) return val;
107 b += rembits;
108 bitwidth -= rembits;
109 rembits = 8;
110 }
111
112 val |= (*sourcepos & ((1 << bitwidth) - 1)) << b;
113 *sourcepos >>= bitwidth;
114 rembits -= bitwidth;
115
116 return val;
117}
118
119
120
121/** WARNING - do we even need to pass `right`? */
122/** WARNING - why bother memsetting at all? The whole array is written... */
123// if we do memset, dumb_silence() would be neater...
124static int decompress8(DUMBFILE *f, sample_t *left, sample_t *right, int len, int cmwt)
125{
126 int blocklen, blockpos;
127 byte bitwidth;
128 word val;
129 char d1, d2;
130
131 memset(left, 0, len * sizeof(*left));
132 if (right) {
133 memset(right, 0, len * sizeof(*right));
134 len <<= 1;
135 }
136
137 while (len > 0) {
138 //Read a block of compressed data:
139 if (readblock(f))
140 return -1;
141 //Set up a few variables
142 blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes
143 blockpos = 0;
144 bitwidth = 9;
145 d1 = d2 = 0;
146 //Start the decompression:
147 while (blockpos < blocklen) {
148 //Read a value:
149 val = (word)readbits(bitwidth);
150 //Check for bit width change:
151
152 if (bitwidth < 7) { //Method 1:
153 if (val == (1 << (bitwidth - 1))) {
154 val = (word)readbits(3) + 1;
155 bitwidth = (val < bitwidth) ? val : val + 1;
156 continue;
157 }
158 }
159 else if (bitwidth < 9) { //Method 2
160 byte border = (0xFF >> (9 - bitwidth)) - 4;
161
162 if (val > border && val <= (border + 8)) {
163 val -= border;
164 bitwidth = (val < bitwidth) ? val : val + 1;
165 continue;
166 }
167 }
168 else if (bitwidth == 9) { //Method 3
169 if (val & 0x100) {
170 bitwidth = (val + 1) & 0xFF;
171 continue;
172 }
173 }
174 else { //Illegal width, abort ?
175 freeblock();
176 return -1;
177 }
178
179 //Expand the value to signed byte:
180 {
181 char v; //The sample value:
182 if (bitwidth < 8) {
183 byte shift = 8 - bitwidth;
184 v = (val << shift);
185 v >>= shift;
186 }
187 else
188 v = (char)val;
189
190 //And integrate the sample value
191 //(It always has to end with integration doesn't it ? ;-)
192 d1 += v;
193 d2 += d1;
194 }
195
196 //Store !
197 /* Version 2.15 was an unofficial version with hacked compression
198 * code. Yay, better compression :D
199 */
200 if (right && (len & 1))
201 *right++ = (int)(signed char)(cmwt == 0x215 ? d2 : d1) << 16;
202 else
203 *left++ = (int)(signed char)(cmwt == 0x215 ? d2 : d1) << 16;
204 len--;
205 blockpos++;
206 }
207 freeblock();
208 }
209 return 0;
210}
211
212
213
214static int decompress16(DUMBFILE *f, sample_t *left, sample_t *right, int len, int cmwt)
215{
216 int blocklen, blockpos;
217 byte bitwidth;
218 long val;
219 short d1, d2;
220
221 memset(left, 0, len * sizeof(*left));
222 if (right) {
223 memset(right, 0, len * sizeof(*right));
224 len <<= 1;
225 }
226
227 while (len > 0) {
228 //Read a block of compressed data:
229 if (readblock(f))
230 return -1;
231 //Set up a few variables
232 blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes
233 blockpos = 0;
234 bitwidth = 17;
235 d1 = d2 = 0;
236 //Start the decompression:
237 while (blockpos < blocklen) {
238 val = readbits(bitwidth);
239 //Check for bit width change:
240
241 if (bitwidth < 7) { //Method 1:
242 if (val == (1 << (bitwidth - 1))) {
243 val = readbits(4) + 1;
244 bitwidth = (val < bitwidth) ? val : val + 1;
245 continue;
246 }
247 }
248 else if (bitwidth < 17) { //Method 2
249 word border = (0xFFFF >> (17 - bitwidth)) - 8;
250
251 if (val > border && val <= (border + 16)) {
252 val -= border;
253 bitwidth = val < bitwidth ? val : val + 1;
254 continue;
255 }
256 }
257 else if (bitwidth == 17) { //Method 3
258 if (val & 0x10000) {
259 bitwidth = (val + 1) & 0xFF;
260 continue;
261 }
262 }
263 else { //Illegal width, abort ?
264 freeblock();
265 return -1;
266 }
267
268 //Expand the value to signed byte:
269 {
270 short v; //The sample value:
271 if (bitwidth < 16) {
272 byte shift = 16 - bitwidth;
273 v = (short)(val << shift);
274 v >>= shift;
275 }
276 else
277 v = (short)val;
278
279 //And integrate the sample value
280 //(It always has to end with integration doesn't it ? ;-)
281 d1 += v;
282 d2 += d1;
283 }
284
285 //Store !
286 /* Version 2.15 was an unofficial version with hacked compression
287 * code. Yay, better compression :D
288 */
289 if (right && (len & 1))
290 *right++ = (int)(signed short)(cmwt == 0x215 ? d2 : d1) << 8;
291 else
292 *left++ = (int)(signed short)(cmwt == 0x215 ? d2 : d1) << 8;
293 len--;
294 blockpos++;
295 }
296 freeblock();
297 }
298 return 0;
299}
300
301
302
303static int it_read_envelope(IT_ENVELOPE *envelope, DUMBFILE *f)
304{
305 int n;
306
307 envelope->flags = dumbfile_getc(f);
308 envelope->n_nodes = dumbfile_getc(f);
309 envelope->loop_start = dumbfile_getc(f);
310 envelope->loop_end = dumbfile_getc(f);
311 envelope->sus_loop_start = dumbfile_getc(f);
312 envelope->sus_loop_end = dumbfile_getc(f);
313 for (n = 0; n < envelope->n_nodes; n++) {
314 envelope->node_y[n] = dumbfile_getc(f);
315 envelope->node_t[n] = dumbfile_igetw(f);
316 }
317 dumbfile_skip(f, 75 - envelope->n_nodes * 3 + 1);
318
319 return dumbfile_error(f);
320}
321
322
323
324static int it_read_old_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f)
325{
326 int n;
327
328 if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)
329 return -1;
330
331 /* Skip DOS Filename. */
332 dumbfile_skip(f, 13);
333
334 instrument->volume_envelope.flags = dumbfile_getc(f);
335 instrument->volume_envelope.loop_start = dumbfile_getc(f);
336 instrument->volume_envelope.loop_end = dumbfile_getc(f);
337 instrument->volume_envelope.sus_loop_start = dumbfile_getc(f);
338 instrument->volume_envelope.sus_loop_end = dumbfile_getc(f);
339
340 /* Skip two unused bytes. */
341 dumbfile_skip(f, 2);
342
343 /* In the old instrument format, fadeout ranges from 0 to 64, and is
344 * subtracted at intervals from a value starting at 512. In the new
345 * format, all these values are doubled. Therefore we double when loading
346 * from the old instrument format - that way we don't have to think about
347 * it later.
348 */
349 instrument->fadeout = dumbfile_igetw(f) << 1;
350 instrument->new_note_action = dumbfile_getc(f);
351 instrument->dup_check_type = dumbfile_getc(f);
352 instrument->dup_check_action = DCA_NOTE_CUT; // This might be wrong!
353 /** WARNING - what is the duplicate check action for old-style instruments? */
354
355 /* Skip Tracker Version and Number of Samples. These are only used in
356 * separate instrument files. Also skip unused bytes and Instrument Name.
357 */
358 dumbfile_skip(f, 36);
359
360 instrument->pp_separation = 0;
361 instrument->pp_centre = 60;
362 instrument->global_volume = 128;
363 /** WARNING - should global_volume be 64 or something? */
364 instrument->default_pan = 32;
365 /** WARNING - should default_pan be 128, meaning don`t use? */
366 instrument->random_volume = 0;
367 instrument->random_pan = 0;
368
369 for (n = 0; n < 120; n++) {
370 instrument->map_note[n] = dumbfile_getc(f);
371 instrument->map_sample[n] = dumbfile_getc(f);
372 }
373
374 /* Skip "Volume envelope (200 bytes)". */
375 // - need to know better what this is for though.
376 dumbfile_skip(f, 200);
377
378#if defined(INVESTIGATE_OLD_INSTRUMENTS) && 0
379 fprintf(stderr, "Inst %02d Env:", n);
380#endif
381
382 for (n = 0; n < 25; n++)
383 {
384 instrument->volume_envelope.node_t[n] = dumbfile_getc(f);
385 instrument->volume_envelope.node_y[n] = dumbfile_getc(f);
386
387#if defined(INVESTIGATE_OLD_INSTRUMENTS) && 0
388 fprintf(stderr, " %d,%d",
389 instrument->volume_envelope.node_t[n],
390 instrument->volume_envelope.node_y[n]);
391#endif
392
393 // This loop is unfinished, as we can probably escape from it before
394 // the end if we want to. Hence the otherwise useless dumbfile_skip()
395 // call below.
396 }
397 dumbfile_skip(f, 50 - (n << 1));
398 instrument->volume_envelope.n_nodes = n;
399
400#if defined(INVESTIGATE_OLD_INSTRUMENTS) && 0
401 fprintf(stderr, "\n");
402#endif
403
404 if (dumbfile_error(f))
405 return -1;
406
407 instrument->filter_cutoff = 127;
408 instrument->filter_resonance = 0;
409
410 instrument->pan_envelope.flags = 0;
411 instrument->pitch_envelope.flags = 0;
412
413 return 0;
414}
415
416
417
418static int it_read_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f)
419{
420 int n;
421
422 if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)
423 return -1;
424
425 /* Skip DOS Filename. */
426 dumbfile_skip(f, 13);
427
428 instrument->new_note_action = dumbfile_getc(f);
429 instrument->dup_check_type = dumbfile_getc(f);
430 instrument->dup_check_action = dumbfile_getc(f);
431 instrument->fadeout = dumbfile_igetw(f);
432 instrument->pp_separation = dumbfile_getc(f);
433 instrument->pp_centre = dumbfile_getc(f);
434 instrument->global_volume = dumbfile_getc(f);
435 instrument->default_pan = dumbfile_getc(f);
436 instrument->random_volume = dumbfile_getc(f);
437 instrument->random_pan = dumbfile_getc(f);
438
439 /* Skip Tracker Version and Number of Samples. These are only used in
440 * separate instrument files. Also skip unused byte and Instrument Name.
441 */
442 dumbfile_skip(f, 30);
443
444 instrument->filter_cutoff = dumbfile_getc(f);
445 instrument->filter_resonance = dumbfile_getc(f);
446
447 /* Skip MIDI Channel, Program and Bank. */
448 dumbfile_skip(f, 4);
449
450 for (n = 0; n < 120; n++) {
451 instrument->map_note[n] = dumbfile_getc(f);
452 instrument->map_sample[n] = dumbfile_getc(f);
453 }
454
455 if (dumbfile_error(f))
456 return -1;
457
458 if (it_read_envelope(&instrument->volume_envelope, f)) return -1;
459 if (it_read_envelope(&instrument->pan_envelope, f)) return -1;
460 if (it_read_envelope(&instrument->pitch_envelope, f)) return -1;
461
462 return 0;
463}
464
465
466
467static int it_read_sample_header(IT_SAMPLE *sample, unsigned char *convert, long *offset, DUMBFILE *f)
468{
469 if (dumbfile_mgetl(f) != IT_SAMPLE_SIGNATURE)
470 return -1;
471
472 /* Skip DOS Filename. */
473 dumbfile_skip(f, 13);
474
475 sample->global_volume = dumbfile_getc(f);
476 sample->flags = dumbfile_getc(f);
477 sample->default_volume = dumbfile_getc(f);
478
479 /* Skip Sample Name. */
480 dumbfile_skip(f, 26);
481
482 *convert = dumbfile_getc(f);
483 sample->default_pan = dumbfile_getc(f);
484 sample->length = dumbfile_igetl(f);
485 sample->loop_start = dumbfile_igetl(f);
486 sample->loop_end = dumbfile_igetl(f);
487 sample->C5_speed = dumbfile_igetl(f);
488 sample->sus_loop_start = dumbfile_igetl(f);
489 sample->sus_loop_end = dumbfile_igetl(f);
490
491#ifdef STEREO_SAMPLES_COUNT_AS_TWO
492 if (sample->flags & IT_SAMPLE_STEREO) {
493 sample->length >>= 1;
494 sample->loop_start >>= 1;
495 sample->loop_end >>= 1;
496 sample->C5_speed >>= 1;
497 sample->sus_loop_start >>= 1;
498 sample->sus_loop_end >>= 1;
499 }
500#endif
501
502 if (sample->flags & IT_SAMPLE_EXISTS) {
503 if (sample->length <= 0)
504 sample->flags &= ~IT_SAMPLE_EXISTS;
505 else {
506 if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
507 sample->flags &= ~IT_SAMPLE_LOOP;
508 else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
509 sample->flags &= ~IT_SAMPLE_LOOP;
510
511 if ((unsigned int)sample->sus_loop_end > (unsigned int)sample->length)
512 sample->flags &= ~IT_SAMPLE_SUS_LOOP;
513 else if ((unsigned int)sample->sus_loop_start >= (unsigned int)sample->sus_loop_end)
514 sample->flags &= ~IT_SAMPLE_SUS_LOOP;
515
516 /* We may be able to truncate the sample to save memory. */
517 if (sample->flags & IT_SAMPLE_LOOP) {
518 if ((sample->flags & IT_SAMPLE_SUS_LOOP) && sample->sus_loop_end >= sample->loop_end)
519 sample->length = sample->sus_loop_end;
520 else
521 sample->length = sample->loop_end;
522 }
523 }
524 }
525
526 *offset = dumbfile_igetl(f);
527
528 sample->vibrato_speed = dumbfile_getc(f);
529 sample->vibrato_depth = dumbfile_getc(f);
530 sample->vibrato_rate = dumbfile_getc(f);
531 sample->vibrato_waveform = dumbfile_getc(f);
532
533 return dumbfile_error(f);
534}
535
536
537
538static long it_read_sample_data(int cmwt, IT_SAMPLE *sample, unsigned char convert, DUMBFILE *f)
539{
540 long n;
541
542 sample->left = malloc(sample->length * sizeof(*sample->left));
543 if (!sample->left)
544 return -1;
545
546 if (sample->flags & IT_SAMPLE_STEREO) {
547 sample->right = malloc(sample->length * sizeof(*sample->right));
548 if (!sample->right)
549 return -1;
550 }
551
552 if (sample->flags & 8) {
553 /* If the sample is packed, then we must unpack it. */
554
555 /** WARNING - unresolved business here... test with ModPlug? */
556
557 if (sample->flags & IT_SAMPLE_STEREO)
558 return -1;
559
560/*
561//#ifndef STEREO_SAMPLES_COUNT_AS_TWO
562 ASSERT(!(sample->flags & IT_SAMPLE_STEREO));
563//#endif
564*/
565 if (sample->flags & IT_SAMPLE_16BIT)
566 decompress16(f, sample->left, sample->right, sample->length, cmwt);
567 else
568 decompress8(f, sample->left, sample->right, sample->length, cmwt);
569 } else if (sample->flags & IT_SAMPLE_STEREO) {
570 if (sample->flags & IT_SAMPLE_16BIT) {
571 if (convert & 2) {
572 for (n = 0; n < sample->length; n++) {
573 sample->left[n] = (int)(signed short)dumbfile_mgetw(f) << 8;
574 sample->right[n] = (int)(signed short)dumbfile_mgetw(f) << 8;
575 }
576 } else {
577 for (n = 0; n < sample->length; n++) {
578 sample->left[n] = (int)(signed short)dumbfile_igetw(f) << 8;
579 sample->right[n] = (int)(signed short)dumbfile_igetw(f) << 8;
580 }
581 }
582 } else {
583 for (n = 0; n < sample->length; n++) {
584 sample->left[n] = (int)(signed char)dumbfile_getc(f) << 16;
585 sample->right[n] = (int)(signed char)dumbfile_getc(f) << 16;
586 }
587 }
588 } else if (sample->flags & IT_SAMPLE_16BIT) {
589 if (convert & 2)
590 for (n = 0; n < sample->length; n++)
591 sample->left[n] = (int)(signed short)dumbfile_mgetw(f) << 8;
592 else
593 for (n = 0; n < sample->length; n++)
594 sample->left[n] = (int)(signed short)dumbfile_igetw(f) << 8;
595 } else
596 for (n = 0; n < sample->length; n++)
597 sample->left[n] = (int)(signed char)dumbfile_getc(f) << 16;
598
599 if (dumbfile_error(f))
600 return -1;
601
602 if (!(convert & 1)) {
603 /* Convert to signed. */
604 for (n = 0; n < sample->length; n++)
605 sample->left[n] ^= 0xFF800000;
606
607 if (sample->right)
608 for (n = 0; n < sample->length; n++)
609 sample->right[n] ^= 0xFF800000;
610 }
611
612 /* NOT SUPPORTED:
613 *
614 * convert & 4 - Samples stored as delta values
615 * convert & 16 - Samples stored as TX-Wave 12-bit values
616 * convert & 32 - Left/Right/All Stereo prompt
617 */
618
619 return 0;
620}
621
622
623
624#define DETECT_DUPLICATE_CHANNELS
625#ifdef DETECT_DUPLICATE_CHANNELS
626#include <stdio.h>
627#endif
628static int it_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer)
629{
630 unsigned char cmask[DUMB_IT_N_CHANNELS];
631 unsigned char cnote[DUMB_IT_N_CHANNELS];
632 unsigned char cinstrument[DUMB_IT_N_CHANNELS];
633 unsigned char cvolpan[DUMB_IT_N_CHANNELS];
634 unsigned char ceffect[DUMB_IT_N_CHANNELS];
635 unsigned char ceffectvalue[DUMB_IT_N_CHANNELS];
636#ifdef DETECT_DUPLICATE_CHANNELS
637 IT_ENTRY *dupentry[DUMB_IT_N_CHANNELS];
638#endif
639
640 int n_entries = 0;
641 int buflen;
642 int bufpos = 0;
643
644 IT_ENTRY *entry;
645
646 unsigned char channel;
647 unsigned char mask;
648
649 memset(cmask, 0, sizeof(cmask));
650 memset(cnote, 0, sizeof(cnote));
651 memset(cinstrument, 0, sizeof(cinstrument));
652 memset(cvolpan, 0, sizeof(cvolpan));
653 memset(ceffect, 0, sizeof(ceffect));
654 memset(ceffectvalue, 0, sizeof(ceffectvalue));
655#ifdef DETECT_DUPLICATE_CHANNELS
656 {
657 int i;
658 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL;
659 }
660#endif
661
662 buflen = dumbfile_igetw(f);
663 pattern->n_rows = dumbfile_igetw(f);
664
665 /* Skip four unused bytes. */
666 dumbfile_skip(f, 4);
667
668 if (dumbfile_error(f))
669 return -1;
670
671 /* Read in the pattern data. */
672 dumbfile_getnc((char *)buffer, buflen, f);
673
674 if (dumbfile_error(f))
675 return -1;
676
677 /* Scan the pattern data, and work out how many entries we need room for. */
678 while (bufpos < buflen) {
679 unsigned char b = buffer[bufpos++];
680
681 if (b == 0) {
682 /* End of row */
683 n_entries++;
684 continue;
685 }
686
687 channel = (b - 1) & 63;
688
689 if (b & 128)
690 cmask[channel] = mask = buffer[bufpos++];
691 else
692 mask = cmask[channel];
693
694 {
695 static const unsigned char used[16] = {0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5};
696 n_entries += (mask != 0);
697 bufpos += used[mask & 15];
698 }
699 }
700
701 pattern->n_entries = n_entries;
702
703 pattern->entry = malloc(n_entries * sizeof(*pattern->entry));
704
705 if (!pattern->entry)
706 return -1;
707
708 bufpos = 0;
709 memset(cmask, 0, sizeof(cmask));
710
711 entry = pattern->entry;
712
713 while (bufpos < buflen) {
714 unsigned char b = buffer[bufpos++];
715
716 if (b == 0) {
717 /* End of row */
718 IT_SET_END_ROW(entry);
719 entry++;
720#ifdef DETECT_DUPLICATE_CHANNELS
721 {
722 int i;
723 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL;
724 }
725#endif
726 continue;
727 }
728
729 channel = (b - 1) & 63;
730
731 if (b & 128)
732 cmask[channel] = mask = buffer[bufpos++];
733 else
734 mask = cmask[channel];
735
736 if (mask) {
737 entry->mask = (mask & 15) | (mask >> 4);
738 entry->channel = channel;
739
740 if (mask & IT_ENTRY_NOTE)
741 cnote[channel] = entry->note = buffer[bufpos++];
742 else if (mask & (IT_ENTRY_NOTE << 4))
743 entry->note = cnote[channel];
744
745 if (mask & IT_ENTRY_INSTRUMENT)
746 cinstrument[channel] = entry->instrument = buffer[bufpos++];
747 else if (mask & (IT_ENTRY_INSTRUMENT << 4))
748 entry->instrument = cinstrument[channel];
749
750 if (mask & IT_ENTRY_VOLPAN)
751 cvolpan[channel] = entry->volpan = buffer[bufpos++];
752 else if (mask & (IT_ENTRY_VOLPAN << 4))
753 entry->volpan = cvolpan[channel];
754
755 if (mask & IT_ENTRY_EFFECT) {
756 ceffect[channel] = entry->effect = buffer[bufpos++];
757 ceffectvalue[channel] = entry->effectvalue = buffer[bufpos++];
758 } else {
759 entry->effect = ceffect[channel];
760 entry->effectvalue = ceffectvalue[channel];
761 }
762
763#if defined( DETECT_DUPLICATE_CHANNELS) && 0
764 if (dupentry[channel]) {
765 FILE *f = fopen("dupentry.txt", "a");
766 if (!f) abort();
767 fprintf(f, "Two events on channel %d:", channel);
768 fprintf(f, " Event #1:");
769 if (dupentry[channel]->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", dupentry[channel]->note ); else fprintf(f, " ...");
770 if (dupentry[channel]->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", dupentry[channel]->instrument); else fprintf(f, " ...");
771 if (dupentry[channel]->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", dupentry[channel]->volpan ); else fprintf(f, " ...");
772 if (dupentry[channel]->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + dupentry[channel]->effect, dupentry[channel]->effectvalue); else fprintf(f, " ...\n");
773 fprintf(f, " Event #2:");
774 if (entry->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", entry->note ); else fprintf(f, " ...");
775 if (entry->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", entry->instrument); else fprintf(f, " ...");
776 if (entry->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", entry->volpan ); else fprintf(f, " ...");
777 if (entry->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + entry->effect, entry->effectvalue); else fprintf(f, " ...\n");
778 fclose(f);
779 }
780 dupentry[channel] = entry;
781#endif
782
783 entry++;
784 }
785 }
786
787 ASSERT(entry == pattern->entry + n_entries);
788
789 return 0;
790}
791
792
793
794/* Currently we assume the sample data are stored after the sample headers in
795 * module files. This assumption may be unjustified; let me know if you have
796 * trouble.
797 */
798
799#define IT_COMPONENT_INSTRUMENT 1
800#define IT_COMPONENT_PATTERN 2
801#define IT_COMPONENT_SAMPLE 3
802
803typedef struct IT_COMPONENT
804{
805 unsigned char type;
806 unsigned char n;
807 long offset;
808 short sampfirst; /* component[sampfirst] = first sample data after this */
809 short sampnext; /* sampnext is used to create linked lists of sample data */
810}
811IT_COMPONENT;
812
813
814
815static int it_component_compare(const void *e1, const void *e2)
816{
817 return ((const IT_COMPONENT *)e1)->offset -
818 ((const IT_COMPONENT *)e2)->offset;
819}
820
821
822
823static sigdata_t *it_load_sigdata(DUMBFILE *f)
824{
825 DUMB_IT_SIGDATA *sigdata;
826
827 int cwt, cmwt;
828 int special;
829
830 IT_COMPONENT *component;
831 int n_components = 0;
832
833 unsigned char sample_convert[256];
834
835 int n;
836
837 unsigned char *buffer;
838
839 if (dumbfile_mgetl(f) != IT_SIGNATURE)
840 return NULL;
841
842 sigdata = malloc(sizeof(*sigdata));
843
844 if (!sigdata)
845 return NULL;
846
847 sigdata->order = NULL;
848 sigdata->instrument = NULL;
849 sigdata->sample = NULL;
850 sigdata->pattern = NULL;
851 sigdata->midi = NULL;
852 sigdata->checkpoint = NULL;
853
854 /* Skip song name and pattern row highlight info. */
855 dumbfile_skip(f, 28);
856
857 sigdata->n_orders = dumbfile_igetw(f);
858 sigdata->n_instruments = dumbfile_igetw(f);
859 sigdata->n_samples = dumbfile_igetw(f);
860 sigdata->n_patterns = dumbfile_igetw(f);
861
862 cwt = dumbfile_igetw(f);
863 cmwt = dumbfile_igetw(f);
864
865 sigdata->flags = dumbfile_igetw(f);
866 special = dumbfile_igetw(f);
867
868 sigdata->global_volume = dumbfile_getc(f);
869 sigdata->mixing_volume = dumbfile_getc(f);
870 sigdata->speed = dumbfile_getc(f);
871 if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
872 sigdata->tempo = dumbfile_getc(f);
873 sigdata->pan_separation = dumbfile_getc(f); /** WARNING: use this */
874
875 /* Skip Pitch Wheel Depth, Message Length, Message Offset and Reserved. */
876 dumbfile_skip(f, 11);
877
878 dumbfile_getnc((char *)sigdata->channel_pan, DUMB_IT_N_CHANNELS, f);
879 dumbfile_getnc((char *)sigdata->channel_volume, DUMB_IT_N_CHANNELS, f);
880
881 if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_instruments > 256 || sigdata->n_samples > 256 || sigdata->n_patterns > 256) {
882 _dumb_it_unload_sigdata(sigdata);
883 return NULL;
884 }
885
886 sigdata->order = malloc(sigdata->n_orders);
887 if (!sigdata->order) {
888 _dumb_it_unload_sigdata(sigdata);
889 return NULL;
890 }
891
892 if (sigdata->n_instruments) {
893 sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
894 if (!sigdata->instrument) {
895 _dumb_it_unload_sigdata(sigdata);
896 return NULL;
897 }
898 }
899
900 if (sigdata->n_samples) {
901 sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
902 if (!sigdata->sample) {
903 _dumb_it_unload_sigdata(sigdata);
904 return NULL;
905 }
906 for (n = 0; n < sigdata->n_samples; n++)
907 sigdata->sample[n].right = sigdata->sample[n].left = NULL;
908 }
909
910 if (sigdata->n_patterns) {
911 sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
912 if (!sigdata->pattern) {
913 _dumb_it_unload_sigdata(sigdata);
914 return NULL;
915 }
916 for (n = 0; n < sigdata->n_patterns; n++)
917 sigdata->pattern[n].entry = NULL;
918 }
919
920 dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f);
921 sigdata->restart_position = 0;
922
923 component = malloc(768 * sizeof(*component));
924 if (!component) {
925 _dumb_it_unload_sigdata(sigdata);
926 return NULL;
927 }
928
929 for (n = 0; n < sigdata->n_instruments; n++) {
930 component[n_components].type = IT_COMPONENT_INSTRUMENT;
931 component[n_components].n = n;
932 component[n_components].offset = dumbfile_igetl(f);
933 component[n_components].sampfirst = -1;
934 n_components++;
935 }
936
937 for (n = 0; n < sigdata->n_samples; n++) {
938 component[n_components].type = IT_COMPONENT_SAMPLE;
939 component[n_components].n = n;
940 component[n_components].offset = dumbfile_igetl(f);
941 component[n_components].sampfirst = -1;
942 n_components++;
943 }
944
945 for (n = 0; n < sigdata->n_patterns; n++) {
946 long offset = dumbfile_igetl(f);
947 if (offset) {
948 component[n_components].type = IT_COMPONENT_PATTERN;
949 component[n_components].n = n;
950 component[n_components].offset = offset;
951 component[n_components].sampfirst = -1;
952 n_components++;
953 } else {
954 /* Empty 64-row pattern */
955 sigdata->pattern[n].n_rows = 64;
956 sigdata->pattern[n].n_entries = 0;
957 }
958 }
959
960 if (dumbfile_error(f)) {
961 free(component);
962 _dumb_it_unload_sigdata(sigdata);
963 return NULL;
964 }
965
966 if (!(sigdata->flags & 128) != !(special & 8)) {
967#if 0
968 fprintf(stderr, "Flags Bit 7 (\"Request embedded MIDI configuration\"): %s\n", sigdata->flags & 128 ? "=SET=" : "clear");
969 fprintf(stderr, "Special Bit 3 (\"MIDI configuration embedded\") : %s\n", special & 8 ? "=SET=" : "clear");
970 fprintf(stderr, "entheh would like to investigate this IT file.\n");
971 fprintf(stderr, "Please contact him! entheh@users.sf.net\n");
972#endif
973 }
974
975 if (special & 8) {
976 /* MIDI configuration is embedded. */
977 unsigned char mididata[32];
978 int i;
979 sigdata->midi = malloc(sizeof(*sigdata->midi));
980 if (!sigdata->midi) {
981 free(component);
982 _dumb_it_unload_sigdata(sigdata);
983 return NULL;
984 // Should we be happy with this outcome in some situations?
985 }
986 // What are we skipping?
987 i = dumbfile_igetw(f);
988 if (dumbfile_error(f) || dumbfile_skip(f, 8*i)) {
989 free(component);
990 _dumb_it_unload_sigdata(sigdata);
991 return NULL;
992 }
993 /* Read embedded MIDI configuration */
994 // What are the first 9 commands for?
995 if (dumbfile_skip(f, 32*9)) {
996 free(component);
997 _dumb_it_unload_sigdata(sigdata);
998 return NULL;
999 }
1000 for (i = 0; i < 16; i++) {
1001 unsigned char len = 0;
1002 int j, leftdigit = -1;
1003 if (dumbfile_getnc((char *)mididata, 32, f) < 32) {
1004 free(component);
1005 _dumb_it_unload_sigdata(sigdata);
1006 return NULL;
1007 }
1008 sigdata->midi->SFmacroz[i] = 0;
1009 for (j = 0; j < 32; j++) {
1010 if (leftdigit >= 0) {
1011 if (mididata[j] == 0) {
1012 sigdata->midi->SFmacro[i][len++] = leftdigit;
1013 break;
1014 } else if (mididata[j] == ' ')
1015 sigdata->midi->SFmacro[i][len++] = leftdigit;
1016 else if (mididata[j] >= '0' && mididata[j] <= '9')
1017 sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0');
1018 else if (mididata[j] >= 'A' && mididata[j] <= 'F')
1019 sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA);
1020 leftdigit = -1;
1021 } else if (mididata[j] == 0)
1022 break;
1023 else if (mididata[j] == 'z')
1024 sigdata->midi->SFmacroz[i] |= 1 << len++;
1025 else if (mididata[j] >= '0' && mididata[j] <= '9')
1026 leftdigit = mididata[j] - '0';
1027 else if (mididata[j] >= 'A' && mididata[j] <= 'F')
1028 leftdigit = mididata[j] - 'A' + 0xA;
1029 }
1030 sigdata->midi->SFmacrolen[i] = len;
1031 }
1032 for (i = 0; i < 128; i++) {
1033 unsigned char len = 0;
1034 int j, leftdigit = -1;
1035 dumbfile_getnc((char *)mididata, 32, f);
1036 for (j = 0; j < 32; j++) {
1037 if (leftdigit >= 0) {
1038 if (mididata[j] == 0) {
1039 sigdata->midi->Zmacro[i][len++] = leftdigit;
1040 break;
1041 } else if (mididata[j] == ' ')
1042 sigdata->midi->Zmacro[i][len++] = leftdigit;
1043 else if (mididata[j] >= '0' && mididata[j] <= '9')
1044 sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0');
1045 else if (mididata[j] >= 'A' && mididata[j] <= 'F')
1046 sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA);
1047 leftdigit = -1;
1048 } else if (mididata[j] == 0)
1049 break;
1050 else if (mididata[j] >= '0' && mididata[j] <= '9')
1051 leftdigit = mididata[j] - '0';
1052 else if (mididata[j] >= 'A' && mididata[j] <= 'F')
1053 leftdigit = mididata[j] - 'A' + 0xA;
1054 }
1055 sigdata->midi->Zmacrolen[i] = len;
1056 }
1057 }
1058
1059 sigdata->flags &= IT_REAL_FLAGS;
1060
1061 qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare);
1062
1063 buffer = malloc(65536);
1064 if (!buffer) {
1065 free(component);
1066 _dumb_it_unload_sigdata(sigdata);
1067 return NULL;
1068 }
1069
1070 for (n = 0; n < n_components; n++) {
1071 long offset;
1072 int m;
1073
1074 if (it_seek(f, component[n].offset)) {
1075 free(buffer);
1076 free(component);
1077 _dumb_it_unload_sigdata(sigdata);
1078 return NULL;
1079 }
1080
1081 switch (component[n].type) {
1082
1083 case IT_COMPONENT_INSTRUMENT:
1084 if (cmwt < 0x200)
1085 m = it_read_old_instrument(&sigdata->instrument[component[n].n], f);
1086 else
1087 m = it_read_instrument(&sigdata->instrument[component[n].n], f);
1088
1089 if (m) {
1090 free(buffer);
1091 free(component);
1092 _dumb_it_unload_sigdata(sigdata);
1093 return NULL;
1094 }
1095 break;
1096
1097 case IT_COMPONENT_PATTERN:
1098 if (it_read_pattern(&sigdata->pattern[component[n].n], f, buffer)) {
1099 free(buffer);
1100 free(component);
1101 _dumb_it_unload_sigdata(sigdata);
1102 return NULL;
1103 }
1104 break;
1105
1106 case IT_COMPONENT_SAMPLE:
1107 if (it_read_sample_header(&sigdata->sample[component[n].n], &sample_convert[component[n].n], &offset, f)) {
1108 free(buffer);
1109 free(component);
1110 _dumb_it_unload_sigdata(sigdata);
1111 return NULL;
1112 }
1113
1114 if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) {
1115 short *sample;
1116
1117 for (m = n + 1; m < n_components; m++)
1118 if (component[m].offset > offset)
1119 break;
1120 m--;
1121
1122 sample = &component[m].sampfirst;
1123
1124 while (*sample >= 0 && component[*sample].offset <= offset)
1125 sample = &component[*sample].sampnext;
1126
1127 component[n].sampnext = *sample;
1128 *sample = n;
1129
1130 component[n].offset = offset;
1131 }
1132 }
1133
1134 m = component[n].sampfirst;
1135
1136 while (m >= 0) {
1137 if (it_seek(f, component[m].offset)) {
1138 free(buffer);
1139 free(component);
1140 _dumb_it_unload_sigdata(sigdata);
1141 return NULL;
1142 }
1143
1144 if (it_read_sample_data(cmwt, &sigdata->sample[component[m].n], sample_convert[component[m].n], f)) {
1145 free(buffer);
1146 free(component);
1147 _dumb_it_unload_sigdata(sigdata);
1148 return NULL;
1149 }
1150
1151 m = component[m].sampnext;
1152 }
1153 }
1154
1155 free(buffer);
1156 free(component);
1157
1158 _dumb_it_fix_invalid_orders(sigdata);
1159
1160 return sigdata;
1161}
1162
1163
1164
1165DUH *dumb_read_it(DUMBFILE *f)
1166{
1167 sigdata_t *sigdata;
1168 long length;
1169
1170 DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
1171
1172 sigdata = it_load_sigdata(f);
1173
1174 if (!sigdata)
1175 return NULL;
1176
1177 length = _dumb_it_build_checkpoints(sigdata);
1178
1179 return make_duh(length, 1, &descptr, &sigdata);
1180}
1181
diff --git a/apps/codecs/dumb/src/it/itrender.c b/apps/codecs/dumb/src/it/itrender.c
deleted file mode 100644
index 103654fd77..0000000000
--- a/apps/codecs/dumb/src/it/itrender.c
+++ /dev/null
@@ -1,3512 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * itrender.c - Code to render an Impulse Tracker / / \ \
12 * module. | < / \_
13 * | \/ /\ /
14 * Written - painstakingly - by entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <math.h>
21#include <stdlib.h>
22
23#include "dumb.h"
24#include "internal/it.h"
25
26
27
28static IT_PLAYING *dup_playing(IT_PLAYING *src, IT_CHANNEL *dstchannel, IT_CHANNEL *srcchannel)
29{
30 IT_PLAYING *dst;
31
32 if (!src) return NULL;
33
34 dst = malloc(sizeof(*dst));
35 if (!dst) return NULL;
36
37 dst->flags = src->flags;
38
39 ASSERT(src->channel);
40 dst->channel = &dstchannel[src->channel - srcchannel];
41 dst->sample = src->sample;
42 dst->instrument = src->instrument;
43 dst->env_instrument = src->env_instrument;
44
45 dst->sampnum = src->sampnum;
46 dst->instnum = src->instnum;
47
48 dst->channel_volume = src->channel_volume;
49
50 dst->volume = src->volume;
51 dst->pan = src->pan;
52
53 dst->note = src->note;
54
55 dst->filter_cutoff = src->filter_cutoff;
56 dst->filter_resonance = src->filter_resonance;
57
58 dst->true_filter_cutoff = src->true_filter_cutoff;
59 dst->true_filter_resonance = src->true_filter_resonance;
60
61 dst->vibrato_speed = src->vibrato_speed;
62 dst->vibrato_depth = src->vibrato_depth;
63 dst->vibrato_n = src->vibrato_n;
64 dst->vibrato_time = src->vibrato_time;
65
66 dst->tremolo_speed = src->tremolo_speed;
67 dst->tremolo_depth = src->tremolo_depth;
68 dst->tremolo_time = src->tremolo_time;
69
70 dst->sample_vibrato_time = src->sample_vibrato_time;
71 dst->sample_vibrato_depth = src->sample_vibrato_depth;
72
73 dst->slide = src->slide;
74 dst->delta = src->delta;
75
76 dst->volume_envelope = src->volume_envelope;
77 dst->pan_envelope = src->pan_envelope;
78 dst->pitch_envelope = src->pitch_envelope;
79
80 dst->fadeoutcount = src->fadeoutcount;
81
82 dst->filter_state[0] = src->filter_state[0];
83 dst->filter_state[1] = src->filter_state[1];
84
85 dst->resampler[0] = src->resampler[0];
86 dst->resampler[1] = src->resampler[1];
87 dst->resampler[1].pickup_data = dst->resampler[0].pickup_data = dst;
88 dst->time_lost = src->time_lost;
89
90 return dst;
91}
92
93
94
95static void dup_channel(IT_CHANNEL *dst, IT_CHANNEL *src)
96{
97 dst->flags = src->flags;
98
99 dst->volume = src->volume;
100 dst->volslide = src->volslide;
101 dst->xm_volslide = src->xm_volslide;
102
103 dst->pan = src->pan;
104 dst->truepan = src->truepan;
105
106 dst->channelvolume = src->channelvolume;
107 dst->channelvolslide = src->channelvolslide;
108
109 dst->instrument = src->instrument;
110 dst->note = src->note;
111
112 dst->SFmacro = src->SFmacro;
113
114 dst->filter_cutoff = src->filter_cutoff;
115 dst->filter_resonance = src->filter_resonance;
116
117 dst->note_cut_count = src->note_cut_count;
118 dst->note_delay_count = src->note_delay_count;
119 dst->note_delay_entry = src->note_delay_entry;
120
121 dst->arpeggio = src->arpeggio;
122 dst->retrig = src->retrig;
123 dst->xm_retrig = src->xm_retrig;
124 dst->retrig_tick = src->retrig_tick;
125
126 dst->tremor_time = src->tremor_time;
127
128 dst->portamento = src->portamento;
129 dst->toneporta = src->toneporta;
130 dst->destnote = src->destnote;
131
132 dst->sample = src->sample;
133 dst->truenote = src->truenote;
134
135 dst->midi_state = src->midi_state;
136
137 dst->lastvolslide = src->lastvolslide;
138 dst->lastDKL = src->lastDKL;
139 dst->lastEF = src->lastEF;
140 dst->lastG = src->lastG;
141 dst->lastHspeed = src->lastHspeed;
142 dst->lastHdepth = src->lastHdepth;
143 dst->lastRspeed = src->lastRspeed;
144 dst->lastRdepth = src->lastRdepth;
145 dst->lastI = src->lastI;
146 dst->lastJ = src->lastJ;
147 dst->lastN = src->lastN;
148 dst->lastO = src->lastO;
149 dst->high_offset = src->high_offset;
150 dst->lastQ = src->lastQ;
151 dst->lastS = src->lastS;
152 dst->pat_loop_row = src->pat_loop_row;
153 dst->pat_loop_count = src->pat_loop_count;
154 dst->lastW = src->lastW;
155
156 dst->xm_lastE1 = src->xm_lastE1;
157 dst->xm_lastE2 = src->xm_lastE2;
158 dst->xm_lastEA = src->xm_lastEA;
159 dst->xm_lastEB = src->xm_lastEB;
160 dst->xm_lastX1 = src->xm_lastX1;
161 dst->xm_lastX2 = src->xm_lastX2;
162
163 dst->playing = dup_playing(src->playing, dst, src);
164}
165
166
167
168/* Allocate the new callbacks first, then pass them to this function!
169 * It will free them on failure.
170 */
171static DUMB_IT_SIGRENDERER *dup_sigrenderer(DUMB_IT_SIGRENDERER *src, int n_channels, IT_CALLBACKS *callbacks)
172{
173 DUMB_IT_SIGRENDERER *dst;
174 int i;
175
176 if (!src) {
177 if (callbacks) free(callbacks);
178 return NULL;
179 }
180
181 dst = malloc(sizeof(*dst));
182 if (!dst) {
183 if (callbacks) free(callbacks);
184 return NULL;
185 }
186
187 dst->sigdata = src->sigdata;
188
189 dst->n_channels = n_channels;
190
191 dst->globalvolume = src->globalvolume;
192 dst->globalvolslide = src->globalvolslide;
193
194 dst->tempo = src->tempo;
195 dst->temposlide = src->temposlide;
196
197 for (i = 0; i < DUMB_IT_N_CHANNELS; i++)
198 dup_channel(&dst->channel[i], &src->channel[i]);
199
200 for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++)
201 dst->playing[i] = dup_playing(src->playing[i], dst->channel, src->channel);
202
203 dst->tick = src->tick;
204 dst->speed = src->speed;
205 dst->rowcount = src->rowcount;
206
207 dst->order = src->order;
208 dst->row = src->row;
209 dst->processorder = src->processorder;
210 dst->processrow = src->processrow;
211 dst->breakrow = src->breakrow;
212 dst->pat_loop_row = src->pat_loop_row;
213
214 dst->n_rows = src->n_rows;
215
216 dst->entry_start = src->entry_start;
217 dst->entry = src->entry;
218 dst->entry_end = src->entry_end;
219
220 dst->time_left = src->time_left;
221 dst->sub_time_left = src->sub_time_left;
222
223 dst->click_remover = NULL;
224
225 dst->callbacks = callbacks;
226
227 return dst;
228}
229
230
231
232static IT_MIDI default_midi = {
233 /* unsigned char SFmacro[16][16]; */
234 {
235 {0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
236 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
237 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
238 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
239 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
240 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
241 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
242 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
243 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
244 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
245 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
246 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
247 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
248 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
249 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
250 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
251 },
252 /* unsigned char SFmacrolen[16]; */
253 {4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
254 /* unsigned short SFmacroz[16]; */
255 /* Bitfield; bit 0 set = z in first position */
256 {
257 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
258 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
259 },
260 /* unsigned char Zmacro[128][16]; */
261 {
262 {0xF0, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
263 {0xF0, 0xF0, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
264 {0xF0, 0xF0, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
265 {0xF0, 0xF0, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
266 {0xF0, 0xF0, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
267 {0xF0, 0xF0, 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
268 {0xF0, 0xF0, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
269 {0xF0, 0xF0, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
270 {0xF0, 0xF0, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
271 {0xF0, 0xF0, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
272 {0xF0, 0xF0, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
273 {0xF0, 0xF0, 0x01, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
274 {0xF0, 0xF0, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
275 {0xF0, 0xF0, 0x01, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
276 {0xF0, 0xF0, 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
277 {0xF0, 0xF0, 0x01, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
278
279 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
280 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
281 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
282 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
283 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
284 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
285 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
286 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
287 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
288 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
289 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
290 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
291 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
292 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
293 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
294 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
295
296 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
297 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
298 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
299 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
300 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
301 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
302 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
303 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
304 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
305 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
306 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
307 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
308 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
309 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
310 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
311 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
312
313 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
314 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
315 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
316 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
317 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
318 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
319 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
320 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
321 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
322 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
323 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
324 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
325 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
326 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
327 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
328 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
329
330 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
331 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
332 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
333 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
334 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
335 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
336 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
337 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
338 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
339 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
340 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
341 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
342 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
343 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
344 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
345 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
346
347 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
348 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
349 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
350 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
351 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
352 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
353 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
354 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
355 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
356 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
357 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
358 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
359 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
360 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
361 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
362 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
363
364 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
365 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
366 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
367 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
368 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
369 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
370 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
371 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
372 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
373 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
374 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
375 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
376 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
377 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
378 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
379 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
380
381 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
382 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
383 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
384 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
385 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
386 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
387 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
388 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
389 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
390 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
391 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
392 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
393 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
394 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
395 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
396 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
397 },
398 /* unsigned char Zmacrolen[128]; */
399 {
400 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
401 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
402 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
403 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
404 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
405 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
406 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
407 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
408 }
409};
410
411
412
413static void it_reset_filter_state(IT_FILTER_STATE *state)
414{
415 state->currsample = 0;
416 state->prevsample = 0;
417}
418
419
420
421#define LOG10 2.30258509299
422
423/* IMPORTANT: This function expects one extra sample in 'src' so it can apply
424 * click removal. It reads size samples, starting from src[0], and writes its
425 * output starting at dst[pos]. The pos parameter is required for getting
426 * click removal right.
427 */
428static void it_filter(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, long pos, sample_t *src, long size, int sampfreq, int cutoff, int resonance)
429{
430 float currsample = state->currsample;
431 float prevsample = state->prevsample;
432
433 float a, b, c;
434
435 {
436 float inv_angle = (float)(sampfreq * pow(0.5, 0.25 + cutoff*(1.0/(24<<IT_ENVELOPE_SHIFT))) * (1.0/(2*3.14159265358979323846*110.0)));
437 float loss = (float)exp(resonance*(-LOG10*1.2/128.0));
438 float d, e;
439#if 0
440 loss *= 2; // This is the mistake most players seem to make!
441#endif
442
443#if 1
444 d = (1.0f - loss) / inv_angle;
445 if (d > 2.0f) d = 2.0f;
446 d = (loss - d) * inv_angle;
447 e = inv_angle * inv_angle;
448 a = 1.0f / (1.0f + d + e);
449 c = -e * a;
450 b = 1.0f - a - c;
451#else
452 a = 1.0f / (inv_angle*inv_angle + inv_angle*loss + loss);
453 c = -(inv_angle*inv_angle) * a;
454 b = 1.0f - a - c;
455#endif
456 }
457
458 dst += pos;
459
460 if (cr) {
461 float startstep = src[0]*a + currsample*b + prevsample*c;
462 dumb_record_click(cr, pos, (sample_t)startstep);
463 }
464
465#define INT_FILTERS
466#ifdef INT_FILTERS
467#define MULSCA(a, b) ((int)((LONG_LONG)((a) << 4) * (b) >> 32))
468#define SCALEB 12
469 {
470 int ai = (int)(a * (1 << (16+SCALEB)));
471 int bi = (int)(b * (1 << (16+SCALEB)));
472 int ci = (int)(c * (1 << (16+SCALEB)));
473 sample_t csi = (sample_t)currsample;
474 sample_t psi = (sample_t)prevsample;
475 sample_t *dst_end = dst + size;
476 while (dst < dst_end) {
477 {
478 sample_t nsi = MULSCA(*src++, ai) + MULSCA(csi, bi) + MULSCA(psi, ci);
479 psi = csi;
480 csi = nsi;
481 }
482 *dst++ += csi;
483 }
484 currsample = csi;
485 prevsample = psi;
486 }
487#else
488 {
489 int i = size % 3;
490 while (i > 0) {
491 {
492 float newsample = *src++*a + currsample*b + prevsample*c;
493 prevsample = currsample;
494 currsample = newsample;
495 }
496 *dst++ += (sample_t)currsample;
497 i--;
498 }
499 i = size / 3;
500 while (i > 0) {
501 float newsample;
502 /* Gotta love unrolled loops! */
503 *dst++ += (sample_t)(newsample = *src++*a + currsample*b + prevsample*c);
504 *dst++ += (sample_t)(prevsample = *src++*a + newsample*b + currsample*c);
505 *dst++ += (sample_t)(currsample = *src++*a + prevsample*b + newsample*c);
506 i--;
507 }
508 }
509#endif
510
511 if (cr) {
512 float endstep = *src*a + currsample*b + prevsample*c;
513 dumb_record_click(cr, pos + size, -(sample_t)endstep);
514 }
515
516 state->currsample = currsample;
517 state->prevsample = prevsample;
518}
519
520#undef LOG10
521
522
523
524static signed char it_sine[256] = {
525 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23,
526 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,
527 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
528 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
529 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60,
530 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46,
531 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26,
532 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2,
533 0, -2, -3, -5, -6, -8, -9,-11,-12,-14,-16,-17,-19,-20,-22,-23,
534 -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44,
535 -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59,
536 -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64,
537 -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60,
538 -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,
539 -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26,
540 -24,-23,-22,-20,-19,-17,-16,-14,-12,-11, -9, -8, -6, -5, -3, -2
541};
542
543
544
545#if 0
546/** WARNING: use these! */
547/** JULIEN: Plus for XM compatibility it could be interesting to rename
548 * it_sawtooth[] to it_rampdown[], and add an it_rampup[].
549 * Also, still for XM compat', twood be good if it was possible to tell the
550 * the player not to retrig' the waveform on a new instrument.
551 * Both of these are only for completness though, as I don't think it would
552 * be very noticeable ;)
553 */
554/** ENTHEH: IT also has the 'don't retrig' thingy :) */
555
556static signed char it_sawtooth[256] = {
557 64, 63, 63, 62, 62, 61, 61, 60, 60, 59, 59, 58, 58, 57, 57, 56,
558 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48,
559 48, 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 40,
560 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 32,
561 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26, 25, 25, 24,
562 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16,
563 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8,
564 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0,
565 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -7, -8,
566 -8, -9, -9,-10,-10,-11,-11,-12,-12,-13,-13,-14,-14,-15,-15,-16,
567 -16,-17,-17,-18,-18,-19,-19,-20,-20,-21,-21,-22,-22,-23,-23,-24,
568 -24,-25,-25,-26,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32,
569 -32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,
570 -40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-46,-47,-47,-48,
571 -48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-54,-54,-55,-55,-56,
572 -56,-57,-57,-58,-58,-59,-59,-60,-60,-61,-61,-62,-62,-63,-63,-64
573};
574
575
576
577static signed char it_squarewave[256] = {
578 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
579 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
580 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
581 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
582 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
583 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
584 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
585 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
586 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
587 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
588 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
589 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
590 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
591 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
592 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
593 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
594};
595
596#endif
597
598
599
600static void reset_tick_counts(DUMB_IT_SIGRENDERER *sigrenderer)
601{
602 int i;
603
604 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
605 IT_CHANNEL *channel = &sigrenderer->channel[i];
606 channel->note_cut_count = 0;
607 channel->note_delay_count = 0;
608 }
609}
610
611
612
613static void reset_effects(DUMB_IT_SIGRENDERER *sigrenderer)
614{
615 int i;
616
617 sigrenderer->globalvolslide = 0;
618 sigrenderer->temposlide = 0;
619
620 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
621 IT_CHANNEL *channel = &sigrenderer->channel[i];
622 channel->volslide = 0;
623 channel->xm_volslide = 0;
624 channel->channelvolslide = 0;
625 channel->arpeggio = 0;
626 channel->retrig = 0;
627 if (channel->xm_retrig) {
628 channel->xm_retrig = 0;
629 channel->retrig_tick = 0;
630 }
631 channel->tremor_time &= 127;
632 channel->portamento = 0;
633 channel->toneporta = 0;
634 if (channel->playing) {
635 channel->playing->vibrato_n = 0;
636 channel->playing->tremolo_speed = 0;
637 channel->playing->tremolo_depth = 0;
638 }
639 }
640}
641
642
643
644static void update_tremor(IT_CHANNEL *channel)
645{
646 if ((channel->tremor_time & 128) && channel->playing) {
647 if (channel->tremor_time == 128)
648 channel->tremor_time = (channel->lastI >> 4) | 192;
649 else if (channel->tremor_time == 192)
650 channel->tremor_time = (channel->lastI & 15) | 128;
651 else
652 channel->tremor_time--;
653 }
654}
655
656
657
658static void it_pickup_loop(DUMB_RESAMPLER *resampler, void *data)
659{
660 resampler->pos -= resampler->end - resampler->start;
661 ((IT_PLAYING *)data)->time_lost += resampler->end - resampler->start;
662}
663
664
665
666static void it_pickup_pingpong_loop(DUMB_RESAMPLER *resampler, void *data)
667{
668 if (resampler->dir < 0) {
669 resampler->pos = (resampler->start << 1) - 1 - resampler->pos;
670 resampler->subpos ^= 65535;
671 resampler->dir = 1;
672 ((IT_PLAYING *)data)->time_lost += (resampler->end - resampler->start) << 1;
673 } else {
674 resampler->pos = (resampler->end << 1) - 1 - resampler->pos;
675 resampler->subpos ^= 65535;
676 resampler->dir = -1;
677 }
678}
679
680
681
682static void it_pickup_stop_at_end(DUMB_RESAMPLER *resampler, void *data)
683{
684 (void)data;
685
686 if (resampler->dir < 0) {
687 resampler->pos = (resampler->start << 1) - 1 - resampler->pos;
688 resampler->subpos ^= 65535;
689 /* By rights, time_lost would be updated here. However, there is no
690 * need at this point; it will not be used.
691 *
692 * ((IT_PLAYING *)data)->time_lost += (resampler->src_end - resampler->src_start) << 1;
693 */
694 resampler->dir = 1;
695 } else
696 resampler->dir = 0;
697}
698
699
700
701static void it_playing_update_resamplers(IT_PLAYING *playing)
702{
703 if ((playing->sample->flags & IT_SAMPLE_SUS_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) {
704 playing->resampler[0].start = playing->sample->sus_loop_start;
705 playing->resampler[0].end = playing->sample->sus_loop_end;
706 if (playing->sample->flags & IT_SAMPLE_PINGPONG_SUS_LOOP)
707 playing->resampler[0].pickup = &it_pickup_pingpong_loop;
708 else
709 playing->resampler[0].pickup = &it_pickup_loop;
710 } else if (playing->sample->flags & IT_SAMPLE_LOOP) {
711 playing->resampler[0].start = playing->sample->loop_start;
712 playing->resampler[0].end = playing->sample->loop_end;
713 if (playing->sample->flags & IT_SAMPLE_PINGPONG_LOOP)
714 playing->resampler[0].pickup = &it_pickup_pingpong_loop;
715 else
716 playing->resampler[0].pickup = &it_pickup_loop;
717 } else {
718 if (playing->sample->flags & IT_SAMPLE_SUS_LOOP)
719 playing->resampler[0].start = playing->sample->sus_loop_start;
720 else
721 playing->resampler[0].start = 0;
722 playing->resampler[0].end = playing->sample->length;
723 playing->resampler[0].pickup = &it_pickup_stop_at_end;
724 }
725 playing->resampler[1].start = playing->resampler[0].start;
726 playing->resampler[1].end = playing->resampler[0].end;
727 playing->resampler[1].pickup = playing->resampler[0].pickup;
728 ASSERT(playing->resampler[0].pickup_data == playing);
729 ASSERT(playing->resampler[1].pickup_data == playing);
730}
731
732
733
734/* This should be called whenever the sample or sample position changes. */
735static void it_playing_reset_resamplers(IT_PLAYING *playing, long pos)
736{
737 dumb_reset_resampler(&playing->resampler[0], playing->sample->left, pos, 0, 0);
738 dumb_reset_resampler(&playing->resampler[1], playing->sample->right, pos, 0, 0);
739 playing->resampler[1].pickup_data = playing->resampler[0].pickup_data = playing;
740 playing->time_lost = 0;
741 playing->flags &= ~IT_PLAYING_DEAD;
742 it_playing_update_resamplers(playing);
743}
744
745
746
747static void update_retrig(IT_CHANNEL *channel)
748{
749 if (channel->xm_retrig) {
750 channel->retrig_tick--;
751 if (channel->retrig_tick <= 0) {
752 if (channel->playing) it_playing_reset_resamplers(channel->playing, 0);
753 channel->retrig_tick = channel->xm_retrig;
754 }
755 } else if (channel->retrig & 0x0F) {
756 channel->retrig_tick--;
757 if (channel->retrig_tick <= 0) {
758 if (channel->retrig < 0x10) {
759 } else if (channel->retrig < 0x20) {
760 channel->volume--;
761 if (channel->volume > 64) channel->volume = 0;
762 } else if (channel->retrig < 0x30) {
763 channel->volume -= 2;
764 if (channel->volume > 64) channel->volume = 0;
765 } else if (channel->retrig < 0x40) {
766 channel->volume -= 4;
767 if (channel->volume > 64) channel->volume = 0;
768 } else if (channel->retrig < 0x50) {
769 channel->volume -= 8;
770 if (channel->volume > 64) channel->volume = 0;
771 } else if (channel->retrig < 0x60) {
772 channel->volume -= 16;
773 if (channel->volume > 64) channel->volume = 0;
774 } else if (channel->retrig < 0x70) {
775 channel->volume <<= 1;
776 channel->volume /= 3;
777 } else if (channel->retrig < 0x80) {
778 channel->volume >>= 1;
779 } else if (channel->retrig < 0x90) {
780 } else if (channel->retrig < 0xA0) {
781 channel->volume++;
782 if (channel->volume > 64) channel->volume = 64;
783 } else if (channel->retrig < 0xB0) {
784 channel->volume += 2;
785 if (channel->volume > 64) channel->volume = 64;
786 } else if (channel->retrig < 0xC0) {
787 channel->volume += 4;
788 if (channel->volume > 64) channel->volume = 64;
789 } else if (channel->retrig < 0xD0) {
790 channel->volume += 8;
791 if (channel->volume > 64) channel->volume = 64;
792 } else if (channel->retrig < 0xE0) {
793 channel->volume += 16;
794 if (channel->volume > 64) channel->volume = 64;
795 } else if (channel->retrig < 0xF0) {
796 channel->volume *= 3;
797 channel->volume >>= 1;
798 if (channel->volume > 64) channel->volume = 64;
799 } else {
800 channel->volume <<= 1;
801 if (channel->volume > 64) channel->volume = 64;
802 }
803 if (channel->playing) it_playing_reset_resamplers(channel->playing, 0);
804 channel->retrig_tick = channel->retrig & 0x0F;
805 }
806 }
807}
808
809
810
811static void update_smooth_effects(DUMB_IT_SIGRENDERER *sigrenderer)
812{
813 int i;
814
815 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
816 IT_CHANNEL *channel = &sigrenderer->channel[i];
817 IT_PLAYING *playing = channel->playing;
818
819 if (playing) {
820 playing->vibrato_time += playing->vibrato_n *
821 (playing->vibrato_speed << 2);
822 playing->tremolo_time += playing->tremolo_speed << 2;
823 }
824 }
825}
826
827
828
829static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer)
830{
831 int i;
832
833 if (sigrenderer->globalvolslide) {
834 sigrenderer->globalvolume += sigrenderer->globalvolslide;
835 if (sigrenderer->globalvolume > 128) {
836 if (sigrenderer->globalvolslide >= 0)
837 sigrenderer->globalvolume = 128;
838 else
839 sigrenderer->globalvolume = 0;
840 }
841 }
842
843 if (sigrenderer->temposlide) {
844 sigrenderer->tempo += sigrenderer->temposlide;
845 if (sigrenderer->tempo < 32) {
846 if (sigrenderer->temposlide >= 0)
847 sigrenderer->tempo = 255;
848 else
849 sigrenderer->tempo = 32;
850 }
851 }
852
853 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
854 IT_CHANNEL *channel = &sigrenderer->channel[i];
855 IT_PLAYING *playing = channel->playing;
856
857 if (channel->xm_volslide) {
858 channel->volume += channel->xm_volslide;
859 if (channel->volume > 64) {
860 if (channel->xm_volslide >= 0)
861 channel->volume = 64;
862 else
863 channel->volume = 0;
864 }
865 }
866
867 if (channel->volslide) {
868 channel->volume += channel->volslide;
869 if (channel->volume > 64) {
870 if (channel->volslide >= 0)
871 channel->volume = 64;
872 else
873 channel->volume = 0;
874 }
875 }
876
877 if (channel->channelvolslide) {
878 channel->channelvolume += channel->channelvolslide;
879 if (channel->channelvolume > 64) {
880 if (channel->channelvolslide >= 0)
881 channel->channelvolume = 64;
882 else
883 channel->channelvolume = 0;
884 }
885 if (channel->playing)
886 channel->playing->channel_volume = channel->channelvolume;
887 }
888
889 update_tremor(channel);
890
891 channel->arpeggio = (channel->arpeggio << 4) | (channel->arpeggio >> 8);
892 channel->arpeggio &= 0xFFF;
893
894 update_retrig(channel);
895
896 if (playing) {
897 playing->slide += channel->portamento;
898
899 if (sigrenderer->sigdata->flags & IT_LINEAR_SLIDES) {
900 if (channel->toneporta && channel->destnote < 120) {
901 int currpitch = ((playing->note - 60) << 8) + playing->slide;
902 int destpitch = (channel->destnote - 60) << 8;
903 if (currpitch > destpitch) {
904 currpitch -= channel->toneporta;
905 if (currpitch < destpitch) {
906 currpitch = destpitch;
907 channel->destnote = IT_NOTE_OFF;
908 }
909 } else if (currpitch < destpitch) {
910 currpitch += channel->toneporta;
911 if (currpitch > destpitch) {
912 currpitch = destpitch;
913 channel->destnote = IT_NOTE_OFF;
914 }
915 }
916 playing->slide = currpitch - ((playing->note - 60) << 8);
917 }
918 } else {
919 if (channel->toneporta && channel->destnote < 120) {
920 float amiga_multiplier = playing->sample->C5_speed * (1.0f / AMIGA_DIVISOR);
921
922 float deltanote = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note);
923 /* deltanote is 1.0 for C-5, 0.5 for C-6, etc. */
924
925 float deltaslid = deltanote - playing->slide * amiga_multiplier;
926
927 float destdelta = (float)pow(DUMB_SEMITONE_BASE, 60 - channel->destnote);
928 if (deltaslid < destdelta) {
929 playing->slide -= channel->toneporta;
930 deltaslid = deltanote - playing->slide * amiga_multiplier;
931 if (deltaslid > destdelta) {
932 playing->note = channel->destnote;
933 playing->slide = 0;
934 channel->destnote = IT_NOTE_OFF;
935 }
936 } else {
937 playing->slide += channel->toneporta;
938 deltaslid = deltanote - playing->slide * amiga_multiplier;
939 if (deltaslid < destdelta) {
940 playing->note = channel->destnote;
941 playing->slide = 0;
942 channel->destnote = IT_NOTE_OFF;
943 }
944 }
945 }
946 }
947 }
948 }
949
950 update_smooth_effects(sigrenderer);
951}
952
953
954
955static void update_pattern_variables(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry)
956{
957 IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
958
959 if (entry->mask & IT_ENTRY_EFFECT) {
960 if (entry->effect == IT_S) {
961 unsigned char effectvalue = entry->effectvalue;
962 if (effectvalue == 0)
963 effectvalue = channel->lastS;
964 channel->lastS = effectvalue;
965 switch (effectvalue >> 4) {
966 //case IT_S7:
967 case IT_S_PATTERN_LOOP:
968 {
969 unsigned char v = effectvalue & 15;
970 if (v == 0)
971 channel->pat_loop_row = sigrenderer->processrow;
972 else {
973 if (channel->pat_loop_count == 0) {
974 channel->pat_loop_count = v;
975 sigrenderer->pat_loop_row = channel->pat_loop_row;
976 } else {
977 if (--channel->pat_loop_count)
978 sigrenderer->pat_loop_row = channel->pat_loop_row;
979 else if (!(sigrenderer->sigdata->flags & IT_WAS_AN_XM))
980 channel->pat_loop_row = sigrenderer->processrow + 1;
981 }
982 }
983 }
984 break;
985 case IT_S_PATTERN_DELAY:
986 sigrenderer->rowcount = 1 + (effectvalue & 15);
987 break;
988 }
989 }
990 }
991}
992
993
994
995/* This function guarantees that channel->sample will always be valid if it
996 * is nonzero. In other words, to check if it is valid, simply check if it is
997 * nonzero.
998 */
999static void instrument_to_sample(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel)
1000{
1001 if (sigdata->flags & IT_USE_INSTRUMENTS) {
1002 if (channel->instrument >= 1 && channel->instrument <= sigdata->n_instruments) {
1003 if (channel->note < 120) {
1004 channel->sample = sigdata->instrument[channel->instrument-1].map_sample[channel->note];
1005 channel->truenote = sigdata->instrument[channel->instrument-1].map_note[channel->note];
1006 } else
1007 channel->sample = 0;
1008 } else
1009 channel->sample = 0;
1010 } else {
1011 channel->sample = channel->instrument;
1012 channel->truenote = channel->note;
1013 }
1014 if (!(channel->sample >= 1 && channel->sample <= sigdata->n_samples && (sigdata->sample[channel->sample-1].flags & IT_SAMPLE_EXISTS)))
1015 channel->sample = 0;
1016}
1017
1018
1019
1020static void fix_sample_looping(IT_PLAYING *playing)
1021{
1022 if ((playing->sample->flags & (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP)) ==
1023 (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP)) {
1024 if (playing->resampler[0].dir < 0) {
1025 playing->resampler[1].pos = playing->resampler[0].pos = (playing->sample->sus_loop_end << 1) - 1 - playing->resampler[0].pos;
1026 playing->resampler[1].subpos = playing->resampler[0].subpos ^= 65535;
1027 playing->resampler[1].dir = playing->resampler[0].dir = 1;
1028 }
1029
1030 playing->resampler[1].pos = playing->resampler[0].pos += playing->time_lost;
1031 }
1032}
1033
1034
1035
1036static void retrigger_it_envelopes(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel)
1037{
1038 channel->playing->volume_envelope.next_node = 0;
1039 channel->playing->volume_envelope.tick = -1;
1040 channel->playing->pan_envelope.next_node = 0;
1041 channel->playing->pan_envelope.tick = -1;
1042 channel->playing->pitch_envelope.next_node = 0;
1043 channel->playing->pitch_envelope.tick = -1;
1044 channel->playing->fadeoutcount = 1024;
1045 // Should we remove IT_PLAYING_BACKGROUND? Test with sample with sustain loop...
1046 channel->playing->flags &= ~(IT_PLAYING_BACKGROUND | IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING | IT_PLAYING_DEAD);
1047 it_playing_update_resamplers(channel->playing);
1048
1049 if (channel->sample)
1050 if (sigdata->flags & IT_USE_INSTRUMENTS)
1051 channel->playing->env_instrument = &sigdata->instrument[channel->instrument-1];
1052}
1053
1054
1055
1056static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel)
1057{
1058 DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
1059 unsigned char nna;
1060 int i;
1061
1062 if (channel->playing) {
1063#ifdef INVALID_NOTES_CAUSE_NOTE_CUT
1064 if (channel->note == IT_NOTE_OFF)
1065 nna = NNA_NOTE_OFF;
1066 else if (channel->note >= 120 || !channel->playing->instrument || (channel->playing->flags & IT_PLAYING_DEAD))
1067 nna = NNA_NOTE_CUT;
1068 else
1069 nna = channel->playing->instrument->new_note_action;
1070#else
1071 if (channel->note == IT_NOTE_CUT)
1072 nna = NNA_NOTE_CUT;
1073 if (channel->note >= 120)
1074 nna = NNA_NOTE_OFF;
1075 else if (!channel->playing->instrument || (channel->playing->flags & IT_PLAYING_DEAD))
1076 nna = NNA_NOTE_CUT;
1077 else
1078 nna = channel->playing->instrument->new_note_action;
1079#endif
1080
1081 switch (nna) {
1082 case NNA_NOTE_CUT:
1083 free(channel->playing);
1084 channel->playing = NULL;
1085 break;
1086 case NNA_NOTE_OFF:
1087 channel->playing->flags |= IT_PLAYING_BACKGROUND | IT_PLAYING_SUSTAINOFF;
1088 fix_sample_looping(channel->playing);
1089 it_playing_update_resamplers(channel->playing);
1090 if (channel->playing->instrument)
1091 if ((channel->playing->instrument->volume_envelope.flags & (IT_ENVELOPE_ON | IT_ENVELOPE_LOOP_ON)) != IT_ENVELOPE_ON)
1092 channel->playing->flags |= IT_PLAYING_FADING;
1093 break;
1094 case NNA_NOTE_FADE:
1095 channel->playing->flags |= IT_PLAYING_BACKGROUND | IT_PLAYING_FADING;
1096 break;
1097 }
1098 }
1099
1100 if (channel->sample == 0 || channel->note >= 120)
1101 return;
1102
1103 channel->destnote = IT_NOTE_OFF;
1104
1105 if (channel->playing) {
1106 for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
1107 if (!sigrenderer->playing[i]) {
1108 sigrenderer->playing[i] = channel->playing;
1109 channel->playing = NULL;
1110 break;
1111 }
1112 }
1113/** WARNING - come up with some more heuristics for replacing old notes */
1114#if 0
1115 if (channel->playing) {
1116 for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
1117 if (sigrenderer->playing[i]->flags & IT_PLAYING_BACKGROUND) {
1118 write_seqtime();
1119 sequence_c(SEQUENCE_STOP_SIGNAL);
1120 sequence_c(i);
1121 channel->VChannel = &module->VChannel[i];
1122 break;
1123 }
1124 }
1125 }
1126#endif
1127 }
1128
1129 if (channel->playing)
1130 free(channel->playing);
1131
1132 channel->playing = malloc(sizeof(*channel->playing));
1133
1134 if (!channel->playing)
1135 return;
1136
1137 channel->playing->flags = 0;
1138 channel->playing->channel = channel;
1139 channel->playing->sample = &sigdata->sample[channel->sample-1];
1140 if (sigdata->flags & IT_USE_INSTRUMENTS)
1141 channel->playing->instrument = &sigdata->instrument[channel->instrument-1];
1142 else
1143 channel->playing->instrument = NULL;
1144 channel->playing->env_instrument = channel->playing->instrument;
1145 channel->playing->sampnum = channel->sample;
1146 channel->playing->instnum = channel->instrument;
1147 channel->playing->channel_volume = channel->channelvolume;
1148 channel->playing->note = channel->truenote;
1149 channel->playing->filter_cutoff = 127;
1150 channel->playing->filter_resonance = 0;
1151 channel->playing->true_filter_cutoff = 127 << 8;
1152 channel->playing->true_filter_resonance = 0;
1153 channel->playing->vibrato_speed = 0;
1154 channel->playing->vibrato_depth = 0;
1155 channel->playing->vibrato_n = 0;
1156 channel->playing->vibrato_time = 0;
1157 channel->playing->tremolo_speed = 0;
1158 channel->playing->tremolo_depth = 0;
1159 channel->playing->tremolo_time = 0;
1160 channel->playing->sample_vibrato_time = 0;
1161 channel->playing->sample_vibrato_depth = 0;
1162 channel->playing->slide = 0;
1163 channel->playing->volume_envelope.next_node = 0;
1164 channel->playing->volume_envelope.tick = -1;
1165 channel->playing->pan_envelope.next_node = 0;
1166 channel->playing->pan_envelope.tick = -1;
1167 channel->playing->pitch_envelope.next_node = 0;
1168 channel->playing->pitch_envelope.tick = -1;
1169 channel->playing->fadeoutcount = 1024;
1170 it_reset_filter_state(&channel->playing->filter_state[0]);
1171 it_reset_filter_state(&channel->playing->filter_state[1]);
1172 it_playing_reset_resamplers(channel->playing, 0);
1173
1174 /** WARNING - is everything initialised? */
1175}
1176
1177
1178
1179static void get_default_volpan(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel)
1180{
1181 if (channel->sample == 0)
1182 return;
1183
1184 channel->volume = sigdata->sample[channel->sample-1].default_volume;
1185
1186 {
1187 int pan = sigdata->sample[channel->sample-1].default_pan;
1188 if (pan >= 128 && pan <= 192) {
1189 channel->pan = pan - 128;
1190 return;
1191 }
1192 }
1193
1194 if (sigdata->flags & IT_USE_INSTRUMENTS) {
1195 IT_INSTRUMENT *instrument = &sigdata->instrument[channel->instrument-1];
1196 if (instrument->default_pan <= 64)
1197 channel->pan = instrument->default_pan;
1198 if (instrument->filter_cutoff >= 128)
1199 channel->filter_cutoff = instrument->filter_cutoff - 128;
1200 if (instrument->filter_resonance >= 128)
1201 channel->filter_resonance = instrument->filter_resonance - 128;
1202 }
1203}
1204
1205
1206
1207static void get_true_pan(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel)
1208{
1209 channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
1210
1211 if (!IT_IS_SURROUND_SHIFTED(channel->truepan) && (sigdata->flags & IT_USE_INSTRUMENTS)) {
1212 IT_INSTRUMENT *instrument = &sigdata->instrument[channel->instrument-1];
1213 int truepan = channel->truepan;
1214 truepan += (channel->note - instrument->pp_centre) * instrument->pp_separation << (IT_ENVELOPE_SHIFT - 3);
1215 channel->truepan = MID(0, truepan, 64 << IT_ENVELOPE_SHIFT);
1216 }
1217}
1218
1219
1220
1221static void post_process_it_volpan(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry)
1222{
1223 IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
1224
1225 if (entry->mask & IT_ENTRY_VOLPAN) {
1226 if (entry->volpan <= 84) {
1227 /* Volume */
1228 /* Fine volume slide up */
1229 /* Fine volume slide down */
1230 } else if (entry->volpan <= 94) {
1231 /* Volume slide up */
1232 unsigned char v = entry->volpan - 85;
1233 if (v == 0)
1234 v = channel->lastvolslide;
1235 channel->lastvolslide = v;
1236 /* = effect Dx0 where x == entry->volpan - 85 */
1237 channel->volslide = v;
1238 } else if (entry->volpan <= 104) {
1239 /* Volume slide down */
1240 unsigned char v = entry->volpan - 95;
1241 if (v == 0)
1242 v = channel->lastvolslide;
1243 channel->lastvolslide = v;
1244 /* = effect D0x where x == entry->volpan - 95 */
1245 channel->volslide = -v;
1246 } else if (entry->volpan <= 114) {
1247 /* Portamento down */
1248 unsigned char v = (entry->volpan - 105) << 2;
1249 if (v == 0)
1250 v = channel->lastEF;
1251 channel->lastEF = v;
1252 channel->portamento -= v << 4;
1253 } else if (entry->volpan <= 124) {
1254 /* Portamento up */
1255 unsigned char v = (entry->volpan - 115) << 2;
1256 if (v == 0)
1257 v = channel->lastEF;
1258 channel->lastEF = v;
1259 channel->portamento += v << 4;
1260 } else if (entry->volpan <= 202) {
1261 /* Pan */
1262 /* Tone Portamento */
1263 } else if (entry->volpan <= 212) {
1264 /* Vibrato */
1265 unsigned char v = entry->volpan - 203;
1266 if (v == 0)
1267 v = channel->lastHdepth;
1268 else {
1269 v <<= 2;
1270 channel->lastHdepth = v;
1271 }
1272 if (channel->playing) {
1273 channel->playing->vibrato_speed = channel->lastHspeed;
1274 channel->playing->vibrato_depth = v;
1275 channel->playing->vibrato_n++;
1276 }
1277 }
1278 }
1279}
1280
1281
1282
1283static void it_send_midi(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel, unsigned char byte)
1284{
1285 if (sigrenderer->callbacks->midi)
1286 if ((*sigrenderer->callbacks->midi)(sigrenderer->callbacks->midi_data, channel - sigrenderer->channel, byte))
1287 return;
1288
1289 switch (channel->midi_state) {
1290 case 4: /* Ready to receive resonance parameter */
1291 if (byte < 0x80) channel->filter_resonance = byte;
1292 channel->midi_state = 0;
1293 break;
1294 case 3: /* Ready to receive cutoff parameter */
1295 if (byte < 0x80) channel->filter_cutoff = byte;
1296 channel->midi_state = 0;
1297 break;
1298 case 2: /* Ready for byte specifying which parameter will follow */
1299 if (byte == 0) /* Cutoff */
1300 channel->midi_state = 3;
1301 else if (byte == 1) /* Resonance */
1302 channel->midi_state = 4;
1303 else
1304 channel->midi_state = 0;
1305 break;
1306 default: /* Counting initial F0 bytes */
1307 switch (byte) {
1308 case 0xF0:
1309 channel->midi_state++;
1310 break;
1311 case 0xFA:
1312 case 0xFC:
1313 case 0xFF:
1314 /* Reset filter parameters for all channels */
1315 {
1316 int i;
1317 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
1318 sigrenderer->channel[i].filter_cutoff = 127;
1319 sigrenderer->channel[i].filter_resonance = 0;
1320 //// should we be resetting channel[i].playing->filter_* here?
1321 }
1322 }
1323 /* Fall through */
1324 default:
1325 channel->midi_state = 0;
1326 break;
1327 }
1328 }
1329}
1330
1331
1332
1333/* Returns 1 if a callback caused termination of playback. */
1334static int process_effects(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry)
1335{
1336 DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
1337
1338 IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
1339
1340 if (entry->mask & IT_ENTRY_EFFECT) {
1341 switch (entry->effect) {
1342/*
1343Notes about effects (as compared to other module formats)
1344
1345C This is now in *HEX*. (Used to be in decimal in ST3)
1346E/F/G/H/U You need to check whether the song uses Amiga/Linear slides.
1347H/U Vibrato in Impulse Tracker is two times finer than in
1348 any other tracker and is updated EVERY tick.
1349 If "Old Effects" is *ON*, then the vibrato is played in the
1350 normal manner (every non-row tick and normal depth)
1351E/F/G These commands ALL share the same memory.
1352Oxx Offsets to samples are to the 'xx00th' SAMPLE. (ie. for
1353 16 bit samples, the offset is xx00h*2)
1354 Oxx past the sample end will be ignored, unless "Old Effects"
1355 is ON, in which case the Oxx will play from the end of the
1356 sample.
1357Yxy This uses a table 4 times larger (hence 4 times slower) than
1358 vibrato or tremelo. If the waveform is set to random, then
1359 the 'speed' part of the command is interpreted as a delay.
1360*/
1361 case IT_SET_SPEED:
1362 if (entry->effectvalue)
1363 sigrenderer->tick = sigrenderer->speed = entry->effectvalue;
1364 else if (sigdata->flags & IT_WAS_AN_XM) {
1365 sigrenderer->speed = 0;
1366 if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)(sigrenderer->callbacks->xm_speed_zero_data))
1367 return 1;
1368 }
1369 break;
1370
1371 case IT_JUMP_TO_ORDER: sigrenderer->processorder = entry->effectvalue - 1; sigrenderer->processrow = 0xFFFE; break;
1372 case IT_BREAK_TO_ROW: sigrenderer->breakrow = entry->effectvalue; sigrenderer->processrow = 0xFFFE; break;
1373
1374 case IT_VOLSLIDE_VIBRATO:
1375 if (channel->playing) {
1376 channel->playing->vibrato_speed = channel->lastHspeed;
1377 channel->playing->vibrato_depth = channel->lastHdepth;
1378 channel->playing->vibrato_n++;
1379 }
1380 /* Fall through and process volume slide. */
1381 case IT_VOLUME_SLIDE:
1382 case IT_VOLSLIDE_TONEPORTA:
1383 /* The tone portamento component is handled elsewhere. */
1384 {
1385 unsigned char v = entry->effectvalue;
1386 if (!(sigdata->flags & IT_WAS_A_MOD)) {
1387 if (v == 0)
1388 v = channel->lastDKL;
1389 channel->lastDKL = v;
1390 }
1391 if ((v & 0x0F) == 0) { /* Dx0 */
1392 channel->volslide = v >> 4;
1393 if (channel->volslide == 15 && !(sigdata->flags & IT_WAS_AN_XM)) {
1394 channel->volume += 15;
1395 if (channel->volume > 64) channel->volume = 64;
1396 }
1397 } else if ((v & 0xF0) == 0) { /* D0x */
1398 channel->volslide = -v;
1399 if (channel->volslide == -15 && !(sigdata->flags & IT_WAS_AN_XM)) {
1400 channel->volume -= 15;
1401 if (channel->volume > 64) channel->volume = 0;
1402 }
1403 } else if ((v & 0x0F) == 0x0F) { /* DxF */
1404 channel->volume += v >> 4;
1405 if (channel->volume > 64) channel->volume = 64;
1406 } else if ((v & 0xF0) == 0xF0) { /* DFx */
1407 channel->volume -= v & 15;
1408 if (channel->volume > 64) channel->volume = 0;
1409 }
1410 }
1411 break;
1412 case IT_XM_FINE_VOLSLIDE_DOWN:
1413 {
1414 unsigned char v = entry->effectvalue;
1415 if (v == 0)
1416 v = channel->xm_lastEB;
1417 channel->xm_lastEB = v;
1418 channel->volume -= v;
1419 if (channel->volume > 64) channel->volume = 0;
1420 }
1421 break;
1422 case IT_XM_FINE_VOLSLIDE_UP:
1423 {
1424 unsigned char v = entry->effectvalue;
1425 if (v == 0)
1426 v = channel->xm_lastEA;
1427 channel->xm_lastEA = v;
1428 channel->volume += v;
1429 if (channel->volume > 64) channel->volume = 64;
1430 }
1431 break;
1432 case IT_PORTAMENTO_DOWN:
1433 {
1434 unsigned char v = entry->effectvalue;
1435 if (sigdata->flags & IT_WAS_AN_XM) {
1436 if (!(sigdata->flags & IT_WAS_A_MOD)) {
1437 if (v == 0xF0)
1438 v |= channel->xm_lastE2;
1439 else if (v >= 0xF0)
1440 channel->xm_lastE2 = v & 15;
1441 else if (v == 0xE0)
1442 v |= channel->xm_lastX2;
1443 else
1444 channel->xm_lastX2 = v & 15;
1445 }
1446 } else {
1447 if (v == 0)
1448 v = channel->lastEF;
1449 channel->lastEF = v;
1450 }
1451 if (channel->playing) {
1452 if ((v & 0xF0) == 0xF0)
1453 channel->playing->slide -= (v & 15) << 4;
1454 else if ((v & 0xF0) == 0xE0)
1455 channel->playing->slide -= (v & 15) << 2;
1456 else
1457 channel->portamento -= v << 4;
1458 }
1459 }
1460 break;
1461 case IT_PORTAMENTO_UP:
1462 {
1463 unsigned char v = entry->effectvalue;
1464 if (sigdata->flags & IT_WAS_AN_XM) {
1465 if (!(sigdata->flags & IT_WAS_A_MOD)) {
1466 if (v == 0xF0)
1467 v |= channel->xm_lastE1;
1468 else if (v >= 0xF0)
1469 channel->xm_lastE1 = v & 15;
1470 else if (v == 0xE0)
1471 v |= channel->xm_lastX1;
1472 else
1473 channel->xm_lastX1 = v & 15;
1474 }
1475 } else {
1476 if (v == 0)
1477 v = channel->lastEF;
1478 channel->lastEF = v;
1479 }
1480 if (channel->playing) {
1481 if ((v & 0xF0) == 0xF0)
1482 channel->playing->slide += (v & 15) << 4;
1483 else if ((v & 0xF0) == 0xE0)
1484 channel->playing->slide += (v & 15) << 2;
1485 else
1486 channel->portamento += v << 4;
1487 }
1488 }
1489 break;
1490 case IT_XM_PORTAMENTO_DOWN:
1491 {
1492 unsigned char v = entry->effectvalue;
1493 if (!(sigdata->flags & IT_WAS_A_MOD)) {
1494 if (v == 0)
1495 v = channel->lastJ;
1496 channel->lastJ = v;
1497 }
1498 if (channel->playing)
1499 channel->portamento -= v << 4;
1500 }
1501 break;
1502 case IT_XM_PORTAMENTO_UP:
1503 {
1504 unsigned char v = entry->effectvalue;
1505 if (!(sigdata->flags & IT_WAS_A_MOD)) {
1506 if (v == 0)
1507 v = channel->lastEF;
1508 channel->lastEF = v;
1509 }
1510 if (channel->playing)
1511 channel->portamento += v << 4;
1512 }
1513 break;
1514 case IT_VIBRATO:
1515 {
1516 unsigned char speed = entry->effectvalue >> 4;
1517 unsigned char depth = entry->effectvalue & 15;
1518 if (speed == 0)
1519 speed = channel->lastHspeed;
1520 channel->lastHspeed = speed;
1521 if (depth == 0)
1522 depth = channel->lastHdepth;
1523 else {
1524 if (sigdata->flags & IT_OLD_EFFECTS)
1525 depth <<= 3;
1526 else
1527 depth <<= 2;
1528 channel->lastHdepth = depth;
1529 }
1530 if (channel->playing) {
1531 channel->playing->vibrato_speed = speed;
1532 channel->playing->vibrato_depth = depth;
1533 channel->playing->vibrato_n++;
1534 }
1535 }
1536 break;
1537 case IT_TREMOR:
1538 {
1539 unsigned char v = entry->effectvalue;
1540 if (v == 0)
1541 v = channel->lastI;
1542 else if (!(sigdata->flags & IT_OLD_EFFECTS)) {
1543 if (v & 0xF0) v -= 0x10;
1544 if (v & 0x0F) v -= 0x01;
1545 }
1546 channel->lastI = v;
1547 channel->tremor_time |= 128;
1548 }
1549 update_tremor(channel);
1550 break;
1551 case IT_ARPEGGIO:
1552 {
1553 unsigned char v = entry->effectvalue;
1554 /* XM files have no memory for arpeggio (000 = no effect)
1555 * and we use lastJ for portamento down instead.
1556 */
1557 if (!(sigdata->flags & IT_WAS_AN_XM)) {
1558 if (v == 0)
1559 v = channel->lastJ;
1560 channel->lastJ = v;
1561 }
1562 channel->arpeggio = v;
1563 }
1564 break;
1565 case IT_SET_CHANNEL_VOLUME:
1566 if (sigdata->flags & IT_WAS_AN_XM)
1567 channel->volume = MIN(entry->effectvalue, 64);
1568 else if (entry->effectvalue <= 64)
1569 channel->channelvolume = entry->effectvalue;
1570#ifdef VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
1571 else
1572 channel->channelvolume = 64;
1573#endif
1574 if (channel->playing)
1575 channel->playing->channel_volume = channel->channelvolume;
1576 break;
1577 case IT_CHANNEL_VOLUME_SLIDE:
1578 {
1579 unsigned char v = entry->effectvalue;
1580 if (v == 0)
1581 v = channel->lastN;
1582 channel->lastN = v;
1583 if ((v & 0x0F) == 0) { /* Nx0 */
1584 channel->channelvolslide = v >> 4;
1585 } else if ((v & 0xF0) == 0) { /* N0x */
1586 channel->channelvolslide = -v;
1587 } else {
1588 if ((v & 0x0F) == 0x0F) { /* NxF */
1589 channel->channelvolume += v >> 4;
1590 if (channel->channelvolume > 64) channel->channelvolume = 64;
1591 } else if ((v & 0xF0) == 0xF0) { /* NFx */
1592 channel->channelvolume -= v & 15;
1593 if (channel->channelvolume > 64) channel->channelvolume = 0;
1594 } else
1595 break;
1596 if (channel->playing)
1597 channel->playing->channel_volume = channel->channelvolume;
1598 }
1599 }
1600 break;
1601 case IT_SET_SAMPLE_OFFSET:
1602 {
1603 unsigned char v = entry->effectvalue;
1604 if (sigdata->flags & IT_WAS_A_MOD) {
1605 if (v == 0) break;
1606 } else {
1607 if (v == 0)
1608 v = channel->lastO;
1609 channel->lastO = v;
1610 }
1611 /* Note: we set the offset even if tone portamento is
1612 * specified. Impulse Tracker does the same.
1613 */
1614 if (entry->mask & IT_ENTRY_NOTE) {
1615 if (channel->playing) {
1616 int offset = ((int)channel->high_offset << 16) | ((int)v << 8);
1617 IT_PLAYING *playing = channel->playing;
1618 IT_SAMPLE *sample = playing->sample;
1619 int end;
1620 if ((sample->flags & IT_SAMPLE_SUS_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF))
1621 end = sample->sus_loop_end;
1622 else if (sample->flags & IT_SAMPLE_LOOP)
1623 end = sample->loop_end;
1624 else
1625 end = sample->length;
1626 if (offset < end)
1627 it_playing_reset_resamplers(playing, offset);
1628 else if (sigdata->flags & IT_OLD_EFFECTS)
1629 it_playing_reset_resamplers(playing, end);
1630 }
1631 }
1632 }
1633 break;
1634 //case IT_PANNING_SLIDE:
1635 /** JULIEN: guess what? the docs are wrong! (how unusual ;)
1636 * Pxy seems to memorize its previous value... and there
1637 * might be other mistakes like that... (sigh!)
1638 */
1639 /** ENTHEH: umm... but... the docs say that Pxy memorises its
1640 * value... don't they? :o
1641 */
1642 case IT_RETRIGGER_NOTE:
1643 {
1644 unsigned char v = entry->effectvalue;
1645 if (sigdata->flags & IT_WAS_AN_XM) {
1646 if ((v & 0x0F) == 0) v |= channel->lastQ & 0x0F;
1647 if ((v & 0xF0) == 0) v |= channel->lastQ & 0xF0;
1648 } else {
1649 if (v == 0)
1650 v = channel->lastQ;
1651 }
1652 channel->lastQ = v;
1653 if ((v & 0x0F) == 0) v |= 0x01;
1654 channel->retrig = v;
1655 if (entry->mask & IT_ENTRY_NOTE) {
1656 channel->retrig_tick = v & 0x0F;
1657 /* Emulate a bug */
1658 if (sigdata->flags & IT_WAS_AN_XM)
1659 update_retrig(channel);
1660 } else
1661 update_retrig(channel);
1662 }
1663 break;
1664 case IT_XM_RETRIGGER_NOTE:
1665 channel->retrig_tick = channel->xm_retrig = entry->effectvalue;
1666 if (entry->effectvalue == 0)
1667 if (channel->playing) it_playing_reset_resamplers(channel->playing, 0);
1668 break;
1669 case IT_TREMOLO:
1670 {
1671 unsigned char speed = entry->effectvalue >> 4;
1672 unsigned char depth = entry->effectvalue & 15;
1673 if (speed == 0)
1674 speed = channel->lastRspeed;
1675 channel->lastRspeed = speed;
1676 if (depth == 0)
1677 depth = channel->lastRdepth;
1678 channel->lastRdepth = depth;
1679 if (channel->playing) {
1680 channel->playing->tremolo_speed = speed;
1681 channel->playing->tremolo_depth = depth;
1682 }
1683 }
1684 break;
1685 case IT_S:
1686 {
1687 /* channel->lastS was set in update_pattern_variables(). */
1688 unsigned char effectvalue = channel->lastS;
1689 switch (effectvalue >> 4) {
1690 //case IT_S_SET_FILTER:
1691 //case IT_S_SET_GLISSANDO_CONTROL:
1692 //case IT_S_FINETUNE:
1693 //case IT_S_SET_VIBRATO_WAVEFORM:
1694 //case IT_S_SET_TREMOLO_WAVEFORM:
1695 //case IT_S_SET_PANBRELLO_WAVEFORM:
1696 /* Waveforms for commands S3x, S4x and S5x:
1697 * 0: Sine wave
1698 * 1: Ramp down
1699 * 2: Square wave
1700 * 3: Random wave
1701 */
1702 case IT_S_FINE_PATTERN_DELAY:
1703 sigrenderer->tick += effectvalue & 15;
1704 break;
1705 //case IT_S7:
1706 case IT_S_SET_PAN:
1707 channel->pan =
1708 ((effectvalue & 15) << 2) |
1709 ((effectvalue & 15) >> 2);
1710 channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
1711 break;
1712 case IT_S_SET_SURROUND_SOUND:
1713 if ((effectvalue & 15) == 1)
1714 channel->pan = IT_SURROUND;
1715 channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
1716 break;
1717 case IT_S_SET_HIGH_OFFSET:
1718 channel->high_offset = effectvalue & 15;
1719 break;
1720 //case IT_S_PATTERN_LOOP:
1721 case IT_S_DELAYED_NOTE_CUT:
1722 channel->note_cut_count = effectvalue & 15;
1723 if (!channel->note_cut_count) {
1724 if (sigdata->flags & IT_WAS_AN_XM)
1725 channel->volume = 0;
1726 else
1727 channel->note_cut_count = 1;
1728 }
1729 break;
1730 case IT_S_SET_MIDI_MACRO:
1731 channel->SFmacro = effectvalue & 15;
1732 break;
1733 }
1734 }
1735 break;
1736 case IT_SET_SONG_TEMPO:
1737 {
1738 unsigned char v = entry->effectvalue;
1739 if (v == 0)
1740 v = channel->lastW;
1741 channel->lastW = v;
1742 if (v < 0x10)
1743 sigrenderer->temposlide = -v;
1744 else if (v < 0x20)
1745 sigrenderer->temposlide = v & 15;
1746 else
1747 sigrenderer->tempo = v;
1748 }
1749 break;
1750 case IT_FINE_VIBRATO:
1751 {
1752 unsigned char speed = entry->effectvalue >> 4;
1753 unsigned char depth = entry->effectvalue & 15;
1754 if (speed == 0)
1755 speed = channel->lastHspeed;
1756 channel->lastHspeed = speed;
1757 if (depth == 0)
1758 depth = channel->lastHdepth;
1759 else {
1760 if (sigdata->flags & IT_OLD_EFFECTS)
1761 depth <<= 1;
1762 channel->lastHdepth = depth;
1763 }
1764 if (channel->playing) {
1765 channel->playing->vibrato_speed = speed;
1766 channel->playing->vibrato_depth = depth;
1767 channel->playing->vibrato_n++;
1768 }
1769 }
1770 break;
1771 case IT_SET_GLOBAL_VOLUME:
1772 if (entry->effectvalue <= 128)
1773 sigrenderer->globalvolume = entry->effectvalue;
1774#ifdef VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
1775 else
1776 sigrenderer->globalvolume = 128;
1777#endif
1778 break;
1779 case IT_GLOBAL_VOLUME_SLIDE:
1780 {
1781 unsigned char v = entry->effectvalue;
1782 if (v == 0)
1783 v = channel->lastW;
1784 channel->lastW = v;
1785 if ((v & 0x0F) == 0) { /* Wx0 */
1786 sigrenderer->globalvolslide =
1787 (sigdata->flags & IT_WAS_AN_XM) ? (v >> 4)*2 : (v >> 4);
1788 } else if ((v & 0xF0) == 0) { /* W0x */
1789 sigrenderer->globalvolslide =
1790 (sigdata->flags & IT_WAS_AN_XM) ? (-v)*2 : (-v);
1791 } else if ((v & 0x0F) == 0x0F) { /* WxF */
1792 sigrenderer->globalvolume += v >> 4;
1793 if (sigrenderer->globalvolume > 128) sigrenderer->globalvolume = 128;
1794 } else if ((v & 0xF0) == 0xF0) { /* WFx */
1795 sigrenderer->globalvolume -= v & 15;
1796 if (sigrenderer->globalvolume > 128) sigrenderer->globalvolume = 0;
1797 }
1798 }
1799 break;
1800 case IT_SET_PANNING:
1801 channel->pan = (entry->effectvalue + 2) >> 2;
1802 channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
1803 break;
1804 //case IT_PANBRELLO:
1805 case IT_MIDI_MACRO:
1806 {
1807 IT_MIDI *midi = sigdata->midi ? sigdata->midi : &default_midi;
1808 if (entry->effectvalue >= 0x80) {
1809 int n = midi->Zmacrolen[entry->effectvalue-0x80];
1810 int i;
1811 for (i = 0; i < n; i++)
1812 it_send_midi(sigrenderer, channel, midi->Zmacro[entry->effectvalue-0x80][i]);
1813 } else {
1814 int n = midi->SFmacrolen[channel->SFmacro];
1815 int i, j;
1816 for (i = 0, j = 1; i < n; i++, j <<= 1)
1817 it_send_midi(sigrenderer, channel,
1818 midi->SFmacroz[channel->SFmacro] & j ?
1819 entry->effectvalue : midi->SFmacro[channel->SFmacro][i]);
1820 }
1821 }
1822 break;
1823 }
1824 }
1825
1826 if (!(sigdata->flags & IT_WAS_AN_XM))
1827 post_process_it_volpan(sigrenderer, entry);
1828
1829 return 0;
1830}
1831
1832
1833
1834static int process_it_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry)
1835{
1836 DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
1837 IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
1838
1839 // When tone portamento and instrument are specified:
1840 // If Gxx is off:
1841 // - same sample, do nothing but portamento
1842 // - diff sample, retrigger all but keep current note+slide + do porta
1843 // - if instrument is invalid, nothing; if sample is invalid, cut
1844 // If Gxx is on:
1845 // - same sample or new sample invalid, retrigger envelopes
1846 // - diff sample/inst, start using new envelopes
1847 // When tone portamento is specified alone, sample won't change.
1848 // TODO: consider what happens with instrument alone after all this...
1849
1850 if (entry->mask & (IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT)) {
1851 if (entry->mask & IT_ENTRY_INSTRUMENT)
1852 channel->instrument = entry->instrument;
1853 instrument_to_sample(sigdata, channel);
1854 if (channel->note < 120) {
1855 if ((sigdata->flags & IT_USE_INSTRUMENTS) && channel->sample == 0)
1856 return 1;
1857 if (entry->mask & IT_ENTRY_INSTRUMENT)
1858 get_default_volpan(sigdata, channel);
1859 } else
1860 it_retrigger_note(sigrenderer, channel);
1861 }
1862
1863 /** WARNING: This is not ideal, since channel->playing might not get allocated owing to lack of memory... */
1864 if (channel->playing &&
1865 (((entry->mask & IT_ENTRY_VOLPAN) && entry->volpan >= 193 && entry->volpan <= 202) ||
1866 ((entry->mask & IT_ENTRY_EFFECT) && (entry->effect == IT_TONE_PORTAMENTO || entry->effect == IT_VOLSLIDE_TONEPORTA))))
1867 {
1868 if (entry->mask & IT_ENTRY_INSTRUMENT) {
1869 if (sigdata->flags & IT_COMPATIBLE_GXX)
1870 retrigger_it_envelopes(sigdata, channel);
1871 else if ((!(sigdata->flags & IT_USE_INSTRUMENTS) ||
1872 (channel->instrument >= 1 && channel->instrument <= sigdata->n_instruments)) &&
1873 channel->sample != channel->playing->sampnum)
1874 {
1875 unsigned char note = channel->playing->note;
1876 int slide = channel->playing->slide;
1877 it_retrigger_note(sigrenderer, channel);
1878 if (channel->playing) {
1879 channel->playing->note = note;
1880 channel->playing->slide = slide;
1881 // Should we be preserving sample_vibrato_time? depth?
1882 }
1883 }
1884 }
1885
1886 if ((entry->mask & IT_ENTRY_VOLPAN) && entry->volpan >= 193 && entry->volpan <= 202) {
1887 /* Tone Portamento in the volume column */
1888 static const unsigned char slidetable[] = {0, 1, 4, 8, 16, 32, 64, 96, 128, 255};
1889 unsigned char v = slidetable[entry->volpan - 193];
1890 if (sigdata->flags & IT_COMPATIBLE_GXX) {
1891 if (v == 0)
1892 v = channel->lastG;
1893 channel->lastG = v;
1894 } else {
1895 if (v == 0)
1896 v = channel->lastEF;
1897 channel->lastEF = v;
1898 }
1899 if (entry->mask & IT_ENTRY_NOTE)
1900 if (channel->sample)
1901 channel->destnote = channel->truenote;
1902 channel->toneporta = v << 4;
1903 } else {
1904 /* Tone Portamento in the effect column */
1905 unsigned char v;
1906 if (entry->effect == IT_TONE_PORTAMENTO)
1907 v = entry->effectvalue;
1908 else
1909 v = 0;
1910 if (sigdata->flags & IT_COMPATIBLE_GXX) {
1911 if (v == 0)
1912 v = channel->lastG;
1913 channel->lastG = v;
1914 } else {
1915 if (v == 0)
1916 v = channel->lastEF;
1917 channel->lastEF = v;
1918 }
1919 if (entry->mask & IT_ENTRY_NOTE)
1920 if (channel->sample)
1921 channel->destnote = channel->truenote;
1922 channel->toneporta = v << 4;
1923 }
1924 } else if ((entry->mask & IT_ENTRY_NOTE) ||
1925 ((entry->mask & IT_ENTRY_INSTRUMENT) && (!channel->playing || entry->instrument != channel->playing->instnum)))
1926 {
1927 if (channel->note < 120) {
1928 get_true_pan(sigdata, channel);
1929 it_retrigger_note(sigrenderer, channel);
1930 }
1931 }
1932
1933 if (entry->mask & IT_ENTRY_VOLPAN) {
1934 if (entry->volpan <= 64) {
1935 /* Volume */
1936 channel->volume = entry->volpan;
1937 } else if (entry->volpan <= 74) {
1938 /* Fine volume slide up */
1939 unsigned char v = entry->volpan - 65;
1940 if (v == 0)
1941 v = channel->lastvolslide;
1942 channel->lastvolslide = v;
1943 /* = effect DxF where x == entry->volpan - 65 */
1944 channel->volume += v;
1945 if (channel->volume > 64) channel->volume = 64;
1946 } else if (entry->volpan <= 84) {
1947 /* Fine volume slide down */
1948 unsigned char v = entry->volpan - 75;
1949 if (v == 0)
1950 v = channel->lastvolslide;
1951 channel->lastvolslide = v;
1952 /* = effect DFx where x == entry->volpan - 75 */
1953 channel->volume -= v;
1954 if (channel->volume > 64) channel->volume = 0;
1955 } else if (entry->volpan < 128) {
1956 /* Volume slide up */
1957 /* Volume slide down */
1958 /* Portamento down */
1959 /* Portamento up */
1960 } else if (entry->volpan <= 192) {
1961 /* Pan */
1962 channel->pan = entry->volpan - 128;
1963 channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
1964 }
1965 /* else */
1966 /* Tone Portamento */
1967 /* Vibrato */
1968 }
1969 return 0;
1970}
1971
1972
1973
1974static void retrigger_xm_envelopes(IT_PLAYING *playing)
1975{
1976 playing->volume_envelope.next_node = 0;
1977 playing->volume_envelope.tick = -1;
1978 playing->pan_envelope.next_node = 0;
1979 playing->pan_envelope.tick = -1;
1980 playing->fadeoutcount = 1024;
1981}
1982
1983
1984
1985static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry)
1986{
1987 DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
1988 IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
1989
1990 if (entry->mask & IT_ENTRY_INSTRUMENT) {
1991 channel->instrument = entry->instrument;
1992 instrument_to_sample(sigdata, channel);
1993 if (channel->playing) {
1994 /* Retrigger vol/pan envelopes if enabled, and cancel fadeout.
1995 * Also reset vol/pan to that of _original_ instrument.
1996 */
1997 channel->playing->flags &= ~(IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING);
1998 it_playing_update_resamplers(channel->playing);
1999
2000 channel->volume = channel->playing->sample->default_volume;
2001 if (channel->pan >= 128 && channel->pan <= 192)
2002 channel->pan = channel->playing->sample->default_pan - 128;
2003
2004 retrigger_xm_envelopes(channel->playing);
2005 }
2006 }
2007
2008 if (entry->mask & IT_ENTRY_NOTE) {
2009 if (!(entry->mask & IT_ENTRY_INSTRUMENT))
2010 instrument_to_sample(sigdata, channel);
2011
2012 if (channel->note >= 120) {
2013 if (channel->playing) {
2014 if (!(sigdata->instrument[channel->instrument-1].volume_envelope.flags & IT_ENVELOPE_ON))
2015 if (!(entry->mask & IT_ENTRY_INSTRUMENT))
2016 channel->volume = 0;
2017 channel->playing->flags |= IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING;
2018 it_playing_update_resamplers(channel->playing);
2019 }
2020 } else if (channel->sample == 0) {
2021 /** If we get here, one of the following is the case:
2022 ** 1. The instrument has never been specified on this channel.
2023 ** 2. The specified instrument is invalid.
2024 ** 3. The instrument has no sample mapped to the selected note.
2025 ** What should happen?
2026 **
2027 ** Experimentation shows that any existing note stops and cannot
2028 ** be brought back. A subsequent instrument change fixes that.
2029 **/
2030 if (channel->playing) {
2031 free(channel->playing);
2032 channel->playing = NULL;
2033 }
2034 return;
2035 } else if (channel->playing && (entry->mask & IT_ENTRY_VOLPAN) && ((entry->volpan>>4) == 0xF)) {
2036 /* Don't retrigger note; portamento in the volume column. */
2037 } else if (channel->playing &&
2038 (entry->mask & IT_ENTRY_EFFECT) &&
2039 (entry->effect == IT_TONE_PORTAMENTO ||
2040 entry->effect == IT_VOLSLIDE_TONEPORTA)) {
2041 /* Don't retrigger note; portamento in the effects column. */
2042 } else {
2043 channel->destnote = IT_NOTE_OFF;
2044
2045 if (!channel->playing) {
2046 channel->playing = malloc(sizeof(*channel->playing));
2047 if (!channel->playing)
2048 return;
2049 // Adding the following seems to do the trick for the case where a piece starts with an instrument alone and then some notes alone.
2050 retrigger_xm_envelopes(channel->playing);
2051 }
2052
2053 channel->playing->flags = 0;
2054 channel->playing->channel = channel;
2055 channel->playing->sample = &sigdata->sample[channel->sample-1];
2056 if (sigdata->flags & IT_USE_INSTRUMENTS)
2057 channel->playing->instrument = &sigdata->instrument[channel->instrument-1];
2058 else
2059 channel->playing->instrument = NULL;
2060 channel->playing->env_instrument = channel->playing->instrument;
2061 channel->playing->sampnum = channel->sample;
2062 channel->playing->instnum = channel->instrument;
2063 channel->playing->channel_volume = channel->channelvolume;
2064 channel->playing->note = channel->truenote;
2065 channel->playing->filter_cutoff = 127;
2066 channel->playing->filter_resonance = 0;
2067 channel->playing->true_filter_cutoff = 127 << 8;
2068 channel->playing->true_filter_resonance = 0;
2069 channel->playing->vibrato_speed = 0;
2070 channel->playing->vibrato_depth = 0;
2071 channel->playing->vibrato_n = 0;
2072 channel->playing->vibrato_time = 0;
2073 channel->playing->tremolo_speed = 0;
2074 channel->playing->tremolo_depth = 0;
2075 channel->playing->tremolo_time = 0;
2076 channel->playing->sample_vibrato_time = 0;
2077 channel->playing->sample_vibrato_depth = 0;
2078 channel->playing->slide = 0;
2079 it_reset_filter_state(&channel->playing->filter_state[0]); // Are these
2080 it_reset_filter_state(&channel->playing->filter_state[1]); // necessary?
2081 it_playing_reset_resamplers(channel->playing, 0);
2082
2083 /** WARNING - is everything initialised? */
2084 }
2085 }
2086
2087 if ((entry->mask & (IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT)) == (IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT)) {
2088 if (channel->playing) retrigger_xm_envelopes(channel->playing);
2089 get_default_volpan(sigdata, channel);
2090 channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
2091 }
2092
2093 if ((entry->mask & IT_ENTRY_VOLPAN) && ((entry->volpan>>4) == 0xF)) {
2094 /* Tone Portamento */
2095 unsigned char v = (entry->volpan & 15) << 4;
2096 if (v == 0)
2097 v = channel->lastG;
2098 channel->lastG = v;
2099 if (entry->mask & IT_ENTRY_NOTE)
2100 if (channel->sample)
2101 channel->destnote = channel->truenote;
2102 channel->toneporta = v << 4;
2103 } else if ((entry->mask & IT_ENTRY_EFFECT) &&
2104 (entry->effect == IT_TONE_PORTAMENTO ||
2105 entry->effect == IT_VOLSLIDE_TONEPORTA)) {
2106 unsigned char v;
2107 if (entry->effect == IT_TONE_PORTAMENTO)
2108 v = entry->effectvalue;
2109 else
2110 v = 0;
2111 if (v == 0)
2112 v = channel->lastG;
2113 channel->lastG = v;
2114 if (entry->mask & IT_ENTRY_NOTE)
2115 if (channel->sample)
2116 channel->destnote = channel->truenote;
2117 channel->toneporta = v << 4;
2118 }
2119
2120 if (entry->mask & IT_ENTRY_VOLPAN) {
2121 int effect = entry->volpan >> 4;
2122 int value = entry->volpan & 15;
2123 switch (effect) {
2124 case 0x6: /* Volume slide down */
2125 channel->xm_volslide = -value;
2126 break;
2127 case 0x7: /* Volume slide up */
2128 channel->xm_volslide = value;
2129 break;
2130 case 0x8: /* Fine volume slide down */
2131 channel->volume -= value;
2132 if (channel->volume > 64) channel->volume = 0;
2133 break;
2134 case 0x9: /* Fine volume slide up */
2135 channel->volume += value;
2136 if (channel->volume > 64) channel->volume = 64;
2137 break;
2138 case 0xA: /* Set vibrato speed */
2139 if (value)
2140 channel->lastHspeed = value;
2141 if (channel->playing)
2142 channel->playing->vibrato_speed = channel->lastHspeed;
2143 break;
2144 case 0xB: /* Vibrato */
2145 if (value)
2146 channel->lastHdepth = value << 2; /** WARNING: correct ? */
2147 if (channel->playing) {
2148 channel->playing->vibrato_depth = channel->lastHdepth;
2149 channel->playing->vibrato_speed = channel->lastHspeed;
2150 channel->playing->vibrato_n++;
2151 }
2152 break;
2153 case 0xC: /* Set panning */
2154 channel->pan = (value*64)/15;
2155 channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
2156 break;
2157 case 0xD: /* Pan slide left */
2158 // TODO
2159 // channel->xm_panslide = -value;
2160 break;
2161 case 0xE: /* Pan slide Right */
2162 // TODO
2163 // channel->xm_panslide = value;
2164 break;
2165 case 0xF: /* Tone porta */
2166 break;
2167 default: /* Volume */
2168 channel->volume = entry->volpan - 0x10;
2169 break;
2170 }
2171 }
2172}
2173
2174
2175
2176/* This function assumes !IT_IS_END_ROW(entry). */
2177static int process_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry)
2178{
2179 DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
2180
2181 if (sigdata->flags & IT_WAS_AN_XM)
2182 process_xm_note_data(sigrenderer, entry);
2183 else
2184 if (process_it_note_data(sigrenderer, entry)) return 0;
2185
2186 return process_effects(sigrenderer, entry);
2187}
2188
2189
2190
2191static int process_entry(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry)
2192{
2193 IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
2194
2195 if (entry->mask & IT_ENTRY_NOTE)
2196 channel->note = entry->note;
2197
2198 if ((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_S) {
2199 /* channel->lastS was set in update_pattern_variables(). */
2200 unsigned char effectvalue = channel->lastS;
2201 if (effectvalue >> 4 == IT_S_NOTE_DELAY) {
2202 channel->note_delay_count = effectvalue & 15;
2203 if (channel->note_delay_count == 0)
2204 channel->note_delay_count = 1;
2205 channel->note_delay_entry = entry;
2206 return 0;
2207 }
2208 }
2209
2210 return process_note_data(sigrenderer, entry);
2211}
2212
2213
2214
2215static void update_tick_counts(DUMB_IT_SIGRENDERER *sigrenderer)
2216{
2217 int i;
2218
2219 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
2220 IT_CHANNEL *channel = &sigrenderer->channel[i];
2221
2222 if (channel->note_cut_count) {
2223 channel->note_cut_count--;
2224 if (channel->note_cut_count == 0) {
2225 if (sigrenderer->sigdata->flags & IT_WAS_AN_XM)
2226 channel->volume = 0;
2227 else if (channel->playing) {
2228 free(channel->playing);
2229 channel->playing = NULL;
2230 }
2231 }
2232 } else if (channel->note_delay_count) {
2233 channel->note_delay_count--;
2234 if (channel->note_delay_count == 0)
2235 process_note_data(sigrenderer, channel->note_delay_entry);
2236 /* Don't bother checking the return value; if the note
2237 * was delayed, there can't have been a speed=0.
2238 */
2239 }
2240 }
2241}
2242
2243
2244
2245static int envelope_get_y(IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe)
2246{
2247 int ys, ye;
2248 int ts, te;
2249 int t;
2250
2251 if (pe->next_node <= 0)
2252 return envelope->node_y[0] << IT_ENVELOPE_SHIFT;
2253
2254 if (pe->next_node >= envelope->n_nodes)
2255 return envelope->node_y[envelope->n_nodes-1] << IT_ENVELOPE_SHIFT;
2256
2257 ys = envelope->node_y[pe->next_node-1] << IT_ENVELOPE_SHIFT;
2258 ts = envelope->node_t[pe->next_node-1];
2259 te = envelope->node_t[pe->next_node];
2260
2261 if (ts == te)
2262 return ys;
2263
2264 ye = envelope->node_y[pe->next_node] << IT_ENVELOPE_SHIFT;
2265
2266 t = pe->tick;
2267
2268 return ys + (ye - ys) * (t - ts) / (te - ts);
2269}
2270
2271
2272
2273static int it_envelope_end(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe)
2274{
2275 if (pe->next_node >= envelope->n_nodes)
2276 return 1;
2277
2278 if (pe->tick < envelope->node_t[pe->next_node]) return 0;
2279
2280 if ((envelope->flags & IT_ENVELOPE_LOOP_ON) &&
2281 envelope->loop_end >= pe->next_node &&
2282 envelope->node_t[envelope->loop_end] <= pe->tick) return 0;
2283
2284 if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) &&
2285 !(playing->flags & IT_PLAYING_SUSTAINOFF) &&
2286 envelope->sus_loop_end >= pe->next_node &&
2287 envelope->node_t[envelope->sus_loop_end] <= pe->tick) return 0;
2288
2289 if (envelope->node_t[envelope->n_nodes-1] <= pe->tick) return 1;
2290
2291 return 0;
2292}
2293
2294
2295
2296/* This returns 1 if the envelope finishes. */
2297static int update_it_envelope(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe)
2298{
2299 if (!(envelope->flags & IT_ENVELOPE_ON))
2300 return 0;
2301
2302 if (pe->next_node >= envelope->n_nodes)
2303 return 1;
2304
2305 while (pe->tick >= envelope->node_t[pe->next_node]) {
2306 if ((envelope->flags & IT_ENVELOPE_LOOP_ON) && pe->next_node == envelope->loop_end) {
2307 pe->next_node = envelope->loop_start;
2308 pe->tick = envelope->node_t[envelope->loop_start];
2309 return it_envelope_end(playing, envelope, pe);
2310 }
2311 if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF) && pe->next_node == envelope->sus_loop_end) {
2312 pe->next_node = envelope->sus_loop_start;
2313 pe->tick = envelope->node_t[envelope->sus_loop_start];
2314 return it_envelope_end(playing, envelope, pe);
2315 }
2316
2317 pe->next_node++;
2318
2319 if (pe->next_node >= envelope->n_nodes)
2320 return 1;
2321 }
2322
2323 pe->tick++;
2324
2325 return it_envelope_end(playing, envelope, pe);
2326}
2327
2328
2329
2330static void update_it_envelopes(IT_PLAYING *playing)
2331{
2332 IT_ENVELOPE *envelope = &playing->env_instrument->volume_envelope;
2333
2334 if (update_it_envelope(playing, envelope, &playing->volume_envelope)) {
2335 playing->flags |= IT_PLAYING_FADING;
2336 if (envelope->n_nodes && envelope->node_y[envelope->n_nodes-1] == 0)
2337 playing->flags |= IT_PLAYING_DEAD;
2338 }
2339
2340 update_it_envelope(playing, &playing->env_instrument->pan_envelope, &playing->pan_envelope);
2341 update_it_envelope(playing, &playing->env_instrument->pitch_envelope, &playing->pitch_envelope);
2342}
2343
2344
2345
2346static int xm_envelope_is_sustaining(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe)
2347{
2348 if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF))
2349 if (envelope->sus_loop_start < envelope->n_nodes)
2350 if (pe->tick == envelope->node_t[envelope->sus_loop_start])
2351 return 1;
2352 return 0;
2353}
2354
2355
2356
2357static void update_xm_envelope(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe)
2358{
2359 if (!(envelope->flags & IT_ENVELOPE_ON))
2360 return;
2361
2362 if (xm_envelope_is_sustaining(playing, envelope, pe))
2363 return;
2364
2365 if (pe->tick >= envelope->node_t[envelope->n_nodes-1])
2366 return;
2367
2368 pe->tick++;
2369
2370 /* pe->next_node must be kept up to date for envelope_get_y(). */
2371 while (pe->tick > envelope->node_t[pe->next_node])
2372 pe->next_node++;
2373
2374 if ((envelope->flags & IT_ENVELOPE_LOOP_ON) && envelope->loop_end < envelope->n_nodes) {
2375 if (pe->tick == envelope->node_t[envelope->loop_end]) {
2376 pe->next_node = MID(0, envelope->loop_start, envelope->n_nodes - 1);
2377 pe->tick = envelope->node_t[pe->next_node];
2378 }
2379 }
2380
2381 if (xm_envelope_is_sustaining(playing, envelope, pe))
2382 return;
2383
2384 if (pe->tick >= envelope->node_t[envelope->n_nodes-1])
2385 return;
2386}
2387
2388
2389
2390static void update_xm_envelopes(IT_PLAYING *playing)
2391{
2392 update_xm_envelope(playing, &playing->env_instrument->volume_envelope, &playing->volume_envelope);
2393 update_xm_envelope(playing, &playing->env_instrument->pan_envelope, &playing->pan_envelope);
2394}
2395
2396
2397
2398static void update_fadeout(DUMB_IT_SIGDATA *sigdata, IT_PLAYING *playing)
2399{
2400 if (playing->flags & IT_PLAYING_FADING) {
2401 playing->fadeoutcount -= playing->env_instrument->fadeout;
2402 if (playing->fadeoutcount <= 0) {
2403 playing->fadeoutcount = 0;
2404 if (!(sigdata->flags & IT_WAS_AN_XM))
2405 playing->flags |= IT_PLAYING_DEAD;
2406 }
2407 }
2408}
2409
2410
2411
2412static void process_playing(DUMB_IT_SIGDATA *sigdata, IT_PLAYING *playing)
2413{
2414 if (playing->instrument) {
2415 if (sigdata->flags & IT_WAS_AN_XM)
2416 update_xm_envelopes(playing);
2417 else
2418 update_it_envelopes(playing);
2419 update_fadeout(sigdata, playing);
2420 }
2421
2422 //Calculate final volume if required
2423 //Calculate final pan if required
2424
2425 if (sigdata->flags & IT_WAS_AN_XM) {
2426 /* 'depth' is used to store the tick number for XM files. */
2427 if (playing->sample_vibrato_depth < playing->sample->vibrato_rate)
2428 playing->sample_vibrato_depth++;
2429 } else {
2430 playing->sample_vibrato_depth += playing->sample->vibrato_rate;
2431 if (playing->sample_vibrato_depth > playing->sample->vibrato_depth << 8)
2432 playing->sample_vibrato_depth = playing->sample->vibrato_depth << 8;
2433 }
2434
2435 playing->sample_vibrato_time += playing->sample->vibrato_speed;
2436}
2437
2438
2439
2440static void process_all_playing(DUMB_IT_SIGRENDERER *sigrenderer)
2441{
2442 DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
2443 int i;
2444
2445 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
2446 IT_CHANNEL *channel = &sigrenderer->channel[i];
2447 IT_PLAYING *playing = channel->playing;
2448
2449 if (playing) {
2450 int vibrato_shift = it_sine[playing->vibrato_time];
2451 vibrato_shift *= playing->vibrato_n;
2452 vibrato_shift *= playing->vibrato_depth;
2453 vibrato_shift >>= 4;
2454
2455 if (sigdata->flags & IT_OLD_EFFECTS)
2456 vibrato_shift = -vibrato_shift;
2457
2458 playing->volume = channel->volume;
2459 playing->pan = channel->truepan;
2460
2461 if (sigdata->flags & IT_LINEAR_SLIDES) {
2462 int currpitch = ((playing->note - 60) << 8) + playing->slide
2463 + vibrato_shift;
2464
2465 /* We add a feature here, which is that of keeping the pitch
2466 * within range. Otherwise it crashes. Trust me. It happened.
2467 * The limit 32768 gives almost 11 octaves either way.
2468 */
2469 if (currpitch < -32768)
2470 currpitch = -32768;
2471 else if (currpitch > 32767)
2472 currpitch = 32767;
2473
2474 playing->delta = (float)pow(DUMB_PITCH_BASE, currpitch);
2475 playing->delta *= playing->sample->C5_speed / 65536.0f;
2476 } else {
2477 int slide = playing->slide + vibrato_shift;
2478
2479 playing->delta = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note);
2480 /* playing->delta is 1.0 for C-5, 0.5 for C-6, etc. */
2481
2482 playing->delta *= 1.0f / playing->sample->C5_speed;
2483
2484 playing->delta -= slide / AMIGA_DIVISOR;
2485
2486 if (playing->delta < (1.0f / 65536.0f) / 32768.0f) {
2487 // Should XM notes die if Amiga slides go out of range?
2488 playing->flags |= IT_PLAYING_DEAD;
2489 continue;
2490 }
2491
2492 playing->delta = (1.0f / 65536.0f) / playing->delta;
2493 }
2494
2495 playing->delta *= (float)pow(DUMB_SEMITONE_BASE, channel->arpeggio >> 8);
2496
2497 playing->filter_cutoff = channel->filter_cutoff;
2498 playing->filter_resonance = channel->filter_resonance;
2499 }
2500 }
2501
2502 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
2503 if (sigrenderer->channel[i].playing) {
2504 process_playing(sigdata, sigrenderer->channel[i].playing);
2505 if (!(sigdata->flags & IT_WAS_AN_XM)) {
2506 if ((sigrenderer->channel[i].playing->flags & (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) == (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) {
2507 free(sigrenderer->channel[i].playing);
2508 sigrenderer->channel[i].playing = NULL;
2509 }
2510 }
2511 }
2512 }
2513
2514 for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
2515 if (sigrenderer->playing[i]) {
2516 process_playing(sigdata, sigrenderer->playing[i]);
2517 if (sigrenderer->playing[i]->flags & IT_PLAYING_DEAD) {
2518 free(sigrenderer->playing[i]);
2519 sigrenderer->playing[i] = NULL;
2520 }
2521 }
2522 }
2523}
2524
2525
2526
2527static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer)
2528{
2529 DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
2530
2531 // Set note vol/freq to vol/freq set for each channel
2532
2533 if (sigrenderer->speed && --sigrenderer->tick == 0) {
2534 reset_tick_counts(sigrenderer);
2535 sigrenderer->tick = sigrenderer->speed;
2536 sigrenderer->rowcount--;
2537 if (sigrenderer->rowcount == 0) {
2538 sigrenderer->rowcount = 1;
2539 if (sigrenderer->pat_loop_row >= 0) {
2540 int n = sigrenderer->pat_loop_row - 1;
2541 sigrenderer->row = sigrenderer->processrow = n;
2542 sigrenderer->pat_loop_row = -1;
2543 if (n < 0)
2544 sigrenderer->entry = NULL;
2545 else {
2546 sigrenderer->entry = sigrenderer->entry_start;
2547 while (n) {
2548 while (sigrenderer->entry < sigrenderer->entry_end) {
2549 if (IT_IS_END_ROW(sigrenderer->entry)) {
2550 sigrenderer->entry++;
2551 break;
2552 }
2553 sigrenderer->entry++;
2554 }
2555 n--;
2556 }
2557 }
2558 }
2559
2560 sigrenderer->processrow++;
2561
2562 if (sigrenderer->processrow >= sigrenderer->n_rows) {
2563 IT_PATTERN *pattern;
2564 int n;
2565
2566 sigrenderer->processrow = sigrenderer->breakrow;
2567 sigrenderer->breakrow = 0;
2568
2569 for (;;) {
2570 sigrenderer->processorder++;
2571
2572 if (sigrenderer->processorder >= sigdata->n_orders) {
2573 sigrenderer->processorder = sigdata->restart_position;
2574 if (sigrenderer->processorder >= sigdata->n_orders) {
2575 /* Restarting beyond end. We'll loop for now. */
2576 sigrenderer->processorder = -1;
2577 continue;
2578 }
2579 }
2580
2581 n = sigdata->order[sigrenderer->processorder];
2582
2583 if (n < sigdata->n_patterns)
2584 break;
2585
2586#ifdef INVALID_ORDERS_END_SONG
2587 if (n != IT_ORDER_SKIP)
2588 sigrenderer->processorder = -1;
2589#else
2590 if (n == IT_ORDER_END)
2591 sigrenderer->processorder = -1;
2592#endif
2593 }
2594
2595 pattern = &sigdata->pattern[n];
2596
2597 sigrenderer->n_rows = pattern->n_rows;
2598
2599 if (sigrenderer->processrow >= sigrenderer->n_rows)
2600 sigrenderer->processrow = 0;
2601
2602/** WARNING - everything pertaining to a new pattern initialised? */
2603
2604 sigrenderer->entry = sigrenderer->entry_start = pattern->entry;
2605 sigrenderer->entry_end = sigrenderer->entry + pattern->n_entries;
2606
2607 if (sigrenderer->order >= sigrenderer->processorder) {
2608 if (sigrenderer->callbacks->loop) {
2609 if ((*sigrenderer->callbacks->loop)(sigrenderer->callbacks->loop_data))
2610 return 1;
2611 if (sigrenderer->speed == 0)
2612 goto speed0; /* I love goto */
2613 }
2614 }
2615 sigrenderer->order = sigrenderer->processorder;
2616
2617 n = sigrenderer->processrow;
2618 while (n) {
2619 while (sigrenderer->entry < sigrenderer->entry_end) {
2620 if (IT_IS_END_ROW(sigrenderer->entry)) {
2621 sigrenderer->entry++;
2622 break;
2623 }
2624 sigrenderer->entry++;
2625 }
2626 n--;
2627 }
2628 sigrenderer->row = sigrenderer->processrow;
2629 } else {
2630 if (sigrenderer->entry) {
2631 while (sigrenderer->entry < sigrenderer->entry_end) {
2632 if (IT_IS_END_ROW(sigrenderer->entry)) {
2633 sigrenderer->entry++;
2634 break;
2635 }
2636 sigrenderer->entry++;
2637 }
2638 sigrenderer->row++;
2639 } else {
2640 sigrenderer->entry = sigrenderer->entry_start;
2641 sigrenderer->row = 0;
2642 }
2643 }
2644
2645 reset_effects(sigrenderer);
2646
2647 {
2648 IT_ENTRY *entry = sigrenderer->entry;
2649
2650 while (entry < sigrenderer->entry_end && !IT_IS_END_ROW(entry))
2651 update_pattern_variables(sigrenderer, entry++);
2652 }
2653
2654 {
2655 IT_ENTRY *entry = sigrenderer->entry;
2656
2657 while (entry < sigrenderer->entry_end && !IT_IS_END_ROW(entry))
2658 if (process_entry(sigrenderer, entry++))
2659 return 1;
2660 }
2661
2662 if (!(sigdata->flags & IT_OLD_EFFECTS))
2663 update_smooth_effects(sigrenderer);
2664 } else {
2665 {
2666 IT_ENTRY *entry = sigrenderer->entry;
2667
2668 while (entry < sigrenderer->entry_end && !IT_IS_END_ROW(entry))
2669 process_effects(sigrenderer, entry++);
2670 /* Don't bother checking the return value; if there
2671 * was a pattern delay, there can't be a speed=0.
2672 */
2673 }
2674
2675 update_effects(sigrenderer);
2676 }
2677 } else {
2678 speed0:
2679 update_effects(sigrenderer);
2680 update_tick_counts(sigrenderer);
2681 }
2682
2683 process_all_playing(sigrenderer);
2684
2685 sigrenderer->time_left += TICK_TIME_DIVIDEND / sigrenderer->tempo;
2686
2687 return 0;
2688}
2689
2690
2691
2692int dumb_it_max_to_mix = 64;
2693
2694
2695
2696static float calculate_volume(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float volume)
2697{
2698 if (volume != 0) {
2699 int vol;
2700
2701 if (playing->channel->flags & IT_CHANNEL_MUTED)
2702 return 0;
2703
2704 if ((playing->channel->tremor_time & 192) == 128)
2705 return 0;
2706
2707 vol = it_sine[playing->tremolo_time];
2708 vol *= playing->tremolo_depth;
2709
2710 vol = (playing->volume << 5) + vol;
2711
2712 if (vol <= 0)
2713 return 0;
2714
2715 if (vol > 64 << 5)
2716 vol = 64 << 5;
2717
2718 volume *= vol; /* 64 << 5 */
2719 volume *= playing->sample->global_volume; /* 64 */
2720 volume *= playing->channel_volume; /* 64 */
2721 volume *= sigrenderer->globalvolume; /* 128 */
2722 volume *= sigrenderer->sigdata->mixing_volume; /* 128 */
2723 volume *= 1.0f / ((64 << 5) * 64.0f * 64.0f * 128.0f * 128.0f);
2724
2725 if (volume && playing->instrument) {
2726 if (playing->env_instrument->volume_envelope.flags & IT_ENVELOPE_ON) {
2727 volume *= envelope_get_y(&playing->env_instrument->volume_envelope, &playing->volume_envelope);
2728 volume *= 1.0f / (64 << IT_ENVELOPE_SHIFT);
2729 }
2730 volume *= playing->instrument->global_volume; /* 128 */
2731 volume *= playing->fadeoutcount; /* 1024 */
2732 volume *= 1.0f / (128.0f * 1024.0f);
2733 }
2734 }
2735
2736 return volume;
2737}
2738
2739
2740
2741static int apply_pan_envelope(IT_PLAYING *playing)
2742{
2743 int pan = playing->pan;
2744 if (pan <= 64 << IT_ENVELOPE_SHIFT && playing->env_instrument && (playing->env_instrument->pan_envelope.flags & IT_ENVELOPE_ON)) {
2745 int p = envelope_get_y(&playing->env_instrument->pan_envelope, &playing->pan_envelope);
2746 if (pan > 32 << IT_ENVELOPE_SHIFT)
2747 p *= (64 << IT_ENVELOPE_SHIFT) - pan;
2748 else
2749 p *= pan;
2750 pan += p >> (5 + IT_ENVELOPE_SHIFT);
2751 }
2752 return pan;
2753}
2754
2755
2756
2757/* Note: if a click remover is provided, and store_end_sample is set, then
2758 * the end point will be computed twice. This situation should not arise.
2759 */
2760static long render_playing(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float volume, float delta, long pos, long size, sample_t **samples, int store_end_sample, int *left_to_mix)
2761{
2762 int pan;
2763
2764 long size_rendered;
2765
2766 if (playing->flags & IT_PLAYING_DEAD)
2767 return 0;
2768
2769 if (*left_to_mix <= 0)
2770 volume = 0;
2771
2772 pan = apply_pan_envelope(playing);
2773
2774#define RESAMPLERV(rv, resampler, dst, volume) \
2775{ \
2776 rv = dumb_resample(resampler, dst, size, volume, delta); \
2777 if (store_end_sample) \
2778 (dst)[rv] = RESAMPLE_VALUE(resampler, volume); \
2779}
2780
2781#define RESAMPLE(resampler, dst, volume) \
2782{ \
2783 int i; \
2784 RESAMPLERV(i, resampler, dst, volume); \
2785}
2786
2787#define RESAMPLE_VALUE(resampler, volume) \
2788 dumb_resample_get_current_sample(resampler, volume)
2789
2790 if (volume == 0) {
2791 size_rendered = dumb_resample(&playing->resampler[0], NULL, size, 0, delta);
2792 if (playing->sample->flags & IT_SAMPLE_STEREO)
2793 dumb_resample(&playing->resampler[1], NULL, size, 0, delta);
2794 } else {
2795 if (sigrenderer->n_channels == 2) {
2796 float vol = volume;
2797 DUMB_RESAMPLER start = playing->resampler[0];
2798 if (!IT_IS_SURROUND_SHIFTED(pan)) vol *= 2.0f - pan * (1.0f / (32 << IT_ENVELOPE_SHIFT));
2799 if (sigrenderer->click_remover && sigrenderer->click_remover[0])
2800 dumb_record_click(sigrenderer->click_remover[0], pos, RESAMPLE_VALUE(&playing->resampler[0], vol));
2801 RESAMPLERV(size_rendered, &playing->resampler[0], samples[0] + pos, vol);
2802 if (sigrenderer->click_remover && sigrenderer->click_remover[0])
2803 dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -RESAMPLE_VALUE(&playing->resampler[0], vol));
2804 vol = -vol;
2805 if (!IT_IS_SURROUND_SHIFTED(pan)) vol += 2.0f * volume;
2806 if (playing->sample->flags & IT_SAMPLE_STEREO) {
2807 if (sigrenderer->click_remover && sigrenderer->click_remover[1])
2808 dumb_record_click(sigrenderer->click_remover[1], pos, RESAMPLE_VALUE(&playing->resampler[1], vol));
2809 RESAMPLE(&playing->resampler[1], samples[1] + pos, vol);
2810 if (sigrenderer->click_remover && sigrenderer->click_remover[1])
2811 dumb_record_click(sigrenderer->click_remover[1], pos + size_rendered, -RESAMPLE_VALUE(&playing->resampler[1], vol));
2812 } else {
2813 playing->resampler[0] = start;
2814 if (sigrenderer->click_remover && sigrenderer->click_remover[1])
2815 dumb_record_click(sigrenderer->click_remover[1], pos, RESAMPLE_VALUE(&playing->resampler[0], vol));
2816 RESAMPLE(&playing->resampler[0], samples[1] + pos, vol);
2817 if (sigrenderer->click_remover && sigrenderer->click_remover[1])
2818 dumb_record_click(sigrenderer->click_remover[1], pos + size_rendered, -RESAMPLE_VALUE(&playing->resampler[0], vol));
2819 }
2820 } else {
2821 if (playing->sample->flags & IT_SAMPLE_STEREO) {
2822 float vol = 0.5f * volume;
2823 if (!IT_IS_SURROUND_SHIFTED(pan)) vol *= 2.0f - pan * (1.0f / (32 << IT_ENVELOPE_SHIFT));
2824 if (sigrenderer->click_remover && sigrenderer->click_remover[0]) {
2825 sample_t startstep, endstep;
2826 startstep = RESAMPLE_VALUE(&playing->resampler[0], vol);
2827 RESAMPLE(&playing->resampler[0], samples[0] + pos, vol);
2828 endstep = RESAMPLE_VALUE(&playing->resampler[0], vol);
2829 if (!IT_IS_SURROUND_SHIFTED(pan)) vol = 2.0f * volume - vol;
2830 startstep += RESAMPLE_VALUE(&playing->resampler[1], vol);
2831 RESAMPLERV(size_rendered, &playing->resampler[1], samples[0] + pos, vol);
2832 endstep += RESAMPLE_VALUE(&playing->resampler[1], vol);
2833 dumb_record_click(sigrenderer->click_remover[0], pos, startstep);
2834 dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -endstep);
2835 } else {
2836 RESAMPLE(&playing->resampler[0], samples[0] + pos, vol);
2837 if (!IT_IS_SURROUND_SHIFTED(pan)) vol = 2.0f * volume - vol;
2838 RESAMPLERV(size_rendered, &playing->resampler[1], samples[0] + pos, vol);
2839 }
2840 } else {
2841 if (sigrenderer->click_remover && sigrenderer->click_remover[0])
2842 dumb_record_click(sigrenderer->click_remover[0], pos, RESAMPLE_VALUE(&playing->resampler[0], volume));
2843 RESAMPLERV(size_rendered, &playing->resampler[0], samples[0] + pos, volume);
2844 if (sigrenderer->click_remover && sigrenderer->click_remover[0])
2845 dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -RESAMPLE_VALUE(&playing->resampler[0], volume));
2846 }
2847 }
2848 (*left_to_mix)--;
2849 }
2850
2851 if (playing->resampler[0].dir == 0)
2852 playing->flags |= IT_PLAYING_DEAD;
2853
2854 return size_rendered;
2855}
2856
2857
2858
2859typedef struct IT_TO_MIX
2860{
2861 IT_PLAYING *playing;
2862 float volume;
2863}
2864IT_TO_MIX;
2865
2866
2867
2868static int it_to_mix_compare(const void *e1, const void *e2)
2869{
2870 if (((const IT_TO_MIX *)e1)->volume > ((const IT_TO_MIX *)e2)->volume)
2871 return -1;
2872
2873 if (((const IT_TO_MIX *)e1)->volume < ((const IT_TO_MIX *)e2)->volume)
2874 return 1;
2875
2876 return 0;
2877}
2878
2879
2880
2881static void apply_pitch_modifications(DUMB_IT_SIGDATA *sigdata, IT_PLAYING *playing, float *delta, int *cutoff)
2882{
2883 {
2884 int sample_vibrato_shift = it_sine[playing->sample_vibrato_time];
2885
2886 if (sigdata->flags & IT_WAS_AN_XM) {
2887 int depth = playing->sample->vibrato_depth; /* True depth */
2888 if (playing->sample->vibrato_rate) {
2889 depth *= playing->sample_vibrato_depth; /* Tick number */
2890 depth /= playing->sample->vibrato_rate; /* XM sweep */
2891 }
2892 sample_vibrato_shift *= depth;
2893 } else
2894 sample_vibrato_shift *= playing->sample_vibrato_depth >> 8;
2895
2896 sample_vibrato_shift >>= 4;
2897
2898 *delta *= (float)pow(DUMB_PITCH_BASE, sample_vibrato_shift);
2899 }
2900
2901 if (playing->env_instrument &&
2902 (playing->env_instrument->pitch_envelope.flags & IT_ENVELOPE_ON))
2903 {
2904 int p = envelope_get_y(&playing->env_instrument->pitch_envelope, &playing->pitch_envelope);
2905 if (playing->env_instrument->pitch_envelope.flags & IT_ENVELOPE_PITCH_IS_FILTER)
2906 *cutoff = (*cutoff * (p+(32<<IT_ENVELOPE_SHIFT))) >> (6 + IT_ENVELOPE_SHIFT);
2907 else
2908 *delta *= (float)pow(DUMB_PITCH_BASE, p >> (IT_ENVELOPE_SHIFT - 7));
2909 }
2910}
2911
2912
2913
2914static void render(DUMB_IT_SIGRENDERER *sigrenderer, float volume, float delta, long pos, long size, sample_t **samples)
2915{
2916 int i;
2917
2918 int n_to_mix = 0;
2919 IT_TO_MIX to_mix[DUMB_IT_TOTAL_CHANNELS];
2920 int left_to_mix = dumb_it_max_to_mix;
2921
2922 sample_t **samples_to_filter = NULL;
2923
2924 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
2925 if (sigrenderer->channel[i].playing && !(sigrenderer->channel[i].playing->flags & IT_PLAYING_DEAD)) {
2926 to_mix[n_to_mix].playing = sigrenderer->channel[i].playing;
2927 to_mix[n_to_mix].volume = volume == 0 ? 0 : calculate_volume(sigrenderer, sigrenderer->channel[i].playing, volume);
2928 n_to_mix++;
2929 }
2930 }
2931
2932 for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
2933 if (sigrenderer->playing[i]) { /* Won't be dead; it would have been freed. */
2934 to_mix[n_to_mix].playing = sigrenderer->playing[i];
2935 to_mix[n_to_mix].volume = volume == 0 ? 0 : calculate_volume(sigrenderer, sigrenderer->playing[i], volume);
2936 n_to_mix++;
2937 }
2938 }
2939
2940 if (volume != 0)
2941 qsort(to_mix, n_to_mix, sizeof(IT_TO_MIX), &it_to_mix_compare);
2942
2943 for (i = 0; i < n_to_mix; i++) {
2944 IT_PLAYING *playing = to_mix[i].playing;
2945 float note_delta = delta * playing->delta;
2946 int cutoff = playing->filter_cutoff << IT_ENVELOPE_SHIFT;
2947
2948 apply_pitch_modifications(sigrenderer->sigdata, playing, &note_delta, &cutoff);
2949
2950 if (cutoff != 127 << IT_ENVELOPE_SHIFT || playing->filter_resonance != 0) {
2951 playing->true_filter_cutoff = cutoff;
2952 playing->true_filter_resonance = playing->filter_resonance;
2953 }
2954
2955 if (to_mix[i].volume && (playing->true_filter_cutoff != 127 << IT_ENVELOPE_SHIFT || playing->true_filter_resonance != 0)) {
2956 if (!samples_to_filter) {
2957 samples_to_filter = create_sample_buffer(sigrenderer->n_channels, size + 1);
2958 if (!samples_to_filter) {
2959 render_playing(sigrenderer, playing, 0, note_delta, pos, size, NULL, 0, &left_to_mix);
2960 continue;
2961 }
2962 }
2963 {
2964 long size_rendered;
2965 DUMB_CLICK_REMOVER **cr = sigrenderer->click_remover;
2966 dumb_silence(samples_to_filter[0], sigrenderer->n_channels * (size + 1));
2967 sigrenderer->click_remover = NULL;
2968 size_rendered = render_playing(sigrenderer, playing, to_mix[i].volume, note_delta, 0, size, samples_to_filter, 1, &left_to_mix);
2969 sigrenderer->click_remover = cr;
2970 it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[0], pos, samples_to_filter[0], size_rendered,
2971 65536.0f/delta, playing->true_filter_cutoff, playing->true_filter_resonance);
2972 if (sigrenderer->n_channels == 2)
2973 it_filter(cr ? cr[1] : NULL, &playing->filter_state[1], samples[1], pos, samples_to_filter[1], size_rendered,
2974 65536.0f/delta, playing->true_filter_cutoff, playing->true_filter_resonance);
2975 // warning: filtering is not prevented by low left_to_mix!
2976 }
2977 } else {
2978 it_reset_filter_state(&playing->filter_state[0]);
2979 it_reset_filter_state(&playing->filter_state[1]);
2980 render_playing(sigrenderer, playing, to_mix[i].volume, note_delta, pos, size, samples, 0, &left_to_mix);
2981 }
2982 }
2983
2984 destroy_sample_buffer(samples_to_filter);
2985
2986 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
2987 if (sigrenderer->channel[i].playing) {
2988 if ((sigrenderer->channel[i].playing->flags & (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) == (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) {
2989 free(sigrenderer->channel[i].playing);
2990 sigrenderer->channel[i].playing = NULL;
2991 }
2992 }
2993 }
2994
2995 for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
2996 if (sigrenderer->playing[i]) {
2997 if (sigrenderer->playing[i]->flags & IT_PLAYING_DEAD) {
2998 free(sigrenderer->playing[i]);
2999 sigrenderer->playing[i] = NULL;
3000 }
3001 }
3002 }
3003}
3004
3005
3006
3007static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_channels, int startorder, IT_CALLBACKS *callbacks, DUMB_CLICK_REMOVER **cr)
3008{
3009 DUMB_IT_SIGRENDERER *sigrenderer;
3010 int i;
3011
3012 if (startorder > sigdata->n_orders) {
3013 free(callbacks);
3014 dumb_destroy_click_remover_array(n_channels, cr);
3015 return NULL;
3016 }
3017
3018 sigrenderer = malloc(sizeof(*sigrenderer));
3019 if (!sigrenderer) {
3020 free(callbacks);
3021 dumb_destroy_click_remover_array(n_channels, cr);
3022 return NULL;
3023 }
3024
3025 sigrenderer->callbacks = callbacks;
3026 sigrenderer->click_remover = cr;
3027
3028 sigrenderer->sigdata = sigdata;
3029 sigrenderer->n_channels = n_channels;
3030 sigrenderer->globalvolume = sigdata->global_volume;
3031 sigrenderer->tempo = sigdata->tempo;
3032
3033 for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
3034 IT_CHANNEL *channel = &sigrenderer->channel[i];
3035#if IT_CHANNEL_MUTED != 1
3036#error this is wrong
3037#endif
3038 channel->flags = sigdata->channel_pan[i] >> 7;
3039 channel->volume = (sigdata->flags & IT_WAS_AN_XM) ? 0 : 64;
3040 channel->pan = sigdata->channel_pan[i] & 0x7F;
3041 channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
3042 channel->channelvolume = sigdata->channel_volume[i];
3043 channel->instrument = 0;
3044 channel->note = 0;
3045 channel->SFmacro = 0;
3046 channel->filter_cutoff = 127;
3047 channel->filter_resonance = 0;
3048 channel->xm_retrig = 0;
3049 channel->retrig_tick = 0;
3050 channel->tremor_time = 0;
3051 channel->midi_state = 0;
3052 channel->lastvolslide = 0;
3053 channel->lastDKL = 0;
3054 channel->lastEF = 0;
3055 channel->lastG = 0;
3056 channel->lastHspeed = 0;
3057 channel->lastHdepth = 0;
3058 channel->lastRspeed = 0;
3059 channel->lastRdepth = 0;
3060 channel->lastI = 0;
3061 channel->lastJ = 0;
3062 channel->lastN = 0;
3063 channel->lastO = 0;
3064 channel->high_offset = 0;
3065 channel->lastQ = 0;
3066 channel->lastS = 0;
3067 channel->pat_loop_row = 0;
3068 channel->pat_loop_count = 0;
3069 channel->lastW = 0;
3070 channel->xm_lastE1 = 0;
3071 channel->xm_lastE2 = 0;
3072 channel->xm_lastEA = 0;
3073 channel->xm_lastEB = 0;
3074 channel->xm_lastX1 = 0;
3075 channel->xm_lastX2 = 0;
3076 channel->playing = NULL;
3077 }
3078
3079 for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++)
3080 sigrenderer->playing[i] = NULL;
3081
3082 sigrenderer->speed = sigdata->speed;
3083
3084 sigrenderer->processrow = 0;
3085 sigrenderer->breakrow = 0;
3086 sigrenderer->pat_loop_row = -1;
3087 sigrenderer->rowcount = 1;
3088
3089 reset_tick_counts(sigrenderer);
3090
3091 sigrenderer->tick = sigrenderer->speed;
3092
3093 {
3094 IT_PATTERN *pattern;
3095 int n;
3096
3097 sigrenderer->processorder = startorder;
3098 for (;;) {
3099 n = sigdata->order[sigrenderer->processorder];
3100
3101 if (n < sigdata->n_patterns)
3102 break;
3103
3104#ifdef INVALID_ORDERS_END_SONG
3105 if (n != IT_ORDER_SKIP)
3106#else
3107 if (n == IT_ORDER_END)
3108#endif
3109 {
3110 _dumb_it_end_sigrenderer(sigrenderer);
3111 return NULL;
3112 }
3113
3114 sigrenderer->processorder++;
3115 if (sigrenderer->processorder >= sigdata->n_orders)
3116 sigrenderer->processorder = 0;
3117 if (sigrenderer->processorder == startorder) {
3118 _dumb_it_end_sigrenderer(sigrenderer);
3119 return NULL;
3120 }
3121 }
3122
3123 pattern = &sigdata->pattern[n];
3124
3125 sigrenderer->n_rows = pattern->n_rows;
3126
3127/** WARNING - everything pertaining to a new pattern initialised? */
3128
3129 sigrenderer->entry = sigrenderer->entry_start = pattern->entry;
3130 sigrenderer->entry_end = sigrenderer->entry + pattern->n_entries;
3131
3132 sigrenderer->order = sigrenderer->processorder;
3133 sigrenderer->row = 0;
3134 }
3135
3136 reset_effects(sigrenderer);
3137
3138 {
3139 IT_ENTRY *entry = sigrenderer->entry;
3140
3141 while (entry < sigrenderer->entry_end && !IT_IS_END_ROW(entry))
3142 update_pattern_variables(sigrenderer, entry++);
3143 }
3144
3145 {
3146 IT_ENTRY *entry = sigrenderer->entry;
3147
3148 while (entry < sigrenderer->entry_end && !IT_IS_END_ROW(entry)) {
3149 if (process_entry(sigrenderer, entry++)) {
3150 /* Oops, that song ended quickly! */
3151 _dumb_it_end_sigrenderer(sigrenderer);
3152 return NULL;
3153 }
3154 }
3155 }
3156
3157 if (!(sigdata->flags & IT_OLD_EFFECTS))
3158 update_smooth_effects(sigrenderer);
3159
3160 process_all_playing(sigrenderer);
3161
3162 sigrenderer->time_left = TICK_TIME_DIVIDEND / sigrenderer->tempo;
3163 sigrenderer->sub_time_left = 0;
3164
3165 return sigrenderer;
3166}
3167
3168
3169
3170void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data)
3171{
3172 if (sigrenderer) {
3173 sigrenderer->callbacks->loop = callback;
3174 sigrenderer->callbacks->loop_data = data;
3175 }
3176}
3177
3178
3179
3180void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data)
3181{
3182 if (sigrenderer) {
3183 sigrenderer->callbacks->xm_speed_zero = callback;
3184 sigrenderer->callbacks->xm_speed_zero_data = data;
3185 }
3186}
3187
3188
3189
3190void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data, int channel, unsigned char byte), void *data)
3191{
3192 if (sigrenderer) {
3193 sigrenderer->callbacks->midi = callback;
3194 sigrenderer->callbacks->midi_data = data;
3195 }
3196}
3197
3198
3199
3200static IT_CALLBACKS *create_callbacks(void)
3201{
3202 IT_CALLBACKS *callbacks = malloc(sizeof(*callbacks));
3203 if (!callbacks) return NULL;
3204 callbacks->loop = NULL;
3205 callbacks->xm_speed_zero = NULL;
3206 callbacks->midi = NULL;
3207 return callbacks;
3208}
3209
3210
3211
3212static DUMB_IT_SIGRENDERER *dumb_it_init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_channels, int startorder)
3213{
3214 IT_CALLBACKS *callbacks;
3215
3216 if (!sigdata) return NULL;
3217
3218 callbacks = create_callbacks();
3219 if (!callbacks) return NULL;
3220
3221 return init_sigrenderer(sigdata, n_channels, startorder, callbacks,
3222 dumb_create_click_remover_array(n_channels));
3223}
3224
3225
3226
3227DUH_SIGRENDERER *dumb_it_start_at_order(DUH *duh, int n_channels, int startorder)
3228{
3229 DUMB_IT_SIGDATA *itsd = duh_get_it_sigdata(duh);
3230 DUMB_IT_SIGRENDERER *itsr = dumb_it_init_sigrenderer(itsd, n_channels, startorder);
3231 return duh_encapsulate_it_sigrenderer(itsr, n_channels, 0);
3232}
3233
3234
3235
3236static sigrenderer_t *it_start_sigrenderer(DUH *duh, sigdata_t *vsigdata, int n_channels, long pos)
3237{
3238 DUMB_IT_SIGDATA *sigdata = vsigdata;
3239 DUMB_IT_SIGRENDERER *sigrenderer;
3240
3241 (void)duh;
3242
3243 {
3244 IT_CALLBACKS *callbacks = create_callbacks();
3245 if (!callbacks) return NULL;
3246
3247 if (sigdata->checkpoint) {
3248 IT_CHECKPOINT *checkpoint = sigdata->checkpoint;
3249 while (checkpoint->next && checkpoint->next->time < pos)
3250 checkpoint = checkpoint->next;
3251 sigrenderer = dup_sigrenderer(checkpoint->sigrenderer, n_channels, callbacks);
3252 if (!sigrenderer) return NULL;
3253 sigrenderer->click_remover = dumb_create_click_remover_array(n_channels);
3254 pos -= checkpoint->time;
3255 } else {
3256 sigrenderer = init_sigrenderer(sigdata, n_channels, 0, callbacks,
3257 dumb_create_click_remover_array(n_channels));
3258 if (!sigrenderer) return NULL;
3259 }
3260 }
3261
3262 for (;;) {
3263 if (sigrenderer->time_left >= pos)
3264 break;
3265
3266 render(sigrenderer, 0, 1.0f, 0, sigrenderer->time_left, NULL);
3267
3268 pos -= sigrenderer->time_left;
3269 sigrenderer->time_left = 0;
3270
3271 if (process_tick(sigrenderer)) {
3272 _dumb_it_end_sigrenderer(sigrenderer);
3273 return NULL;
3274 }
3275 }
3276
3277 render(sigrenderer, 0, 1.0f, 0, pos, NULL);
3278 sigrenderer->time_left -= pos;
3279
3280 /** WARNING - everything initialised? */
3281
3282 return sigrenderer;
3283}
3284
3285
3286
3287static long it_sigrenderer_get_samples(
3288 sigrenderer_t *vsigrenderer,
3289 float volume, float delta,
3290 long size, sample_t **samples
3291)
3292{
3293 DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer;
3294 long pos;
3295 int dt;
3296 long todo;
3297 LONG_LONG t;
3298
3299 if (sigrenderer->order < 0) return 0;
3300
3301 pos = 0;
3302 dt = (int)(delta * 65536.0f + 0.5f);
3303
3304 /* When samples is finally used in render_playing(), it won't be used if
3305 * volume is 0.
3306 */
3307 if (!samples) volume = 0;
3308
3309 for (;;) {
3310 todo = (long)((((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left) / dt);
3311
3312 if (todo >= size)
3313 break;
3314
3315 render(sigrenderer, volume, delta, pos, todo, samples);
3316
3317 pos += todo;
3318 size -= todo;
3319
3320 t = sigrenderer->sub_time_left - (LONG_LONG)todo * dt;
3321 sigrenderer->sub_time_left = (long)t & 65535;
3322 sigrenderer->time_left += (long)(t >> 16);
3323
3324 if (process_tick(sigrenderer)) {
3325 sigrenderer->order = -1;
3326 sigrenderer->row = -1;
3327 return pos;
3328 }
3329 }
3330
3331 render(sigrenderer, volume, delta, pos, size, samples);
3332
3333 pos += size;
3334
3335 t = sigrenderer->sub_time_left - (LONG_LONG)size * dt;
3336 sigrenderer->sub_time_left = (long)t & 65535;
3337 sigrenderer->time_left += (long)(t >> 16);
3338
3339 dumb_remove_clicks_array(sigrenderer->n_channels, sigrenderer->click_remover, samples, pos, 512.0f / delta);
3340
3341 return pos;
3342}
3343
3344
3345
3346static void it_sigrenderer_get_current_sample(sigrenderer_t *vsigrenderer, float volume, sample_t *samples)
3347{
3348 DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer;
3349 (void)volume; // for consideration: in any of these such functions, is 'volume' going to be required?
3350 dumb_click_remover_get_offset_array(sigrenderer->n_channels, sigrenderer->click_remover, samples);
3351}
3352
3353
3354
3355void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer)
3356{
3357 DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer;
3358
3359 int i;
3360
3361 if (sigrenderer) {
3362 for (i = 0; i < DUMB_IT_N_CHANNELS; i++)
3363 if (sigrenderer->channel[i].playing)
3364 free(sigrenderer->channel[i].playing);
3365
3366 for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++)
3367 if (sigrenderer->playing[i])
3368 free(sigrenderer->playing[i]);
3369
3370 dumb_destroy_click_remover_array(sigrenderer->n_channels, sigrenderer->click_remover);
3371
3372 if (sigrenderer->callbacks)
3373 free(sigrenderer->callbacks);
3374
3375 free(vsigrenderer);
3376 }
3377}
3378
3379
3380
3381DUH_SIGTYPE_DESC _dumb_sigtype_it = {
3382 SIGTYPE_IT,
3383 NULL,
3384 &it_start_sigrenderer,
3385 NULL,
3386 &it_sigrenderer_get_samples,
3387 &it_sigrenderer_get_current_sample,
3388 &_dumb_it_end_sigrenderer,
3389 &_dumb_it_unload_sigdata
3390};
3391
3392
3393
3394DUH_SIGRENDERER *duh_encapsulate_it_sigrenderer(DUMB_IT_SIGRENDERER *it_sigrenderer, int n_channels, long pos)
3395{
3396 return duh_encapsulate_raw_sigrenderer(it_sigrenderer, &_dumb_sigtype_it, n_channels, pos);
3397}
3398
3399
3400
3401DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer)
3402{
3403 return duh_get_raw_sigrenderer(sigrenderer, SIGTYPE_IT);
3404}
3405
3406
3407
3408/* Values of 64 or more will access NNA channels here. */
3409void dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel, DUMB_IT_CHANNEL_STATE *state)
3410{
3411 IT_PLAYING *playing;
3412 int t; /* temporary var for holding accurate pan and filter cutoff */
3413 float delta;
3414 ASSERT(channel < DUMB_IT_TOTAL_CHANNELS);
3415 if (!sr) { state->sample = 0; return; }
3416 if (channel >= DUMB_IT_N_CHANNELS) {
3417 playing = sr->playing[channel - DUMB_IT_N_CHANNELS];
3418 if (!playing) { state->sample = 0; return; }
3419 } else {
3420 playing = sr->channel[channel].playing;
3421 if (!playing) { state->sample = 0; return; }
3422 }
3423
3424 if (playing->flags & IT_PLAYING_DEAD) { state->sample = 0; return; }
3425
3426 state->channel = playing->channel - sr->channel;
3427 state->sample = playing->sampnum;
3428 state->volume = calculate_volume(sr, playing, 1.0f);
3429
3430 t = apply_pan_envelope(playing);
3431 state->pan = (unsigned char)((t + 128) >> IT_ENVELOPE_SHIFT);
3432 state->subpan = (signed char)t;
3433
3434 delta = playing->delta * 65536.0f;
3435 t = playing->filter_cutoff << IT_ENVELOPE_SHIFT;
3436 apply_pitch_modifications(sr->sigdata, playing, &delta, &t);
3437 state->freq = (int)delta;
3438 if (t == 127 << IT_ENVELOPE_SHIFT && playing->filter_resonance == 0) {
3439 state->filter_resonance = playing->true_filter_resonance;
3440 t = playing->true_filter_cutoff;
3441 } else
3442 state->filter_resonance = playing->filter_resonance;
3443 state->filter_cutoff = (unsigned char)(t >> 8);
3444 state->filter_subcutoff = (unsigned char)t;
3445}
3446
3447
3448
3449int dumb_it_callback_terminate(void *data)
3450{
3451 (void)data;
3452 return 1;
3453}
3454
3455
3456
3457int dumb_it_callback_midi_block(void *data, int channel, unsigned char byte)
3458{
3459 (void)data;
3460 (void)channel;
3461 (void)byte;
3462 return 1;
3463}
3464
3465
3466
3467#define IT_CHECKPOINT_INTERVAL (30 * 65536) /* Half a minute */
3468
3469
3470
3471/* Returns the length of the module, up until it first loops. */
3472long _dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata)
3473{
3474 IT_CHECKPOINT *checkpoint = malloc(sizeof(*checkpoint));
3475 if (!checkpoint) return 0;
3476 checkpoint->time = 0;
3477 checkpoint->sigrenderer = dumb_it_init_sigrenderer(sigdata, 0, 0);
3478 if (!checkpoint->sigrenderer) {
3479 free(checkpoint);
3480 return 0;
3481 }
3482 checkpoint->sigrenderer->callbacks->loop = &dumb_it_callback_terminate;
3483 checkpoint->sigrenderer->callbacks->xm_speed_zero = &dumb_it_callback_terminate;
3484 sigdata->checkpoint = checkpoint;
3485
3486 for (;;) {
3487 long l;
3488 DUMB_IT_SIGRENDERER *sigrenderer = dup_sigrenderer(checkpoint->sigrenderer, 0, checkpoint->sigrenderer->callbacks);
3489 checkpoint->sigrenderer->callbacks = NULL;
3490 if (!sigrenderer) {
3491 checkpoint->next = NULL;
3492 return checkpoint->time;
3493 }
3494
3495 l = it_sigrenderer_get_samples(sigrenderer, 0, 1.0f, IT_CHECKPOINT_INTERVAL, NULL);
3496 if (l < IT_CHECKPOINT_INTERVAL) {
3497 _dumb_it_end_sigrenderer(sigrenderer);
3498 checkpoint->next = NULL;
3499 return checkpoint->time + l;
3500 }
3501
3502 checkpoint->next = malloc(sizeof(*checkpoint->next));
3503 if (!checkpoint->next) {
3504 _dumb_it_end_sigrenderer(sigrenderer);
3505 return checkpoint->time + IT_CHECKPOINT_INTERVAL;
3506 }
3507
3508 checkpoint->next->time = checkpoint->time + IT_CHECKPOINT_INTERVAL;
3509 checkpoint = checkpoint->next;
3510 checkpoint->sigrenderer = sigrenderer;
3511 }
3512}
diff --git a/apps/codecs/dumb/src/it/itunload.c b/apps/codecs/dumb/src/it/itunload.c
deleted file mode 100644
index 8f282bea2e..0000000000
--- a/apps/codecs/dumb/src/it/itunload.c
+++ /dev/null
@@ -1,71 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * itunload.c - Code to free an Impulse Tracker / / \ \
12 * module from memory. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21
22#include "dumb.h"
23#include "internal/it.h"
24
25
26
27void _dumb_it_unload_sigdata(sigdata_t *vsigdata)
28{
29 if (vsigdata) {
30 DUMB_IT_SIGDATA *sigdata = vsigdata;
31 int n;
32
33 if (sigdata->order)
34 free(sigdata->order);
35
36 if (sigdata->instrument)
37 free(sigdata->instrument);
38
39 if (sigdata->sample) {
40 for (n = 0; n < sigdata->n_samples; n++) {
41 if (sigdata->sample[n].left)
42 free(sigdata->sample[n].left);
43 if (sigdata->sample[n].right)
44 free(sigdata->sample[n].right);
45 }
46 free(sigdata->sample);
47 }
48
49 if (sigdata->pattern) {
50 for (n = 0; n < sigdata->n_patterns; n++)
51 if (sigdata->pattern[n].entry)
52 free(sigdata->pattern[n].entry);
53 free(sigdata->pattern);
54 }
55
56 if (sigdata->midi)
57 free(sigdata->midi);
58
59 {
60 IT_CHECKPOINT *checkpoint = sigdata->checkpoint;
61 while (checkpoint) {
62 IT_CHECKPOINT *next = checkpoint->next;
63 _dumb_it_end_sigrenderer(checkpoint->sigrenderer);
64 free(checkpoint);
65 checkpoint = next;
66 }
67 }
68
69 free(vsigdata);
70 }
71}
diff --git a/apps/codecs/dumb/src/it/loadmod.c b/apps/codecs/dumb/src/it/loadmod.c
deleted file mode 100644
index f7bbcb50e6..0000000000
--- a/apps/codecs/dumb/src/it/loadmod.c
+++ /dev/null
@@ -1,42 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * loadmod.c - Code to read a good old-fashioned / / \ \
12 * Amiga module file, opening and | < / \_
13 * closing it for you. | \/ /\ /
14 * \_ / > /
15 * By entheh. | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include "dumb.h"
21#include "internal/it.h"
22
23
24
25/* dumb_load_mod(): loads a MOD file into a DUH struct, returning a pointer
26 * to the DUH struct. When you have finished with it, you must pass the
27 * pointer to unload_duh() so that the memory can be freed.
28 */
29DUH *dumb_load_mod(const char *filename)
30{
31 DUH *duh;
32 DUMBFILE *f = dumbfile_open(filename);
33
34 if (!f)
35 return NULL;
36
37 duh = dumb_read_mod(f);
38
39 dumbfile_close(f);
40
41 return duh;
42}
diff --git a/apps/codecs/dumb/src/it/loads3m.c b/apps/codecs/dumb/src/it/loads3m.c
deleted file mode 100644
index dfe6a9268e..0000000000
--- a/apps/codecs/dumb/src/it/loads3m.c
+++ /dev/null
@@ -1,42 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * loads3m.c - Code to read a ScreamTracker 3 / / \ \
12 * file, opening and closing it for | < / \_
13 * you. | \/ /\ /
14 * \_ / > /
15 * By entheh. | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include "dumb.h"
21#include "internal/it.h"
22
23
24
25/* dumb_load_s3m(): loads an S3M file into a DUH struct, returning a pointer
26 * to the DUH struct. When you have finished with it, you must pass the
27 * pointer to unload_duh() so that the memory can be freed.
28 */
29DUH *dumb_load_s3m(const char *filename)
30{
31 DUH *duh;
32 DUMBFILE *f = dumbfile_open(filename);
33
34 if (!f)
35 return NULL;
36
37 duh = dumb_read_s3m(f);
38
39 dumbfile_close(f);
40
41 return duh;
42}
diff --git a/apps/codecs/dumb/src/it/loadxm.c b/apps/codecs/dumb/src/it/loadxm.c
deleted file mode 100644
index 9cee06d6ee..0000000000
--- a/apps/codecs/dumb/src/it/loadxm.c
+++ /dev/null
@@ -1,42 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * loadxm.c - Code to read a Fast Tracker II / / \ \
12 * file, opening and closing it for | < / \_
13 * you. | \/ /\ /
14 * \_ / > /
15 * By entheh. | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include "dumb.h"
21#include "internal/it.h"
22
23
24
25/* dumb_load_xm(): loads an XM file into a DUH struct, returning a pointer
26 * to the DUH struct. When you have finished with it, you must pass the
27 * pointer to unload_duh() so that the memory can be freed.
28 */
29DUH *dumb_load_xm(const char *filename)
30{
31 DUH *duh;
32 DUMBFILE *f = dumbfile_open(filename);
33
34 if (!f)
35 return NULL;
36
37 duh = dumb_read_xm(f);
38
39 dumbfile_close(f);
40
41 return duh;
42}
diff --git a/apps/codecs/dumb/src/it/readmod.c b/apps/codecs/dumb/src/it/readmod.c
deleted file mode 100644
index 452c8900a4..0000000000
--- a/apps/codecs/dumb/src/it/readmod.c
+++ /dev/null
@@ -1,594 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * readmod.c - Code to read a good old-fashioned / / \ \
12 * Amiga module from an open file. | < / \_
13 * | \/ /\ /
14 * By Ben Davis. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21#include <string.h>
22#include <math.h>
23
24#include "dumb.h"
25#include "internal/it.h"
26
27
28
29static int it_mod_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer)
30{
31 int pos;
32 int channel;
33 int row;
34 IT_ENTRY *entry;
35
36 pattern->n_rows = 64;
37
38 if (n_channels == 0) {
39 /* Read the first four channels, leaving gaps for the rest. */
40 for (pos = 0; pos < 64*8*4; pos += 8*4)
41 dumbfile_getnc(buffer + pos, 4*4, f);
42 /* Read the other channels into the gaps we left. */
43 for (pos = 4*4; pos < 64*8*4; pos += 8*4)
44 dumbfile_getnc(buffer + pos, 4*4, f);
45
46 n_channels = 8;
47 } else
48 dumbfile_getnc(buffer, 64 * n_channels * 4, f);
49
50 if (dumbfile_error(f))
51 return -1;
52
53 /* compute number of entries */
54 pattern->n_entries = 64; /* Account for the row end markers */
55 pos = 0;
56 for (row = 0; row < 64; row++) {
57 for (channel = 0; channel < n_channels; channel++) {
58 if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3])
59 pattern->n_entries++;
60 pos += 4;
61 }
62 }
63
64 pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
65 if (!pattern->entry)
66 return -1;
67
68 entry = pattern->entry;
69 pos = 0;
70 for (row = 0; row < 64; row++) {
71 for (channel = 0; channel < n_channels; channel++) {
72 if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3]) {
73 unsigned char sample = (buffer[pos+0] & 0xF0) | (buffer[pos+2] >> 4);
74 int period = ((int)(buffer[pos+0] & 0x0F) << 8) | buffer[pos+1];
75
76 entry->channel = channel;
77 entry->mask = 0;
78
79 if (period) {
80 int note;
81 entry->mask |= IT_ENTRY_NOTE;
82
83 /* frequency = (AMIGA_DIVISOR / 8) / (period * 2)
84 * C-1: period = 214 -> frequency = 16726
85 * so, set C5_speed to 16726
86 * and period = 214 should translate to C5 aka 60
87 * halve the period, go up an octive
88 *
89 * period = 214 / pow(DUMB_SEMITONE_BASE, note - 60)
90 * pow(DUMB_SEMITONE_BASE, note - 60) = 214 / period
91 * note - 60 = log(214/period) / log(DUMB_SEMITONE_BASE)
92 */
93 note = (int)floor(log(214.0/period) / log(DUMB_SEMITONE_BASE) + 60.5);
94 entry->note = MID(0, note, 119);
95 // or should we preserve the period?
96 //entry->note = buffer[pos+0] & 0x0F; /* High nibble */
97 //entry->volpan = buffer[pos+1]; /* Low byte */
98 // and what about finetune?
99 }
100
101 if (sample) {
102 entry->mask |= IT_ENTRY_INSTRUMENT;
103 entry->instrument = sample;
104 }
105
106 _dumb_it_xm_convert_effect(buffer[pos+2] & 0x0F, buffer[pos+3], entry);
107
108 entry++;
109 }
110 pos += 4;
111 }
112 IT_SET_END_ROW(entry);
113 entry++;
114 }
115
116 return 0;
117}
118
119
120
121/* This function does not skip the name (22 bytes); it is assumed the caller
122 * has already done that.
123 */
124static int it_mod_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
125{
126 int finetune;
127
128/**
129 21 22 Chars Sample 1 name. If the name is not a full
130 22 chars in length, it will be null
131 terminated.
132
133If
134the sample name begins with a '#' character (ASCII $23 (35)) then this is
135assumed not to be an instrument name, and is probably a message.
136*/
137 sample->length = dumbfile_mgetw(f) << 1;
138 finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
139/** Each finetune step changes the note 1/8th of a semitone. */
140 sample->global_volume = 64;
141 sample->default_volume = dumbfile_getc(f); // Should we be setting global_volume to this instead?
142 sample->loop_start = dumbfile_mgetw(f) << 1;
143 sample->loop_end = sample->loop_start + (dumbfile_mgetw(f) << 1);
144/**
145Once this sample has been played completely from beginning
146to end, if the repeat length (next field) is greater than two bytes it
147will loop back to this position in the sample and continue playing. Once
148it has played for the repeat length, it continues to loop back to the
149repeat start offset. This means the sample continues playing until it is
150told to stop.
151*/
152
153 if (sample->length <= 0) {
154 sample->flags = 0;
155 return 0;
156 }
157
158 sample->flags = IT_SAMPLE_EXISTS;
159
160 sample->default_pan = 0;
161 sample->C5_speed = (long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
162 // the above line might be wrong
163
164 if (sample->loop_end > sample->length)
165 sample->loop_end = sample->length;
166
167 if (sample->loop_end - sample->loop_start > 2)
168 sample->flags |= IT_SAMPLE_LOOP;
169
170 sample->vibrato_speed = 0;
171 sample->vibrato_depth = 0;
172 sample->vibrato_rate = 0;
173 sample->vibrato_waveform = 0; // do we have to set _all_ these?
174
175 return dumbfile_error(f);
176}
177
178
179
180static int it_mod_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f)
181{
182 long i;
183 long truncated_size;
184
185 /* let's get rid of the sample data coming after the end of the loop */
186 if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
187 truncated_size = sample->length - sample->loop_end;
188 sample->length = sample->loop_end;
189 } else {
190 truncated_size = 0;
191 }
192
193 sample->left = malloc(sample->length * sizeof(*sample->left));
194
195 if (!sample->left)
196 return -1;
197
198 /* Sample data are stored in "8-bit two's compliment format" (sic). */
199 for (i = 0; i < sample->length; i++)
200 sample->left[i] = (int)(signed char)dumbfile_getc(f) << 16;
201
202 /* skip truncated data */
203 dumbfile_skip(f, truncated_size);
204 // Should we be truncating it?
205
206 if (dumbfile_error(f))
207 return -1;
208
209 return 0;
210}
211
212
213
214typedef struct BUFFERED_MOD BUFFERED_MOD;
215
216struct BUFFERED_MOD
217{
218 unsigned char *buffered;
219 long ptr, len;
220 DUMBFILE *remaining;
221};
222
223
224
225static int buffer_mod_skip(void *f, long n)
226{
227 BUFFERED_MOD *bm = f;
228 if (bm->buffered) {
229 bm->ptr += n;
230 if (bm->ptr >= bm->len) {
231 free(bm->buffered);
232 bm->buffered = NULL;
233 return dumbfile_skip(bm->remaining, bm->ptr - bm->len);
234 }
235 return 0;
236 }
237 return dumbfile_skip(bm->remaining, n);
238}
239
240
241
242static int buffer_mod_getc(void *f)
243{
244 BUFFERED_MOD *bm = f;
245 if (bm->buffered) {
246 int rv = bm->buffered[bm->ptr++];
247 if (bm->ptr >= bm->len) {
248 free(bm->buffered);
249 bm->buffered = NULL;
250 }
251 return rv;
252 }
253 return dumbfile_getc(bm->remaining);
254}
255
256
257
258static long buffer_mod_getnc(char *ptr, long n, void *f)
259{
260 BUFFERED_MOD *bm = f;
261 if (bm->buffered) {
262 int left = bm->len - bm->ptr;
263 if (n >= left) {
264 int rv;
265 memcpy(ptr, bm->buffered + bm->ptr, left);
266 free(bm->buffered);
267 bm->buffered = NULL;
268 rv = dumbfile_getnc(ptr + left, n - left, bm->remaining);
269 return left + MAX(rv, 0);
270 }
271 memcpy(ptr, bm->buffered + bm->ptr, n);
272 bm->ptr += n;
273 return n;
274 }
275 return dumbfile_getnc(ptr, n, bm->remaining);
276}
277
278
279
280static void buffer_mod_close(void *f)
281{
282 BUFFERED_MOD *bm = f;
283 if (bm->buffered) free(bm->buffered);
284 /* Do NOT close bm->remaining */
285 free(f);
286}
287
288
289
290DUMBFILE_SYSTEM buffer_mod_dfs = {
291 NULL,
292 &buffer_mod_skip,
293 &buffer_mod_getc,
294 &buffer_mod_getnc,
295 &buffer_mod_close
296};
297
298
299
300#define MOD_FFT_OFFSET (20 + 31*(22+2+1+1+2+2) + 1 + 1 + 128)
301
302static DUMBFILE *dumbfile_buffer_mod(DUMBFILE *f, unsigned long *fft)
303{
304 BUFFERED_MOD *bm = malloc(sizeof(*bm));
305 if (!bm) return NULL;
306
307 bm->buffered = malloc(MOD_FFT_OFFSET + 4);
308 if (!bm->buffered) {
309 free(bm);
310 return NULL;
311 }
312
313 bm->len = dumbfile_getnc(bm->buffered, MOD_FFT_OFFSET + 4, f);
314
315 if (bm->len > 0) {
316 if (bm->len >= MOD_FFT_OFFSET + 4)
317 *fft = (unsigned long)bm->buffered[MOD_FFT_OFFSET ] << 24
318 | (unsigned long)bm->buffered[MOD_FFT_OFFSET+1] << 16
319 | (unsigned long)bm->buffered[MOD_FFT_OFFSET+2] << 8
320 | (unsigned long)bm->buffered[MOD_FFT_OFFSET+3];
321 else
322 *fft = 0;
323 bm->ptr = 0;
324 } else {
325 free(bm->buffered);
326 bm->buffered = NULL;
327 }
328
329 bm->remaining = f;
330
331 return dumbfile_open_ex(bm, &buffer_mod_dfs);
332}
333
334
335
336static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f)
337{
338 DUMB_IT_SIGDATA *sigdata;
339 int n_channels;
340 int i;
341 unsigned long fft;
342
343 f = dumbfile_buffer_mod(f, &fft);
344 if (!f)
345 return NULL;
346
347 /**
348 1 20 Chars Title of the song. If the title is not a
349 full 20 chars in length, it will be null-
350 terminated.
351 */
352 if (dumbfile_skip(f, 20)) {
353 dumbfile_close(f);
354 return NULL;
355 }
356
357 sigdata = malloc(sizeof(*sigdata));
358 if (!sigdata) {
359 dumbfile_close(f);
360 return NULL;
361 }
362
363 sigdata->n_samples = 31;
364
365 switch (fft) {
366 case DUMB_ID('M','.','K','.'):
367 case DUMB_ID('M','!','K','!'):
368 case DUMB_ID('M','&','K','!'):
369 case DUMB_ID('N','.','T','.'):
370 case DUMB_ID('F','L','T','4'):
371 n_channels = 4;
372 break;
373 case DUMB_ID('F','L','T','8'):
374 n_channels = 0;
375 /* 0 indicates a special case; two four-channel patterns must be
376 * combined into one eight-channel pattern. Pattern indexes must
377 * be halved. Why oh why do they obfuscate so?
378 */
379 for (i = 0; i < 128; i++)
380 sigdata->order[i] >>= 1;
381 break;
382 case DUMB_ID('C','D','8','1'):
383 case DUMB_ID('O','C','T','A'):
384 case DUMB_ID('O','K','T','A'):
385 n_channels = 8;
386 break;
387 case DUMB_ID('1','6','C','N'):
388 n_channels = 16;
389 break;
390 case DUMB_ID('3','2','C','N'):
391 n_channels = 32;
392 break;
393 default:
394 /* If we get an illegal tag, assume 4 channels 15 samples. */
395 if ((fft & 0x0000FFFFL) == DUMB_ID(0,0,'C','H')) {
396 if (fft >= '1' << 24 && fft < '4' << 24) {
397 n_channels = ((fft & 0x00FF0000L) >> 16) - '0';
398 if ((unsigned int)n_channels >= 10) {
399 /* Rightmost character wasn't a digit. */
400 n_channels = 4;
401 sigdata->n_samples = 15;
402 } else {
403 n_channels += (((fft & 0xFF000000L) >> 24) - '0') * 10;
404 /* MODs should really only go up to 32 channels, but we're lenient. */
405 if ((unsigned int)(n_channels - 1) >= DUMB_IT_N_CHANNELS - 1) {
406 /* No channels or too many? Can't be right... */
407 n_channels = 4;
408 sigdata->n_samples = 15;
409 }
410 }
411 } else {
412 n_channels = 4;
413 sigdata->n_samples = 15;
414 }
415 } else if ((fft & 0x00FFFFFFL) == DUMB_ID(0,'C','H','N')) {
416 n_channels = (fft >> 24) - '0';
417 if ((unsigned int)(n_channels - 1) >= 9) {
418 /* Character was '0' or it wasn't a digit */
419 n_channels = 4;
420 sigdata->n_samples = 15;
421 }
422 } else if ((fft & 0xFFFFFF00L) == DUMB_ID('T','D','Z',0)) {
423 n_channels = (fft & 0x000000FFL) - '0';
424 if ((unsigned int)(n_channels - 1) >= 9) {
425 /* We've been very lenient, given that it should have
426 * been 1, 2 or 3, but this MOD has been very naughty and
427 * must be punished.
428 */
429 n_channels = 4;
430 sigdata->n_samples = 15;
431 }
432 } else {
433 n_channels = 4;
434 sigdata->n_samples = 15;
435 }
436 }
437
438 sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
439 if (!sigdata->sample) {
440 free(sigdata);
441 dumbfile_close(f);
442 return NULL;
443 }
444
445 sigdata->order = NULL;
446 sigdata->instrument = NULL;
447 sigdata->pattern = NULL;
448 sigdata->midi = NULL;
449 sigdata->checkpoint = NULL;
450
451 for (i = 0; i < sigdata->n_samples; i++)
452 sigdata->sample[i].right = sigdata->sample[i].left = NULL;
453
454 for (i = 0; i < sigdata->n_samples; i++) {
455 if (dumbfile_skip(f, 22) ||
456 it_mod_read_sample_header(&sigdata->sample[i], f))
457 {
458 _dumb_it_unload_sigdata(sigdata);
459 dumbfile_close(f);
460 return NULL;
461 }
462 }
463
464 sigdata->n_orders = dumbfile_getc(f);
465 sigdata->restart_position = dumbfile_getc(f);
466 // what if this is >= 127? what about with Fast Tracker II?
467
468 if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
469 _dumb_it_unload_sigdata(sigdata);
470 dumbfile_close(f);
471 return NULL;
472 }
473
474 //if (sigdata->restart_position >= sigdata->n_orders)
475 //sigdata->restart_position = 0;
476
477 sigdata->order = malloc(128); /* We may need to scan the extra ones! */
478 if (!sigdata->order) {
479 _dumb_it_unload_sigdata(sigdata);
480 dumbfile_close(f);
481 return NULL;
482 }
483 if (dumbfile_getnc(sigdata->order, 128, f) < 128) {
484 _dumb_it_unload_sigdata(sigdata);
485 dumbfile_close(f);
486 return NULL;
487 }
488
489 /* "The old NST format contains only 15 samples (instead of 31). Further
490 * it doesn't contain a file format tag (id). So Pattern data offset is
491 * at 20+15*30+1+1+128."
492 * - Then I shall assume the File Format Tag never exists if there are
493 * only 15 samples. I hope this isn't a faulty assumption...
494 */
495 if (sigdata->n_samples == 31)
496 dumbfile_skip(f, 4);
497
498 /* Work out how many patterns there are. */
499 sigdata->n_patterns = -1;
500 for (i = 0; i < 128; i++)
501 if (sigdata->n_patterns < sigdata->order[i])
502 sigdata->n_patterns = sigdata->order[i];
503 sigdata->n_patterns++;
504
505 /* May as well try to save a tiny bit of memory. */
506 if (sigdata->n_orders < 128) {
507 unsigned char *order = realloc(sigdata->order, sigdata->n_orders);
508 if (order) sigdata->order = order;
509 }
510
511 sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
512 if (!sigdata->pattern) {
513 _dumb_it_unload_sigdata(sigdata);
514 dumbfile_close(f);
515 return NULL;
516 }
517 for (i = 0; i < sigdata->n_patterns; i++)
518 sigdata->pattern[i].entry = NULL;
519
520 /* Read in the patterns */
521 {
522 unsigned char *buffer = malloc(256 * n_channels); /* 64 rows * 4 bytes */
523 if (!buffer) {
524 _dumb_it_unload_sigdata(sigdata);
525 dumbfile_close(f);
526 return NULL;
527 }
528 for (i = 0; i < sigdata->n_patterns; i++) {
529 if (it_mod_read_pattern(&sigdata->pattern[i], f, n_channels, buffer) != 0) {
530 free(buffer);
531 _dumb_it_unload_sigdata(sigdata);
532 dumbfile_close(f);
533 return NULL;
534 }
535 }
536 free(buffer);
537 }
538
539 /* And finally, the sample data */
540 for (i = 0; i < sigdata->n_samples; i++) {
541 if (it_mod_read_sample_data(&sigdata->sample[i], f)) {
542 _dumb_it_unload_sigdata(sigdata);
543 dumbfile_close(f);
544 return NULL;
545 }
546 }
547
548 dumbfile_close(f); /* Destroy the BUFFERED_MOD DUMBFILE we were using. */
549 /* The DUMBFILE originally passed to our function is intact. */
550
551 /* Now let's initialise the remaining variables, and we're done! */
552 sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
553
554 sigdata->global_volume = 128;
555 sigdata->mixing_volume = 48;
556 /* We want 50 ticks per second; 50/6 row advances per second;
557 * 50*10=500 row advances per minute; 500/4=125 beats per minute.
558 */
559 sigdata->speed = 6;
560 sigdata->tempo = 125;
561 sigdata->pan_separation = 128;
562
563 memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
564
565 for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
566 sigdata->channel_pan[i+0] = 16;
567 sigdata->channel_pan[i+1] = 48;
568 sigdata->channel_pan[i+2] = 48;
569 sigdata->channel_pan[i+3] = 16;
570 }
571
572 _dumb_it_fix_invalid_orders(sigdata);
573
574 return sigdata;
575}
576
577
578
579DUH *dumb_read_mod(DUMBFILE *f)
580{
581 sigdata_t *sigdata;
582 long length;
583
584 DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
585
586 sigdata = it_mod_load_sigdata(f);
587
588 if (!sigdata)
589 return NULL;
590
591 length = _dumb_it_build_checkpoints(sigdata);
592
593 return make_duh(length, 1, &descptr, &sigdata);
594}
diff --git a/apps/codecs/dumb/src/it/reads3m.c b/apps/codecs/dumb/src/it/reads3m.c
deleted file mode 100644
index 22152c8ff9..0000000000
--- a/apps/codecs/dumb/src/it/reads3m.c
+++ /dev/null
@@ -1,668 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * reads3m.c - Code to read a ScreamTracker 3 / / \ \
12 * module from an open file. | < / \_
13 * | \/ /\ /
14 * By entheh. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20// IT_STEREO... :o
21#include <stdlib.h>
22#include <string.h>
23
24#include "dumb.h"
25#include "internal/it.h"
26
27
28
29/** WARNING: this is duplicated in itread.c */
30static int it_seek(DUMBFILE *f, long offset)
31{
32 long pos = dumbfile_pos(f);
33
34 if (pos > offset)
35 return -1;
36
37 if (pos < offset)
38 if (dumbfile_skip(f, offset - pos))
39 return -1;
40
41 return 0;
42}
43
44
45
46static int it_s3m_read_sample_header(IT_SAMPLE *sample, long *offset, DUMBFILE *f)
47{
48 unsigned char type;
49 int flags;
50
51 type = dumbfile_getc(f);
52
53 if (type > 1) {
54 /** WARNING: no adlib support */
55 }
56
57 /* Skip DOS Filename */
58 dumbfile_skip(f, 13);
59
60 *offset = dumbfile_igetw(f) << 4;
61
62 sample->length = dumbfile_igetl(f);
63 sample->loop_start = dumbfile_igetl(f);
64 sample->loop_end = dumbfile_igetl(f);
65
66 sample->default_volume = dumbfile_getc(f);
67
68 dumbfile_skip(f, 1);
69
70 if (dumbfile_getc(f) != 0)
71 /* Sample is packed apparently (or error reading from file). We don't
72 * know how to read packed samples.
73 */
74 return -1;
75
76 flags = dumbfile_getc(f);
77
78 sample->C5_speed = dumbfile_igetl(f) << 1;
79
80 /* Skip four unused bytes, three internal variables and sample name. */
81 dumbfile_skip(f, 4+2+2+4+28);
82
83 if (type == 0) {
84 /* Looks like no-existy. Anyway, there's for sure no 'SCRS'... */
85 sample->flags &= ~IT_SAMPLE_EXISTS;
86 return dumbfile_error(f);
87 }
88
89 if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','S'))
90 return -1;
91
92 sample->global_volume = 64;
93
94 sample->flags = IT_SAMPLE_EXISTS;
95 if (flags & 1) sample->flags |= IT_SAMPLE_LOOP;
96 if (flags & 2) sample->flags |= IT_SAMPLE_STEREO;
97 if (flags & 4) sample->flags |= IT_SAMPLE_16BIT;
98
99 sample->default_pan = 0; // 0 = don't use, or 160 = centre?
100
101 if (sample->length <= 0)
102 sample->flags &= ~IT_SAMPLE_EXISTS;
103 else if (sample->flags & IT_SAMPLE_LOOP) {
104 if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
105 sample->flags &= ~IT_SAMPLE_LOOP;
106 else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
107 sample->flags &= ~IT_SAMPLE_LOOP;
108 else
109 /* ScreamTracker seems not to save what comes after the loop end
110 * point, but rather to assume it is a duplicate of what comes at
111 * the loop start point. I am not completely sure of this though.
112 * It is easy to evade; simply truncate the sample.
113 */
114 sample->length = sample->loop_end;
115 }
116
117
118 //Do we need to set all these?
119 sample->vibrato_speed = 0;
120 sample->vibrato_depth = 0;
121 sample->vibrato_rate = 0;
122 sample->vibrato_waveform = IT_VIBRATO_SINE;
123
124 return dumbfile_error(f);
125}
126
127
128
129static int it_s3m_read_sample_data(IT_SAMPLE *sample, int ffi, DUMBFILE *f)
130{
131 long n;
132
133 sample->left = malloc(sample->length * sizeof(*sample->left));
134 if (!sample->left)
135 return -1;
136
137 if (sample->flags & IT_SAMPLE_STEREO) {
138 sample->right = malloc(sample->length * sizeof(*sample->right));
139 if (!sample->right)
140 return -1;
141 }
142
143 if (sample->flags & IT_SAMPLE_STEREO) {
144 if (sample->flags & IT_SAMPLE_16BIT) {
145 for (n = 0; n < sample->length; n++)
146 sample->left[n] = (int)(signed short)dumbfile_igetw(f) << 8;
147 for (n = 0; n < sample->length; n++)
148 sample->right[n] = (int)(signed short)dumbfile_igetw(f) << 8;
149 } else {
150 for (n = 0; n < sample->length; n++)
151 sample->left[n] = (int)(signed char)dumbfile_getc(f) << 16;
152 for (n = 0; n < sample->length; n++)
153 sample->right[n] = (int)(signed char)dumbfile_getc(f) << 16;
154 }
155 } else if (sample->flags & IT_SAMPLE_16BIT)
156 for (n = 0; n < sample->length; n++)
157 sample->left[n] = (int)(signed short)dumbfile_igetw(f) << 8;
158 else
159 for (n = 0; n < sample->length; n++)
160 sample->left[n] = (int)(signed char)dumbfile_getc(f) << 16;
161
162 if (dumbfile_error(f))
163 return -1;
164
165 if (ffi != 1) {
166 /* Convert to signed. */
167 for (n = 0; n < sample->length; n++)
168 sample->left[n] ^= 0xFF800000;
169
170 if (sample->right)
171 for (n = 0; n < sample->length; n++)
172 sample->right[n] ^= 0xFF800000;
173 }
174
175 return 0;
176}
177
178
179
180static int it_s3m_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer)
181{
182 int buflen = 0;
183 int bufpos = 0;
184
185 IT_ENTRY *entry;
186
187 unsigned char channel;
188
189 /* Haha, this is hilarious!
190 *
191 * Well, after some experimentation, it seems that different S3M writers
192 * define the format in different ways. The S3M docs say that the first
193 * two bytes hold the "length of [the] packed pattern", and the packed
194 * pattern data follow. Judging by the contents of ARMANI.S3M, packaged
195 * with ScreamTracker itself, the measure of length _includes_ the two
196 * bytes used to store the length; in other words, we should read
197 * (length - 2) more bytes. However, aryx.s3m, packaged with ModPlug
198 * Tracker, excludes these two bytes, so (length) more bytes must be
199 * read.
200 *
201 * Call me crazy, but I just find it insanely funny that the format was
202 * misunderstood in this way :D
203 *
204 * Now we can't just risk reading two extra bytes, because then we
205 * overshoot, and DUMBFILEs don't support backward seeking (for a good
206 * reason). Luckily, there is a way. We can read the data little by
207 * little, and stop when we have 64 rows in memory. Provided we protect
208 * against buffer overflow, this method should work with all sensibly
209 * written S3M files. If you find one for which it does not work, please
210 * let me know at entheh@users.sf.net so I can look at it.
211 */
212
213 /* Discard the length. */
214 dumbfile_skip(f, 2);
215
216 if (dumbfile_error(f))
217 return -1;
218
219 pattern->n_rows = 0;
220 pattern->n_entries = 0;
221
222 /* Read in the pattern data, little by little, and work out how many
223 * entries we need room for. Sorry, but this is just so funny...
224 */
225 for (;;) {
226 unsigned char b = buffer[buflen++] = dumbfile_getc(f);
227
228#if 1
229 static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5};
230 channel = b & 31;
231 b >>= 5;
232 pattern->n_entries++;
233 if (b) {
234 if (buflen + (signed char)used[b] >= 65536) return -1;
235 dumbfile_getnc((char *)buffer + buflen, used[b], f);
236 buflen += used[b];
237 } else {
238 /* End of row */
239 if (++pattern->n_rows == 64) break;
240 if (buflen >= 65536) return -1;
241 }
242#else
243 if (b == 0) {
244 /* End of row */
245 pattern->n_entries++;
246 if (++pattern->n_rows == 64) break;
247 if (buflen >= 65536) return -1;
248 } else {
249 static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5};
250 channel = b & 31;
251 b >>= 5;
252 if (b) {
253 pattern->n_entries++;
254 if (buflen + used[b] >= 65536) return -1;
255 dumbfile_getnc(buffer + buflen, used[b], f);
256 buflen += used[b];
257 }
258 }
259#endif
260
261 /* We have ensured that buflen < 65536 at this point, so it is safe
262 * to iterate and read at least one more byte without checking.
263 * However, now would be a good time to check for errors reading from
264 * the file.
265 */
266
267 if (dumbfile_error(f))
268 return -1;
269 }
270
271 pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
272
273 if (!pattern->entry)
274 return -1;
275
276 entry = pattern->entry;
277
278 while (bufpos < buflen) {
279 unsigned char b = buffer[bufpos++];
280
281#if 1
282 if (!(b & ~31))
283#else
284 if (b == 0)
285#endif
286 {
287 /* End of row */
288 IT_SET_END_ROW(entry);
289 entry++;
290 continue;
291 }
292
293 channel = b & 31;
294
295 if (b & 224) {
296 entry->mask = 0;
297 entry->channel = channel;
298
299 if (b & 32) {
300 unsigned char n = buffer[bufpos++];
301 if (n != 255) {
302 if (n == 254)
303 entry->note = IT_NOTE_CUT;
304 else
305 entry->note = (n >> 4) * 12 + (n & 15);
306 entry->mask |= IT_ENTRY_NOTE;
307 }
308
309 entry->instrument = buffer[bufpos++];
310 if (entry->instrument)
311 entry->mask |= IT_ENTRY_INSTRUMENT;
312 }
313
314 if (b & 64) {
315 entry->volpan = buffer[bufpos++];
316 if (entry->volpan != 255)
317 entry->mask |= IT_ENTRY_VOLPAN;
318 }
319
320 if (b & 128) {
321 entry->effect = buffer[bufpos++];
322 entry->effectvalue = buffer[bufpos++];
323 if (entry->effect != 255) {
324 entry->mask |= IT_ENTRY_EFFECT;
325 if (entry->effect == IT_BREAK_TO_ROW)
326 entry->effectvalue -= (entry->effectvalue >> 4) * 6;
327 }
328 /** WARNING: ARGH! CONVERT TEH EFFECTS!@~ */
329 }
330
331 entry++;
332 }
333 }
334
335 ASSERT(entry == pattern->entry + pattern->n_entries);
336
337 return 0;
338}
339
340
341
342/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */
343/* Currently we assume the sample data are stored after the sample headers in
344 * module files. This assumption may be unjustified; let me know if you have
345 * trouble.
346 */
347
348#define IT_COMPONENT_INSTRUMENT 1
349#define IT_COMPONENT_PATTERN 2
350#define IT_COMPONENT_SAMPLE 3
351
352typedef struct IT_COMPONENT
353{
354 unsigned char type;
355 unsigned char n;
356 long offset;
357 short sampfirst; /* component[sampfirst] = first sample data after this */
358 short sampnext; /* sampnext is used to create linked lists of sample data */
359}
360IT_COMPONENT;
361
362
363
364static int it_component_compare(const void *e1, const void *e2)
365{
366 return ((const IT_COMPONENT *)e1)->offset -
367 ((const IT_COMPONENT *)e2)->offset;
368}
369
370
371
372static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f)
373{
374 DUMB_IT_SIGDATA *sigdata;
375
376 int flags, cwtv, ffi;
377 int default_pan_present;
378
379 IT_COMPONENT *component;
380 int n_components = 0;
381
382 int n;
383
384 unsigned char *buffer;
385
386 /* Skip song name. */
387 if (dumbfile_skip(f, 28)) return NULL;
388
389 if (dumbfile_getc(f) != 0x1A) return NULL;
390 if (dumbfile_getc(f) != 16) return NULL;
391
392 if (dumbfile_skip(f, 2)) return NULL;
393
394 sigdata = malloc(sizeof(*sigdata));
395
396 if (!sigdata)
397 return NULL;
398
399 sigdata->order = NULL;
400 sigdata->instrument = NULL;
401 sigdata->sample = NULL;
402 sigdata->pattern = NULL;
403 sigdata->midi = NULL;
404 sigdata->checkpoint = NULL;
405
406 sigdata->n_orders = dumbfile_igetw(f);
407 sigdata->n_instruments = 0;
408 sigdata->n_samples = dumbfile_igetw(f);
409 sigdata->n_patterns = dumbfile_igetw(f);
410
411 if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 256 || sigdata->n_patterns > 256) {
412 _dumb_it_unload_sigdata(sigdata);
413 return NULL;
414 }
415
416 sigdata->order = malloc(sigdata->n_orders);
417 if (!sigdata->order) {
418 _dumb_it_unload_sigdata(sigdata);
419 return NULL;
420 }
421
422 if (sigdata->n_samples) {
423 sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
424 if (!sigdata->sample) {
425 _dumb_it_unload_sigdata(sigdata);
426 return NULL;
427 }
428 for (n = 0; n < sigdata->n_samples; n++)
429 sigdata->sample[n].right = sigdata->sample[n].left = NULL;
430 }
431
432 if (sigdata->n_patterns) {
433 sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
434 if (!sigdata->pattern) {
435 _dumb_it_unload_sigdata(sigdata);
436 return NULL;
437 }
438 for (n = 0; n < sigdata->n_patterns; n++)
439 sigdata->pattern[n].entry = NULL;
440 }
441
442 flags = dumbfile_igetw(f);
443
444 cwtv = dumbfile_igetw(f);
445
446 if (cwtv == 0x1300) {
447 /** WARNING: volume slides on every frame */
448 }
449
450 ffi = dumbfile_igetw(f);
451
452 /** WARNING: which ones? */
453 sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
454
455 if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','M')) {
456 _dumb_it_unload_sigdata(sigdata);
457 return NULL;
458 }
459
460 sigdata->global_volume = dumbfile_getc(f) << 1;
461 sigdata->speed = dumbfile_getc(f);
462 if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
463 sigdata->tempo = dumbfile_getc(f);
464 /*master_volume = */dumbfile_getc(f); // 7 bits; +128 for stereo
465 //what do we do with master_volume? it's not the same as mixing volume...
466 sigdata->mixing_volume = 48;
467
468 /* Skip GUS Ultra Click Removal byte. */
469 dumbfile_getc(f);
470
471 default_pan_present = dumbfile_getc(f);
472
473 dumbfile_skip(f, 8);
474
475 /* Skip Special Custom Data Pointer. */
476 /** WARNING: investigate this? */
477 dumbfile_igetw(f);
478
479 /* Channel settings for 32 channels, 255=unused, +128=disabled */
480 {
481 int i;
482 for (i = 0; i < 32; i++) {
483 int c = dumbfile_getc(f);
484 if (!(c & (128 | 16))) { /* +128=disabled, +16=Adlib */
485 sigdata->channel_volume[i] = 64;
486 sigdata->channel_pan[i] = c & 8 ? 12 : 3;
487 /** WARNING: ah, but it should be 7 for mono... */
488 } else {
489 /** WARNING: this could be improved if we support channel muting... */
490 sigdata->channel_volume[i] = 0;
491 sigdata->channel_pan[i] = 7;
492 }
493 }
494 }
495
496 /* Orders, byte each, length = sigdata->n_orders (should be even) */
497 dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f);
498 sigdata->restart_position = 0;
499
500 component = malloc(768*sizeof(*component));
501 if (!component) {
502 _dumb_it_unload_sigdata(sigdata);
503 return NULL;
504 }
505
506 for (n = 0; n < sigdata->n_samples; n++) {
507 component[n_components].type = IT_COMPONENT_SAMPLE;
508 component[n_components].n = n;
509 component[n_components].offset = dumbfile_igetw(f) << 4;
510 component[n_components].sampfirst = -1;
511 n_components++;
512 }
513
514 for (n = 0; n < sigdata->n_patterns; n++) {
515 long offset = dumbfile_igetw(f) << 4;
516 if (offset) {
517 component[n_components].type = IT_COMPONENT_PATTERN;
518 component[n_components].n = n;
519 component[n_components].offset = offset;
520 component[n_components].sampfirst = -1;
521 n_components++;
522 } else {
523 /** WARNING: Empty 64-row pattern ... ? (this does happen!) */
524 sigdata->pattern[n].n_rows = 64;
525 sigdata->pattern[n].n_entries = 0;
526 }
527 }
528
529 qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare);
530
531 /* I found a really dumb S3M file that claimed to contain default pan
532 * data but didn't contain any. Programs would load it by reading part of
533 * the first instrument header, assuming the data to be default pan
534 * positions, and then rereading the instrument module. We cannot do this
535 * without obfuscating the file input model, so we insert an extra check
536 * here that we won't overrun the start of the first component.
537 */
538 if (default_pan_present == 252 && component[0].offset >= dumbfile_pos(f) + 32) {
539 /* Channel default pan positions */
540 int i;
541 for (i = 0; i < 32; i++) {
542 int c = dumbfile_getc(f);
543 if (c & 32)
544 sigdata->channel_pan[i] = c & 15;
545 }
546 }
547
548 {
549 int i;
550 for (i = 0; i < 32; i++) {
551 sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3;
552 sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7;
553 }
554 }
555
556 /** WARNING: is this right? */
557 sigdata->pan_separation = 64;
558
559 if (dumbfile_error(f)) {
560 free(component);
561 _dumb_it_unload_sigdata(sigdata);
562 return NULL;
563 }
564
565 buffer = malloc(65536);
566 if (!buffer) {
567 free(component);
568 _dumb_it_unload_sigdata(sigdata);
569 return NULL;
570 }
571
572 for (n = 0; n < n_components; n++) {
573 long offset;
574 int m;
575
576 if (it_seek(f, component[n].offset)) {
577 free(buffer);
578 free(component);
579 _dumb_it_unload_sigdata(sigdata);
580 return NULL;
581 }
582
583 switch (component[n].type) {
584
585 case IT_COMPONENT_PATTERN:
586 if (it_s3m_read_pattern(&sigdata->pattern[component[n].n], f, buffer)) {
587 free(buffer);
588 free(component);
589 _dumb_it_unload_sigdata(sigdata);
590 return NULL;
591 }
592 break;
593
594 case IT_COMPONENT_SAMPLE:
595 if (it_s3m_read_sample_header(&sigdata->sample[component[n].n], &offset, f)) {
596 free(buffer);
597 free(component);
598 _dumb_it_unload_sigdata(sigdata);
599 return NULL;
600 }
601
602 if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) {
603 short *sample;
604
605 for (m = n + 1; m < n_components; m++)
606 if (component[m].offset > offset)
607 break;
608 m--;
609
610 sample = &component[m].sampfirst;
611
612 while (*sample >= 0 && component[*sample].offset <= offset)
613 sample = &component[*sample].sampnext;
614
615 component[n].sampnext = *sample;
616 *sample = n;
617
618 component[n].offset = offset;
619 }
620 }
621
622 m = component[n].sampfirst;
623
624 while (m >= 0) {
625 if (it_seek(f, component[m].offset)) {
626 free(buffer);
627 free(component);
628 _dumb_it_unload_sigdata(sigdata);
629 return NULL;
630 }
631
632 if (it_s3m_read_sample_data(&sigdata->sample[component[m].n], ffi, f)) {
633 free(buffer);
634 free(component);
635 _dumb_it_unload_sigdata(sigdata);
636 return NULL;
637 }
638
639 m = component[m].sampnext;
640 }
641 }
642
643 free(buffer);
644 free(component);
645
646 _dumb_it_fix_invalid_orders(sigdata);
647
648 return sigdata;
649}
650
651
652
653DUH *dumb_read_s3m(DUMBFILE *f)
654{
655 sigdata_t *sigdata;
656 long length;
657
658 DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
659
660 sigdata = it_s3m_load_sigdata(f);
661
662 if (!sigdata)
663 return NULL;
664
665 length = _dumb_it_build_checkpoints(sigdata);
666
667 return make_duh(length, 1, &descptr, &sigdata);
668}
diff --git a/apps/codecs/dumb/src/it/readxm.c b/apps/codecs/dumb/src/it/readxm.c
deleted file mode 100644
index 2aeda1fa67..0000000000
--- a/apps/codecs/dumb/src/it/readxm.c
+++ /dev/null
@@ -1,998 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * readxm.c - Code to read a Fast Tracker II / / \ \
12 * module from an open file. | < / \_
13 * | \/ /\ /
14 * By Julien Cugniere. Some bits of code taken \_ / > /
15 * from reads3m.c. | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21#include <string.h>
22#include <math.h>
23
24#include "dumb.h"
25#include "internal/it.h"
26
27
28
29/** TODO:
30
31 * XM_TREMOLO doesn't sound quite right...
32 * XM_E_SET_FINETUNE todo.
33 * XM_SET_ENVELOPE_POSITION todo.
34
35 * VIBRATO conversion needs to be checked (sample/effect/volume). Plus check
36 that effect memory is correct when using XM_VOLSLIDE_VIBRATO.
37 - sample vibrato (instrument vibrato) is now handled correctly. - entheh
38
39 * XM_E_SET_VIBRATO/TREMOLO_CONTROL: effectvalue&4 -> don't retrig wave when
40 a new instrument is played. In retrigger_note()?. Is it worth implementing?
41
42 * Lossy fadeout approximation. 0..31 converted to 0 --> won't fade at all.
43
44 * Replace DUMB's sawtooth by ramp_down/ramp_up. Update XM loader.
45
46 * A lot of things need to be reset when the end of the song is reached.
47
48 * It seems that IT and XM don't behave the same way when dealing with
49 mixed loops. When IT encounters multiple SBx (x>0) commands on the same
50 row, it decrements the loop count for all, but only execute the loop of
51 the last one (highest channel). FT2 only decrements the loop count of the
52 last one. Not that I know of any modules using so convoluted combinations!
53
54 * Maybe we could remove patterns that don't appear in the order table ? Or
55 provide a function to "optimize" a DUMB_IT_SIGDATA ?
56
57*/
58
59
60
61#define XM_LINEAR_FREQUENCY 1 /* otherwise, use amiga slides */
62
63#define XM_ENTRY_PACKED 128
64#define XM_ENTRY_NOTE 1
65#define XM_ENTRY_INSTRUMENT 2
66#define XM_ENTRY_VOLUME 4
67#define XM_ENTRY_EFFECT 8
68#define XM_ENTRY_EFFECTVALUE 16
69
70#define XM_NOTE_OFF 97
71
72#define XM_ENVELOPE_ON 1
73#define XM_ENVELOPE_SUSTAIN 2
74#define XM_ENVELOPE_LOOP 4
75
76#define XM_SAMPLE_NO_LOOP 0
77#define XM_SAMPLE_FORWARD_LOOP 1
78#define XM_SAMPLE_PINGPONG_LOOP 2
79#define XM_SAMPLE_16BIT 16
80#define XM_SAMPLE_STEREO 32
81
82#define XM_VIBRATO_SINE 0
83#define XM_VIBRATO_SQUARE 1
84#define XM_VIBRATO_RAMP_DOWN 2
85#define XM_VIBRATO_RAMP_UP 3
86
87
88
89/* Probably useless :) */
90static const char xm_convert_vibrato[] = {
91 IT_VIBRATO_SINE,
92 IT_VIBRATO_SQUARE,
93 IT_VIBRATO_SAWTOOTH,
94 IT_VIBRATO_SAWTOOTH
95};
96
97
98
99#define XM_MAX_SAMPLES_PER_INSTRUMENT 16
100
101
102
103/* Extra data that doesn't fit inside IT_INSTRUMENT */
104typedef struct XM_INSTRUMENT_EXTRA
105{
106 int n_samples;
107 int vibrato_type;
108 int vibrato_sweep; /* 0-0xFF */
109 int vibrato_depth; /* 0-0x0F */
110 int vibrato_speed; /* 0-0x3F */
111}
112XM_INSTRUMENT_EXTRA;
113
114
115
116/* Frees the original block if it can't resize it or if size is 0, and acts
117 * as malloc if ptr is NULL.
118 */
119static void *safe_realloc(void *ptr, size_t size)
120{
121 if (ptr == NULL)
122 return malloc(size);
123
124 if (size == 0) {
125 free(ptr);
126 return NULL;
127 } else {
128 void *new_block = realloc(ptr, size);
129 if (!new_block)
130 free(ptr);
131 return new_block;
132 }
133}
134
135
136
137/* The interpretation of the XM volume column is left to the player. Here, we
138 * just filter bad values.
139 */
140// This function is so tiny now, should we inline it?
141static void it_xm_convert_volume(int volume, IT_ENTRY *entry)
142{
143 entry->mask |= IT_ENTRY_VOLPAN;
144 entry->volpan = volume;
145
146 switch (volume >> 4) {
147 case 0xA: /* set vibrato speed */
148 case 0xB: /* vibrato */
149 case 0xF: /* tone porta */
150 case 0x6: /* vol slide up */
151 case 0x7: /* vol slide down */
152 case 0x8: /* fine vol slide up */
153 case 0x9: /* fine vol slide down */
154 case 0xC: /* set panning */
155 case 0xD: /* pan slide left */
156 case 0xE: /* pan slide right */
157 case 0x1: /* set volume */
158 case 0x2: /* set volume */
159 case 0x3: /* set volume */
160 case 0x4: /* set volume */
161 break;
162
163 case 0x5:
164 if (volume == 0x50)
165 break; /* set volume */
166 /* else fall through */
167
168 default:
169 entry->mask &= ~IT_ENTRY_VOLPAN;
170 break;
171 }
172}
173
174
175
176static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer)
177{
178 int size;
179 int pos;
180 int channel;
181 int row;
182 int effect, effectvalue;
183 IT_ENTRY *entry;
184
185 /* pattern header size */
186 if (dumbfile_igetl(f) != 0x09) {
187 TRACE("XM error: unexpected pattern header size\n");
188 return -1;
189 }
190
191 /* pattern data packing type */
192 if (dumbfile_getc(f) != 0) {
193 TRACE("XM error: unexpected pattern packing type\n");
194 return -1;
195 }
196
197 pattern->n_rows = dumbfile_igetw(f); /* 1..256 */
198 size = dumbfile_igetw(f);
199 pattern->n_entries = 0;
200
201 if (dumbfile_error(f))
202 return -1;
203
204 if (size == 0)
205 return 0;
206
207 if (size > 1280 * n_channels) {
208 TRACE("XM error: pattern data size > %d bytes\n", 1280 * n_channels);
209 return -1;
210 }
211
212 if (dumbfile_getnc(buffer, size, f) < size)
213 return -1;
214
215 /* compute number of entries */
216 pattern->n_entries = 0;
217 pos = channel = row = 0;
218 while (pos < size) {
219 if (!(buffer[pos] & XM_ENTRY_PACKED) || (buffer[pos] & 31))
220 pattern->n_entries++;
221
222 channel++;
223 if (channel >= n_channels) {
224 channel = 0;
225 row++;
226 pattern->n_entries++;
227 }
228
229 if (buffer[pos] & XM_ENTRY_PACKED) {
230 static const char offset[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
231 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5 };
232 pos += 1 + offset[buffer[pos] & 31];
233 } else {
234 pos += 5;
235 }
236 }
237
238 if (row != pattern->n_rows) {
239 TRACE("XM error: wrong number of rows in pattern data\n");
240 return -1;
241 }
242
243 pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
244 if (!pattern->entry)
245 return -1;
246
247 /* read the entries */
248 entry = pattern->entry;
249 pos = channel = row = 0;
250 while (pos < size) {
251 unsigned char mask;
252
253 if (buffer[pos] & XM_ENTRY_PACKED)
254 mask = buffer[pos++] & 31;
255 else
256 mask = 31;
257
258 if (mask) {
259 ASSERT(entry < pattern->entry + pattern->n_entries);
260
261 entry->channel = channel;
262 entry->mask = 0;
263
264 if (mask & XM_ENTRY_NOTE) {
265 int note = buffer[pos++]; /* 1-96 <=> C0-B7 */
266 entry->note = (note == XM_NOTE_OFF) ? (IT_NOTE_OFF) : (note-1);
267 entry->mask |= IT_ENTRY_NOTE;
268 }
269
270 if (mask & XM_ENTRY_INSTRUMENT) {
271 entry->instrument = buffer[pos++]; /* 1-128 */
272 entry->mask |= IT_ENTRY_INSTRUMENT;
273 }
274
275 if (mask & XM_ENTRY_VOLUME)
276 it_xm_convert_volume(buffer[pos++], entry);
277
278 effect = effectvalue = 0;
279 if (mask & XM_ENTRY_EFFECT) effect = buffer[pos++];
280 if (mask & XM_ENTRY_EFFECTVALUE) effectvalue = buffer[pos++];
281 _dumb_it_xm_convert_effect(effect, effectvalue, entry);
282
283 entry++;
284 }
285
286 channel++;
287 if (channel >= n_channels) {
288 channel = 0;
289 row++;
290 IT_SET_END_ROW(entry);
291 entry++;
292 }
293 }
294
295 return 0;
296}
297
298
299
300static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data, int y_offset)
301{
302 int i, pos;
303
304 if (envelope->n_nodes > 12) {
305 TRACE("XM error: wrong number of envelope nodes (%d)\n", envelope->n_nodes);
306 envelope->n_nodes = 0;
307 return -1;
308 }
309
310 pos = 0;
311 for (i = 0; i < envelope->n_nodes; i++) {
312 envelope->node_t[i] = data[pos++];
313 if (data[pos] > 64) {
314 TRACE("XM error: out-of-range envelope node (node_y[%d]=%d)\n", i, data[pos]);
315 envelope->n_nodes = 0;
316 return -1;
317 }
318 envelope->node_y[i] = (signed char)(data[pos++] + y_offset);
319 }
320
321 return 0;
322}
323
324
325
326static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA *extra, DUMBFILE *f)
327{
328 unsigned long size, bytes_read;
329 unsigned short vol_points[24];
330 unsigned short pan_points[24];
331 int i, type;
332
333 /* Header size. Tends to be more than the actual size of the structure.
334 * So unread bytes must be skipped before reading the first sample
335 * header.
336 */
337 size = dumbfile_igetl(f);
338
339 //memset(instrument, 0, sizeof(*instrument));
340 dumbfile_skip(f, 22); /* Instrument name */
341 dumbfile_skip(f, 1); /* Instrument type. Should be 0, but seems random. */
342 extra->n_samples = dumbfile_igetw(f);
343
344 if (dumbfile_error(f) || (unsigned int)extra->n_samples > XM_MAX_SAMPLES_PER_INSTRUMENT)
345 return -1;
346
347 bytes_read = 4 + 22 + 1 + 2;
348
349 if (extra->n_samples) {
350 /* sample header size */
351 if (dumbfile_igetl(f) != 0x28) {
352 TRACE("XM error: unexpected sample header size\n");
353 return -1;
354 }
355
356 /* sample map */
357 for (i = 0; i < 96; i++) {
358 instrument->map_sample[i] = dumbfile_getc(f) + 1;
359 instrument->map_note[i] = i;
360 }
361
362 if (dumbfile_error(f))
363 return 1;
364
365 /* volume/panning envelopes */
366 for (i = 0; i < 24; i++)
367 vol_points[i] = dumbfile_igetw(f);
368 for (i = 0; i < 24; i++)
369 pan_points[i] = dumbfile_igetw(f);
370
371 instrument->volume_envelope.n_nodes = dumbfile_getc(f);
372 instrument->pan_envelope.n_nodes = dumbfile_getc(f);
373
374 if (dumbfile_error(f))
375 return -1;
376
377 instrument->volume_envelope.sus_loop_start = dumbfile_getc(f);
378 instrument->volume_envelope.loop_start = dumbfile_getc(f);
379 instrument->volume_envelope.loop_end = dumbfile_getc(f);
380
381 instrument->pan_envelope.sus_loop_start = dumbfile_getc(f);
382 instrument->pan_envelope.loop_start = dumbfile_getc(f);
383 instrument->pan_envelope.loop_end = dumbfile_getc(f);
384
385 /* The envelope handler for XM files won't use sus_loop_end. */
386
387 type = dumbfile_getc(f);
388 instrument->volume_envelope.flags = 0;
389 if ((type & XM_ENVELOPE_ON) && instrument->volume_envelope.n_nodes)
390 instrument->volume_envelope.flags |= IT_ENVELOPE_ON;
391 if (type & XM_ENVELOPE_LOOP) instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON;
392#if 1
393 if (type & XM_ENVELOPE_SUSTAIN) instrument->volume_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP;
394#else // This is now handled in itrender.c
395 /* let's avoid fading out when reaching the last envelope node */
396 if (!(type & XM_ENVELOPE_LOOP)) {
397 instrument->volume_envelope.loop_start = instrument->volume_envelope.n_nodes-1;
398 instrument->volume_envelope.loop_end = instrument->volume_envelope.n_nodes-1;
399 }
400 instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON;
401#endif
402
403 type = dumbfile_getc(f);
404 instrument->pan_envelope.flags = 0;
405 if ((type & XM_ENVELOPE_ON) && instrument->pan_envelope.n_nodes)
406 instrument->pan_envelope.flags |= IT_ENVELOPE_ON;
407 if (type & XM_ENVELOPE_LOOP) instrument->pan_envelope.flags |= IT_ENVELOPE_LOOP_ON; // should this be here?
408 if (type & XM_ENVELOPE_SUSTAIN) instrument->pan_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP;
409
410 if (it_xm_make_envelope(&instrument->volume_envelope, vol_points, 0) != 0) {
411 TRACE("XM error: volume envelope\n");
412 if (instrument->volume_envelope.flags & IT_ENVELOPE_ON) return -1;
413 }
414
415 if (it_xm_make_envelope(&instrument->pan_envelope, pan_points, -32) != 0) {
416 TRACE("XM error: pan envelope\n");
417 if (instrument->pan_envelope.flags & IT_ENVELOPE_ON) return -1;
418 }
419
420 instrument->pitch_envelope.flags = 0;
421
422 extra->vibrato_type = dumbfile_getc(f);
423 extra->vibrato_sweep = dumbfile_getc(f);
424 extra->vibrato_depth = dumbfile_getc(f);
425 extra->vibrato_speed = dumbfile_getc(f);
426
427 if (dumbfile_error(f) || extra->vibrato_type >= 4)
428 return -1;
429
430 /** WARNING: lossy approximation */
431 instrument->fadeout = (dumbfile_igetw(f)*128 + 64)/0xFFF;
432
433 dumbfile_skip(f, 2); /* reserved */
434
435 bytes_read += 4 + 96 + 48 + 48 + 14*1 + 2 + 2;
436 }
437
438 if (dumbfile_skip(f, size - bytes_read))
439 return -1;
440
441 instrument->new_note_action = NNA_NOTE_CUT;
442 instrument->dup_check_type = DCT_OFF;
443 instrument->dup_check_action = DCA_NOTE_CUT;
444 instrument->pp_separation = 0;
445 instrument->pp_centre = 60; /* C-5 */
446 instrument->global_volume = 128;
447 instrument->default_pan = 32;
448 instrument->random_volume = 0;
449 instrument->random_pan = 0;
450 instrument->filter_cutoff = 0;
451 instrument->filter_resonance = 0;
452
453 return 0;
454}
455
456
457
458/* I (entheh) have two XM files saved by a very naughty program. After a
459 * 16-bit sample, it saved a rogue byte. The length of the sample was indeed
460 * an odd number, incremented to include the rogue byte.
461 *
462 * In this function we are converting sample lengths and loop points so they
463 * are measured in samples. This means we forget about the extra bytes, and
464 * they don't get skipped. So we fail trying to read the next instrument.
465 *
466 * To get around this, this function returns the number of rogue bytes that
467 * won't be accounted for by reading sample->length samples. It returns a
468 * negative number on failure.
469 */
470static int it_xm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
471{
472 int type;
473 int relative_note_number; /* relative to C4 */
474 int finetune;
475 int roguebytes;
476 int roguebytesmask;
477
478 sample->length = dumbfile_igetl(f);
479 sample->loop_start = dumbfile_igetl(f);
480 sample->loop_end = sample->loop_start + dumbfile_igetl(f);
481 sample->global_volume = 64;
482 sample->default_volume = dumbfile_getc(f);
483 finetune = (signed char)dumbfile_getc(f); /* -128..127 <=> -1 semitone .. +127/128 of a semitone */
484 type = dumbfile_getc(f);
485 sample->default_pan = (dumbfile_getc(f)*64)/255 | 128; /* 0-255 */
486 relative_note_number = (signed char)dumbfile_getc(f);
487
488 dumbfile_skip(f, 1); /* reserved */
489 dumbfile_skip(f, 22); /* sample name */
490
491 if (dumbfile_error(f))
492 return -1;
493
494 sample->C5_speed = (long)(16726.0*pow(DUMB_SEMITONE_BASE, relative_note_number)*pow(DUMB_PITCH_BASE, finetune*2));
495
496 sample->flags = IT_SAMPLE_EXISTS;
497
498 roguebytes = (int)sample->length;
499 roguebytesmask = 3;
500
501 if (type & XM_SAMPLE_16BIT) {
502 sample->flags |= IT_SAMPLE_16BIT;
503 sample->length >>= 1;
504 sample->loop_start >>= 1;
505 sample->loop_end >>= 1;
506 } else
507 roguebytesmask >>= 1;
508
509 if (type & XM_SAMPLE_STEREO) {
510 sample->flags |= IT_SAMPLE_STEREO;
511 sample->length >>= 1;
512 sample->loop_start >>= 1;
513 sample->loop_end >>= 1;
514 } else
515 roguebytesmask >>= 1;
516
517 roguebytes &= roguebytesmask;
518
519 if ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end) {
520 if (type & XM_SAMPLE_FORWARD_LOOP) sample->flags |= IT_SAMPLE_LOOP;
521 if (type & XM_SAMPLE_PINGPONG_LOOP) sample->flags |= IT_SAMPLE_LOOP | IT_SAMPLE_PINGPONG_LOOP;
522 }
523
524 if (sample->length <= 0)
525 sample->flags &= ~IT_SAMPLE_EXISTS;
526 else if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
527 sample->flags &= ~IT_SAMPLE_LOOP;
528 else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
529 sample->flags &= ~IT_SAMPLE_LOOP;
530
531 return roguebytes;
532}
533
534
535
536static int it_xm_read_sample_data(IT_SAMPLE *sample, unsigned char roguebytes, DUMBFILE *f)
537{
538 int old;
539 long i;
540 long truncated_size;
541
542 if (!(sample->flags & IT_SAMPLE_EXISTS))
543 return dumbfile_skip(f, roguebytes);
544
545 /* let's get rid of the sample data coming after the end of the loop */
546 if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
547 truncated_size = sample->length - sample->loop_end;
548 sample->length = sample->loop_end;
549 } else {
550 truncated_size = 0;
551 }
552
553 sample->left = malloc(sample->length * sizeof(*sample->left));
554 if (!sample->left)
555 return -1;
556
557 if (sample->flags & IT_SAMPLE_STEREO) {
558 sample->right = malloc(sample->length * sizeof(*sample->right));
559 if (!sample->right)
560 return -1;
561 }
562
563 /* sample data is stored as signed delta values */
564 old = 0;
565 if (sample->flags & IT_SAMPLE_16BIT) {
566 for (i = 0; i < sample->length; i++) {
567 old = sample->left[i] = (int)(signed short)(old + dumbfile_igetw(f));
568 sample->left[i] <<= 8;
569 }
570 } else {
571 for (i = 0; i < sample->length; i++) {
572 old = sample->left[i] = (int)(signed char)(old + dumbfile_getc(f));
573 sample->left[i] <<= 16;
574 }
575 }
576
577 /* skip truncated data */
578 dumbfile_skip(f, (sample->flags & IT_SAMPLE_16BIT) ? (2*truncated_size) : (truncated_size));
579
580 if (sample->flags & IT_SAMPLE_STEREO) {
581 old = 0;
582 if (sample->flags & IT_SAMPLE_16BIT) {
583 for (i = 0; i < sample->length; i++) {
584 old = sample->right[i] = (int)(signed short)(old + dumbfile_igetw(f));
585 sample->right[i] <<= 8;
586 }
587 } else {
588 for (i = 0; i < sample->length; i++) {
589 old = sample->right[i] = (int)(signed char)(old + dumbfile_getc(f));
590 sample->right[i] <<= 16;
591 }
592 }
593 /* skip truncated data */
594 dumbfile_skip(f, (sample->flags & IT_SAMPLE_16BIT) ? (2*truncated_size) : (truncated_size));
595 }
596
597 dumbfile_skip(f, roguebytes);
598
599 if (dumbfile_error(f))
600 return -1;
601
602 return 0;
603}
604
605
606
607/* "Real programmers don't document. If it was hard to write,
608 * it should be hard to understand."
609 *
610 * (Never trust the documentation provided with a tracker.
611 * Real files are the only truth...)
612 */
613static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f)
614{
615 DUMB_IT_SIGDATA *sigdata;
616 char id_text[18];
617
618 int flags;
619 int n_channels;
620 int total_samples;
621 int i, j;
622
623 /* check ID text */
624 if (dumbfile_getnc(id_text, 17, f) < 17)
625 return NULL;
626 id_text[17] = 0;
627 if (strcmp(id_text, "Extended Module: ") != 0) {
628 TRACE("XM error: Not an Extended Module\n");
629 return NULL;
630 }
631
632 /* song name */
633 if (dumbfile_skip(f, 20))
634 return NULL;
635
636 if (dumbfile_getc(f) != 0x1A) {
637 TRACE("XM error: 0x1A not found\n");
638 return NULL;
639 }
640
641 /* tracker name */
642 if (dumbfile_skip(f, 20))
643 return NULL;
644
645 /* version number */
646 if (dumbfile_igetw(f) != 0x0104) {
647 TRACE("XM error: wrong format version\n");
648 return NULL;
649 }
650
651 /*
652 ------------------
653 --- Header ---
654 ------------------
655 */
656
657 /* header size */
658 if (dumbfile_igetl(f) != 0x0114) {
659 TRACE("XM error: unexpected header size\n");
660 return NULL;
661 }
662
663 sigdata = malloc(sizeof(*sigdata));
664 if (!sigdata)
665 return NULL;
666
667 sigdata->order = NULL;
668 sigdata->instrument = NULL;
669 sigdata->sample = NULL;
670 sigdata->pattern = NULL;
671 sigdata->midi = NULL;
672 sigdata->checkpoint = NULL;
673
674 sigdata->n_samples = 0;
675 sigdata->n_orders = dumbfile_igetw(f);
676 sigdata->restart_position = dumbfile_igetw(f);
677 n_channels = dumbfile_igetw(f); /* max 32 but we'll be lenient */
678 sigdata->n_patterns = dumbfile_igetw(f);
679 sigdata->n_instruments = dumbfile_igetw(f); /* max 128 */
680 flags = dumbfile_igetw(f);
681 sigdata->speed = dumbfile_igetw(f);
682 sigdata->tempo = dumbfile_igetw(f);
683
684 /* sanity checks */
685 if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_orders > 256 || sigdata->n_patterns > 256 || sigdata->n_instruments > 128 || n_channels > DUMB_IT_N_CHANNELS) {
686 _dumb_it_unload_sigdata(sigdata);
687 return NULL;
688 }
689
690 //if (sigdata->restart_position >= sigdata->n_orders)
691 //sigdata->restart_position = 0;
692
693 /* order table */
694 sigdata->order = malloc(sigdata->n_orders*sizeof(*sigdata->order));
695 if (!sigdata->order) {
696 _dumb_it_unload_sigdata(sigdata);
697 return NULL;
698 }
699 dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
700 dumbfile_skip(f, 256 - sigdata->n_orders);
701
702 if (dumbfile_error(f)) {
703 _dumb_it_unload_sigdata(sigdata);
704 return NULL;
705 }
706
707 /*
708 --------------------
709 --- Patterns ---
710 --------------------
711 */
712
713 sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
714 if (!sigdata->pattern) {
715 _dumb_it_unload_sigdata(sigdata);
716 return NULL;
717 }
718 for (i = 0; i < sigdata->n_patterns; i++)
719 sigdata->pattern[i].entry = NULL;
720
721 {
722 unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */
723 if (!buffer) {
724 _dumb_it_unload_sigdata(sigdata);
725 return NULL;
726 }
727 for (i = 0; i < sigdata->n_patterns; i++) {
728 if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer) != 0) {
729 free(buffer);
730 _dumb_it_unload_sigdata(sigdata);
731 return NULL;
732 }
733 }
734 free(buffer);
735 }
736
737 /*
738 -----------------------------------
739 --- Instruments and Samples ---
740 -----------------------------------
741 */
742
743 sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
744 if (!sigdata->instrument) {
745 _dumb_it_unload_sigdata(sigdata);
746 return NULL;
747 }
748
749 /* With XM, samples are not global, they're part of an instrument. In a
750 * file, each instrument is stored with its samples. Because of this, I
751 * don't know how to find how many samples are present in the file. Thus
752 * I have to do n_instruments reallocation on sigdata->sample.
753 * Looking at FT2, it doesn't seem possible to have more than 16 samples
754 * per instrument (even though n_samples is stored as 2 bytes). So maybe
755 * we could allocate a 128*16 array of samples, and shrink it back to the
756 * correct size when we know it?
757 * Alternatively, I could allocate samples by blocks of N (still O(n)),
758 * or double the number of allocated samples when I need more (O(log n)).
759 */
760 total_samples = 0;
761 sigdata->sample = NULL;
762
763 for (i = 0; i < sigdata->n_instruments; i++) {
764 XM_INSTRUMENT_EXTRA extra;
765
766 if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) {
767 TRACE("XM error: instrument %d\n", i+1);
768 _dumb_it_unload_sigdata(sigdata);
769 return NULL;
770 }
771
772 if (extra.n_samples) {
773 unsigned char roguebytes[XM_MAX_SAMPLES_PER_INSTRUMENT];
774
775 /* adjust instrument sample map (make indices absolute) */
776 for (j = 0; j < 96; j++)
777 sigdata->instrument[i].map_sample[j] += total_samples;
778
779 sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples));
780 if (!sigdata->sample) {
781 _dumb_it_unload_sigdata(sigdata);
782 return NULL;
783 }
784 for (j = total_samples; j < total_samples+extra.n_samples; j++)
785 sigdata->sample[j].right = sigdata->sample[j].left = NULL;
786
787 /* read instrument's samples */
788 for (j = 0; j < extra.n_samples; j++) {
789 IT_SAMPLE *sample = &sigdata->sample[total_samples+j];
790 int b = it_xm_read_sample_header(sample, f);
791 if (b < 0) {
792 _dumb_it_unload_sigdata(sigdata);
793 return NULL;
794 }
795 roguebytes[j] = b;
796 // Any reason why these can't be set inside it_xm_read_sample_header()?
797 sample->vibrato_speed = extra.vibrato_speed;
798 sample->vibrato_depth = extra.vibrato_depth;
799 sample->vibrato_rate = extra.vibrato_sweep;
800 /* Rate and sweep don't match, but the difference is
801 * accounted for in itrender.c.
802 */
803 sample->vibrato_waveform = xm_convert_vibrato[extra.vibrato_type];
804 }
805 for (j = 0; j < extra.n_samples; j++) {
806 if (it_xm_read_sample_data(&sigdata->sample[total_samples+j], roguebytes[j], f) != 0) {
807 _dumb_it_unload_sigdata(sigdata);
808 return NULL;
809 }
810 }
811 total_samples += extra.n_samples;
812 }
813 }
814
815 sigdata->n_samples = total_samples;
816
817 sigdata->flags = IT_WAS_AN_XM | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO | IT_USE_INSTRUMENTS;
818 // Are we OK with IT_COMPATIBLE_GXX off?
819 //
820 // When specifying note + instr + tone portamento, and an old note is still playing (even after note off):
821 // - If Compatible Gxx is on, the new note will be triggered only if the instrument _changes_.
822 // - If Compatible Gxx is off, the new note will always be triggered, provided the instrument is specified.
823 // - FT2 seems to do the latter (unconfirmed).
824
825 // Err, wait. XM playback has its own code. The change made to the IT
826 // playbackc code didn't affect XM playback. Forget this then. There's
827 // still a bug in XM playback though, and it'll need some investigation...
828 // tomorrow...
829
830 // UPDATE: IT_COMPATIBLE_GXX is required to be on, so that tone porta has
831 // separate memory from portamento.
832
833 if (flags & XM_LINEAR_FREQUENCY)
834 sigdata->flags |= IT_LINEAR_SLIDES;
835
836 sigdata->global_volume = 128;
837 sigdata->mixing_volume = 48;
838 sigdata->pan_separation = 128;
839
840 memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
841 memset(sigdata->channel_pan, 32, DUMB_IT_N_CHANNELS);
842
843 _dumb_it_fix_invalid_orders(sigdata);
844
845 return sigdata;
846}
847
848
849
850#if 0 // no fucking way, dude!
851
852/* The length returned is the time required to play from the beginning of the
853 * file to the last row of the last order (which is when the player will
854 * loop). Depending on the song, the sound might stop sooner.
855 * Due to fixed point roundoffs, I think this is only reliable to the second.
856 * Full precision could be achieved by using a double during the computation,
857 * or maybe a LONG_LONG.
858 */
859long it_compute_length(const DUMB_IT_SIGDATA *sigdata)
860{
861 IT_PATTERN *pattern;
862 int tempo, speed;
863 int loop_start[IT_N_CHANNELS];
864 char loop_count[IT_N_CHANNELS];
865 int order, entry;
866 int row_first_entry = 0;
867 int jump, jump_dest;
868 int delay, fine_delay;
869 int i;
870 long t;
871
872 if (!sigdata)
873 return 0;
874
875 tempo = sigdata->tempo;
876 speed = sigdata->speed;
877 order = entry = 0;
878 jump = jump_dest = 0;
879 t = 0;
880
881 /* for each PATTERN */
882 for (order = 0; order < sigdata->n_orders; order++) {
883
884 if (sigdata->order[order] == IT_ORDER_END) break;
885 if (sigdata->order[order] == IT_ORDER_SKIP) continue;
886
887 for (i = 0; i < IT_N_CHANNELS; i++)
888 loop_count[i] = -1;
889
890 pattern = &sigdata->pattern[ sigdata->order[order] ];
891 entry = 0;
892 if (jump == IT_BREAK_TO_ROW) {
893 int row = 0;
894 while (row < jump_dest)
895 if (pattern->entry[entry++].channel >= IT_N_CHANNELS)
896 row++;
897 }
898
899 /* for each ROW */
900 while (entry < pattern->n_entries) {
901 row_first_entry = entry;
902 delay = fine_delay = 0;
903 jump = 0;
904
905 /* for each note NOTE */
906 while (entry < pattern->n_entries && pattern->entry[entry].channel < IT_N_CHANNELS) {
907 int value = pattern->entry[entry].effectvalue;
908 int channel = pattern->entry[entry].channel;
909
910 switch (pattern->entry[entry].effect) {
911
912 case IT_SET_SPEED: speed = value; break;
913
914 case IT_JUMP_TO_ORDER:
915 if (value <= order) /* infinite loop */
916 return 0;
917 jump = IT_JUMP_TO_ORDER;
918 jump_dest = value;
919 break;
920
921 case IT_BREAK_TO_ROW:
922 jump = IT_BREAK_TO_ROW;
923 jump_dest = value;
924 break;
925
926 case IT_S:
927 switch (HIGH(value)) {
928 case IT_S_PATTERN_DELAY: delay = LOW(value); break;
929 case IT_S_FINE_PATTERN_DELAY: fine_delay = LOW(value); break;
930 case IT_S_PATTERN_LOOP:
931 if (LOW(value) == 0) {
932 loop_start[channel] = row_first_entry;
933 } else {
934 if (loop_count[channel] == -1)
935 loop_count[channel] = LOW(value);
936
937 if (loop_count[channel]) {
938 jump = IT_S_PATTERN_LOOP;
939 jump_dest = loop_start[channel];
940 }
941 loop_count[channel]--;
942 }
943 break;
944 }
945 break;
946
947 case IT_SET_SONG_TEMPO:
948 switch (HIGH(value)) { /* slides happen every non-row frames */
949 case 0: tempo = tempo - LOW(value)*(speed-1); break;
950 case 1: tempo = tempo + LOW(value)*(speed-1); break;
951 default: tempo = value;
952 }
953 tempo = MID(32, tempo, 255);
954 break;
955 }
956
957 entry++;
958 }
959
960 /* end of ROW */
961 entry++;
962 t += TICK_TIME_DIVIDEND * (speed*(1+delay) + fine_delay) / tempo;
963
964 if (jump == IT_JUMP_TO_ORDER) {
965 order = jump_dest - 1;
966 break;
967 } else if (jump == IT_BREAK_TO_ROW)
968 break;
969 else if (jump == IT_S_PATTERN_LOOP)
970 entry = jump_dest - 1;
971 }
972
973 /* end of PATTERN */
974 }
975
976 return t;
977}
978
979#endif /* 0 */
980
981
982
983DUH *dumb_read_xm(DUMBFILE *f)
984{
985 sigdata_t *sigdata;
986 long length;
987
988 DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
989
990 sigdata = it_xm_load_sigdata(f);
991
992 if (!sigdata)
993 return NULL;
994
995 length = _dumb_it_build_checkpoints(sigdata);
996
997 return make_duh(length, 1, &descptr, &sigdata);
998}
diff --git a/apps/codecs/dumb/src/it/xmeffect.c b/apps/codecs/dumb/src/it/xmeffect.c
deleted file mode 100644
index 6e28d5effb..0000000000
--- a/apps/codecs/dumb/src/it/xmeffect.c
+++ /dev/null
@@ -1,255 +0,0 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * xmeffect.c - Code for converting MOD/XM / / \ \
12 * effects to IT effects. | < / \_
13 * | \/ /\ /
14 * By Julien Cugniere. Ripped out of readxm.c \_ / > /
15 * by entheh. | \ / /
16 * | ' /
17 * \__/
18 */
19
20
21
22#include <stdlib.h>
23#include <string.h>
24
25#include "dumb.h"
26#include "internal/it.h"
27
28#ifdef SIMULATOR
29#include "debug.h"
30#endif
31
32
33#if 0
34unsigned char **_dumb_malloc2(int w, int h)
35{
36 unsigned char **line = malloc(h * sizeof(*line));
37 int i;
38 if (!line) return NULL;
39
40 line[0] = malloc(w * h * sizeof(*line[0]));
41 if (!line[0]) {
42 free(line);
43 return NULL;
44 }
45
46 for (i = 1; i < h; i++)
47 line[i] = line[i-1] + w;
48
49 memset(line[0], 0, w*h);
50
51 return line;
52}
53
54
55
56void _dumb_free2(unsigned char **line)
57{
58 if (line) {
59 if (line[0])
60 free(line[0]);
61 free(line);
62 }
63}
64
65
66
67/* Effects having a memory. 2 means that the two parts of the effectvalue
68 * should be handled separately.
69 */
70static const char xm_has_memory[] = {
71/* 0 1 2 3 4 5 6 7 8 9 A B C D (E) F G H K L P R T (X) */
72 0, 1, 1, 1, 2, 1, 1, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
73
74/* E0 E1 E2 E3 E4 E5 E6 E7 E9 EA EB EC ED EE X1 X2 */
75 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
76};
77#endif
78
79
80
81/* Effects marked with 'special' are handled specifically in itrender.c */
82void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry)
83{
84#ifdef SIMULATOR
85const int log = 0;
86#endif
87
88 if ((!effect && !value) || (effect >= XM_N_EFFECTS))
89 return;
90
91#ifdef SIMULATOR
92if (log) DEBUGF("%c%02X", (effect<10)?('0'+effect):('A'+effect-10), value);
93#endif
94
95 /* Linearisation of the effect number... */
96 if (effect == XM_E) {
97 effect = EBASE + HIGH(value);
98 value = LOW(value);
99 } else if (effect == XM_X) {
100 effect = XBASE + HIGH(value);
101 value = LOW(value);
102 }
103
104#ifdef SIMULATOR
105if (log) DEBUGF(" - %2d %02X", effect, value);
106#endif
107
108#if 0 // This should be handled in itrender.c!
109 /* update effect memory */
110 switch (xm_has_memory[effect]) {
111 case 1:
112 if (!value)
113 value = memory[entry->channel][effect];
114 else
115 memory[entry->channel][effect] = value;
116 break;
117
118 case 2:
119 if (!HIGH(value))
120 SET_HIGH(value, HIGH(memory[entry->channel][effect]));
121 else
122 SET_HIGH(memory[entry->channel][effect], HIGH(value));
123
124 if (!LOW(value))
125 SET_LOW(value, LOW(memory[entry->channel][effect]));
126 else
127 SET_LOW(memory[entry->channel][effect], LOW(value));
128 break;
129 }
130#endif
131
132 /* convert effect */
133 entry->mask |= IT_ENTRY_EFFECT;
134 switch (effect) {
135
136 case XM_APPREGIO: effect = IT_ARPEGGIO; break;
137 case XM_VIBRATO: effect = IT_VIBRATO; break;
138 case XM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break; /** TODO: glissando control */
139 case XM_TREMOLO: effect = IT_TREMOLO; break;
140 case XM_SET_PANNING: effect = IT_SET_PANNING; break;
141 case XM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break;
142 case XM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break;
143 case XM_MULTI_RETRIG: effect = IT_RETRIGGER_NOTE; break;
144 case XM_TREMOR: effect = IT_TREMOR; break;
145 case XM_PORTAMENTO_UP: effect = IT_XM_PORTAMENTO_UP; break;
146 case XM_PORTAMENTO_DOWN: effect = IT_XM_PORTAMENTO_DOWN; break;
147 case XM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break; /* special */
148 case XM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break; /* special */
149 case XM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break; /* special */
150
151 case XM_PATTERN_BREAK:
152 effect = IT_BREAK_TO_ROW;
153 value = BCD_TO_NORMAL(value);
154 break;
155
156 case XM_VOLUME_SLIDE: /* special */
157 effect = IT_VOLUME_SLIDE;
158 value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
159 break;
160
161 case XM_PANNING_SLIDE:
162 effect = IT_PANNING_SLIDE;
163 value = HIGH(value) ? EFFECT_VALUE(0, HIGH(value)) : EFFECT_VALUE(LOW(value), 0);
164 break;
165
166 case XM_GLOBAL_VOLUME_SLIDE: /* special */
167 effect = IT_GLOBAL_VOLUME_SLIDE;
168 value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
169 break;
170
171 case XM_SET_TEMPO_BPM:
172 effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
173 break;
174
175 case XM_SET_GLOBAL_VOLUME:
176 effect = IT_SET_GLOBAL_VOLUME;
177 value *= 2;
178 break;
179
180 case XM_KEY_OFF:
181 /** WARNING: In FT2, the value seems to do something... Oh well,
182 * this is undocumented anyway!
183 */
184 entry->mask &= ~IT_ENTRY_EFFECT;
185 entry->mask |= IT_ENTRY_NOTE;
186 entry->note = IT_NOTE_OFF;
187 break;
188
189 case EBASE+XM_E_SET_FILTER: effect = SBASE+IT_S_SET_FILTER; break;
190 case EBASE+XM_E_SET_GLISSANDO_CONTROL: effect = SBASE+IT_S_SET_GLISSANDO_CONTROL; break; /** TODO */
191 case EBASE+XM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break; /** TODO */
192 case EBASE+XM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break;
193 case EBASE+XM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break;
194 case EBASE+XM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break;
195 case EBASE+XM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break;
196 case EBASE+XM_E_FINE_VOLSLIDE_UP: effect = IT_XM_FINE_VOLSLIDE_UP; break;
197 case EBASE+XM_E_FINE_VOLSLIDE_DOWN: effect = IT_XM_FINE_VOLSLIDE_DOWN; break;
198
199 case EBASE + XM_E_FINE_PORTA_UP:
200 effect = IT_PORTAMENTO_UP;
201 value = EFFECT_VALUE(0xF, value);
202 break;
203
204 case EBASE + XM_E_FINE_PORTA_DOWN:
205 effect = IT_PORTAMENTO_DOWN;
206 value = EFFECT_VALUE(0xF, value);
207 break;
208
209 case EBASE + XM_E_RETRIG_NOTE:
210 effect = IT_XM_RETRIGGER_NOTE;
211 value = EFFECT_VALUE(0, value);
212 break;
213
214 case EBASE + XM_E_SET_VIBRATO_CONTROL:
215 effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM;
216 value &= ~4; /** TODO: value&4 -> don't retrig wave */
217 break;
218
219 case EBASE + XM_E_SET_TREMOLO_CONTROL:
220 effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM;
221 value &= ~4; /** TODO: value&4 -> don't retrig wave */
222 break;
223
224 case XBASE + XM_X_EXTRAFINE_PORTA_UP:
225 effect = IT_PORTAMENTO_UP;
226 value = EFFECT_VALUE(0xE, value);
227 break;
228
229 case XBASE + XM_X_EXTRAFINE_PORTA_DOWN:
230 effect = IT_PORTAMENTO_DOWN;
231 value = EFFECT_VALUE(0xE, value);
232 break;
233
234 default:
235 /* user effect (often used in demos for synchronisation) */
236 entry->mask &= ~IT_ENTRY_EFFECT;
237 }
238
239#ifdef SIMULATOR
240if (log) DEBUGF(" - %2d %02X", effect, value);
241#endif
242
243 /* Inverse linearisation... */
244 if (effect >= SBASE && effect < SBASE+16) {
245 value = EFFECT_VALUE(effect-SBASE, value);
246 effect = IT_S;
247 }
248
249#ifdef SIMULATOR
250if (log) DEBUGF(" - %c%02X\n", 'A'+effect-1, value);
251#endif
252
253 entry->effect = effect;
254 entry->effectvalue = value;
255}