Update DUMB to version 2.0.0.

This commit is contained in:
Christopher Snowhill 2017-09-26 16:11:54 -07:00
parent 78b69b010d
commit 47a6afe62c
106 changed files with 19176 additions and 19508 deletions

View file

@ -1,3 +1,4 @@
```
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
@ -8,7 +9,7 @@
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
* / \
* / . \
* release.txt - Release notes for DUMB. / / \ \
* CHANGELOG.md - Release notes for DUMB. / / \ \
* | < / \_
* | \/ /\ /
* \_ / > /
@ -16,11 +17,35 @@
* | ' /
* \__/
*/
```
# DUMB Changelog
*******************************************
*** DUMB v0.9.3, released 7 August 2005 ***
*******************************************
## v2.0.0, released 26 September 2017
* Memory leak and bug fixes
* Audio playback quality improvements for STM
* Added support for FEST MOD files
* Default resampling quality is now cubic
* Allegro 4 support
* New dumbplay, dumbout examples
* Multiple cmake fixes
* Deprecated `duh_render()`, use `duh_render_float()` and `duh_render_int()`
* Removed API deprecated since 0.9.3, see the
[DUMB 0.9.3 deprecation reference](http://dumb.sourceforge.net/index.php?page=docs&doc=deprec)
## v1.0.0, released 17 January 2015
* Support newer compilers
* Better audio playback quality
* More supported formats
* SSE optimizations support
* CMake support
* New resamplers
* Seek support
* Fixes, cleanups, speedups.
## v0.9.3, released 7 August 2005
Hello! Welcome to a long-awaited-or-probably-just-given-up-on-by-everybody
release! New to this release are lower memory usage, faster mixing loops,
@ -173,9 +198,7 @@ That's it! I hope you enjoy this long-awaited-or-probably-just-given-up-on-
by-everybody release of DUMB!
******************************************
*** DUMB v0.9.2, released 2 April 2003 ***
******************************************
## v0.9.2, released 2 April 2003
Yes, there really has been a release. This is not a day-late April fools'
joke.
@ -272,9 +295,7 @@ explained in licence.txt. However, the request is still there ...
As usual, enjoy!
**********************************************
*** DUMB v0.9.1, released 19 December 2002 ***
**********************************************
## v0.9.1, released 19 December 2002
Hi again! Lots to say this time, so I shall cut right to the chase.
@ -355,9 +376,7 @@ the last release; they are relevant for this release too.
That's all folks! Until next time.
*******************************************
*** DUMB v0.9, released 16 October 2002 ***
*******************************************
## v0.9, released 16 October 2002
MOD support is here! DUMB now supports all four of the common module formats.
As usual, there have also been some improvements to the way modules are
@ -431,9 +450,7 @@ Off you go.
Bye.
********************************************
*** DUMB v0.8.1, released 11 August 2002 ***
********************************************
## v0.8.1, released 11 August 2002
This is a minor release that fixes a few bugs. One of these bugs, however,
was pretty serious. dumb_register_dat_xm() was never coded! It was prototyped
@ -487,9 +504,7 @@ The point about length not being calculated also applies to XM files.
Enjoy :)
****************************************
*** DUMB v0.8, released 14 June 2002 ***
****************************************
## v0.8, released 14 June 2002
Welcome to the second release of DUMB!
@ -530,9 +545,7 @@ going myself (72 GBP, and I'd have to wear a suit, ugh), but with all the
noise outside I shall enjoy pumping up the speakers tonight!
****************************************
*** DUMB v0.7, released 2 March 2002 ***
****************************************
## DUMB v0.7, released 2 March 2002
This is the first release of DUMB, and parts of the library are not
crystallised. Don't let this put you off! Provided you don't try to use any

View file

@ -0,0 +1,35 @@
# Compiling
## 1. CMake
### 1.1. Example
In libdumb project root, run:
```
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_SHARED_LIBS:BOOL=ON -DBUILD_ALLEGRO4:BOOL=ON ..
make
make install
```
### 1.2. Steps
1. Create a new temporary build directory and cd into it
2. Run libdumb cmake file with cmake (eg. `cmake -DCMAKE_INSTALL_PREFIX=/install/dir -DBUILD_SHARED_LIBS:BOOL=ON -DCMAKE_BUILD_TYPE=Release path/to/dumb/cmake/dir`).
3. Run make (eg. just `make` or `mingw32-make` or something).
4. If needed, run make install.
### 1.3. Flags
* `CMAKE_INSTALL_PREFIX` sets the installation path prefix.
* `CMAKE_BUILD_TYPE` chooses the build type: `Release`, `Debug`, `RelWithDebInfo`, or `MinSizeRel`. Debug libraries will be named `libdumbd`, release libraries `libdumb`. Default is `Release`.
* `BUILD_SHARED_LIBS` selects whether cmake should build a dynamic (`ON`) or static (`OFF`) library. Default is `OFF`.
* `BUILD_ALLEGRO4` enables (`ON`) or disables (`OFF`) the optional Allegro 4 support. This requires Allegro 4 installed on the system. Default is `ON`.
* `BUILD_EXAMPLES` selects example binaries. These example binaries require argtable2 and SDL2 libraries. Default is `ON`.
* `USE_SSE` enables or disables SSE support. Default is `ON`.
* You may also need to tell cmake what kind of makefiles to create with the "-G" flag. Eg. for MSYS one would say something like `cmake -G "MSYS Makefiles" .`.
## 2. Visual Studio
TODO

View file

@ -0,0 +1,226 @@
Specification of DUMBFILE_SYSTEM
================================
DUMB is designed filesystem-agnostic, even though the C standard library
already defines an abstraction over files on a disk. This is useful because
Allegro 4 and 5 define their own abstractions.
To register your own filesystem abstraction with DUMB, you must create an
instance of struct `DUMBFILE_SYSTEM`, fill in your own function pointers
according to the specification below, and call `register_dumbfile_system` on
your instance.
The header `dumb.h` defines `DUMBFILE_SYSTEM` as a struct of function pointers:
```
typedef struct DUMBFILE_SYSTEM
{
void *(*open)(const char *filename);
int (*skip)(void *f, dumb_off_t n);
int (*getc)(void *f);
dumb_ssize_t (*getnc)(char *ptr, size_t n, void *f);
void (*close)(void *f);
int (*seek)(void *f, dumb_off_t n);
dumb_off_t (*get_size)(void *f);
}
DUMBFILE_SYSTEM;
```
Here, `dumb_off_t` is a signed integer at least 64 bits wide, it is intended
to measure file offsets. The return type `dumb_ssize_t` is a signed integer
exactly as wide as `size_t`, it is intended to store either a `size_t` or a
negative error code. Both `dumb_*_t` are defined in `dumb.h`.
The function pointers `skip` and `getnc` are optional, i.e., you may set
some of these to `NULL` in your struct instance. DUMB will then try to
mimick the missing functions' behavior by calling your `getc` several times.
If DUMB is built with debugging flags, it will assert that all other
functions are not `NULL`. In release mode, DUMB will silently fail.
Your non-`NULL` function pointers must conform to the following specification.
open
----
```
void *(*open)(const char *filename);
```
Open a file for reading.
Arguments:
* `const char *filename`: A normal filename as understood by the operating
system. Will be opened for reading.
Returns as `void *`:
* the address of a file handle on successfully opening the file.
DUMB will pass this file handle as argument to other functions of
the `DUMBFILE_SYSTEM`.
* `NULL` on error during opening the file.
Each file has a *position* internally managed by DUMB. A newly opened file
has a position of 0. Other functions from the `DUMBFILE_SYSTEM` can move
this position around.
DUMB allocates memory for the successfully opened file, and will store opaque
information in that memory, e.g., the DUMB-internal file position. This memory
be freed when DUMB calls `close` on the file's handle. The memory is separate
from your own filesystem implementation: You are responsible for supplying the
data, and DUMB is responsible for storing anything about interpreting that
data.
skip
----
```
int (*skip)(void *f, dumb_off_t n);
```
Advance the position in the file.
Arguments:
* `void *f`: A file handle that `open` returned. Guaranteed non-`NULL`.
* `dumb_off_t n`: Number of bytes to advance in the file. DUMB will only
call this with `n >= 0`. For `n < 0`, the behavior of `skip` is undefined.
Returns as `int`:
* `0` on successfully skipping ahead by `n` bytes.
* `-1` on error.
It is legal to set `skip = NULL` in a `DUMBFILE_SYSTEM`. DUMB will then call
`getc` a total of `n` times to skip ahead in a file. For speed, it is
advisable to supply a proper `skip` implementation.
getc
----
```
int (*getc)(void *f);
```
Read a byte from the file.
Arguments:
* `void *f`: A file handle that `open` returned. Guaranteed non-`NULL`.
Returns as `int`:
* the value of the byte read, on successfully reading one byte.
* `-1` on error.
After a succesful read, DUMB will treat the file as advanced by one byte.
getnc
-----
```
dumb_ssize_t (*getnc)(char *ptr, size_t n, void *f);
```
Read up to the given number of bytes from the file into a given buffer.
* `char *ptr`: The start of a buffer provided by DUMB.
* `size_t n`: The length of the number of bytes to be read.
* `void *f`: A file handle that `open` returned. Guaranteed non-`NULL`.
Returns as `dumb_ssize_t`:
* the number of bytes successfully read, if it was possible to read at least
one byte.
* `-1` on error.
This function shall bytes from the file `f` and store them in sequence in the
buffer beginning at `ptr`. It shall read fewer than `n` bytes if end of file
is encountered before `n` bytes could have been read, otherwise it should read
`n` bytes.
It is legal to set `skip = NULL` in a `DUMBFILE_SYSTEM`. DUMB will then call
`getc` a total of `n` times and store the results in its buffer.
close
-----
```
void (*close)(void *f);
```
Closes a file that has been opened before with `open`.
Arguments:
* `void *f`: A file handle that `open` returned. Guaranteed non-`NULL`.
DUMB will deallocate the memory that it used to interpret the file. You are
free to treat your resource however you would like: You may deallocate it, or
keep it around for other things. For example, Allegro 5's implementation
of `close` takes a void pointer and does nothing with it at all.
seek
----
```
int (*seek)(void *f, dumb_off_t n);
```
Jump to an arbitrary position in the file.
Arguments:
* `void *f`: A file handle that `open` returned. Guaranteed non-`NULL`.
* `dumb_off_t n`: The position in the file, relative to the beginning.
There is no guarantee whether `n >= 0`.
Returns as `int`:
* `0` on successfully seeking in the file.
* `-1` on error.
DUMB will modify its internal position of the file accordingly.
A value of `n < 0` shall set the file into an erroneous state from which no
bytes can be read.
get_size
--------
```
dumb_off_t (*get_size)(void *f);
```
Get the length in bytes, i.e., the position after the final byte, of a file.
Arguments:
* `void *f`: A file handle that `open` returned. Guaranteed non-`NULL`.
Returns as `dumb_off_t`:
* the length of the file in bytes.

View file

@ -0,0 +1,96 @@
# Dynamic Universal Music Bibliotheque (libdumb)
_______ ____ __ ___ ___
\ _ \ \ / \ / \ \ / / ' ' '
| | \ \ | | || | \/ | . .
| | | | | | || ||\ /| |
| | | | | | || || \/ | | ' ' '
| | | | | | || || | | . .
| |_/ / \ \__// || | |
/_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
/ \
/ . \
/ / \ \
| < / \_
| \/ /\ /
\_ / > /
| \ / /
| ' /
\__/
## Introduction
DUMB is a module audio renderer library. It reads module files and
outputs audio that can be dumped to the actual audio playback library.
This is a fork of the original dumb (http://dumb.sf.net/) by Ben Davis.
## Features
- Supports playback of the following module formats. The tracker software or
library the format is known for is given in parentheses. This does not mean
that DUMB does not support files created by other trackers provided that they
output files in one of those formats.
* IT (Impulse Tracker)
* XM (Fasttracker II)
* MOD (Ultimate SoundTracker, ProTracker)
* STM (Scream Tracker)
* S3M (Scream Tracker 3)
* 669 (Composer 669)
* AMF Asylum Music Format
* AMF Digital Sound and Music Interface Advanced Music Format
* DSM Digital Sound Interface Kit module format
* MTM (MultiTracker)
* OKT (Oktalyzer)
* PSM (Protracker Studio)
Both the older PSM16 and the newer PSM format is supported.
* PTM (PolyTracker)
* RIFF AM/AMFF (Galaxy Music System internal format)
- Audio generated can be used in any way; DUMB does not necessarily send it
straight to a sound output system
- Portable
- Faithful to the original trackers, especially IT; if it plays a module
wrongly, it is considered a bug
- Accurate support for low-pass resonant filters for IT files
- Very accurate timing and pitching; completely deterministic playback
- Click removal
- Six resampling quality settings: aliasing, aliasing with bandwidth limiting,
linear interpolation, linear interpolation with bandwidth limiting, cubic
interpolation, and a compile-time-configurable fast sinc resampler
- Number of samples playing at once can be limited to reduce processor usage,
but samples will come back in when other louder ones stop
- Option to take longer loading but seek fast to any point before the music
first loops (seeking time increases beyond this point)
- All notes will be present and correct even if a module's playback is started
in the middle
- Optional Allegro 4 or Allegro 5 integration support
- Facility to embed music files in other files (e.g. Allegro datafiles)
## Installation
Currently you need to compile libdumb yourself. For more details, please see
the file [COMPILING.md](COMPILING.md).
## License
See [LICENSE](LICENSE) for license details.
## Contributing
Bugs, feature requests and patches can be submitted at https://github.com/kode54/dumb/.

File diff suppressed because it is too large Load diff

View file

@ -20,8 +20,6 @@
#ifndef INTERNAL_ALDUMB_H
#define INTERNAL_ALDUMB_H
void _dat_unload_duh(void *duh);
#endif /* INTERNAL_DUMB_H */

View file

@ -6,38 +6,38 @@
#ifdef BARRAY_DECORATE
#undef PASTE
#undef EVALUATE
#define PASTE(a,b) a ## b
#define EVALUATE(a,b) PASTE(a,b)
#define bit_array_create EVALUATE(BARRAY_DECORATE,_bit_array_create)
#define bit_array_destroy EVALUATE(BARRAY_DECORATE,_bit_array_destroy)
#define bit_array_dup EVALUATE(BARRAY_DECORATE,_bit_array_dup)
#define bit_array_reset EVALUATE(BARRAY_DECORATE,_bit_array_reset)
#define bit_array_set EVALUATE(BARRAY_DECORATE,_bit_array_set)
#define bit_array_set_range EVALUATE(BARRAY_DECORATE,_bit_array_set_range)
#define bit_array_test EVALUATE(BARRAY_DECORATE,_bit_array_test)
#define bit_array_test_range EVALUATE(BARRAY_DECORATE,_bit_array_test_range)
#define bit_array_clear EVALUATE(BARRAY_DECORATE,_bit_array_clear)
#define bit_array_clear_range EVALUATE(BARRAY_DECORATE,_bit_array_clear_range)
#define bit_array_merge EVALUATE(BARRAY_DECORATE,_bit_array_merge)
#define bit_array_mask EVALUATE(BARRAY_DECORATE,_bit_array_mask)
#define PASTE(a, b) a##b
#define EVALUATE(a, b) PASTE(a, b)
#define bit_array_create EVALUATE(BARRAY_DECORATE, _bit_array_create)
#define bit_array_destroy EVALUATE(BARRAY_DECORATE, _bit_array_destroy)
#define bit_array_dup EVALUATE(BARRAY_DECORATE, _bit_array_dup)
#define bit_array_reset EVALUATE(BARRAY_DECORATE, _bit_array_reset)
#define bit_array_set EVALUATE(BARRAY_DECORATE, _bit_array_set)
#define bit_array_set_range EVALUATE(BARRAY_DECORATE, _bit_array_set_range)
#define bit_array_test EVALUATE(BARRAY_DECORATE, _bit_array_test)
#define bit_array_test_range EVALUATE(BARRAY_DECORATE, _bit_array_test_range)
#define bit_array_clear EVALUATE(BARRAY_DECORATE, _bit_array_clear)
#define bit_array_clear_range EVALUATE(BARRAY_DECORATE, _bit_array_clear_range)
#define bit_array_merge EVALUATE(BARRAY_DECORATE, _bit_array_merge)
#define bit_array_mask EVALUATE(BARRAY_DECORATE, _bit_array_mask)
#endif
void * bit_array_create(size_t size);
void bit_array_destroy(void * array);
void * bit_array_dup(void * array);
void *bit_array_create(size_t size);
void bit_array_destroy(void *array);
void *bit_array_dup(void *array);
void bit_array_reset(void * array);
void bit_array_reset(void *array);
void bit_array_set(void * array, size_t bit);
void bit_array_set_range(void * array, size_t bit, size_t count);
void bit_array_set(void *array, size_t bit);
void bit_array_set_range(void *array, size_t bit, size_t count);
int bit_array_test(void * array, size_t bit);
int bit_array_test_range(void * array, size_t bit, size_t count);
int bit_array_test(void *array, size_t bit);
int bit_array_test_range(void *array, size_t bit, size_t count);
void bit_array_clear(void * array, size_t bit);
void bit_array_clear_range(void * array, size_t bit, size_t count);
void bit_array_clear(void *array, size_t bit);
void bit_array_clear_range(void *array, size_t bit, size_t count);
void bit_array_merge(void * array, void * source, size_t offset);
void bit_array_mask(void * array, void * source, size_t offset);
void bit_array_merge(void *array, void *source, size_t offset);
void bit_array_mask(void *array, void *source, size_t offset);
#endif

View file

@ -26,47 +26,50 @@
#ifndef INTERNAL_DUMB_H
#define INTERNAL_DUMB_H
#include "../dumb.h"
#undef MIN
#undef MAX
#undef MID
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
#define MID(x,y,z) MAX((x), MIN((y), (z)))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MID(x, y, z) MAX((x), MIN((y), (z)))
#undef ABS
#define ABS(x) (((x) >= 0) ? (x) : (-(x)))
typedef struct DUH_SIGTYPE_DESC_LINK
{
struct DUH_SIGTYPE_DESC_LINK *next;
DUH_SIGTYPE_DESC *desc;
}
DUH_SIGTYPE_DESC_LINK;
#ifndef LONG_LONG
#if defined __GNUC__ || defined __INTEL_COMPILER || defined __MWERKS__ || \
defined __sgi
#define LONG_LONG long long
#elif defined _MSC_VER || defined __WATCOMC__
#define LONG_LONG __int64
#else
#error 64-bit integer type unknown
#endif
#endif
typedef struct DUH_SIGTYPE_DESC_LINK {
struct DUH_SIGTYPE_DESC_LINK *next;
DUH_SIGTYPE_DESC *desc;
} DUH_SIGTYPE_DESC_LINK;
typedef struct DUH_SIGNAL
{
sigdata_t *sigdata;
DUH_SIGTYPE_DESC *desc;
}
DUH_SIGNAL;
typedef struct DUH_SIGNAL {
sigdata_t *sigdata;
DUH_SIGTYPE_DESC *desc;
} DUH_SIGNAL;
struct DUH {
dumb_off_t length;
struct DUH
{
long length;
int n_tags;
char *(*tag)[2];
int n_tags;
char *(*tag)[2];
int n_signals;
DUH_SIGNAL **signal;
int n_signals;
DUH_SIGNAL **signal;
};
DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(long type);
#endif /* INTERNAL_DUMB_H */

View file

@ -1,13 +1,12 @@
#ifndef DUMBFILE_H
#define DUMBFILE_H
#include "../dumb.h"
struct DUMBFILE
{
const DUMBFILE_SYSTEM *dfs;
void *file;
long pos;
};
#endif // DUMBFILE_H
#ifndef DUMBFILE_H
#define DUMBFILE_H
#include "../dumb.h"
struct DUMBFILE {
const DUMBFILE_SYSTEM *dfs;
void *file;
long pos;
};
#endif // DUMBFILE_H

View file

@ -1,18 +0,0 @@
#ifndef _FIR_RESAMPLER_H_
#define _FIR_RESAMPLER_H_
void fir_init();
void * fir_resampler_create();
void fir_resampler_delete(void *);
void * fir_resampler_dup(void *);
int fir_resampler_get_free_count(void *);
void fir_resampler_write_sample(void *, short sample);
void fir_resampler_set_rate( void *, double new_factor );
int fir_resampler_ready(void *);
void fir_resampler_clear(void *);
int fir_resampler_get_sample(void *);
void fir_resampler_remove_sample(void *);
#endif

File diff suppressed because it is too large Load diff

View file

@ -5,36 +5,44 @@
#ifdef RESAMPLER_DECORATE
#undef PASTE
#undef EVALUATE
#define PASTE(a,b) a ## b
#define EVALUATE(a,b) PASTE(a,b)
#define resampler_init EVALUATE(RESAMPLER_DECORATE,_resampler_init)
#define resampler_create EVALUATE(RESAMPLER_DECORATE,_resampler_create)
#define resampler_delete EVALUATE(RESAMPLER_DECORATE,_resampler_delete)
#define resampler_dup EVALUATE(RESAMPLER_DECORATE,_resampler_dup)
#define resampler_dup_inplace EVALUATE(RESAMPLER_DECORATE,_resampler_dup_inplace)
#define resampler_set_quality EVALUATE(RESAMPLER_DECORATE,_resampler_set_quality)
#define resampler_get_free_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_free_count)
#define resampler_write_sample EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample)
#define resampler_write_sample_fixed EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample_fixed)
#define resampler_write_sample_float EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample_float)
#define resampler_set_rate EVALUATE(RESAMPLER_DECORATE,_resampler_set_rate)
#define resampler_ready EVALUATE(RESAMPLER_DECORATE,_resampler_ready)
#define resampler_clear EVALUATE(RESAMPLER_DECORATE,_resampler_clear)
#define resampler_get_sample_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample_count)
#define resampler_get_sample EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample)
#define resampler_get_sample_float EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample_float)
#define resampler_remove_sample EVALUATE(RESAMPLER_DECORATE,_resampler_remove_sample)
#define PASTE(a, b) a##b
#define EVALUATE(a, b) PASTE(a, b)
#define resampler_init EVALUATE(RESAMPLER_DECORATE, _resampler_init)
#define resampler_create EVALUATE(RESAMPLER_DECORATE, _resampler_create)
#define resampler_delete EVALUATE(RESAMPLER_DECORATE, _resampler_delete)
#define resampler_dup EVALUATE(RESAMPLER_DECORATE, _resampler_dup)
#define resampler_dup_inplace \
EVALUATE(RESAMPLER_DECORATE, _resampler_dup_inplace)
#define resampler_set_quality \
EVALUATE(RESAMPLER_DECORATE, _resampler_set_quality)
#define resampler_get_free_count \
EVALUATE(RESAMPLER_DECORATE, _resampler_get_free_count)
#define resampler_write_sample \
EVALUATE(RESAMPLER_DECORATE, _resampler_write_sample)
#define resampler_write_sample_fixed \
EVALUATE(RESAMPLER_DECORATE, _resampler_write_sample_fixed)
#define resampler_write_sample_float \
EVALUATE(RESAMPLER_DECORATE, _resampler_write_sample_float)
#define resampler_set_rate EVALUATE(RESAMPLER_DECORATE, _resampler_set_rate)
#define resampler_ready EVALUATE(RESAMPLER_DECORATE, _resampler_ready)
#define resampler_clear EVALUATE(RESAMPLER_DECORATE, _resampler_clear)
#define resampler_get_sample_count \
EVALUATE(RESAMPLER_DECORATE, _resampler_get_sample_count)
#define resampler_get_sample EVALUATE(RESAMPLER_DECORATE, _resampler_get_sample)
#define resampler_get_sample_float \
EVALUATE(RESAMPLER_DECORATE, _resampler_get_sample_float)
#define resampler_remove_sample \
EVALUATE(RESAMPLER_DECORATE, _resampler_remove_sample)
#endif
void resampler_init(void);
void * resampler_create(void);
void *resampler_create(void);
void resampler_delete(void *);
void * resampler_dup(const void *);
void *resampler_dup(const void *);
void resampler_dup_inplace(void *, const void *);
enum
{
enum {
RESAMPLER_QUALITY_MIN = 0,
RESAMPLER_QUALITY_ZOH = 0,
RESAMPLER_QUALITY_BLEP = 1,
@ -51,7 +59,7 @@ int resampler_get_free_count(void *);
void resampler_write_sample(void *, short sample);
void resampler_write_sample_fixed(void *, int sample, unsigned char depth);
void resampler_write_sample_float(void *, float sample);
void resampler_set_rate( void *, double new_factor );
void resampler_set_rate(void *, double new_factor);
int resampler_ready(void *);
void resampler_clear(void *);
int resampler_get_sample_count(void *);

View file

@ -3,22 +3,20 @@
struct riff;
struct riff_chunk
{
unsigned type;
struct riff_chunk {
unsigned type;
long offset;
unsigned size;
struct riff * nested;
unsigned size;
struct riff *nested;
};
struct riff
{
unsigned type;
unsigned chunk_count;
struct riff_chunk * chunks;
struct riff {
unsigned type;
unsigned chunk_count;
struct riff_chunk *chunks;
};
struct riff * riff_parse( DUMBFILE * f, long offset, long size, unsigned proper );
void riff_free( struct riff * );
struct riff *riff_parse(DUMBFILE *f, long offset, long size, unsigned proper);
void riff_free(struct riff *);
#endif

View file

@ -36,13 +36,13 @@
#define STACK_ALLOC_H
#ifdef WIN32
# include <malloc.h>
#include <malloc.h>
#else
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# else
# include <stdlib.h>
# endif
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#else
#include <stdlib.h>
#endif
#endif
/**
@ -86,15 +86,21 @@
#include <valgrind/memcheck.h>
#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size)-1))
#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
#define PUSH(stack, size, type) \
(VALGRIND_MAKE_NOACCESS(stack, 1000), ALIGN((stack), sizeof(type)), \
VALGRIND_MAKE_WRITABLE(stack, ((size) * sizeof(type))), \
(stack) += ((size) * sizeof(type)), \
(type *)((stack) - ((size) * sizeof(type))))
#else
#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size)-1))
#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
#define PUSH(stack, size, type) \
(ALIGN((stack), sizeof(type)), (stack) += ((size) * sizeof(type)), \
(type *)((stack) - ((size) * sizeof(type))))
#endif
@ -103,11 +109,10 @@
#define ALLOC(var, size, type) type var[size]
#elif defined(USE_ALLOCA)
#define VARDECL(var) var
#define ALLOC(var, size, type) var = alloca(sizeof(type)*(size))
#define ALLOC(var, size, type) var = alloca(sizeof(type) * (size))
#else
#define VARDECL(var) var
#define ALLOC(var, size, type) var = PUSH(stack, size, type)
#endif
#endif

View file

@ -2,30 +2,19 @@
#define _T_ARRAY_H_
#include <stdlib.h>
#include "internal/dumb.h"
#ifndef LONG_LONG
#if defined __GNUC__ || defined __INTEL_COMPILER || defined __MWERKS__
#define LONG_LONG long long
#elif defined _MSC_VER || defined __WATCOMC__
#define LONG_LONG __int64
#elif defined __sgi
#define LONG_LONG long long
#else
#error 64-bit integer type unknown
#endif
#endif
void *timekeeping_array_create(size_t size);
void timekeeping_array_destroy(void *array);
void *timekeeping_array_dup(void *array);
void * timekeeping_array_create(size_t size);
void timekeeping_array_destroy(void * array);
void * timekeeping_array_dup(void * array);
void timekeeping_array_reset(void *array, size_t loop_start);
void timekeeping_array_reset(void * array, size_t loop_start);
void timekeeping_array_push(void *array, size_t index, LONG_LONG time);
void timekeeping_array_bump(void *array, size_t index);
void timekeeping_array_push(void * array, size_t index, LONG_LONG time);
void timekeeping_array_bump(void * array, size_t index);
unsigned int timekeeping_array_get_count(void *array, size_t index);
unsigned int timekeeping_array_get_count(void * array, size_t index);
LONG_LONG timekeeping_array_get_item(void * array, size_t index);
LONG_LONG timekeeping_array_get_item(void *array, size_t index);
#endif

View file

@ -1,77 +0,0 @@
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
* | | | | | | || ||\ /| |
* | | | | | | || || \/ | | ' ' '
* | | | | | | || || | | . .
* | |_/ / \ \__// || | |
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
* / \
* / . \
* licence.txt - Conditions for use of DUMB. / / \ \
* | < / \_
* If you do not agree to these terms, please | \/ /\ /
* do not use DUMB. \_ / > /
* | \ / /
* Information in [brackets] is provided to aid | ' /
* interpretation of the licence. \__/
*/
Dynamic Universal Music Bibliotheque, Version 0.9.3
Copyright (C) 2001-2005 Ben Davis, Robert J Ohannessian and Julien Cugniere
This software is provided 'as-is', without any express or implied warranty.
In no event shall the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a
product, you are requested to acknowledge its use in the product
documentation, along with details on where to get an unmodified version of
this software, but this is not a strict requirement.
[Note that the above point asks for a link to DUMB, not just a mention.
Googling for DUMB doesn't help much! The URL is "http://dumb.sf.net/".]
[The link was originally strictly required. This was changed for two
reasons. Firstly, if many projects request an acknowledgement, the list of
acknowledgements can become quite unmanageable. Secondly, DUMB was placing
a restriction on the code using it, preventing people from using the GNU
General Public Licence which disallows any such restrictions. See
http://www.gnu.org/philosophy/bsd.html for more information on this
subject. However, if DUMB plays a significant part in your project, we do
urge you to acknowledge its use.]
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed from or altered in any source distribution.
4. If you are using the Program in someone else's bedroom on any Monday at
3:05 pm, you are not allowed to modify the Program for ten minutes. [This
clause provided by Inphernic; every licence should contain at least one
clause, the reasoning behind which is far from obvious.]
5. Users who wish to use DUMB for the specific purpose of playing music are
required to feed their dog on every full moon (if deemed appropriate).
[This clause provided by Allefant, who couldn't remember what Inphernic's
clause was.]
6. No clause in this licence shall prevent this software from being depended
upon by a product licensed under the GNU General Public Licence. If such a
clause is deemed to exist, Debian, then it shall be respected in spirit as
far as possible and all other clauses shall continue to apply in full
force.
We regret that we cannot provide any warranty, not even the implied warranty
of merchantability or fitness for a particular purpose.
Some files generated or copied by automake, autoconf and friends are
available in an extra download. These fall under separate licences but are
all free to distribute. Please check their licences as necessary.

View file

@ -1,541 +0,0 @@
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
* | | | | | | || ||\ /| |
* | | | | | | || || \/ | | ' ' '
* | | | | | | || || | | . .
* | |_/ / \ \__// || | |
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
* / \
* / . \
* readme.txt - General information on DUMB. / / \ \
* | < / \_
* | \/ /\ /
* \_ / > /
* | \ / /
* | ' /
* \__/
*/
********************
*** Introduction ***
********************
Thank you for downloading DUMB v0.9.3! You should have the following
documentation:
readme.txt - This file
licence.txt - Conditions for the use of this software
release.txt - Release notes and changes for this and past releases
docs/
howto.txt - Step-by-step instructions on adding DUMB to your project
faq.txt - Frequently asked questions and answers to them
dumb.txt - DUMB library reference
deprec.txt - Information about deprecated parts of the API
ptr.txt - Quick introduction to pointers for those who need it
fnptr.txt - Explanation of function pointers for those who need it
modplug.txt - Our official position regarding ModPlug Tracker
This file will help you get DUMB set up. If you have not yet done so, please
read licence.txt and release.txt before proceeding. After you've got DUMB set
up, please refer to the files in the docs/ directory at your convenience. I
recommend you start with howto.txt.
****************
*** Features ***
****************
Here is the statutory feature list:
- Freeware
- Supports playback of IT, XM, S3M and MOD files
- Faithful to the original trackers, especially IT; if it plays your module
wrongly, please tell me so I can fix the bug! (But please don't complain
about differences between DUMB and ModPlug Tracker; see docs/modplug.txt)
- Accurate support for low-pass resonant filters for IT files
- Very accurate timing and pitching; completely deterministic playback
- Click removal
- Facility to embed music files in other files (e.g. Allegro datafiles)
- Three resampling quality settings: aliasing, linear interpolation and cubic
interpolation
- Number of samples playing at once can be limited to reduce processor usage,
but samples will come back in when other louder ones stop
- All notes will be present and correct even if you start a piece of music in
the middle
- Option to take longer loading but seek fast to any point before the music
first loops (seeking time increases beyond this point)
- Audio generated can be used in any way; DUMB does not necessarily send it
straight to a sound output system
- Can be used with Allegro, can be used without (if you'd like to help make
DUMB more approachable to people who aren't using Allegro, please contact
me)
- Makefile provided for DJGPP, MinGW, Linux, BeOS and Mac OS X
- Project files provided for MSVC 6
- Autotools-based configure script available as a separate download for
masochists
- Code should port anywhere that has a 32-bit C compiler; instructions on
compiling it manually are available further down
*********************
*** What you need ***
*********************
To use DUMB, you need a 32-bit C compiler (GCC and MSVC are fine). If you
have Allegro, DUMB can integrate with its audio streams and datafiles, making
your life easier. If you do not wish to use Allegro, you will have to do some
work to get music playing back. The 'dumbplay' example program requires
Allegro.
Allegro - http://alleg.sf.net/
**********************************************
*** How to set DUMB up with DJGPP or MinGW ***
**********************************************
You should have got the .zip version. If for some reason you got the .tar.gz
version instead, you may have to convert make/config.bat to DOS text file
format. WinZip does this automatically by default. Otherwise, loading it into
MS EDIT and saving it again should do the trick (but do not do this to the
Makefiles as it destroys tabs). You will have to do the same for any files
you want to view in Windows Notepad. If you have problems, just go and
download the .zip instead.
Make sure you preserved the directory structure when you extracted DUMB from
the archive. Most unzipping programs will do this by default, but pkunzip
requires you to pass -d. If not, please delete DUMB and extract it again
properly.
If you are using Windows, open an MS-DOS Prompt or a Windows Command Line.
Change to the directory into which you unzipped DUMB.
If you are using MinGW (and you haven't renamed 'mingw32-make'), type:
mingw32-make
Otherwise, type the following:
make
DUMB will ask you whether you wish to compile for DJGPP or MinGW. Then it
will ask you whether you want support for Allegro. (You have to have made and
installed Allegro's optimised library for this to work.) Finally, it will
compile optimised and debugging builds of DUMB, along with the example
programs. When it has finished, run one of the following to install the
libraries:
make install
mingw32-make install
All done! If you ever need the configuration again (e.g. if you compiled for
DJGPP before and you want to compile for MinGW now), run one of the
following:
make config
mingw32-make config
See the comments in the Makefile for other targets.
Note: the Makefile will only work properly if you have COMSPEC or ComSpec set
to point to command.com or cmd.exe. If you set it to point to a Unix-style
shell, the Makefile won't work.
Please let me know if you have any trouble.
As an alternative, MSYS users may attempt to use the configure script,
available in dumb-0.9.3-autotools.tar.gz. This has been found to work without
Allegro, and is untested with Allegro. I should appreciate feedback from
anyone else who tries this. I do not recommend its use, partly because it
creates dynamically linked libraries and I don't know how to stop it from
doing that (see the section on compiling DUMB manually), and partly because
autotools are plain evil.
Scroll down for information on the example programs. Refer to docs/howto.txt
when you are ready to start programming with DUMB. If you use DUMB in a game,
let me know - I might decide to place a link to your game on DUMB's website!
******************************************************
*** How to set DUMB up with Microsoft Visual C++ 6 ***
******************************************************
If you have a newer version of Microsoft Visual C++ or Visual Something that
supports C++, please try these instructions and let me know if it works.
You should have got the .zip version. If for some reason you got the .tar.gz
version instead, you may have to convert some files to DOS text file format.
WinZip does this automatically by default. Otherwise, loading such files into
MS EDIT and saving them again should do the trick. You will have to do this
for any files you want to view in Windows Notepad. If you have problems, just
go and download the .zip instead.
Make sure you preserved the directory structure when you extracted DUMB from
the archive. Most unzipping programs will do this by default, but pkunzip
requires you to pass -d. If not, please delete DUMB and extract it again
properly.
DUMB comes with a workspace Microsoft Visual C++ 6, containing projects for
the DUMB core, the Allegro interface library and each of the examples. The
first thing you might want to do is load the workspace up and have a look
around. You will find it in the dumb\vc6 directory under the name dumb.dsw.
Note that the aldumb and dumbplay projects require Allegro, so they won't
work if you don't have Allegro. Nevertheless, dumbplay is the best-commented
of the examples, so do have a look.
When you are ready to add DUMB to your project, follow these instructions:
1. Open your project in VC++.
2. Select Project|Insert Project into Workspace...
3. Navigate to the dumb\vc6\dumb directory and select dumb.dsp.
Alternatively, if you know that you are statically linking with a library
that uses the statically linked multithreaded runtime (/MT), you may wish
to select dumb_static.dsp in the dumb_static subdirectory instead.
4. Select Build|Set Active Configuration..., and reselect one of your
project's configurations.
5. Select Project|Dependencies... and ensure your project is dependent on
DUMB.
6. Select Project|Settings..., Settings for: All Configurations, C/C++ tab,
Preprocessor category. Add the DUMB include directory to the Additional
Include Directories box.
7. Ensure that for all the projects in the workspace (or more likely just all
the projects in a particular dependency chain) the run-time libraries are
the same. That's in Project|Settings, C/C++ tab, Code generation category,
Use run-time library dropdown. The settings for Release and Debug are
separate, so you'll have to change them one at a time. Exactly which run-
time library you use will depend on what you need; it doesn't appear that
DUMB has any particular requirements, so set it to whatever you're using
now. (It will have to be /MD, the multithreaded DLL library, if you are
statically linking with Allegro. If you are dynamically linking with
Allegro than it doesn't matter.)
8. If you are using Allegro, do some or all of the above for the aldumb.dsp
project in the aldumb directory too.
Good thing you only have to do all that once ... or twice ...
If you have the Intel compiler installed, it will - well, should - be used to
compile DUMB. The only setting I [Tom Seddon] added is /QxiM. This allows the
compiler to use PPro and MMX instructions, and so when compiling with Intel
the resultant EXE will require a Pentium II or greater. I don't think this is
unreasonable. After all, it is 2003 :)
[Note from Ben: the Intel compiler is evil! It makes AMD processors look bad!
Patch it or boycott it or something!]
If you don't have the Intel compiler, VC will compile DUMB as normal.
This project file and these instructions were provided by Tom Seddon (I hope
I got his name right; I had to guess it from his e-mail address!). Chad
Austin has since changed the project files around, and I've just attempted to
hack them to incorporate new source files. I've also tried to update the
instructions using guesswork and some knowledge of Visual J++ (you heard me).
The instructions and the project files are to this day untested by me. If you
have problems, check the download page at http://dumb.sf.net/ to see if they
are addressed; failing that, direct queries to me and I'll try to figure them
out.
If you have any comments at all on how the VC6 projects are laid out, or how
the instructions could be improved, I should be really grateful to hear them.
I am a perfectionist, after all. :)
Scroll down for information on the example programs. When you are ready to
start using DUMB, refer to docs/howto.txt. If you use DUMB in a game, let me
know - I might decide to place a link to your game on DUMB's website!
******************************************************
*** How to set DUMB up on Linux, BeOS and Mac OS X ***
******************************************************
You should have got the .tar.gz version. If for some reason you got the .zip
version instead, you may have to strip all characters with ASCII code 13 from
some of the text files. If you have problems, just go and download the
.tar.gz instead.
You have two options. There is a Makefile which should cope with most
systems. The first option is to use this default Makefile, and the procedure
is explained below. The second option is to download
dumb-0.9.3-autotools.tar.gz, extract it over the installation, run
./configure and use the generated Makefile. Users who choose to do this are
left to their own devices but advised to read the information at the end of
this section. I strongly recommend the first option.
If you are not using the configure script, the procedure is as follows.
First, run the following command as a normal user:
make
You will be asked whether you want Allegro support. Then, unless you are on
BeOS, you will be asked where you'd like DUMB to install its headers,
libraries and examples (which will go in the include/, lib/ and bin/
subdirectories of the prefix you specify). BeOS has fixed locations for these
files. You may use shell variables here, e.g. $HOME or ${HOME}, but ~ will
not work. Once you have specified these pieces of information, the optimised
and debugging builds of DUMB will be compiled, along with the examples. When
it has finished, you can install them with:
make install
You may need to be root for this to work. It depends on the prefix you chose.
Note: the Makefile will only work if COMSPEC and ComSpec are both undefined.
If either of these is defined, the Makefile will try to build for a Windows
system, and will fail.
Please let me know if you have any trouble.
Scroll down for information on the example programs. Refer to docs/howto.txt
when you are ready to start programming with DUMB. If you use DUMB in a game,
let me know - I might decide to place a link to your game on DUMB's website!
Important information for users of the configure script follows.
The Makefile generated by the configure script creates dynamically linked
libraries, and I don't know how to stop it from doing so. See the section
below on building DUMB manually for why I recommend linking DUMB statically.
However, if you choose to use the configure script, note the following.
The default Makefile is a copy of Makefile.rdy (short for 'ready'), and it
must exist with the name Makefile.rdy in order to work. The configure script
will overwrite Makefile, so if you want the default Makefile back, just run:
cp Makefile.rdy Makefile
Do not use a symlink, as that would result in Makefile.rdy getting
overwritten next time the configure script is run!
You can also access the usual build system by passing '-f Makefile.rdy' to
Make.
********************************************************
*** How to build DUMB manually if nothing else works ***
********************************************************
Those porting to platforms without floating point support should be aware
that DUMB does use floating point operations but not in the inner loops. They
are used for volume and note pitch calculations, and they are used when
initialising the filter algorithm for given cut-off and resonance values.
Please let me know if this is a problem for you. If there is enough demand, I
may be able to eliminate one or both of these cases.
All of the library source code may be found in the src/ subdirectory. There
are headers in the include/ subdirectory, and src/helpers/resample.c also
#includes some .inc files in its own directory.
There are four subdirectories under src/. For projects not using Allegro, you
will need all the files in src/core/, src/helpers/ and src/it/. If you are
using Allegro, you will want the src/allegro/ subdirectory too. For
consistency with the other build systems, the contents of src/allegro/ should
be compiled into a separate library.
I recommend static-linking DUMB, since the version information is done via
macros and the API has a tendency to change. If you static-link, then once
your program is in binary form, you can be sure that changes to the installed
version of DUMB won't cause it to malfuction. It is my fault that the API has
been so unstable. Sorry!
Compile each .c file separately. As mentioned above, you will need to specify
two places to look for #include files: the include/ directory and the source
file's own directory. You will also need to define the symbol
DUMB_DECLARE_DEPRECATED on the command line.
Do not compile the .inc files separately.
You may need to edit dumb.h and add your own definition for LONG_LONG. It
should be a 64-bit integer. If you do this, please see if you can add a check
for your compiler so that it still works with other compilers.
DUMB has two build modes. If you define the symbol DEBUGMODE, some checks for
programmer error will be incorporated into the library. Otherwise it will be
built without any such checks. (DUMB will however always thoroughly check the
validity of files it is loading. If you ever find a module file that crashes
DUMB, please let me know!)
I recommend building two versions of the library, one with DEBUGMODE defined
and debugging information included, and the other with compiler optimisation
enabled. If you can install DUMB system-wide so that your projects, and other
people's, can simply #include <dumb.h> or <aldumb.h> and link with libraries
by simple name with no path, then that is ideal.
If you successfully port DUMB to a new platform, please let me know!
****************************
*** The example programs ***
****************************
Three example programs are provided. On DOS and Windows, you can find them in
the examples subdirectory. On other systems they will be installed system-
wide.
dumbplay
This program will only be built if you have Allegro. Pass it the filename
of an IT, XM, S3M or MOD file, and it will play it. It's not a polished
player with real-time threading or anything - so don't complain about it
stuttering while you use other programs - but it does show DUMB's fidelity
nicely. You can control the playback quality by editing dumb.ini, which
must be in the current working directory. (This is a flaw for systems
where the program is installed system-wide, but it is non-fatal.) Have a
look at the examples/dumb.ini file for further information.
dumbout
This program does not need Allegro. You can use it to stream an IT, XM,
S3M or MOD file to raw PCM. This can be used as input to an encoder like
oggenc (with appropriate command-line options), or it can be sent to a
.pcm file which can be read by any respectable waveform editor. This
program is also convenient for timing DUMB. Compare the time it takes to
render a module with the module's playing time! dumbout doesn't try to
read any configuration file; the options are set on the command line.
dumb2wav
This program is much the same as dumbout, but it writes a .wav file with
the appropriate header. Thanks go to Chad Austin for this useful tool.
*********************************************
*** Downloading music or writing your own ***
*********************************************
If you would like to compose your own music modules, then this section should
help get you started.
The best programs for the job are the trackers that pioneered the file
formats:
Impulse Tracker - IT files - http://www.lim.com.au/ImpulseTracker/
Fast Tracker II - XM files - http://www.fasttracker2.com/
Scream Tracker 3 - S3M files - No official site known, please use Google
MOD files come from the Amiga; I do not know what PC tracker to recommend for
editing these. If you know of one, let me know! In the meantime, I would
recommend using a more advanced file format. However, don't convert your
existing MODs just for the sake of it.
Fast Tracker II is Shareware. It offers a very flashy interface and has a
game embedded, but the IT file format is more powerful and better defined. By
all means try them both and see which you prefer; it is largely a matter of
taste (and, in some cases, religion). Impulse Tracker and Scream Tracker 3
are Freeware, although you can donate to Impulse Tracker and receive a
slightly upgraded version. DUMB is likely to be at its best with IT files.
These editors are DOS programs. Users of DOS-incapable operating systems may
like to try ModPlug Tracker, but should read docs/modplug.txt before using it
for any serious work. If you use a different operating system, or if you know
of any module editors for Windows that are more faithful to the original
trackers' playback, please give me some links so I can put them here!
ModPlug Tracker - http://www.modplug.com/
If you have an x86 Linux system with VGA-compatible hardware (which covers
all PC graphics cards I've ever seen), you should be able to get Impulse
Tracker running with DOSEMU. You will have to give it access to the VGA ports
and run it in a true console, as it will not work with the X-based VGA
emulation. I personally added the SB16 emulation to DOSEMU, so you can even
use filters! However, it corrupts samples alarmingly often when saving on my
system - probably a DOSEMU issue. If you set this up, I am curious to know
whether it works for you.
DOSEMU - http://www.dosemu.org/
BEWARE OF WINAMP! Although it's excellent for MP3s, it is notorious for being
one of the worst module players in existence; very many modules play wrongly
with it. There are plug-ins available to improve Winamp's module support, for
example WSP.
Winamp - http://www.winamp.com/
WSP - http://www.spytech.cz/index.php?sec=demo
(There is a Winamp plug-in that uses DUMB, but it is unreliable. If anyone
would like to work on it, please get in touch.)
While I am at it I should also point out that Winamp is notorious for
containing security flaws. Install it at your own risk, and if it is your
work computer, check with your boss first!
Samples and instruments are the building blocks of music modules. You can
download samples at
http://www.tump.net/
If you would like to download module files composed by other people, check
the following sites:
http://www.modarchive.com/
http://www.scene.org/
http://www.tump.net/
http://www.homemusic.cc/main.php
http://www.modplug.com/
Once again, if you know of more sites where samples or module files are
available for download, please let me know.
If you wish to use someone's music in your game, please respect the
composer's wishes. In general, you should ask the composer. Music that has
been placed in the Public Domain can be used by anyone for anything, but it
wouldn't do any harm to ask anyway if you know who the author is. In many
cases the author will be thrilled, so don't hesitate!
A note about converting modules from one format to another, or converting
from MIDI: don't do it, unless you are a musician and are prepared to go
through the file and make sure everything sounds the way it should! The
module formats are all slightly different, and MIDI is very different;
converting from one format to another will usually do some damage.
Instead, it is recommended that you allow DUMB to interpret the original file
as it sees fit. DUMB may make mistakes (it does a lot of conversion on
loading), but future versions of DUMB will be able to rectify these mistakes.
On the other hand, if you convert the file, the damage is permanent.
***********************
*** Contact details ***
***********************
If you have trouble with DUMB, or want to contact me for any other reason, my
e-mail address is given below. Please do get in touch, even if I appear to
have disappeared!
If you wish to chat online about something, perhaps on IRC, that can most
likely be arranged. Send me an e-mail.
******************
*** Conclusion ***
******************
This is the conclusion.
Ben Davis
entheh@users.sf.net

View file

@ -22,50 +22,39 @@
#include "dumb.h"
#include "internal/dumb.h"
typedef struct DUMB_ATEXIT_PROC
{
struct DUMB_ATEXIT_PROC *next;
void (*proc)(void);
}
DUMB_ATEXIT_PROC;
typedef struct DUMB_ATEXIT_PROC {
struct DUMB_ATEXIT_PROC *next;
void (*proc)(void);
} DUMB_ATEXIT_PROC;
static DUMB_ATEXIT_PROC *dumb_atexit_proc = NULL;
int dumb_atexit(void (*proc)(void)) {
DUMB_ATEXIT_PROC *dap = dumb_atexit_proc;
while (dap) {
if (dap->proc == proc)
return 0;
dap = dap->next;
}
int dumb_atexit(void (*proc)(void))
{
DUMB_ATEXIT_PROC *dap = dumb_atexit_proc;
dap = malloc(sizeof(*dap));
while (dap) {
if (dap->proc == proc) return 0;
dap = dap->next;
}
if (!dap)
return -1;
dap = malloc(sizeof(*dap));
dap->next = dumb_atexit_proc;
dap->proc = proc;
dumb_atexit_proc = dap;
if (!dap)
return -1;
dap->next = dumb_atexit_proc;
dap->proc = proc;
dumb_atexit_proc = dap;
return 0;
return 0;
}
void dumb_exit(void)
{
while (dumb_atexit_proc) {
DUMB_ATEXIT_PROC *next = dumb_atexit_proc->next;
(*dumb_atexit_proc->proc)();
free(dumb_atexit_proc);
dumb_atexit_proc = next;
}
void dumb_exit(void) {
while (dumb_atexit_proc) {
DUMB_ATEXIT_PROC *next = dumb_atexit_proc->next;
(*dumb_atexit_proc->proc)();
free(dumb_atexit_proc);
dumb_atexit_proc = next;
}
}

View file

@ -26,17 +26,9 @@
#include "dumb.h"
#include "internal/dumb.h"
dumb_off_t duh_get_length(DUH *duh) { return duh ? duh->length : 0; }
long duh_get_length(DUH *duh)
{
return duh ? duh->length : 0;
}
void duh_set_length(DUH *duh, long length)
{
if (duh)
duh->length = length;
void duh_set_length(DUH *duh, dumb_off_t length) {
if (duh)
duh->length = length;
}

View file

@ -22,37 +22,32 @@
#include "dumb.h"
#include "internal/dumb.h"
const char *duh_get_tag(DUH *duh, const char *key) {
int i;
ASSERT(key);
if (!duh || !duh->tag)
return NULL;
for (i = 0; i < duh->n_tags; i++)
if (strcmp(key, duh->tag[i][0]) == 0)
return duh->tag[i][1];
const char *duh_get_tag(DUH *duh, const char *key)
{
int i;
ASSERT(key);
if (!duh || !duh->tag) return NULL;
for (i = 0; i < duh->n_tags; i++)
if (strcmp(key, duh->tag[i][0]) == 0)
return duh->tag[i][1];
return NULL;
return NULL;
}
int duh_get_tag_iterator_size(DUH *duh)
{
return (duh && duh->tag ? duh->n_tags : 0);
int duh_get_tag_iterator_size(DUH *duh) {
return (duh && duh->tag ? duh->n_tags : 0);
}
int duh_get_tag_iterator_get(DUH *duh, const char **key, const char **tag,
int i) {
ASSERT(key);
ASSERT(tag);
if (!duh || !duh->tag || i >= duh->n_tags)
return -1;
int duh_get_tag_iterator_get(DUH *duh, const char **key, const char **tag, int i)
{
ASSERT(key);
ASSERT(tag);
if (!duh || !duh->tag || i >= duh->n_tags) return -1;
*key = duh->tag[i][0];
*tag = duh->tag[i][1];
*key = duh->tag[i][0];
*tag = duh->tag[i][1];
return 0;
return 0;
}

View file

@ -22,398 +22,352 @@
#include "dumb.h"
#include "internal/dumb.h"
static const DUMBFILE_SYSTEM *the_dfs = NULL;
void register_dumbfile_system(const DUMBFILE_SYSTEM *dfs)
{
ASSERT(dfs);
ASSERT(dfs->open);
ASSERT(dfs->getc);
ASSERT(dfs->close);
void register_dumbfile_system(const DUMBFILE_SYSTEM *dfs) {
ASSERT(dfs);
ASSERT(dfs->open);
ASSERT(dfs->getc);
ASSERT(dfs->close);
ASSERT(dfs->seek);
ASSERT(dfs->get_size);
the_dfs = dfs;
the_dfs = dfs;
}
#include "internal/dumbfile.h"
DUMBFILE *dumbfile_open(const char *filename) {
DUMBFILE *f;
ASSERT(the_dfs);
DUMBFILE *dumbfile_open(const char *filename)
{
DUMBFILE *f;
f = (DUMBFILE *)malloc(sizeof(*f));
ASSERT(the_dfs);
if (!f)
return NULL;
f = (DUMBFILE *) malloc(sizeof(*f));
f->dfs = the_dfs;
if (!f)
return NULL;
f->file = (*the_dfs->open)(filename);
f->dfs = the_dfs;
if (!f->file) {
free(f);
return NULL;
}
f->file = (*the_dfs->open)(filename);
f->pos = 0;
if (!f->file) {
free(f);
return NULL;
}
f->pos = 0;
return f;
return f;
}
DUMBFILE *dumbfile_open_ex(void *file, const DUMBFILE_SYSTEM *dfs) {
DUMBFILE *f;
ASSERT(dfs);
ASSERT(dfs->getc);
ASSERT(file);
DUMBFILE *dumbfile_open_ex(void *file, const DUMBFILE_SYSTEM *dfs)
{
DUMBFILE *f;
f = (DUMBFILE *)malloc(sizeof(*f));
ASSERT(dfs);
ASSERT(dfs->getc);
ASSERT(file);
if (!f) {
if (dfs->close)
(*dfs->close)(file);
return NULL;
}
f = (DUMBFILE *) malloc(sizeof(*f));
f->dfs = dfs;
f->file = file;
if (!f) {
if (dfs->close)
(*dfs->close)(file);
return NULL;
}
f->pos = 0;
f->dfs = dfs;
f->file = file;
f->pos = 0;
return f;
return f;
}
dumb_off_t dumbfile_pos(DUMBFILE *f) {
ASSERT(f);
long dumbfile_pos(DUMBFILE *f)
{
ASSERT(f);
return f->pos;
return f->pos;
}
/* Move forward in the file from the current position by n bytes. */
int dumbfile_skip(DUMBFILE *f, dumb_off_t n) {
int rv;
ASSERT(f);
ASSERT(n >= 0);
int dumbfile_skip(DUMBFILE *f, long n)
{
int rv;
if (f->pos < 0)
return -1;
ASSERT(f);
ASSERT(n >= 0);
f->pos += n;
if (f->pos < 0)
return -1;
if (f->dfs->skip) {
rv = (*f->dfs->skip)(f->file, n);
if (rv) {
f->pos = -1;
return rv;
}
} else {
while (n) {
rv = (*f->dfs->getc)(f->file);
if (rv < 0) {
f->pos = -1;
return rv;
}
n--;
}
}
f->pos += n;
if (f->dfs->skip) {
rv = (*f->dfs->skip)(f->file, n);
if (rv) {
f->pos = -1;
return rv;
}
} else {
while (n) {
rv = (*f->dfs->getc)(f->file);
if (rv < 0) {
f->pos = -1;
return rv;
}
n--;
}
}
return 0;
return 0;
}
int dumbfile_getc(DUMBFILE *f) {
int rv;
ASSERT(f);
int dumbfile_getc(DUMBFILE *f)
{
int rv;
if (f->pos < 0)
return -1;
ASSERT(f);
rv = (*f->dfs->getc)(f->file);
if (f->pos < 0)
return -1;
if (rv < 0) {
f->pos = -1;
return rv;
}
rv = (*f->dfs->getc)(f->file);
f->pos++;
if (rv < 0) {
f->pos = -1;
return rv;
}
f->pos++;
return rv;
return rv;
}
int dumbfile_igetw(DUMBFILE *f) {
int l, h;
ASSERT(f);
int dumbfile_igetw(DUMBFILE *f)
{
int l, h;
if (f->pos < 0)
return -1;
ASSERT(f);
l = (*f->dfs->getc)(f->file);
if (l < 0) {
f->pos = -1;
return l;
}
if (f->pos < 0)
return -1;
h = (*f->dfs->getc)(f->file);
if (h < 0) {
f->pos = -1;
return h;
}
l = (*f->dfs->getc)(f->file);
if (l < 0) {
f->pos = -1;
return l;
}
f->pos += 2;
h = (*f->dfs->getc)(f->file);
if (h < 0) {
f->pos = -1;
return h;
}
f->pos += 2;
return l | (h << 8);
return l | (h << 8);
}
int dumbfile_mgetw(DUMBFILE *f) {
int l, h;
ASSERT(f);
int dumbfile_mgetw(DUMBFILE *f)
{
int l, h;
if (f->pos < 0)
return -1;
ASSERT(f);
h = (*f->dfs->getc)(f->file);
if (h < 0) {
f->pos = -1;
return h;
}
if (f->pos < 0)
return -1;
l = (*f->dfs->getc)(f->file);
if (l < 0) {
f->pos = -1;
return l;
}
h = (*f->dfs->getc)(f->file);
if (h < 0) {
f->pos = -1;
return h;
}
f->pos += 2;
l = (*f->dfs->getc)(f->file);
if (l < 0) {
f->pos = -1;
return l;
}
f->pos += 2;
return l | (h << 8);
return l | (h << 8);
}
long dumbfile_igetl(DUMBFILE *f) {
unsigned long rv, b;
ASSERT(f);
long dumbfile_igetl(DUMBFILE *f)
{
unsigned long rv, b;
if (f->pos < 0)
return -1;
ASSERT(f);
rv = (*f->dfs->getc)(f->file);
if ((signed long)rv < 0) {
f->pos = -1;
return rv;
}
if (f->pos < 0)
return -1;
b = (*f->dfs->getc)(f->file);
if ((signed long)b < 0) {
f->pos = -1;
return b;
}
rv |= b << 8;
rv = (*f->dfs->getc)(f->file);
if ((signed long)rv < 0) {
f->pos = -1;
return rv;
}
b = (*f->dfs->getc)(f->file);
if ((signed long)b < 0) {
f->pos = -1;
return b;
}
rv |= b << 16;
b = (*f->dfs->getc)(f->file);
if ((signed long)b < 0) {
f->pos = -1;
return b;
}
rv |= b << 8;
b = (*f->dfs->getc)(f->file);
if ((signed long)b < 0) {
f->pos = -1;
return b;
}
rv |= b << 24;
b = (*f->dfs->getc)(f->file);
if ((signed long)b < 0) {
f->pos = -1;
return b;
}
rv |= b << 16;
f->pos += 4;
b = (*f->dfs->getc)(f->file);
if ((signed long)b < 0) {
f->pos = -1;
return b;
}
rv |= b << 24;
f->pos += 4;
return rv;
return rv;
}
long dumbfile_mgetl(DUMBFILE *f) {
unsigned long rv, b;
ASSERT(f);
long dumbfile_mgetl(DUMBFILE *f)
{
unsigned long rv, b;
if (f->pos < 0)
return -1;
ASSERT(f);
rv = (*f->dfs->getc)(f->file);
if ((signed long)rv < 0) {
f->pos = -1;
return rv;
}
rv <<= 24;
if (f->pos < 0)
return -1;
b = (*f->dfs->getc)(f->file);
if ((signed long)b < 0) {
f->pos = -1;
return b;
}
rv |= b << 16;
rv = (*f->dfs->getc)(f->file);
if ((signed long)rv < 0) {
f->pos = -1;
return rv;
}
rv <<= 24;
b = (*f->dfs->getc)(f->file);
if ((signed long)b < 0) {
f->pos = -1;
return b;
}
rv |= b << 8;
b = (*f->dfs->getc)(f->file);
if ((signed long)b < 0) {
f->pos = -1;
return b;
}
rv |= b << 16;
b = (*f->dfs->getc)(f->file);
if ((signed long)b < 0) {
f->pos = -1;
return b;
}
rv |= b;
b = (*f->dfs->getc)(f->file);
if ((signed long)b < 0) {
f->pos = -1;
return b;
}
rv |= b << 8;
f->pos += 4;
b = (*f->dfs->getc)(f->file);
if ((signed long)b < 0) {
f->pos = -1;
return b;
}
rv |= b;
f->pos += 4;
return rv;
return rv;
}
unsigned long dumbfile_cgetul(DUMBFILE *f) {
unsigned long rv = 0;
int v;
do {
v = dumbfile_getc(f);
unsigned long dumbfile_cgetul(DUMBFILE *f)
{
unsigned long rv = 0;
int v;
if (v < 0)
return v;
do {
v = dumbfile_getc(f);
rv <<= 7;
rv |= v & 0x7F;
} while (v & 0x80);
if (v < 0)
return v;
rv <<= 7;
rv |= v & 0x7F;
} while (v & 0x80);
return rv;
return rv;
}
signed long dumbfile_cgetsl(DUMBFILE *f) {
unsigned long rv = dumbfile_cgetul(f);
if (f->pos < 0)
return rv;
signed long dumbfile_cgetsl(DUMBFILE *f)
{
unsigned long rv = dumbfile_cgetul(f);
if (f->pos < 0)
return rv;
return (rv >> 1) | (rv << 31);
return (rv >> 1) | (rv << 31);
}
dumb_ssize_t dumbfile_getnc(char *ptr, size_t n, DUMBFILE *f) {
dumb_ssize_t rv;
ASSERT(f);
ASSERT(n >= 0);
long dumbfile_getnc(char *ptr, long n, DUMBFILE *f)
{
long rv;
if (f->pos < 0)
return -1;
ASSERT(f);
ASSERT(n >= 0);
if (f->dfs->getnc) {
rv = (*f->dfs->getnc)(ptr, n, f->file);
if (rv < (dumb_ssize_t)n) {
f->pos = -1;
return MAX(rv, 0);
}
} else {
for (rv = 0; rv < (dumb_ssize_t)n; rv++) {
int c = (*f->dfs->getc)(f->file);
if (c < 0) {
f->pos = -1;
return rv;
}
*ptr++ = c;
}
}
if (f->pos < 0)
return -1;
f->pos += rv;
if (f->dfs->getnc) {
rv = (*f->dfs->getnc)(ptr, n, f->file);
if (rv < n) {
f->pos = -1;
return MAX(rv, 0);
}
} else {
for (rv = 0; rv < n; rv++) {
int c = (*f->dfs->getc)(f->file);
if (c < 0) {
f->pos = -1;
return rv;
}
*ptr++ = c;
}
}
f->pos += rv;
return rv;
return rv;
}
int dumbfile_seek(DUMBFILE *f, long n, int origin)
{
switch ( origin )
{
case DFS_SEEK_CUR: n += f->pos; break;
case DFS_SEEK_END: n += (*f->dfs->get_size)(f->file); break;
/* Move to an arbitrary position n in the file, specified relative to origin,
* where origin shall be one of the DFS_SEEK_* constants.
*/
int dumbfile_seek(DUMBFILE *f, dumb_off_t n, int origin) {
switch (origin) {
case DFS_SEEK_CUR:
n += f->pos;
break;
case DFS_SEEK_END:
n += (*f->dfs->get_size)(f->file);
break;
default:
break; /* keep n, seek position from beginning of file */
}
f->pos = n;
return (*f->dfs->seek)(f->file, n);
}
long dumbfile_get_size(DUMBFILE *f)
{
dumb_off_t dumbfile_get_size(DUMBFILE *f) {
return (*f->dfs->get_size)(f->file);
}
int dumbfile_error(DUMBFILE *f) {
ASSERT(f);
int dumbfile_error(DUMBFILE *f)
{
ASSERT(f);
return f->pos < 0;
return f->pos < 0;
}
int dumbfile_close(DUMBFILE *f) {
int rv;
ASSERT(f);
int dumbfile_close(DUMBFILE *f)
{
int rv;
rv = f->pos < 0;
ASSERT(f);
if (f->dfs->close)
(*f->dfs->close)(f->file);
rv = f->pos < 0;
free(f);
if (f->dfs->close)
(*f->dfs->close)(f->file);
free(f);
return rv;
return rv;
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/dumb.h"
/* load_duh(): loads a .duh file, returning a pointer to a DUH struct.
* When you have finished with it, you must pass the pointer to unload_duh()
* so that the memory can be freed.
*/
DUH *load_duh(const char *filename)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *load_duh(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = read_duh(f);
duh = read_duh(f);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -23,129 +23,124 @@
#include "dumb.h"
#include "internal/dumb.h"
static DUH_SIGNAL *make_signal(DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata) {
DUH_SIGNAL *signal;
ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) ||
(!desc->start_sigrenderer && !desc->end_sigrenderer));
ASSERT(desc->sigrenderer_generate_samples &&
desc->sigrenderer_get_current_sample);
static DUH_SIGNAL *make_signal(DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata)
{
DUH_SIGNAL *signal;
signal = malloc(sizeof(*signal));
ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample);
if (!signal) {
if (desc->unload_sigdata)
if (sigdata)
(*desc->unload_sigdata)(sigdata);
return NULL;
}
signal = malloc(sizeof(*signal));
signal->desc = desc;
signal->sigdata = sigdata;
if (!signal) {
if (desc->unload_sigdata)
if (sigdata)
(*desc->unload_sigdata)(sigdata);
return NULL;
}
signal->desc = desc;
signal->sigdata = sigdata;
return signal;
return signal;
}
DUH *make_duh(dumb_off_t length, int n_tags, const char *const tags[][2],
int n_signals, DUH_SIGTYPE_DESC *desc[], sigdata_t *sigdata[]) {
DUH *duh = malloc(sizeof(*duh));
int i;
int fail;
if (duh) {
duh->n_signals = n_signals;
DUH *make_duh(
long length,
int n_tags,
const char *const tags[][2],
int n_signals,
DUH_SIGTYPE_DESC *desc[],
sigdata_t *sigdata[]
)
{
DUH *duh = malloc(sizeof(*duh));
int i;
int fail;
duh->signal = malloc(n_signals * sizeof(*duh->signal));
if (duh) {
duh->n_signals = n_signals;
if (!duh->signal) {
free(duh);
duh = NULL;
}
}
duh->signal = malloc(n_signals * sizeof(*duh->signal));
if (!duh) {
for (i = 0; i < n_signals; i++)
if (desc[i]->unload_sigdata)
if (sigdata[i])
(*desc[i]->unload_sigdata)(sigdata[i]);
return NULL;
}
if (!duh->signal) {
free(duh);
duh = NULL;
}
}
duh->n_tags = 0;
duh->tag = NULL;
if (!duh) {
for (i = 0; i < n_signals; i++)
if (desc[i]->unload_sigdata)
if (sigdata[i])
(*desc[i]->unload_sigdata)(sigdata[i]);
return NULL;
}
fail = 0;
duh->n_tags = 0;
duh->tag = NULL;
for (i = 0; i < n_signals; i++) {
duh->signal[i] = make_signal(desc[i], sigdata[i]);
if (!duh->signal[i])
fail = 1;
}
fail = 0;
if (fail) {
unload_duh(duh);
return NULL;
}
for (i = 0; i < n_signals; i++) {
duh->signal[i] = make_signal(desc[i], sigdata[i]);
if (!duh->signal[i])
fail = 1;
}
duh->length = length;
if (fail) {
unload_duh(duh);
return NULL;
}
{
int mem = n_tags * 2; /* account for NUL terminators here */
char *ptr;
duh->length = length;
for (i = 0; i < n_tags; i++)
mem += strlen(tags[i][0]) + strlen(tags[i][1]);
{
int mem = n_tags * 2; /* account for NUL terminators here */
char *ptr;
if (mem <= 0)
return duh;
for (i = 0; i < n_tags; i++)
mem += strlen(tags[i][0]) + strlen(tags[i][1]);
duh->tag = malloc(n_tags * sizeof(*duh->tag));
if (!duh->tag)
return duh;
duh->tag[0][0] = malloc(mem);
if (!duh->tag[0][0]) {
free(duh->tag);
duh->tag = NULL;
return duh;
}
duh->n_tags = n_tags;
ptr = duh->tag[0][0];
for (i = 0; i < n_tags; i++) {
duh->tag[i][0] = ptr;
strcpy(ptr, tags[i][0]);
ptr += strlen(tags[i][0]) + 1;
duh->tag[i][1] = ptr;
strcpy(ptr, tags[i][1]);
ptr += strlen(tags[i][1]) + 1;
}
}
if (mem <= 0) return duh;
duh->tag = malloc(n_tags * sizeof(*duh->tag));
if (!duh->tag) return duh;
duh->tag[0][0] = malloc(mem);
if (!duh->tag[0][0]) {
free(duh->tag);
duh->tag = NULL;
return duh;
}
duh->n_tags = n_tags;
ptr = duh->tag[0][0];
for (i = 0; i < n_tags; i++) {
duh->tag[i][0] = ptr;
strcpy(ptr, tags[i][0]);
ptr += strlen(tags[i][0]) + 1;
duh->tag[i][1] = ptr;
strcpy(ptr, tags[i][1]);
ptr += strlen(tags[i][1]) + 1;
}
}
return duh;
return duh;
}
int duh_add_signal(DUH *duh, DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata)
{
DUH_SIGNAL **signal;
int duh_add_signal(DUH *duh, DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata) {
DUH_SIGNAL **signal;
if ( !duh || !desc || !sigdata ) return -1;
if (!duh || !desc || !sigdata)
return -1;
signal = ( DUH_SIGNAL ** ) realloc( duh->signal, ( duh->n_signals + 1 ) * sizeof( *duh->signal ) );
if ( !signal ) return -1;
duh->signal = signal;
signal = (DUH_SIGNAL **)realloc(duh->signal, (duh->n_signals + 1) *
sizeof(*duh->signal));
if (!signal)
return -1;
duh->signal = signal;
memmove( signal + 1, signal, duh->n_signals * sizeof( *signal ) );
duh->n_signals++;
memmove(signal + 1, signal, duh->n_signals * sizeof(*signal));
duh->n_signals++;
signal[ 0 ] = make_signal( desc, sigdata );
if ( !signal[ 0 ] ) return -1;
signal[0] = make_signal(desc, sigdata);
if (!signal[0])
return -1;
return 0;
return 0;
}

View file

@ -22,37 +22,32 @@
#include "dumb.h"
#include "internal/dumb.h"
/* You have to specify the type of sigdata, proving you know what to do with
* the pointer. If you get it wrong, you can expect NULL back.
*/
sigdata_t *duh_get_raw_sigdata(DUH *duh, int sig, long type)
{
int i;
DUH_SIGNAL *signal;
sigdata_t *duh_get_raw_sigdata(DUH *duh, int sig, long type) {
int i;
DUH_SIGNAL *signal;
if (!duh) return NULL;
if (!duh)
return NULL;
if ( sig >= 0 )
{
if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL;
if (sig >= 0) {
if ((unsigned int)sig >= (unsigned int)duh->n_signals)
return NULL;
signal = duh->signal[sig];
signal = duh->signal[sig];
if (signal && signal->desc->type == type)
return signal->sigdata;
}
else
{
for ( i = 0; i < duh->n_signals; i++ )
{
signal = duh->signal[i];
if (signal && signal->desc->type == type)
return signal->sigdata;
} else {
for (i = 0; i < duh->n_signals; i++) {
signal = duh->signal[i];
if (signal && signal->desc->type == type)
return signal->sigdata;
}
}
if (signal && signal->desc->type == type)
return signal->sigdata;
}
}
return NULL;
return NULL;
}

View file

@ -22,86 +22,80 @@
#include "dumb.h"
#include "internal/dumb.h"
static DUH_SIGNAL *read_signal(DUH *duh, DUMBFILE *f) {
DUH_SIGNAL *signal;
long type;
signal = malloc(sizeof(*signal));
static DUH_SIGNAL *read_signal(DUH *duh, DUMBFILE *f)
{
DUH_SIGNAL *signal;
long type;
if (!signal)
return NULL;
signal = malloc(sizeof(*signal));
type = dumbfile_mgetl(f);
if (dumbfile_error(f)) {
free(signal);
return NULL;
}
if (!signal)
return NULL;
signal->desc = _dumb_get_sigtype_desc(type);
if (!signal->desc) {
free(signal);
return NULL;
}
type = dumbfile_mgetl(f);
if (dumbfile_error(f)) {
free(signal);
return NULL;
}
if (signal->desc->load_sigdata) {
signal->sigdata = (*signal->desc->load_sigdata)(duh, f);
if (!signal->sigdata) {
free(signal);
return NULL;
}
} else
signal->sigdata = NULL;
signal->desc = _dumb_get_sigtype_desc(type);
if (!signal->desc) {
free(signal);
return NULL;
}
if (signal->desc->load_sigdata) {
signal->sigdata = (*signal->desc->load_sigdata)(duh, f);
if (!signal->sigdata) {
free(signal);
return NULL;
}
} else
signal->sigdata = NULL;
return signal;
return signal;
}
/* read_duh(): reads a DUH from an already open DUMBFILE, and returns its
* pointer, or null on error. The file is not closed.
*/
DUH *read_duh(DUMBFILE *f)
{
DUH *duh;
int i;
DUH *read_duh(DUMBFILE *f) {
DUH *duh;
int i;
if (dumbfile_mgetl(f) != DUH_SIGNATURE)
return NULL;
if (dumbfile_mgetl(f) != DUH_SIGNATURE)
return NULL;
duh = malloc(sizeof(*duh));
if (!duh)
return NULL;
duh = malloc(sizeof(*duh));
if (!duh)
return NULL;
duh->length = dumbfile_igetl(f);
if (dumbfile_error(f) || duh->length <= 0) {
free(duh);
return NULL;
}
duh->length = dumbfile_igetl(f);
if (dumbfile_error(f) || duh->length <= 0) {
free(duh);
return NULL;
}
duh->n_signals = dumbfile_igetl(f);
if (dumbfile_error(f) || duh->n_signals <= 0) {
free(duh);
return NULL;
}
duh->n_signals = (int)dumbfile_igetl(f);
if (dumbfile_error(f) || duh->n_signals <= 0) {
free(duh);
return NULL;
}
duh->signal = malloc(sizeof(*duh->signal) * duh->n_signals);
if (!duh->signal) {
free(duh);
return NULL;
}
duh->signal = malloc(sizeof(*duh->signal) * duh->n_signals);
if (!duh->signal) {
free(duh);
return NULL;
}
for (i = 0; i < duh->n_signals; i++)
duh->signal[i] = NULL;
for (i = 0; i < duh->n_signals; i++)
duh->signal[i] = NULL;
for (i = 0; i < duh->n_signals; i++) {
if (!(duh->signal[i] = read_signal(duh, f))) {
unload_duh(duh);
return NULL;
}
}
for (i = 0; i < duh->n_signals; i++) {
if (!(duh->signal[i] = read_signal(duh, f))) {
unload_duh(duh);
return NULL;
}
}
return duh;
return duh;
}

View file

@ -22,31 +22,24 @@
#include "dumb.h"
#include "internal/dumb.h"
static DUH_SIGTYPE_DESC_LINK *sigtype_desc = NULL;
static DUH_SIGTYPE_DESC_LINK **sigtype_desc_tail = &sigtype_desc;
/* destroy_sigtypes(): frees all memory allocated while registering signal
* types. This function is set up to be called by dumb_exit().
*/
static void destroy_sigtypes(void)
{
DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc, *next;
sigtype_desc = NULL;
sigtype_desc_tail = &sigtype_desc;
static void destroy_sigtypes(void) {
DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc, *next;
sigtype_desc = NULL;
sigtype_desc_tail = &sigtype_desc;
while (desc_link) {
next = desc_link->next;
free(desc_link);
desc_link = next;
}
while (desc_link) {
next = desc_link->next;
free(desc_link);
desc_link = next;
}
}
/* dumb_register_sigtype(): registers a new signal type with DUMB. The signal
* type is identified by a four-character string (e.g. "WAVE"), which you can
* encode using the the DUMB_ID() macro (e.g. DUMB_ID('W','A','V','E')). The
@ -56,49 +49,48 @@ static void destroy_sigtypes(void)
* If a DUH tries to use a signal that has not been registered using this
* function, then the library will fail to load the DUH.
*/
void dumb_register_sigtype(DUH_SIGTYPE_DESC *desc)
{
DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
void dumb_register_sigtype(DUH_SIGTYPE_DESC *desc) {
DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
ASSERT((desc->load_sigdata && desc->unload_sigdata) || (!desc->load_sigdata && !desc->unload_sigdata));
ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample);
ASSERT((desc->load_sigdata && desc->unload_sigdata) ||
(!desc->load_sigdata && !desc->unload_sigdata));
ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) ||
(!desc->start_sigrenderer && !desc->end_sigrenderer));
ASSERT(desc->sigrenderer_generate_samples &&
desc->sigrenderer_get_current_sample);
if (desc_link) {
do {
if (desc_link->desc->type == desc->type) {
desc_link->desc = desc;
return;
}
desc_link = desc_link->next;
} while (desc_link);
} else
dumb_atexit(&destroy_sigtypes);
if (desc_link) {
do {
if (desc_link->desc->type == desc->type) {
desc_link->desc = desc;
return;
}
desc_link = desc_link->next;
} while (desc_link);
} else
dumb_atexit(&destroy_sigtypes);
desc_link = *sigtype_desc_tail = malloc(sizeof(DUH_SIGTYPE_DESC_LINK));
desc_link = *sigtype_desc_tail = malloc(sizeof(DUH_SIGTYPE_DESC_LINK));
if (!desc_link)
return;
if (!desc_link)
return;
desc_link->next = NULL;
sigtype_desc_tail = &desc_link->next;
desc_link->next = NULL;
sigtype_desc_tail = &desc_link->next;
desc_link->desc = desc;
desc_link->desc = desc;
}
/* _dumb_get_sigtype_desc(): searches the registered functions for a signal
* type matching the parameter. If such a sigtype is found, it returns a
* pointer to a sigtype descriptor containing the necessary functions to
* manage the signal. If none is found, it returns NULL.
*/
DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(long type)
{
DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(long type) {
DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
while (desc_link && desc_link->desc->type != type)
desc_link = desc_link->next;
while (desc_link && desc_link->desc->type != type)
desc_link = desc_link->next;
return desc_link ? desc_link->desc : NULL;
return desc_link ? desc_link->desc : NULL;
}

View file

@ -23,309 +23,239 @@
#include "dumb.h"
#include "internal/dumb.h"
/* On the x86, we can use some tricks to speed stuff up */
#if (defined _MSC_VER) || (defined __DJGPP__) || (defined __MINGW__)
// Can't we detect Linux and other x86 platforms here? :/
#define FAST_MID(var, min, max) { \
var -= (min); \
var &= (~var) >> (sizeof(var) * CHAR_BIT - 1); \
var += (min); \
var -= (max); \
var &= var >> (sizeof(var) * CHAR_BIT - 1); \
var += (max); \
}
#define FAST_MID(var, min, max) \
{ \
var -= (min); \
var &= (~var) >> (sizeof(var) * CHAR_BIT - 1); \
var += (min); \
var -= (max); \
var &= var >> (sizeof(var) * CHAR_BIT - 1); \
var += (max); \
}
#define CONVERT8(src, pos, signconv) { \
signed int f = (src + 0x8000) >> 16; \
FAST_MID(f, -128, 127); \
((char*)sptr)[pos] = (char)f ^ signconv; \
}
#define CONVERT8(src, pos, signconv) \
{ \
signed int f = (src + 0x8000) >> 16; \
FAST_MID(f, -128, 127); \
((char *)sptr)[pos] = (char)f ^ signconv; \
}
#define CONVERT16(src, pos, signconv) { \
signed int f = (src + 0x80) >> 8; \
FAST_MID(f, -32768, 32767); \
((short*)sptr)[pos] = (short)(f ^ signconv); \
}
#define CONVERT16(src, pos, signconv) \
{ \
signed int f = (src + 0x80) >> 8; \
FAST_MID(f, -32768, 32767); \
((short *)sptr)[pos] = (short)(f ^ signconv); \
}
#else
#define CONVERT8(src, pos, signconv) \
{ \
signed int f = (src + 0x8000) >> 16; \
f = MID(-128, f, 127); \
((char *)sptr)[pos] = (char)f ^ signconv; \
}
#define CONVERT8(src, pos, signconv) \
{ \
signed int f = (src + 0x8000) >> 16; \
f = MID(-128, f, 127); \
((char *)sptr)[pos] = (char)f ^ signconv; \
}
#define CONVERT16(src, pos, signconv) \
{ \
signed int f = (src + 0x80) >> 8; \
f = MID(-32768, f, 32767); \
((short *)sptr)[pos] = (short)(f ^ signconv); \
}
#define CONVERT16(src, pos, signconv) \
{ \
signed int f = (src + 0x80) >> 8; \
f = MID(-32768, f, 32767); \
((short *)sptr)[pos] = (short)(f ^ signconv); \
}
#endif
#define CONVERT24(src, pos) { \
signed int f = src; \
f = MID(-8388608, f, 8388607); \
((unsigned char*)sptr)[pos ] = (f) & 0xFF; \
((unsigned char*)sptr)[pos+1] = (f >> 8) & 0xFF; \
((unsigned char*)sptr)[pos+2] = (f >> 16) & 0xFF; \
}
#define CONVERT24(src, pos) \
{ \
signed int f = src; \
f = MID(-8388608, f, 8388607); \
((unsigned char *)sptr)[pos] = (f)&0xFF; \
((unsigned char *)sptr)[pos + 1] = (f >> 8) & 0xFF; \
((unsigned char *)sptr)[pos + 2] = (f >> 16) & 0xFF; \
}
#define CONVERT32F(src, pos) { \
((float*)sptr)[pos] = (float)((signed int)src) * (1.0f/(float)(0xffffff/2+1)); \
}
#define CONVERT64F(src, pos) { \
((double*)sptr)[pos] = (double)((signed int)src) * (1.0/(double)(0xffffff/2+1)); \
}
#define CONVERT32F(src, pos) \
{ \
((float *)sptr)[pos] = \
(float)((signed int)src) * (1.0f / (float)(0xffffff / 2 + 1)); \
}
#define CONVERT64F(src, pos) \
{ \
((double *)sptr)[pos] = \
(double)((signed int)src) * (1.0 / (double)(0xffffff / 2 + 1)); \
}
/* This is the only deprecated function in 2.0.0. */
/* DEPRECATED */
DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos)
{
return duh_start_sigrenderer(duh, 0, n_channels, pos);
long duh_render(DUH_SIGRENDERER *sigrenderer, int bits, int unsign,
float volume, float delta, long size, void *sptr) {
long n;
sample_t **sampptr;
int n_channels;
ASSERT(bits == 8 || bits == 16);
ASSERT(sptr);
if (!sigrenderer)
return 0;
n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
ASSERT(n_channels > 0);
/* This restriction will be removed when need be. At the moment, tightly
* optimised loops exist for exactly one or two channels.
*/
ASSERT(n_channels <= 2);
sampptr = allocate_sample_buffer(n_channels, size);
if (!sampptr)
return 0;
dumb_silence(sampptr[0], n_channels * size);
size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size,
sampptr);
if (bits == 16) {
int signconv = unsign ? 0x8000 : 0x0000;
for (n = 0; n < size * n_channels; n++) {
CONVERT16(sampptr[0][n], n, signconv);
}
} else {
char signconv = unsign ? 0x80 : 0x00;
for (n = 0; n < size * n_channels; n++) {
CONVERT8(sampptr[0][n], n, signconv);
}
}
destroy_sample_buffer(sampptr);
return size;
}
long duh_render_int(DUH_SIGRENDERER *sigrenderer, sample_t ***sig_samples,
long *sig_samples_size, int bits, int unsign, float volume,
float delta, long size, void *sptr) {
long n;
/* DEPRECATED */
long duh_render(
DUH_SIGRENDERER *sigrenderer,
int bits, int unsign,
float volume, float delta,
long size, void *sptr
)
{
long n;
sample_t **sampptr;
sample_t **sampptr;
int n_channels;
int n_channels;
ASSERT(bits == 8 || bits == 16 || bits == 24);
ASSERT(sptr);
ASSERT(sig_samples);
ASSERT(sig_samples_size);
ASSERT(bits == 8 || bits == 16);
ASSERT(sptr);
if (!sigrenderer)
return 0;
if (!sigrenderer)
return 0;
n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
ASSERT(n_channels > 0);
/* This restriction will be removed when need be. At the moment, tightly
* optimised loops exist for exactly one or two channels.
*/
ASSERT(n_channels <= 2);
ASSERT(n_channels > 0);
/* This restriction will be removed when need be. At the moment, tightly
* optimised loops exist for exactly one or two channels.
*/
ASSERT(n_channels <= 2);
if ((*sig_samples == NULL) || (*sig_samples_size != size)) {
destroy_sample_buffer(*sig_samples);
*sig_samples = allocate_sample_buffer(n_channels, size);
*sig_samples_size = size;
}
sampptr = *sig_samples;
sampptr = allocate_sample_buffer(n_channels, size);
if (!sampptr)
return 0;
if (!sampptr)
return 0;
dumb_silence(sampptr[0], n_channels * size);
dumb_silence(sampptr[0], n_channels * size);
size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size,
sampptr);
size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, sampptr);
if (bits == 24) {
long i = 0;
ASSERT(unsign == 0);
if (bits == 16) {
int signconv = unsign ? 0x8000 : 0x0000;
for (n = 0; n < size * n_channels; n++, i += 3) {
CONVERT24(sampptr[0][n], i);
}
} else if (bits == 16) {
int signconv = unsign ? 0x8000 : 0x0000;
for (n = 0; n < size * n_channels; n++) {
CONVERT16(sampptr[0][n], n, signconv);
}
} else {
char signconv = unsign ? 0x80 : 0x00;
for (n = 0; n < size * n_channels; n++) {
CONVERT16(sampptr[0][n], n, signconv);
}
} else {
char signconv = unsign ? 0x80 : 0x00;
for (n = 0; n < size * n_channels; n++) {
CONVERT8(sampptr[0][n], n, signconv);
}
}
for (n = 0; n < size * n_channels; n++) {
CONVERT8(sampptr[0][n], n, signconv);
}
}
destroy_sample_buffer(sampptr);
return size;
return size;
}
long duh_render_float(DUH_SIGRENDERER *sigrenderer, sample_t ***sig_samples,
long *sig_samples_size, int bits, float volume,
float delta, long size, void *sptr) {
long n;
long duh_render_int(
DUH_SIGRENDERER *sigrenderer,
sample_t ***sig_samples,
long *sig_samples_size,
int bits, int unsign,
float volume, float delta,
long size, void *sptr
)
{
long n;
sample_t **sampptr;
sample_t **sampptr;
int n_channels;
int n_channels;
ASSERT(bits == 32 || bits == 64);
ASSERT(sptr);
ASSERT(sig_samples);
ASSERT(sig_samples_size);
ASSERT(bits == 8 || bits == 16 || bits == 24);
ASSERT(sptr);
ASSERT(sig_samples);
ASSERT(sig_samples_size);
if (!sigrenderer)
return 0;
if (!sigrenderer)
return 0;
n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
ASSERT(n_channels > 0);
/* This restriction will be removed when need be. At the moment, tightly
* optimised loops exist for exactly one or two channels.
*/
ASSERT(n_channels <= 2);
ASSERT(n_channels > 0);
/* This restriction will be removed when need be. At the moment, tightly
* optimised loops exist for exactly one or two channels.
*/
ASSERT(n_channels <= 2);
if ((*sig_samples == NULL) || (*sig_samples_size != size)) {
destroy_sample_buffer(*sig_samples);
*sig_samples = allocate_sample_buffer(n_channels, size);
*sig_samples_size = size;
}
sampptr = *sig_samples;
if ((*sig_samples == NULL) || (*sig_samples_size != size))
{
destroy_sample_buffer(*sig_samples);
*sig_samples = allocate_sample_buffer(n_channels, size);
*sig_samples_size = size;
}
sampptr = *sig_samples;
if (!sampptr)
return 0;
if (!sampptr)
return 0;
dumb_silence(sampptr[0], n_channels * size);
dumb_silence(sampptr[0], n_channels * size);
size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size,
sampptr);
size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, sampptr);
if (bits == 64) {
for (n = 0; n < size * n_channels; n++) {
CONVERT64F(sampptr[0][n], n);
}
} else if (bits == 32) {
for (n = 0; n < size * n_channels; n++) {
CONVERT32F(sampptr[0][n], n);
}
}
if (bits == 24) {
long i = 0;
ASSERT(unsign == 0);
for (n = 0; n < size * n_channels; n++, i += 3) {
CONVERT24(sampptr[0][n], i);
}
} else
if (bits == 16) {
int signconv = unsign ? 0x8000 : 0x0000;
for (n = 0; n < size * n_channels; n++) {
CONVERT16(sampptr[0][n], n, signconv);
}
} else {
char signconv = unsign ? 0x80 : 0x00;
for (n = 0; n < size * n_channels; n++) {
CONVERT8(sampptr[0][n], n, signconv);
}
}
return size;
}
long duh_render_float(
DUH_SIGRENDERER *sigrenderer,
sample_t ***sig_samples,
long *sig_samples_size,
int bits,
float volume, float delta,
long size, void *sptr
)
{
long n;
sample_t **sampptr;
int n_channels;
ASSERT(bits == 32 || bits == 64);
ASSERT(sptr);
ASSERT(sig_samples);
ASSERT(sig_samples_size);
if (!sigrenderer)
return 0;
n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
ASSERT(n_channels > 0);
/* This restriction will be removed when need be. At the moment, tightly
* optimised loops exist for exactly one or two channels.
*/
ASSERT(n_channels <= 2);
if ((*sig_samples == NULL) || (*sig_samples_size != size))
{
destroy_sample_buffer(*sig_samples);
*sig_samples = allocate_sample_buffer(n_channels, size);
*sig_samples_size = size;
}
sampptr = *sig_samples;
if (!sampptr)
return 0;
dumb_silence(sampptr[0], n_channels * size);
size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, sampptr);
if (bits == 64) {
for (n = 0; n < size * n_channels; n++) {
CONVERT64F(sampptr[0][n], n);
}
} else
if (bits == 32) {
for (n = 0; n < size * n_channels; n++) {
CONVERT32F(sampptr[0][n], n);
}
}
return size;
}
/* DEPRECATED */
int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr)
{
return duh_sigrenderer_get_n_channels(dr);
}
/* DEPRECATED */
long duh_renderer_get_position(DUH_SIGRENDERER *dr)
{
return duh_sigrenderer_get_position(dr);
}
/* DEPRECATED */
void duh_end_renderer(DUH_SIGRENDERER *dr)
{
duh_end_sigrenderer(dr);
}
/* DEPRECATED */
DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer)
{
return sigrenderer;
}
/* DEPRECATED */
DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr)
{
return dr;
}
/* DEPRECATED */
DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr)
{
return dr;
return size;
}

View file

@ -22,304 +22,194 @@
#include "dumb.h"
#include "internal/dumb.h"
struct DUH_SIGRENDERER {
DUH_SIGTYPE_DESC *desc;
sigrenderer_t *sigrenderer;
struct DUH_SIGRENDERER
{
DUH_SIGTYPE_DESC *desc;
int n_channels;
sigrenderer_t *sigrenderer;
long pos;
int subpos;
int n_channels;
long pos;
int subpos;
DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback;
void *callback_data;
DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback;
void *callback_data;
};
DUH_SIGRENDERER *duh_start_sigrenderer(DUH *duh, int sig, int n_channels,
long pos) {
DUH_SIGRENDERER *sigrenderer;
DUH_SIGNAL *signal;
DUH_START_SIGRENDERER proc;
DUH_SIGRENDERER *duh_start_sigrenderer(DUH *duh, int sig, int n_channels, long pos)
{
DUH_SIGRENDERER *sigrenderer;
if (!duh)
return NULL;
DUH_SIGNAL *signal;
DUH_START_SIGRENDERER proc;
if ((unsigned int)sig >= (unsigned int)duh->n_signals)
return NULL;
if (!duh)
return NULL;
signal = duh->signal[sig];
if (!signal)
return NULL;
if ((unsigned int)sig >= (unsigned int)duh->n_signals)
return NULL;
sigrenderer = malloc(sizeof(*sigrenderer));
if (!sigrenderer)
return NULL;
signal = duh->signal[sig];
if (!signal)
return NULL;
sigrenderer->desc = signal->desc;
sigrenderer = malloc(sizeof(*sigrenderer));
if (!sigrenderer)
return NULL;
proc = sigrenderer->desc->start_sigrenderer;
sigrenderer->desc = signal->desc;
if (proc) {
duh->signal[sig] = NULL;
sigrenderer->sigrenderer =
(*proc)(duh, signal->sigdata, n_channels, pos);
duh->signal[sig] = signal;
proc = sigrenderer->desc->start_sigrenderer;
if (!sigrenderer->sigrenderer) {
free(sigrenderer);
return NULL;
}
} else
sigrenderer->sigrenderer = NULL;
if (proc) {
duh->signal[sig] = NULL;
sigrenderer->sigrenderer = (*proc)(duh, signal->sigdata, n_channels, pos);
duh->signal[sig] = signal;
sigrenderer->n_channels = n_channels;
if (!sigrenderer->sigrenderer) {
free(sigrenderer);
return NULL;
}
} else
sigrenderer->sigrenderer = NULL;
sigrenderer->pos = pos;
sigrenderer->subpos = 0;
sigrenderer->n_channels = n_channels;
sigrenderer->callback = NULL;
sigrenderer->pos = pos;
sigrenderer->subpos = 0;
sigrenderer->callback = NULL;
return sigrenderer;
return sigrenderer;
}
#include <stdio.h>
void duh_sigrenderer_set_callback(
DUH_SIGRENDERER *sigrenderer,
DUH_SIGRENDERER_CALLBACK callback, void *data
)
{
(void)sigrenderer;
(void)callback;
(void)data;
/*fprintf(stderr,
"Call to deprecated function duh_sigrenderer_set_callback(). The callback\n"
"was not installed. See dumb/docs/deprec.txt for how to fix this.\n");*/
}
void duh_sigrenderer_set_analyser_callback(
DUH_SIGRENDERER *sigrenderer,
DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data
)
{
(void)sigrenderer;
(void)callback;
(void)data;
fprintf(stderr,
"Call to deprecated function duh_sigrenderer_set_analyser_callback(). The\n"
"callback was not installed. See dumb/docs/deprec.txt for how to fix this.\n");
}
void duh_sigrenderer_set_sample_analyser_callback(
DUH_SIGRENDERER *sigrenderer,
DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data
)
{
if (sigrenderer) {
sigrenderer->callback = callback;
sigrenderer->callback_data = data;
}
DUH_SIGRENDERER *sigrenderer,
DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data) {
if (sigrenderer) {
sigrenderer->callback = callback;
sigrenderer->callback_data = data;
}
}
int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer)
{
return sigrenderer ? sigrenderer->n_channels : 0;
int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer) {
return sigrenderer ? sigrenderer->n_channels : 0;
}
long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer) {
DUH_SIGRENDERER_GET_POSITION proc;
if (!sigrenderer)
return -1;
long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer)
{
DUH_SIGRENDERER_GET_POSITION proc;
if (!sigrenderer) return -1;
proc = sigrenderer->desc->sigrenderer_get_position;
if (proc)
return (*proc)(sigrenderer->sigrenderer);
else
return sigrenderer->pos;
proc = sigrenderer->desc->sigrenderer_get_position;
if (proc)
return (*proc)(sigrenderer->sigrenderer);
else
return sigrenderer->pos;
}
void duh_sigrenderer_set_sigparam(DUH_SIGRENDERER *sigrenderer,
unsigned char id, long value) {
DUH_SIGRENDERER_SET_SIGPARAM proc;
if (!sigrenderer)
return;
void duh_sigrenderer_set_sigparam(
DUH_SIGRENDERER *sigrenderer,
unsigned char id, long value
)
{
DUH_SIGRENDERER_SET_SIGPARAM proc;
if (!sigrenderer) return;
proc = sigrenderer->desc->sigrenderer_set_sigparam;
if (proc)
(*proc)(sigrenderer->sigrenderer, id, value);
else
TRACE("Parameter #%d = %ld for signal %c%c%c%c, which does not take parameters.\n",
(int)id,
value,
(int)(sigrenderer->desc->type >> 24),
(int)(sigrenderer->desc->type >> 16),
(int)(sigrenderer->desc->type >> 8),
(int)(sigrenderer->desc->type));
proc = sigrenderer->desc->sigrenderer_set_sigparam;
if (proc)
(*proc)(sigrenderer->sigrenderer, id, value);
else
TRACE("Parameter #%d = %ld for signal %c%c%c%c, which does not take "
"parameters.\n",
(int)id, value, (int)(sigrenderer->desc->type >> 24),
(int)(sigrenderer->desc->type >> 16),
(int)(sigrenderer->desc->type >> 8),
(int)(sigrenderer->desc->type));
}
long duh_sigrenderer_generate_samples(DUH_SIGRENDERER *sigrenderer,
float volume, float delta, long size,
sample_t **samples) {
long rendered;
LONG_LONG t;
if (!sigrenderer)
return 0;
long duh_sigrenderer_generate_samples(
DUH_SIGRENDERER *sigrenderer,
float volume, float delta,
long size, sample_t **samples
)
{
long rendered;
LONG_LONG t;
rendered = (*sigrenderer->desc->sigrenderer_generate_samples)(
sigrenderer->sigrenderer, volume, delta, size, samples);
if (!sigrenderer) return 0;
if (rendered) {
if (sigrenderer->callback)
(*sigrenderer->callback)(sigrenderer->callback_data,
(const sample_t *const *)samples,
sigrenderer->n_channels, rendered);
rendered = (*sigrenderer->desc->sigrenderer_generate_samples)
(sigrenderer->sigrenderer, volume, delta, size, samples);
t = sigrenderer->subpos + (LONG_LONG)(delta * 65536.0 + 0.5) * rendered;
if (rendered) {
if (sigrenderer->callback)
(*sigrenderer->callback)(sigrenderer->callback_data,
(const sample_t *const *)samples, sigrenderer->n_channels, rendered);
sigrenderer->pos += (long)(t >> 16);
sigrenderer->subpos = (int)t & 65535;
}
t = sigrenderer->subpos + (LONG_LONG)(delta * 65536.0 + 0.5) * rendered;
sigrenderer->pos += (long)(t >> 16);
sigrenderer->subpos = (int)t & 65535;
}
return rendered;
return rendered;
}
/* DEPRECATED */
long duh_sigrenderer_get_samples(
DUH_SIGRENDERER *sigrenderer,
float volume, float delta,
long size, sample_t **samples
)
{
sample_t **s;
long rendered;
long i;
int j;
if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL);
s = allocate_sample_buffer(sigrenderer->n_channels, size);
if (!s) return 0;
dumb_silence(s[0], sigrenderer->n_channels * size);
rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s);
for (j = 0; j < sigrenderer->n_channels; j++)
for (i = 0; i < rendered; i++)
samples[j][i] += s[0][i*sigrenderer->n_channels+j];
destroy_sample_buffer(s);
return rendered;
void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer,
float volume, sample_t *samples) {
if (sigrenderer)
(*sigrenderer->desc->sigrenderer_get_current_sample)(
sigrenderer->sigrenderer, volume, samples);
}
void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer) {
if (sigrenderer) {
if (sigrenderer->desc->end_sigrenderer)
if (sigrenderer->sigrenderer)
(*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
/* DEPRECATED */
long duh_render_signal(
DUH_SIGRENDERER *sigrenderer,
float volume, float delta,
long size, sample_t **samples
)
{
sample_t **s;
long rendered;
long i;
int j;
if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL);
s = allocate_sample_buffer(sigrenderer->n_channels, size);
if (!s) return 0;
dumb_silence(s[0], sigrenderer->n_channels * size);
rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s);
for (j = 0; j < sigrenderer->n_channels; j++)
for (i = 0; i < rendered; i++)
samples[j][i] += s[0][i*sigrenderer->n_channels+j] >> 8;
destroy_sample_buffer(s);
return rendered;
free(sigrenderer);
}
}
DUH_SIGRENDERER *duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer,
DUH_SIGTYPE_DESC *desc,
int n_channels, long pos) {
DUH_SIGRENDERER *sigrenderer;
if (desc->start_sigrenderer && !vsigrenderer)
return NULL;
void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples)
{
if (sigrenderer)
(*sigrenderer->desc->sigrenderer_get_current_sample)(sigrenderer->sigrenderer, volume, samples);
sigrenderer = malloc(sizeof(*sigrenderer));
if (!sigrenderer) {
if (desc->end_sigrenderer)
if (vsigrenderer)
(*desc->end_sigrenderer)(vsigrenderer);
return NULL;
}
sigrenderer->desc = desc;
sigrenderer->sigrenderer = vsigrenderer;
sigrenderer->n_channels = n_channels;
sigrenderer->pos = pos;
sigrenderer->subpos = 0;
sigrenderer->callback = NULL;
return sigrenderer;
}
sigrenderer_t *duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer,
long type) {
if (sigrenderer && sigrenderer->desc->type == type)
return sigrenderer->sigrenderer;
void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer)
{
if (sigrenderer) {
if (sigrenderer->desc->end_sigrenderer)
if (sigrenderer->sigrenderer)
(*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
free(sigrenderer);
}
return NULL;
}
DUH_SIGRENDERER *duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, long pos)
{
DUH_SIGRENDERER *sigrenderer;
if (desc->start_sigrenderer && !vsigrenderer) return NULL;
sigrenderer = malloc(sizeof(*sigrenderer));
if (!sigrenderer) {
if (desc->end_sigrenderer)
if (vsigrenderer)
(*desc->end_sigrenderer)(vsigrenderer);
return NULL;
}
sigrenderer->desc = desc;
sigrenderer->sigrenderer = vsigrenderer;
sigrenderer->n_channels = n_channels;
sigrenderer->pos = pos;
sigrenderer->subpos = 0;
sigrenderer->callback = NULL;
return sigrenderer;
}
sigrenderer_t *duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type)
{
if (sigrenderer && sigrenderer->desc->type == type)
return sigrenderer->sigrenderer;
return NULL;
}
#if 0
// This function is disabled because we don't know whether we want to destroy
// the sigrenderer if the type doesn't match. We don't even know if we need

View file

@ -22,43 +22,37 @@
#include "dumb.h"
#include "internal/dumb.h"
static void destroy_signal(DUH_SIGNAL *signal) {
if (signal) {
if (signal->desc)
if (signal->desc->unload_sigdata)
if (signal->sigdata)
(*signal->desc->unload_sigdata)(signal->sigdata);
static void destroy_signal(DUH_SIGNAL *signal)
{
if (signal) {
if (signal->desc)
if (signal->desc->unload_sigdata)
if (signal->sigdata)
(*signal->desc->unload_sigdata)(signal->sigdata);
free(signal);
}
free(signal);
}
}
/* unload_duh(): destroys a DUH struct. You must call this for every DUH
* struct created, when you've finished with it.
*/
void unload_duh(DUH *duh)
{
int i;
void unload_duh(DUH *duh) {
int i;
if (duh) {
if (duh->signal) {
for (i = 0; i < duh->n_signals; i++)
destroy_signal(duh->signal[i]);
if (duh) {
if (duh->signal) {
for (i = 0; i < duh->n_signals; i++)
destroy_signal(duh->signal[i]);
free(duh->signal);
}
free(duh->signal);
}
if (duh->tag) {
if (duh->tag[0][0])
free(duh->tag[0][0]);
free(duh->tag);
}
if (duh->tag) {
if (duh->tag[0][0])
free(duh->tag[0][0]);
free(duh->tag);
}
free(duh);
}
free(duh);
}
}

View file

@ -2,65 +2,54 @@
#include <string.h>
void * bit_array_create(size_t size)
{
size_t bsize = ((size + 7) >> 3) + sizeof(size_t);
void * ret = calloc(1, bsize);
if (ret) *(size_t *)ret = size;
return ret;
void *bit_array_create(size_t size) {
size_t bsize = ((size + 7) >> 3) + sizeof(size_t);
void *ret = calloc(1, bsize);
if (ret)
*(size_t *)ret = size;
return ret;
}
void bit_array_destroy(void * array)
{
if (array) free(array);
void bit_array_destroy(void *array) {
if (array)
free(array);
}
void * bit_array_dup(void * array)
{
if (array)
{
size_t * size = (size_t *) array;
size_t bsize = ((*size + 7) >> 3) + sizeof(*size);
void * ret = malloc(bsize);
if (ret) memcpy(ret, array, bsize);
return ret;
}
return NULL;
void *bit_array_dup(void *array) {
if (array) {
size_t *size = (size_t *)array;
size_t bsize = ((*size + 7) >> 3) + sizeof(*size);
void *ret = malloc(bsize);
if (ret)
memcpy(ret, array, bsize);
return ret;
}
return NULL;
}
void bit_array_reset(void * array)
{
if (array)
{
size_t * size = (size_t *) array;
size_t bsize = (*size + 7) >> 3;
memset(size + 1, 0, bsize);
}
void bit_array_reset(void *array) {
if (array) {
size_t *size = (size_t *)array;
size_t bsize = (*size + 7) >> 3;
memset(size + 1, 0, bsize);
}
}
void bit_array_set(void * array, size_t bit)
{
if (array)
{
size_t * size = (size_t *) array;
if (bit < *size)
{
unsigned char * ptr = (unsigned char *)(size + 1);
ptr[bit >> 3] |= (1U << (bit & 7));
}
}
void bit_array_set(void *array, size_t bit) {
if (array) {
size_t *size = (size_t *)array;
if (bit < *size) {
unsigned char *ptr = (unsigned char *)(size + 1);
ptr[bit >> 3] |= (1U << (bit & 7));
}
}
}
void bit_array_set_range(void * array, size_t bit, size_t count)
{
if (array && count)
{
size_t * size = (size_t *) array;
if (bit < *size)
{
unsigned char * ptr = (unsigned char *)(size + 1);
void bit_array_set_range(void *array, size_t bit, size_t count) {
if (array && count) {
size_t *size = (size_t *)array;
if (bit < *size) {
unsigned char *ptr = (unsigned char *)(size + 1);
size_t i;
for (i = bit; i < *size && i < bit + count; ++i)
ptr[i >> 3] |= (1U << (i & 7));
@ -68,81 +57,66 @@ void bit_array_set_range(void * array, size_t bit, size_t count)
}
}
int bit_array_test(void * array, size_t bit)
{
if (array)
{
size_t * size = (size_t *) array;
if (bit < *size)
{
unsigned char * ptr = (unsigned char *)(size + 1);
if (ptr[bit >> 3] & (1U << (bit & 7)))
{
return 1;
}
}
}
return 0;
int bit_array_test(void *array, size_t bit) {
if (array) {
size_t *size = (size_t *)array;
if (bit < *size) {
unsigned char *ptr = (unsigned char *)(size + 1);
if (ptr[bit >> 3] & (1U << (bit & 7))) {
return 1;
}
}
}
return 0;
}
int bit_array_test_range(void * array, size_t bit, size_t count)
{
if (array)
{
size_t * size = (size_t *) array;
if (bit < *size)
{
unsigned char * ptr = (unsigned char *)(size + 1);
if ((bit & 7) && (count > 8))
{
while ((bit < *size) && count && (bit & 7))
{
if (ptr[bit >> 3] & (1U << (bit & 7))) return 1;
bit++;
count--;
}
}
if (!(bit & 7))
{
while (((*size - bit) >= 8) && (count >= 8))
{
if (ptr[bit >> 3]) return 1;
bit += 8;
count -= 8;
}
}
while ((bit < *size) && count)
{
if (ptr[bit >> 3] & (1U << (bit & 7))) return 1;
bit++;
count--;
}
}
}
return 0;
int bit_array_test_range(void *array, size_t bit, size_t count) {
if (array) {
size_t *size = (size_t *)array;
if (bit < *size) {
unsigned char *ptr = (unsigned char *)(size + 1);
if ((bit & 7) && (count > 8)) {
while ((bit < *size) && count && (bit & 7)) {
if (ptr[bit >> 3] & (1U << (bit & 7)))
return 1;
bit++;
count--;
}
}
if (!(bit & 7)) {
while (((*size - bit) >= 8) && (count >= 8)) {
if (ptr[bit >> 3])
return 1;
bit += 8;
count -= 8;
}
}
while ((bit < *size) && count) {
if (ptr[bit >> 3] & (1U << (bit & 7)))
return 1;
bit++;
count--;
}
}
}
return 0;
}
void bit_array_clear(void * array, size_t bit)
{
if (array)
{
size_t * size = (size_t *) array;
if (bit < *size)
{
unsigned char * ptr = (unsigned char *)(size + 1);
ptr[bit >> 3] &= ~(1U << (bit & 7));
}
}
void bit_array_clear(void *array, size_t bit) {
if (array) {
size_t *size = (size_t *)array;
if (bit < *size) {
unsigned char *ptr = (unsigned char *)(size + 1);
ptr[bit >> 3] &= ~(1U << (bit & 7));
}
}
}
void bit_array_clear_range(void * array, size_t bit, size_t count)
{
if (array && count)
{
size_t * size = (size_t *) array;
if (bit < *size)
{
unsigned char * ptr = (unsigned char *)(size + 1);
void bit_array_clear_range(void *array, size_t bit, size_t count) {
if (array && count) {
size_t *size = (size_t *)array;
if (bit < *size) {
unsigned char *ptr = (unsigned char *)(size + 1);
size_t i;
for (i = bit; i < *size && i < bit + count; ++i)
ptr[i >> 3] &= ~(1U << (i & 7));
@ -150,40 +124,32 @@ void bit_array_clear_range(void * array, size_t bit, size_t count)
}
}
void bit_array_merge(void * dest, void * source, size_t offset)
{
if (dest && source)
{
size_t * dsize = (size_t *) dest;
size_t * ssize = (size_t *) source;
size_t soffset = 0;
while (offset < *dsize && soffset < *ssize)
{
if (bit_array_test(source, soffset))
{
bit_array_set(dest, offset);
}
soffset++;
offset++;
}
}
void bit_array_merge(void *dest, void *source, size_t offset) {
if (dest && source) {
size_t *dsize = (size_t *)dest;
size_t *ssize = (size_t *)source;
size_t soffset = 0;
while (offset < *dsize && soffset < *ssize) {
if (bit_array_test(source, soffset)) {
bit_array_set(dest, offset);
}
soffset++;
offset++;
}
}
}
void bit_array_mask(void * dest, void * source, size_t offset)
{
if (dest && source)
{
size_t * dsize = (size_t *) dest;
size_t * ssize = (size_t *) source;
size_t soffset = 0;
while (offset < *dsize && soffset < *ssize)
{
if (bit_array_test(source, soffset))
{
bit_array_clear(dest, offset);
}
soffset++;
offset++;
}
}
void bit_array_mask(void *dest, void *source, size_t offset) {
if (dest && source) {
size_t *dsize = (size_t *)dest;
size_t *ssize = (size_t *)source;
size_t soffset = 0;
while (offset < *dsize && soffset < *ssize) {
if (bit_array_test(source, soffset)) {
bit_array_clear(dest, offset);
}
soffset++;
offset++;
}
}
}

View file

@ -20,262 +20,238 @@
#include <stdlib.h>
#include <math.h>
#include "dumb.h"
#include "internal/dumb.h"
typedef struct DUMB_CLICK DUMB_CLICK;
struct DUMB_CLICK_REMOVER {
DUMB_CLICK *click;
int n_clicks;
struct DUMB_CLICK_REMOVER
{
DUMB_CLICK *click;
int n_clicks;
int offset;
int offset;
};
struct DUMB_CLICK
{
DUMB_CLICK *next;
long pos;
sample_t step;
struct DUMB_CLICK {
DUMB_CLICK *next;
long pos;
sample_t step;
};
DUMB_CLICK_REMOVER *dumb_create_click_remover(void) {
DUMB_CLICK_REMOVER *cr = malloc(sizeof(*cr));
if (!cr)
return NULL;
cr->click = NULL;
cr->n_clicks = 0;
DUMB_CLICK_REMOVER *dumb_create_click_remover(void)
{
DUMB_CLICK_REMOVER *cr = malloc(sizeof(*cr));
if (!cr) return NULL;
cr->offset = 0;
cr->click = NULL;
cr->n_clicks = 0;
cr->offset = 0;
return cr;
return cr;
}
void dumb_record_click(DUMB_CLICK_REMOVER *cr, long pos, sample_t step) {
DUMB_CLICK *click;
ASSERT(pos >= 0);
void dumb_record_click(DUMB_CLICK_REMOVER *cr, long pos, sample_t step)
{
DUMB_CLICK *click;
if (!cr || !step)
return;
ASSERT(pos >= 0);
if (pos == 0) {
cr->offset -= step;
return;
}
if (!cr || !step) return;
click = malloc(sizeof(*click));
if (!click)
return;
if (pos == 0) {
cr->offset -= step;
return;
}
click->pos = pos;
click->step = step;
click = malloc(sizeof(*click));
if (!click) return;
click->pos = pos;
click->step = step;
click->next = cr->click;
cr->click = click;
cr->n_clicks++;
click->next = cr->click;
cr->click = click;
cr->n_clicks++;
}
static DUMB_CLICK *dumb_click_mergesort(DUMB_CLICK *click, int n_clicks) {
int i;
DUMB_CLICK *c1, *c2, **cp;
if (n_clicks <= 1)
return click;
static DUMB_CLICK *dumb_click_mergesort(DUMB_CLICK *click, int n_clicks)
{
int i;
DUMB_CLICK *c1, *c2, **cp;
/* Split the list into two */
c1 = click;
cp = &c1;
for (i = 0; i < n_clicks; i += 2)
cp = &(*cp)->next;
c2 = *cp;
*cp = NULL;
if (n_clicks <= 1) return click;
/* Sort the sublists */
c1 = dumb_click_mergesort(c1, (n_clicks + 1) >> 1);
c2 = dumb_click_mergesort(c2, n_clicks >> 1);
/* Split the list into two */
c1 = click;
cp = &c1;
for (i = 0; i < n_clicks; i += 2) cp = &(*cp)->next;
c2 = *cp;
*cp = NULL;
/* Merge them */
cp = &click;
while (c1 && c2) {
if (c1->pos > c2->pos) {
*cp = c2;
c2 = c2->next;
} else {
*cp = c1;
c1 = c1->next;
}
cp = &(*cp)->next;
}
if (c2)
*cp = c2;
else
*cp = c1;
/* Sort the sublists */
c1 = dumb_click_mergesort(c1, (n_clicks + 1) >> 1);
c2 = dumb_click_mergesort(c2, n_clicks >> 1);
/* Merge them */
cp = &click;
while (c1 && c2) {
if (c1->pos > c2->pos) {
*cp = c2;
c2 = c2->next;
} else {
*cp = c1;
c1 = c1->next;
}
cp = &(*cp)->next;
}
if (c2)
*cp = c2;
else
*cp = c1;
return click;
return click;
}
void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length,
int step, float halflife) {
DUMB_CLICK *click;
long pos = 0;
int offset;
int factor;
if (!cr)
return;
void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, int step, float halflife)
{
DUMB_CLICK *click;
long pos = 0;
int offset;
int factor;
factor = (int)floor(pow(0.5, 1.0 / halflife) * (1U << 31));
if (!cr) return;
click = dumb_click_mergesort(cr->click, cr->n_clicks);
cr->click = NULL;
cr->n_clicks = 0;
factor = (int)floor(pow(0.5, 1.0/halflife) * (1U << 31));
length *= step;
click = dumb_click_mergesort(cr->click, cr->n_clicks);
cr->click = NULL;
cr->n_clicks = 0;
while (click) {
DUMB_CLICK *next = click->next;
long end = click->pos * step;
ASSERT(end <= length);
offset = cr->offset;
if (offset < 0) {
offset = -offset;
while (pos < end) {
samples[pos] -= offset;
offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32);
pos += step;
}
offset = -offset;
} else {
while (pos < end) {
samples[pos] += offset;
offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32);
pos += step;
}
}
cr->offset = offset - click->step;
free(click);
click = next;
}
length *= step;
while (click) {
DUMB_CLICK *next = click->next;
int end = click->pos * step;
ASSERT(end <= length);
offset = cr->offset;
if (offset < 0) {
offset = -offset;
while (pos < end) {
samples[pos] -= offset;
offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32);
pos += step;
}
offset = -offset;
} else {
while (pos < end) {
samples[pos] += offset;
offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32);
pos += step;
}
}
cr->offset = offset - click->step;
free(click);
click = next;
}
offset = cr->offset;
if (offset < 0) {
offset = -offset;
while (pos < length) {
samples[pos] -= offset;
offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
pos += step;
}
offset = -offset;
} else {
while (pos < length) {
samples[pos] += offset;
offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
pos += step;
}
}
cr->offset = offset;
offset = cr->offset;
if (offset < 0) {
offset = -offset;
while (pos < length) {
samples[pos] -= offset;
offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
pos += step;
}
offset = -offset;
} else {
while (pos < length) {
samples[pos] += offset;
offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
pos += step;
}
}
cr->offset = offset;
}
sample_t dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr)
{
return cr ? cr->offset : 0;
sample_t dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr) {
return cr ? cr->offset : 0;
}
void dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr)
{
if (cr) {
DUMB_CLICK *click = cr->click;
while (click) {
DUMB_CLICK *next = click->next;
free(click);
click = next;
}
free(cr);
}
void dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr) {
if (cr) {
DUMB_CLICK *click = cr->click;
while (click) {
DUMB_CLICK *next = click->next;
free(click);
click = next;
}
free(cr);
}
}
DUMB_CLICK_REMOVER **dumb_create_click_remover_array(int n)
{
int i;
DUMB_CLICK_REMOVER **cr;
if (n <= 0) return NULL;
cr = malloc(n * sizeof(*cr));
if (!cr) return NULL;
for (i = 0; i < n; i++) cr[i] = dumb_create_click_remover();
return cr;
DUMB_CLICK_REMOVER **dumb_create_click_remover_array(int n) {
int i;
DUMB_CLICK_REMOVER **cr;
if (n <= 0)
return NULL;
cr = malloc(n * sizeof(*cr));
if (!cr)
return NULL;
for (i = 0; i < n; i++)
cr[i] = dumb_create_click_remover();
return cr;
}
void dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step)
{
if (cr) {
int i;
for (i = 0; i < n; i++)
dumb_record_click(cr[i], pos, step[i]);
}
void dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, long pos,
sample_t *step) {
if (cr) {
int i;
for (i = 0; i < n; i++)
dumb_record_click(cr[i], pos, step[i]);
}
}
void dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step)
{
if (cr) {
int i;
for (i = 0; i < n; i++)
dumb_record_click(cr[i], pos, -step[i]);
}
void dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, long pos,
sample_t *step) {
if (cr) {
int i;
for (i = 0; i < n; i++)
dumb_record_click(cr[i], pos, -step[i]);
}
}
void dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, long length, float halflife)
{
if (cr) {
int i;
for (i = 0; i < n >> 1; i++) {
dumb_remove_clicks(cr[i << 1], samples[i], length, 2, halflife);
dumb_remove_clicks(cr[(i << 1) + 1], samples[i] + 1, length, 2, halflife);
}
if (n & 1)
dumb_remove_clicks(cr[i << 1], samples[i], length, 1, halflife);
}
void dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr,
sample_t **samples, long length, float halflife) {
if (cr) {
int i;
for (i = 0; i<n>> 1; i++) {
dumb_remove_clicks(cr[i << 1], samples[i], length, 2, halflife);
dumb_remove_clicks(cr[(i << 1) + 1], samples[i] + 1, length, 2,
halflife);
}
if (n & 1)
dumb_remove_clicks(cr[i << 1], samples[i], length, 1, halflife);
}
}
void dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr, sample_t *offset)
{
if (cr) {
int i;
for (i = 0; i < n; i++)
if (cr[i]) offset[i] += cr[i]->offset;
}
void dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr,
sample_t *offset) {
if (cr) {
int i;
for (i = 0; i < n; i++)
if (cr[i])
offset[i] += cr[i]->offset;
}
}
void dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr)
{
if (cr) {
int i;
for (i = 0; i < n; i++) dumb_destroy_click_remover(cr[i]);
free(cr);
}
void dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr) {
if (cr) {
int i;
for (i = 0; i < n; i++)
dumb_destroy_click_remover(cr[i]);
free(cr);
}
}

View file

@ -1,281 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "internal/fir_resampler.h"
enum { fir_width = 16 };
enum { fir_max_res = 1024 };
enum { fir_min_width = (fir_width < 4 ? 4 : fir_width) };
enum { fir_adj_width = fir_min_width / 4 * 4 + 2 };
enum { fir_stereo = 1 }; /* channel count, not boolean value */
enum { fir_write_offset = fir_adj_width * fir_stereo };
enum { fir_buffer_size = fir_width * 2 };
typedef short fir_impulse[fir_adj_width];
/* exp slope to 31/32 of ln(8) */
static const double fir_ratios[32] = {
1.000, 1.067, 1.139, 1.215, 1.297, 1.384, 1.477, 1.576,
1.682, 1.795, 1.915, 2.044, 2.181, 2.327, 2.484, 2.650,
2.828, 3.018, 3.221, 3.437, 3.668, 3.914, 4.177, 4.458,
4.757, 5.076, 5.417, 5.781, 6.169, 6.583, 7.025, 7.497
};
static fir_impulse fir_impulses[32][fir_max_res];
#undef PI
#define PI 3.1415926535897932384626433832795029
static void gen_sinc( double rolloff, int width, double offset, double spacing, double scale,
int count, short* out )
{
double const maxh = 256;
double const step = PI / maxh * spacing;
double const to_w = maxh * 2 / width;
double const pow_a_n = pow( rolloff, maxh );
double angle = (count / 2 - 1 + offset) * -step;
scale /= maxh * 2;
while ( count-- )
{
double w;
*out++ = 0;
w = angle * to_w;
if ( fabs( w ) < PI )
{
double rolloff_cos_a = rolloff * cos( angle );
double num = 1 - rolloff_cos_a -
pow_a_n * cos( maxh * angle ) +
pow_a_n * rolloff * cos( (maxh - 1) * angle );
double den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
double sinc = scale * num / den - scale;
out [-1] = (short) (cos( w ) * sinc + sinc);
}
angle += step;
}
}
typedef struct fir_resampler
{
int write_pos, write_filled;
int read_pos, read_filled;
unsigned short phase;
unsigned int phase_inc;
unsigned int ratio_set;
int buffer_in[fir_buffer_size * 2];
int buffer_out[fir_buffer_size];
} fir_resampler;
void * fir_resampler_create()
{
fir_resampler * r = ( fir_resampler * ) malloc( sizeof(fir_resampler) );
if ( !r ) return 0;
r->write_pos = 0;
r->write_filled = 0;
r->read_pos = 0;
r->read_filled = 0;
r->phase = 0;
r->phase_inc = 0;
r->ratio_set = 0;
memset( r->buffer_in, 0, sizeof(r->buffer_in) );
memset( r->buffer_out, 0, sizeof(r->buffer_out) );
return r;
}
void fir_resampler_delete(void * _r)
{
free( _r );
}
void * fir_resampler_dup(void * _r)
{
fir_resampler * r_in = ( fir_resampler * ) _r;
fir_resampler * r_out = ( fir_resampler * ) malloc( sizeof(fir_resampler) );
if ( !r_out ) return 0;
r_out->write_pos = r_in->write_pos;
r_out->write_filled = r_in->write_filled;
r_out->read_pos = r_in->read_pos;
r_out->read_filled = r_in->read_filled;
r_out->phase = r_in->phase;
r_out->phase_inc = r_in->phase_inc;
r_out->ratio_set = r_in->ratio_set;
memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) );
memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) );
return r_out;
}
int fir_resampler_get_free_count(void *_r)
{
fir_resampler * r = ( fir_resampler * ) _r;
return fir_buffer_size - r->write_filled;
}
int fir_resampler_ready(void *_r)
{
fir_resampler * r = ( fir_resampler * ) _r;
return r->write_filled > fir_adj_width;
}
void fir_resampler_clear(void *_r)
{
fir_resampler * r = ( fir_resampler * ) _r;
r->write_pos = 0;
r->write_filled = 0;
r->read_pos = 0;
r->read_filled = 0;
r->phase = 0;
memset( r->buffer_in, 0, sizeof(r->buffer_in) );
}
void fir_resampler_set_rate(void *_r, double new_factor)
{
fir_resampler * r = ( fir_resampler * ) _r;
r->phase_inc = (int)( new_factor * 65536.0 );
r->ratio_set = 0;
while ( r->ratio_set < 31 && new_factor > fir_ratios[ r->ratio_set ] ) r->ratio_set++;
}
void fir_resampler_write_sample(void *_r, short s)
{
fir_resampler * r = ( fir_resampler * ) _r;
if ( r->write_filled < fir_buffer_size )
{
int s32 = s;
r->buffer_in[ r->write_pos ] = s32;
r->buffer_in[ r->write_pos + fir_buffer_size ] = s32;
++r->write_filled;
r->write_pos = ( r->write_pos + 1 ) % fir_buffer_size;
}
}
void fir_init()
{
double const rolloff = 0.999;
double const gain = 1.0;
int const res = fir_max_res;
int i;
for (i = 0; i < 32; i++)
{
double const ratio_ = fir_ratios[ i ];
double fraction = 1.0 / (double)fir_max_res;
double const filter = (ratio_ < 1.0) ? 1.0 : 1.0 / ratio_;
double pos = 0.0;
short* out = (short*) fir_impulses[ i ];
int n;
for ( n = res; --n >= 0; )
{
gen_sinc( rolloff, (int) (fir_adj_width * filter + 1) & ~1, pos, filter,
(double) (0x7FFF * gain * filter), (int) fir_adj_width, out );
out += fir_adj_width;
pos += fraction;
}
}
}
int fir_resampler_run(void *_r, int ** out_, int * out_end)
{
fir_resampler * r = ( fir_resampler * ) _r;
int in_size = r->write_filled;
int const* in_ = r->buffer_in + fir_buffer_size + r->write_pos - r->write_filled;
int used = 0;
in_size -= fir_write_offset;
if ( in_size > 0 )
{
int* out = *out_;
int const* in = in_;
int const* const in_end = in + in_size;
int phase = r->phase;
int phase_inc = r->phase_inc;
int ratio_set = r->ratio_set;
do
{
// accumulate in extended precision
short const* imp = fir_impulses[ratio_set][(phase & 0xFFC0) >> 6];
int pt = imp [0];
int s = pt * in [0];
int n;
if ( out >= out_end )
break;
for ( n = (fir_adj_width - 2) / 2; n; --n )
{
pt = imp [1];
s += pt * in [1];
// pre-increment more efficient on some RISC processors
imp += 2;
pt = imp [0];
in += 2;
s += pt * in [0];
}
pt = imp [1];
s += pt * in [1];
phase += phase_inc;
in += (phase >> 16) - fir_adj_width + 2;
phase &= 65535;
*out++ = (int) (s >> 7);
}
while ( in < in_end );
r->phase = phase;
*out_ = out;
used = in - in_;
r->write_filled -= used;
}
return used;
}
int fir_resampler_get_sample(void *_r)
{
fir_resampler * r = ( fir_resampler * ) _r;
if ( r->read_filled < 1 )
{
int write_pos = ( r->read_pos + r->read_filled ) % fir_buffer_size;
int write_size = fir_buffer_size - write_pos;
int * out = r->buffer_out + write_pos;
if ( write_size > ( fir_buffer_size - r->read_filled ) )
write_size = fir_buffer_size - r->read_filled;
fir_resampler_run( r, &out, out + write_size );
r->read_filled += out - r->buffer_out - write_pos;
}
if ( r->read_filled < 1 )
return 0;
return r->buffer_out[ r->read_pos ];
}
void fir_resampler_remove_sample(void *_r)
{
fir_resampler * r = ( fir_resampler * ) _r;
if ( r->read_filled > 0 )
{
--r->read_filled;
r->read_pos = ( r->read_pos + 1 ) % fir_buffer_size;
}
}

View file

@ -55,286 +55,286 @@ Carsten Bormann
/* Input : n elements of time doamin data
Output: m lpc coefficients, excitation energy */
static float vorbis_lpc_from_data(float *data,float *lpci,long n,long m){
double *aut=alloca(sizeof(*aut)*(m+1));
double *lpc=alloca(sizeof(*lpc)*(m));
double error;
double epsilon;
long i,j;
static float vorbis_lpc_from_data(float *data, float *lpci, long n, long m) {
double *aut = alloca(sizeof(*aut) * (m + 1));
double *lpc = alloca(sizeof(*lpc) * (m));
double error;
double epsilon;
long i, j;
/* autocorrelation, p+1 lag coefficients */
j=m+1;
while(j--){
double d=0; /* double needed for accumulator depth */
for(i=j;i<n;i++)d+=(double)data[i]*data[(i-j)];
aut[j]=d;
}
/* Generate lpc coefficients from autocorr values */
/* set our noise floor to about -100dB */
error=aut[0] * (1. + 1e-10);
epsilon=1e-9*aut[0]+1e-10;
for(i=0;i<m;i++){
double r= -aut[i+1];
if(error<epsilon){
memset(lpc+i,0,(m-i)*sizeof(*lpc));
goto done;
/* autocorrelation, p+1 lag coefficients */
j = m + 1;
while (j--) {
double d = 0; /* double needed for accumulator depth */
for (i = j; i < n; i++)
d += (double)data[i] * data[(i - j)];
aut[j] = d;
}
/* Sum up this iteration's reflection coefficient; note that in
Vorbis we don't save it. If anyone wants to recycle this code
and needs reflection coefficients, save the results of 'r' from
each iteration. */
/* Generate lpc coefficients from autocorr values */
for(j=0;j<i;j++)r-=lpc[j]*aut[i-j];
r/=error;
/* set our noise floor to about -100dB */
error = aut[0] * (1. + 1e-10);
epsilon = 1e-9 * aut[0] + 1e-10;
/* Update LPC coefficients and total error */
for (i = 0; i < m; i++) {
double r = -aut[i + 1];
lpc[i]=r;
for(j=0;j<i/2;j++){
double tmp=lpc[j];
if (error < epsilon) {
memset(lpc + i, 0, (m - i) * sizeof(*lpc));
goto done;
}
lpc[j]+=r*lpc[i-1-j];
lpc[i-1-j]+=r*tmp;
/* Sum up this iteration's reflection coefficient; note that in
Vorbis we don't save it. If anyone wants to recycle this code
and needs reflection coefficients, save the results of 'r' from
each iteration. */
for (j = 0; j < i; j++)
r -= lpc[j] * aut[i - j];
r /= error;
/* Update LPC coefficients and total error */
lpc[i] = r;
for (j = 0; j < i / 2; j++) {
double tmp = lpc[j];
lpc[j] += r * lpc[i - 1 - j];
lpc[i - 1 - j] += r * tmp;
}
if (i & 1)
lpc[j] += lpc[j] * r;
error *= 1. - r * r;
}
if(i&1)lpc[j]+=lpc[j]*r;
error*=1.-r*r;
done:
}
done:
/* slightly damp the filter */
{
double g = .99;
double damp = g;
for(j=0;j<m;j++){
lpc[j]*=damp;
damp*=g;
/* slightly damp the filter */
{
double g = .99;
double damp = g;
for (j = 0; j < m; j++) {
lpc[j] *= damp;
damp *= g;
}
}
}
for(j=0;j<m;j++)lpci[j]=(float)lpc[j];
for (j = 0; j < m; j++)
lpci[j] = (float)lpc[j];
/* we need the error value to know how big an impulse to hit the
filter with later */
/* we need the error value to know how big an impulse to hit the
filter with later */
return error;
return error;
}
static void vorbis_lpc_predict(float *coeff,float *prime,long m,
float *data,long n){
static void vorbis_lpc_predict(float *coeff, float *prime, long m, float *data,
long n) {
/* in: coeff[0...m-1] LPC coefficients
prime[0...m-1] initial values (allocated size of n+m-1)
out: data[0...n-1] data samples */
/* in: coeff[0...m-1] LPC coefficients
prime[0...m-1] initial values (allocated size of n+m-1)
out: data[0...n-1] data samples */
long i,j,o,p;
float y;
float *work=alloca(sizeof(*work)*(m+n));
long i, j, o, p;
float y;
float *work = alloca(sizeof(*work) * (m + n));
if(!prime)
for(i=0;i<m;i++)
work[i]=0.f;
else
for(i=0;i<m;i++)
work[i]=prime[i];
if (!prime)
for (i = 0; i < m; i++)
work[i] = 0.f;
else
for (i = 0; i < m; i++)
work[i] = prime[i];
for(i=0;i<n;i++){
y=0;
o=i;
p=m;
for(j=0;j<m;j++)
y-=work[o++]*coeff[--p];
for (i = 0; i < n; i++) {
y = 0;
o = i;
p = m;
for (j = 0; j < m; j++)
y -= work[o++] * coeff[--p];
data[i]=work[o]=y;
}
data[i] = work[o] = y;
}
}
#include "dumb.h"
#include "internal/dumb.h"
#include "internal/it.h"
enum { lpc_max = 256 }; /* Maximum number of input samples to train the function */
enum { lpc_order = 32 }; /* Order of the filter */
enum { lpc_extra = 64 }; /* How many samples of padding to predict or silence */
enum {
lpc_max = 256
}; /* Maximum number of input samples to train the function */
enum { lpc_order = 32 }; /* Order of the filter */
enum { lpc_extra = 64 }; /* How many samples of padding to predict or silence */
/* This extra sample padding is really only needed by the FIR resampler, but it
* helps the other resamplers as well. */
/* This extra sample padding is really only needed by the FIR resampler, but it helps the other resamplers as well. */
int dumb_it_add_lpc(struct DUMB_IT_SIGDATA *sigdata){
int dumb_it_add_lpc(struct DUMB_IT_SIGDATA *sigdata) {
float lpc[lpc_order * 2];
float lpc_input[lpc_max * 2];
float lpc_output[lpc_extra * 2];
signed char * s8;
signed short * s16;
signed char *s8;
signed short *s16;
long n, o, offset, lpc_samples;
for ( n = 0; n < sigdata->n_samples; n++ ) {
IT_SAMPLE * sample = sigdata->sample + n;
if ( ( sample->flags & ( IT_SAMPLE_EXISTS | IT_SAMPLE_LOOP) ) == IT_SAMPLE_EXISTS &&
sample->data != NULL ) {
/* If we have enough sample data to train the filter, use the filter to generate the padding */
if ( sample->length >= lpc_order ) {
for (n = 0; n < sigdata->n_samples; n++) {
IT_SAMPLE *sample = sigdata->sample + n;
if ((sample->flags & (IT_SAMPLE_EXISTS | IT_SAMPLE_LOOP)) ==
IT_SAMPLE_EXISTS &&
sample->data != NULL) {
/* If we have enough sample data to train the filter, use the filter
* to generate the padding */
if (sample->length >= lpc_order) {
lpc_samples = sample->length;
if (lpc_samples > lpc_max) lpc_samples = lpc_max;
if (lpc_samples > lpc_max)
lpc_samples = lpc_max;
offset = sample->length - lpc_samples;
if ( sample->flags & IT_SAMPLE_STEREO )
{
if ( sample->flags & IT_SAMPLE_16BIT )
{
s16 = ( signed short * ) sample->data;
if (sample->flags & IT_SAMPLE_STEREO) {
if (sample->flags & IT_SAMPLE_16BIT) {
s16 = (signed short *)sample->data;
s16 += offset * 2;
for ( o = 0; o < lpc_samples; o++ )
{
lpc_input[ o ] = s16[ o * 2 + 0 ];
lpc_input[ o + lpc_max ] = s16[ o * 2 + 1 ];
for (o = 0; o < lpc_samples; o++) {
lpc_input[o] = s16[o * 2 + 0];
lpc_input[o + lpc_max] = s16[o * 2 + 1];
}
}
else
{
s8 = ( signed char * ) sample->data;
} else {
s8 = (signed char *)sample->data;
s8 += offset * 2;
for ( o = 0; o < lpc_samples; o++ )
{
lpc_input[ o ] = s8[ o * 2 + 0 ];
lpc_input[ o + lpc_max ] = s8[ o * 2 + 1 ];
for (o = 0; o < lpc_samples; o++) {
lpc_input[o] = s8[o * 2 + 0];
lpc_input[o + lpc_max] = s8[o * 2 + 1];
}
}
vorbis_lpc_from_data( lpc_input, lpc, lpc_samples, lpc_order );
vorbis_lpc_from_data( lpc_input + lpc_max, lpc + lpc_order, lpc_samples, lpc_order );
vorbis_lpc_from_data(lpc_input, lpc, lpc_samples,
lpc_order);
vorbis_lpc_from_data(lpc_input + lpc_max, lpc + lpc_order,
lpc_samples, lpc_order);
vorbis_lpc_predict( lpc, lpc_input + lpc_samples - lpc_order, lpc_order, lpc_output, lpc_extra );
vorbis_lpc_predict( lpc + lpc_order, lpc_input + lpc_max + lpc_samples - lpc_order, lpc_order, lpc_output + lpc_extra, lpc_extra );
vorbis_lpc_predict(lpc, lpc_input + lpc_samples - lpc_order,
lpc_order, lpc_output, lpc_extra);
vorbis_lpc_predict(
lpc + lpc_order,
lpc_input + lpc_max + lpc_samples - lpc_order,
lpc_order, lpc_output + lpc_extra, lpc_extra);
if (sample->flags & IT_SAMPLE_16BIT) {
s16 = (signed short *)realloc(
sample->data,
(sample->length + lpc_extra) * 2 * sizeof(short));
if (!s16)
return -1;
if ( sample->flags & IT_SAMPLE_16BIT )
{
s16 = ( signed short * ) realloc( sample->data, ( sample->length + lpc_extra ) * 2 * sizeof(short) );
if ( !s16 )
return -1;
sample->data = s16;
s16 += sample->length * 2;
sample->length += lpc_extra;
for ( o = 0; o < lpc_extra; o++ )
{
s16[ o * 2 + 0 ] = lpc_output[ o ];
s16[ o * 2 + 1 ] = lpc_output[ o + lpc_extra ];
for (o = 0; o < lpc_extra; o++) {
s16[o * 2 + 0] = lpc_output[o];
s16[o * 2 + 1] = lpc_output[o + lpc_extra];
}
}
else
{
s8 = ( signed char * ) realloc( sample->data, ( sample->length + lpc_extra ) * 2 );
if ( !s8 )
return -1;
} else {
s8 = (signed char *)realloc(
sample->data, (sample->length + lpc_extra) * 2);
if (!s8)
return -1;
sample->data = s8;
s8 += sample->length * 2;
sample->length += lpc_extra;
for ( o = 0; o < lpc_extra; o++ )
{
s8[ o * 2 + 0 ] = lpc_output[ o ];
s8[ o * 2 + 1 ] = lpc_output[ o + lpc_extra ];
for (o = 0; o < lpc_extra; o++) {
s8[o * 2 + 0] = lpc_output[o];
s8[o * 2 + 1] = lpc_output[o + lpc_extra];
}
}
}
else
{
if ( sample->flags & IT_SAMPLE_16BIT )
{
s16 = ( signed short * ) sample->data;
} else {
if (sample->flags & IT_SAMPLE_16BIT) {
s16 = (signed short *)sample->data;
s16 += offset;
for ( o = 0; o < lpc_samples; o++ )
{
lpc_input[ o ] = s16[ o ];
for (o = 0; o < lpc_samples; o++) {
lpc_input[o] = s16[o];
}
}
else
{
s8 = ( signed char * ) sample->data;
} else {
s8 = (signed char *)sample->data;
s8 += offset;
for ( o = 0; o < lpc_samples; o++ )
{
lpc_input[ o ] = s8[ o ];
for (o = 0; o < lpc_samples; o++) {
lpc_input[o] = s8[o];
}
}
vorbis_lpc_from_data( lpc_input, lpc, lpc_samples, lpc_order );
vorbis_lpc_from_data(lpc_input, lpc, lpc_samples,
lpc_order);
vorbis_lpc_predict( lpc, lpc_input + lpc_samples - lpc_order, lpc_order, lpc_output, lpc_extra );
vorbis_lpc_predict(lpc, lpc_input + lpc_samples - lpc_order,
lpc_order, lpc_output, lpc_extra);
if (sample->flags & IT_SAMPLE_16BIT) {
s16 = (signed short *)realloc(
sample->data,
(sample->length + lpc_extra) * sizeof(short));
if (!s16)
return -1;
if ( sample->flags & IT_SAMPLE_16BIT )
{
s16 = ( signed short * ) realloc( sample->data, ( sample->length + lpc_extra ) * sizeof(short) );
if (!s16)
return -1;
sample->data = s16;
s16 += sample->length;
sample->length += lpc_extra;
for ( o = 0; o < lpc_extra; o++ )
{
s16[ o ] = lpc_output[ o ];
for (o = 0; o < lpc_extra; o++) {
s16[o] = lpc_output[o];
}
}
else
{
s8 = ( signed char * ) realloc( sample->data, sample->length + lpc_extra );
if ( !s8 )
return -1;
} else {
s8 = (signed char *)realloc(sample->data,
sample->length + lpc_extra);
if (!s8)
return -1;
sample->data = s8;
s8 += sample->length;
sample->length += lpc_extra;
for ( o = 0; o < lpc_extra; o++ )
{
s8[ o ] = lpc_output[ o ];
for (o = 0; o < lpc_extra; o++) {
s8[o] = lpc_output[o];
}
}
}
}
else
} else
/* Otherwise, pad with silence. */
{
void *data;
void *data;
offset = sample->length;
lpc_samples = lpc_extra;
sample->length += lpc_samples;
n = 1;
if ( sample->flags & IT_SAMPLE_STEREO ) n *= 2;
if ( sample->flags & IT_SAMPLE_16BIT ) n *= 2;
if (sample->flags & IT_SAMPLE_STEREO)
n *= 2;
if (sample->flags & IT_SAMPLE_16BIT)
n *= 2;
offset *= n;
lpc_samples *= n;
data = realloc( sample->data, offset + lpc_samples );
if (!data)
return -1;
sample->data = data;
memset( (char*)data + offset, 0, lpc_samples );
data = realloc(sample->data, offset + lpc_samples);
if (!data)
return -1;
sample->data = data;
memset((char *)data + offset, 0, lpc_samples);
}
}
}
return 0;
return 0;
}

View file

@ -22,96 +22,73 @@
#include "dumb.h"
typedef struct MEMFILE MEMFILE;
struct MEMFILE
{
const char *ptr, *ptr_begin;
long left, size;
struct MEMFILE {
const char *ptr, *ptr_begin;
size_t left, size;
};
static int dumb_memfile_skip(void *f, long n)
{
MEMFILE *m = f;
if (n > m->left) return -1;
m->ptr += n;
m->left -= n;
return 0;
static int dumb_memfile_skip(void *f, dumb_off_t n) {
MEMFILE *m = f;
if (n > (dumb_off_t)m->left)
return -1;
m->ptr += n;
m->left -= n;
return 0;
}
static int dumb_memfile_getc(void *f)
{
MEMFILE *m = f;
if (m->left <= 0) return -1;
m->left--;
return *(const unsigned char *)m->ptr++;
static int dumb_memfile_getc(void *f) {
MEMFILE *m = f;
if (m->left <= 0)
return -1;
m->left--;
return *(const unsigned char *)m->ptr++;
}
static long dumb_memfile_getnc(char *ptr, long n, void *f)
{
MEMFILE *m = f;
if (n > m->left) n = m->left;
memcpy(ptr, m->ptr, n);
m->ptr += n;
m->left -= n;
return n;
static dumb_ssize_t dumb_memfile_getnc(char *ptr, size_t n, void *f) {
MEMFILE *m = f;
if (n > m->left)
n = m->left;
memcpy(ptr, m->ptr, n);
m->ptr += n;
m->left -= n;
return n;
}
static void dumb_memfile_close(void *f) { free(f); }
static int dumb_memfile_seek(void *f, dumb_off_t n) {
MEMFILE *m = f;
static void dumb_memfile_close(void *f)
{
free(f);
m->ptr = m->ptr_begin + n;
m->left = m->size - n;
return 0;
}
static int dumb_memfile_seek(void *f, long n)
{
MEMFILE *m = f;
m->ptr = m->ptr_begin + n;
m->left = m->size - n;
return 0;
static dumb_off_t dumb_memfile_get_size(void *f) {
MEMFILE *m = f;
return m->size;
}
static const DUMBFILE_SYSTEM memfile_dfs = {NULL,
&dumb_memfile_skip,
&dumb_memfile_getc,
&dumb_memfile_getnc,
&dumb_memfile_close,
&dumb_memfile_seek,
&dumb_memfile_get_size};
static long dumb_memfile_get_size(void *f)
{
MEMFILE *m = f;
return m->size;
}
static const DUMBFILE_SYSTEM memfile_dfs = {
NULL,
&dumb_memfile_skip,
&dumb_memfile_getc,
&dumb_memfile_getnc,
&dumb_memfile_close,
&dumb_memfile_seek,
&dumb_memfile_get_size
};
DUMBFILE *dumbfile_open_memory(const char *data, long size)
{
MEMFILE *m = malloc(sizeof(*m));
if (!m) return NULL;
m->ptr_begin = data;
m->ptr = data;
m->left = size;
m->size = size;
return dumbfile_open_ex(m, &memfile_dfs);
DUMBFILE *dumbfile_open_memory(const char *data, size_t size) {
MEMFILE *m = malloc(sizeof(*m));
if (!m)
return NULL;
m->ptr_begin = data;
m->ptr = data;
m->left = size;
m->size = size;
return dumbfile_open_ex(m, &memfile_dfs);
}

View file

@ -42,51 +42,57 @@
* FIXME: these comments are somewhat out of date now.
*/
#define SUFFIX3 _1
/* For convenience, returns nonzero on stop. */
static int process_pickup(DUMB_RESAMPLER *resampler)
{
if (resampler->overshot < 0) {
resampler->overshot = 0;
dumb_resample(resampler, NULL, 2, MONO_DEST_VOLUME_ZEROS, 1.0f); /* Doesn't matter which SUFFIX3. */
COPYSRC(resampler->X, 0, resampler->X, 1);
}
static int process_pickup(DUMB_RESAMPLER *resampler) {
if (resampler->overshot < 0) {
resampler->overshot = 0;
dumb_resample(resampler, NULL, 2, MONO_DEST_VOLUME_ZEROS,
1.0f); /* Doesn't matter which SUFFIX3. */
COPYSRC(resampler->X, 0, resampler->X, 1);
}
for (;;) {
SRCTYPE *src = resampler->src;
for (;;) {
SRCTYPE *src = resampler->src;
if (resampler->dir < 0) {
if (resampler->overshot >= 3 && resampler->pos+3 >= resampler->start) COPYSRC(resampler->X, 0, src, resampler->pos+3);
if (resampler->overshot >= 2 && resampler->pos+2 >= resampler->start) COPYSRC(resampler->X, 1, src, resampler->pos+2);
if (resampler->overshot >= 1 && resampler->pos+1 >= resampler->start) COPYSRC(resampler->X, 2, src, resampler->pos+1);
resampler->overshot = resampler->start - resampler->pos - 1;
} else {
if (resampler->overshot >= 3 && resampler->pos-3 < resampler->end) COPYSRC(resampler->X, 0, src, resampler->pos-3);
if (resampler->overshot >= 2 && resampler->pos-2 < resampler->end) COPYSRC(resampler->X, 1, src, resampler->pos-2);
if (resampler->overshot >= 1 && resampler->pos-1 < resampler->end) COPYSRC(resampler->X, 2, src, resampler->pos-1);
resampler->overshot = resampler->pos - resampler->end;
}
if (resampler->dir < 0) {
if (resampler->overshot >= 3 &&
resampler->pos + 3 >= resampler->start)
COPYSRC(resampler->X, 0, src, resampler->pos + 3);
if (resampler->overshot >= 2 &&
resampler->pos + 2 >= resampler->start)
COPYSRC(resampler->X, 1, src, resampler->pos + 2);
if (resampler->overshot >= 1 &&
resampler->pos + 1 >= resampler->start)
COPYSRC(resampler->X, 2, src, resampler->pos + 1);
resampler->overshot = (int)(resampler->start - resampler->pos - 1);
} else {
if (resampler->overshot >= 3 && resampler->pos - 3 < resampler->end)
COPYSRC(resampler->X, 0, src, resampler->pos - 3);
if (resampler->overshot >= 2 && resampler->pos - 2 < resampler->end)
COPYSRC(resampler->X, 1, src, resampler->pos - 2);
if (resampler->overshot >= 1 && resampler->pos - 1 < resampler->end)
COPYSRC(resampler->X, 2, src, resampler->pos - 1);
resampler->overshot = (int)(resampler->pos - resampler->end);
}
if (resampler->overshot < 0) {
resampler->overshot = 0;
return 0;
}
if (resampler->overshot < 0) {
resampler->overshot = 0;
return 0;
}
if (!resampler->pickup) {
resampler->dir = 0;
return 1;
}
(*resampler->pickup)(resampler, resampler->pickup_data);
if (resampler->dir == 0) return 1;
ASSERT(resampler->dir == -1 || resampler->dir == 1);
}
if (!resampler->pickup) {
resampler->dir = 0;
return 1;
}
(*resampler->pickup)(resampler, resampler->pickup_data);
if (resampler->dir == 0)
return 1;
ASSERT(resampler->dir == -1 || resampler->dir == 1);
}
}
/* Create mono destination resampler. */
/* SUFFIX3 was set above. */
#define VOLUME_PARAMETERS MONO_DEST_VOLUME_PARAMETERS
@ -101,48 +107,58 @@ static int process_pickup(DUMB_RESAMPLER *resampler)
/* Create stereo destination resampler. */
#define SUFFIX3 _2
#define VOLUME_PARAMETERS DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right
#define VOLUME_VARIABLES lvol, lvolr, lvold, lvolt, lvolm, rvol, rvolr, rvold, rvolt, rvolm
#define SET_VOLUME_VARIABLES { \
if ( volume_left ) { \
lvolr = volume_left->volume; \
lvold = volume_left->delta; \
lvolt = volume_left->target; \
lvolm = volume_left->mix; \
lvol = lvolr * lvolm; \
if ( lvolr == lvolt ) volume_left = NULL; \
} else { \
lvol = 0; \
lvold = 0; \
lvolt = 0; \
lvolm = 0; \
} \
if ( volume_right ) { \
rvolr = volume_right->volume; \
rvold = volume_right->delta; \
rvolt = volume_right->target; \
rvolm = volume_right->mix; \
rvol = rvolr * rvolm; \
if ( rvolr == rvolt ) volume_right = NULL; \
} else { \
rvol = 0; \
rvold = 0; \
rvolt = 0; \
rvolm = 0; \
} \
}
#define RETURN_VOLUME_VARIABLES { \
if ( volume_left ) volume_left->volume = lvolr; \
if ( volume_right ) volume_right->volume = rvolr; \
}
#define VOLUME_PARAMETERS \
DUMB_VOLUME_RAMP_INFO *volume_left, DUMB_VOLUME_RAMP_INFO *volume_right
#define VOLUME_VARIABLES \
lvol, lvolr, lvold, lvolt, lvolm, rvol, rvolr, rvold, rvolt, rvolm
#define SET_VOLUME_VARIABLES \
{ \
if (volume_left) { \
lvolr = volume_left->volume; \
lvold = volume_left->delta; \
lvolt = volume_left->target; \
lvolm = volume_left->mix; \
lvol = lvolr * lvolm; \
if (lvolr == lvolt) \
volume_left = NULL; \
} else { \
lvol = 0; \
lvold = 0; \
lvolt = 0; \
lvolm = 0; \
} \
if (volume_right) { \
rvolr = volume_right->volume; \
rvold = volume_right->delta; \
rvolt = volume_right->target; \
rvolm = volume_right->mix; \
rvol = rvolr * rvolm; \
if (rvolr == rvolt) \
volume_right = NULL; \
} else { \
rvol = 0; \
rvold = 0; \
rvolt = 0; \
rvolm = 0; \
} \
}
#define RETURN_VOLUME_VARIABLES \
{ \
if (volume_left) \
volume_left->volume = lvolr; \
if (volume_right) \
volume_right->volume = rvolr; \
}
#define VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
#define PEEK_FIR STEREO_DEST_PEEK_FIR
#define MIX_FIR STEREO_DEST_MIX_FIR
#define MIX_ZEROS(op) { *dst++ op 0; *dst++ op 0; }
#define MIX_ZEROS(op) \
{ \
*dst++ op 0; \
*dst++ op 0; \
}
#include "resamp3.inc"
#undef MONO_DEST_VOLUMES_ARE_ZERO
#undef SET_MONO_DEST_VOLUME_VARIABLES
#undef RETURN_MONO_DEST_VOLUME_VARIABLES

View file

@ -42,211 +42,231 @@
* FIXME: these comments are somewhat out of date now.
*/
long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size,
VOLUME_PARAMETERS, float delta) {
int dt, inv_dt;
float VOLUME_VARIABLES;
long done;
long todo;
LONG_LONG todo64;
int quality;
if (!resampler || resampler->dir == 0)
return 0;
ASSERT(resampler->dir == -1 || resampler->dir == 1);
long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLUME_PARAMETERS, float delta)
{
int dt, inv_dt;
float VOLUME_VARIABLES;
long done;
long todo;
LONG_LONG todo64;
int quality;
done = 0;
dt = (int)(delta * 65536.0 + 0.5);
if (dt == 0 || dt == (int)-0x80000000)
return 0;
inv_dt = (int)(1.0 / delta * 65536.0 + 0.5);
SET_VOLUME_VARIABLES;
if (!resampler || resampler->dir == 0) return 0;
ASSERT(resampler->dir == -1 || resampler->dir == 1);
if (VOLUMES_ARE_ZERO)
dst = NULL;
done = 0;
dt = (int)(delta * 65536.0 + 0.5);
if (dt == 0 || dt == (int)-0x80000000) return 0;
inv_dt = (int)(1.0 / delta * 65536.0 + 0.5);
SET_VOLUME_VARIABLES;
_dumb_init_cubic();
if (VOLUMES_ARE_ZERO) dst = NULL;
quality = resampler->quality;
_dumb_init_cubic();
while (done < dst_size) {
if (process_pickup(resampler)) {
RETURN_VOLUME_VARIABLES;
return done;
}
quality = resampler->quality;
if ((resampler->dir ^ dt) < 0)
dt = -dt;
while (done < dst_size) {
if (process_pickup(resampler)) {
RETURN_VOLUME_VARIABLES;
return done;
}
if (resampler->dir < 0)
todo64 = ((((LONG_LONG)(resampler->pos - resampler->start) << 16) +
resampler->subpos - dt) /
-dt);
else
todo64 = ((((LONG_LONG)(resampler->end - resampler->pos) << 16) -
resampler->subpos - 1 + dt) /
dt);
if ((resampler->dir ^ dt) < 0)
dt = -dt;
if (todo64 < 0)
todo = 0;
else if (todo64 > dst_size - done)
todo = dst_size - done;
else
todo = (long)todo64;
if (resampler->dir < 0)
todo64 = ((((LONG_LONG)(resampler->pos - resampler->start) << 16) + resampler->subpos - dt) / -dt);
else
todo64 = ((((LONG_LONG)(resampler->end - resampler->pos) << 16) - resampler->subpos - 1 + dt) / dt);
done += todo;
if (todo64 < 0)
todo = 0;
else if (todo64 > dst_size - done)
todo = dst_size - done;
else
todo = (long) todo64;
done += todo;
{
SRCTYPE *src = resampler->src;
long pos = resampler->pos;
int subpos = resampler->subpos;
long diff = pos;
long overshot;
if (resampler->dir < 0) {
if (!dst) {
/* Silence or simulation */
LONG_LONG new_subpos = subpos + (LONG_LONG)dt * todo;
pos += (long)(new_subpos >> 16);
subpos = (long)new_subpos & 65535;
} else {
/* FIR resampling, backwards */
SRCTYPE *x;
if ( resampler->fir_resampler_ratio != delta ) {
resampler_set_rate( resampler->fir_resampler[0], delta );
resampler_set_rate( resampler->fir_resampler[1], delta );
resampler->fir_resampler_ratio = delta;
}
x = &src[pos*SRC_CHANNELS];
while ( todo ) {
while ( ( resampler_get_free_count( resampler->fir_resampler[0] ) ||
(!resampler_get_sample_count( resampler->fir_resampler[0] )
{
SRCTYPE *src = resampler->src;
long pos = resampler->pos;
int subpos = resampler->subpos;
long diff = pos;
long overshot;
if (resampler->dir < 0) {
if (!dst) {
/* Silence or simulation */
LONG_LONG new_subpos = subpos + (LONG_LONG)dt * todo;
pos += (long)(new_subpos >> 16);
subpos = (long)new_subpos & 65535;
} else {
/* FIR resampling, backwards */
SRCTYPE *x;
if (resampler->fir_resampler_ratio != delta) {
resampler_set_rate(resampler->fir_resampler[0], delta);
resampler_set_rate(resampler->fir_resampler[1], delta);
resampler->fir_resampler_ratio = delta;
}
x = &src[pos * SRC_CHANNELS];
while (todo) {
while ((resampler_get_free_count(
resampler->fir_resampler[0]) ||
(!resampler_get_sample_count(
resampler->fir_resampler[0])
#if SRC_CHANNELS == 2
&& !resampler_get_sample_count( resampler->fir_resampler[1] )
&& !resampler_get_sample_count(
resampler->fir_resampler[1])
#endif
) ) && pos >= resampler->start )
{
POKE_FIR(0);
pos--;
x -= SRC_CHANNELS;
}
if ( !resampler_get_sample_count( resampler->fir_resampler[0] ) ) break;
MIX_FIR;
ADVANCE_FIR;
--todo;
}
done -= todo;
}
diff = diff - pos;
overshot = resampler->start - pos - 1;
if (diff >= 3) {
COPYSRC2(resampler->X, 0, overshot < 3, src, pos+3);
COPYSRC2(resampler->X, 1, overshot < 2, src, pos+2);
COPYSRC2(resampler->X, 2, overshot < 1, src, pos+1);
} else if (diff >= 2) {
COPYSRC(resampler->X, 0, resampler->X, 2);
COPYSRC2(resampler->X, 1, overshot < 2, src, pos+2);
COPYSRC2(resampler->X, 2, overshot < 1, src, pos+1);
} else if (diff >= 1) {
COPYSRC(resampler->X, 0, resampler->X, 1);
COPYSRC(resampler->X, 1, resampler->X, 2);
COPYSRC2(resampler->X, 2, overshot < 1, src, pos+1);
}
} else {
if (!dst) {
/* Silence or simulation */
LONG_LONG new_subpos = subpos + (LONG_LONG)dt * todo;
pos += (long)(new_subpos >> 16);
subpos = (long)new_subpos & 65535;
} else {
/* FIR resampling, forwards */
SRCTYPE *x;
if ( resampler->fir_resampler_ratio != delta ) {
resampler_set_rate( resampler->fir_resampler[0], delta );
resampler_set_rate( resampler->fir_resampler[1], delta );
resampler->fir_resampler_ratio = delta;
}
x = &src[pos*SRC_CHANNELS];
while ( todo ) {
while ( ( resampler_get_free_count( resampler->fir_resampler[0] ) ||
(!resampler_get_sample_count( resampler->fir_resampler[0] )
)) &&
pos >= resampler->start) {
POKE_FIR(0);
pos--;
x -= SRC_CHANNELS;
}
if (!resampler_get_sample_count(
resampler->fir_resampler[0]))
break;
MIX_FIR;
ADVANCE_FIR;
--todo;
}
done -= todo;
}
diff = diff - pos;
overshot = resampler->start - pos - 1;
if (diff >= 3) {
COPYSRC2(resampler->X, 0, overshot < 3, src, pos + 3);
COPYSRC2(resampler->X, 1, overshot < 2, src, pos + 2);
COPYSRC2(resampler->X, 2, overshot < 1, src, pos + 1);
} else if (diff >= 2) {
COPYSRC(resampler->X, 0, resampler->X, 2);
COPYSRC2(resampler->X, 1, overshot < 2, src, pos + 2);
COPYSRC2(resampler->X, 2, overshot < 1, src, pos + 1);
} else if (diff >= 1) {
COPYSRC(resampler->X, 0, resampler->X, 1);
COPYSRC(resampler->X, 1, resampler->X, 2);
COPYSRC2(resampler->X, 2, overshot < 1, src, pos + 1);
}
} else {
if (!dst) {
/* Silence or simulation */
LONG_LONG new_subpos = subpos + (LONG_LONG)dt * todo;
pos += (long)(new_subpos >> 16);
subpos = (long)new_subpos & 65535;
} else {
/* FIR resampling, forwards */
SRCTYPE *x;
if (resampler->fir_resampler_ratio != delta) {
resampler_set_rate(resampler->fir_resampler[0], delta);
resampler_set_rate(resampler->fir_resampler[1], delta);
resampler->fir_resampler_ratio = delta;
}
x = &src[pos * SRC_CHANNELS];
while (todo) {
while ((resampler_get_free_count(
resampler->fir_resampler[0]) ||
(!resampler_get_sample_count(
resampler->fir_resampler[0])
#if SRC_CHANNELS == 2
&& !resampler_get_sample_count( resampler->fir_resampler[1] )
&& !resampler_get_sample_count(
resampler->fir_resampler[1])
#endif
) ) && pos < resampler->end )
{
POKE_FIR(0);
pos++;
x += SRC_CHANNELS;
}
if ( !resampler_get_sample_count( resampler->fir_resampler[0] ) ) break;
MIX_FIR;
ADVANCE_FIR;
--todo;
}
done -= todo;
}
diff = pos - diff;
overshot = pos - resampler->end;
if (diff >= 3) {
COPYSRC2(resampler->X, 0, overshot < 3, src, pos-3);
COPYSRC2(resampler->X, 1, overshot < 2, src, pos-2);
COPYSRC2(resampler->X, 2, overshot < 1, src, pos-1);
} else if (diff >= 2) {
COPYSRC(resampler->X, 0, resampler->X, 2);
COPYSRC2(resampler->X, 1, overshot < 2, src, pos-2);
COPYSRC2(resampler->X, 2, overshot < 1, src, pos-1);
} else if (diff >= 1) {
COPYSRC(resampler->X, 0, resampler->X, 1);
COPYSRC(resampler->X, 1, resampler->X, 2);
COPYSRC2(resampler->X, 2, overshot < 1, src, pos-1);
}
}
resampler->pos = pos;
resampler->subpos = subpos;
}
}
)) &&
pos < resampler->end) {
POKE_FIR(0);
pos++;
x += SRC_CHANNELS;
}
if (!resampler_get_sample_count(
resampler->fir_resampler[0]))
break;
MIX_FIR;
ADVANCE_FIR;
--todo;
}
done -= todo;
}
diff = pos - diff;
overshot = pos - resampler->end;
if (diff >= 3) {
COPYSRC2(resampler->X, 0, overshot < 3, src, pos - 3);
COPYSRC2(resampler->X, 1, overshot < 2, src, pos - 2);
COPYSRC2(resampler->X, 2, overshot < 1, src, pos - 1);
} else if (diff >= 2) {
COPYSRC(resampler->X, 0, resampler->X, 2);
COPYSRC2(resampler->X, 1, overshot < 2, src, pos - 2);
COPYSRC2(resampler->X, 2, overshot < 1, src, pos - 1);
} else if (diff >= 1) {
COPYSRC(resampler->X, 0, resampler->X, 1);
COPYSRC(resampler->X, 1, resampler->X, 2);
COPYSRC2(resampler->X, 2, overshot < 1, src, pos - 1);
}
}
resampler->pos = pos;
resampler->subpos = subpos;
}
}
RETURN_VOLUME_VARIABLES;
return done;
RETURN_VOLUME_VARIABLES;
return done;
}
void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler,
VOLUME_PARAMETERS, sample_t *dst) {
float VOLUME_VARIABLES;
SRCTYPE *src;
long pos;
int subpos;
int quality;
SRCTYPE *x;
if (!resampler || resampler->dir == 0) {
MIX_ZEROS(=);
return;
}
ASSERT(resampler->dir == -1 || resampler->dir == 1);
void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETERS, sample_t *dst)
{
float VOLUME_VARIABLES;
SRCTYPE *src;
long pos;
int subpos;
int quality;
SRCTYPE *x;
if (process_pickup(resampler)) {
MIX_ZEROS(=);
return;
}
if (!resampler || resampler->dir == 0) { MIX_ZEROS(=); return; }
ASSERT(resampler->dir == -1 || resampler->dir == 1);
SET_VOLUME_VARIABLES;
if (process_pickup(resampler)) { MIX_ZEROS(=); return; }
if (VOLUMES_ARE_ZERO) {
MIX_ZEROS(=);
return;
}
SET_VOLUME_VARIABLES;
_dumb_init_cubic();
if (VOLUMES_ARE_ZERO) { MIX_ZEROS(=); return; }
quality = resampler->quality;
_dumb_init_cubic();
src = resampler->src;
pos = resampler->pos;
subpos = resampler->subpos;
x = resampler->X;
quality = resampler->quality;
src = resampler->src;
pos = resampler->pos;
subpos = resampler->subpos;
x = resampler->X;
if (resampler->dir < 0) {
HEAVYASSERT(pos >= resampler->start);
/* FIR resampling, backwards */
PEEK_FIR;
} else {
HEAVYASSERT(pos < resampler->end);
/* FIR resampling, forwards */
PEEK_FIR;
}
if (resampler->dir < 0) {
HEAVYASSERT(pos >= resampler->start);
/* FIR resampling, backwards */
PEEK_FIR;
} else {
HEAVYASSERT(pos < resampler->end);
/* FIR resampling, forwards */
PEEK_FIR;
}
}
#undef MIX_ZEROS
#undef MIX_FIR
#undef PEEK_FIR

View file

@ -43,11 +43,8 @@
*/
#include <math.h>
#include "dumb.h"
#include "internal/resampler.h"
#include "internal/dumb.h"
/* Compile with -DHEAVYDEBUG if you want to make sure the pick-up function is
* called when it should be. There will be a considerable performance hit,
@ -59,15 +56,12 @@
#define HEAVYASSERT(cond)
#endif
/* Make MSVC shut the hell up about if ( upd ) UPDATE_VOLUME() conditions being constant */
/* Make MSVC shut the hell up about if ( upd ) UPDATE_VOLUME() conditions being
* constant */
#ifdef _MSC_VER
#pragma warning(disable:4127 4701)
#pragma warning(disable : 4127 4701)
#endif
/* A global variable for controlling resampling quality wherever a local
* specification doesn't override it. The following values are valid:
*
@ -83,68 +77,60 @@
*/
int dumb_resampling_quality = DUMB_RQ_CUBIC;
//#define MULSC(a, b) ((int)((LONG_LONG)(a) * (b) >> 16))
//#define MULSC(a, b) ((a) * ((b) >> 2) >> 14)
#define MULSCV(a, b) ((int)((LONG_LONG)(a) * (b) >> 32))
#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32))
#define MULSC16(a, b) ((int)((LONG_LONG)((a) << 12) * ((b) << 12) >> 32))
/* Executes the content 'iterator' times.
* Clobbers the 'iterator' variable.
* The loop is unrolled by four.
*/
#if 0
#define LOOP4(iterator, CONTENT) \
{ \
if ((iterator) & 2) { \
CONTENT; \
CONTENT; \
} \
if ((iterator) & 1) { \
CONTENT; \
} \
(iterator) >>= 2; \
while (iterator) { \
CONTENT; \
CONTENT; \
CONTENT; \
CONTENT; \
(iterator)--; \
} \
}
#define LOOP4(iterator, CONTENT) \
{ \
if ((iterator)&2) { \
CONTENT; \
CONTENT; \
} \
if ((iterator)&1) { \
CONTENT; \
} \
(iterator) >>= 2; \
while (iterator) { \
CONTENT; \
CONTENT; \
CONTENT; \
CONTENT; \
(iterator)--; \
} \
}
#else
#define LOOP4(iterator, CONTENT) \
{ \
while ( (iterator)-- ) \
{ \
CONTENT; \
} \
}
#define LOOP4(iterator, CONTENT) \
{ \
while ((iterator)--) { \
CONTENT; \
} \
}
#endif
#define PASTERAW(a, b) a ## b /* This does not expand macros in b ... */
#define PASTE(a, b) PASTERAW(a, b) /* ... but b is expanded during this substitution. */
#define PASTERAW(a, b) a##b /* This does not expand macros in b ... */
#define PASTE(a, b) \
PASTERAW(a, b) /* ... but b is expanded during this substitution. */
#define X PASTE(x.x, SRCBITS)
void _dumb_init_cubic(void) {
static int done = 0;
if (done)
return;
resampler_init();
void _dumb_init_cubic(void)
{
static int done = 0;
if (done) return;
resampler_init();
done = 1;
done = 1;
}
/* Create resamplers for 24-in-32-bit source samples. */
/* #define SUFFIX
@ -154,7 +140,8 @@ void _dumb_init_cubic(void)
*/
#define process_pickup PASTE(process_pickup, SUFFIX2)
#define dumb_resample PASTE(PASTE(dumb_resample, SUFFIX2), SUFFIX3)
#define dumb_resample_get_current_sample PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX2), SUFFIX3)
#define dumb_resample_get_current_sample \
PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX2), SUFFIX3)
#define SRCTYPE sample_t
#define SRCBITS 24
@ -166,13 +153,15 @@ void _dumb_init_cubic(void)
#undef dumb_resample
#undef process_pickup
/* Now define the proper ones that use SUFFIX. */
#define dumb_reset_resampler PASTE(dumb_reset_resampler, SUFFIX)
#define dumb_start_resampler PASTE(dumb_start_resampler, SUFFIX)
#define process_pickup PASTE(PASTE(process_pickup, SUFFIX), SUFFIX2)
#define dumb_resample PASTE(PASTE(PASTE(dumb_resample, SUFFIX), SUFFIX2), SUFFIX3)
#define dumb_resample_get_current_sample PASTE(PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX), SUFFIX2), SUFFIX3)
#define dumb_resample \
PASTE(PASTE(PASTE(dumb_resample, SUFFIX), SUFFIX2), SUFFIX3)
#define dumb_resample_get_current_sample \
PASTE(PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX), SUFFIX2), \
SUFFIX3)
#define dumb_end_resampler PASTE(dumb_end_resampler, SUFFIX)
/* Create resamplers for 16-bit source samples. */
@ -189,7 +178,6 @@ void _dumb_init_cubic(void)
#define FIR(x) (x * (1.0f / 256.0f))
#include "resample.inc"
#undef dumb_reset_resampler
#undef dumb_start_resampler
#undef process_pickup
@ -197,134 +185,148 @@ void _dumb_init_cubic(void)
#undef dumb_resample_get_current_sample
#undef dumb_end_resampler
void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, long pos, long start, long end, int quality)
{
if (n == 8)
dumb_reset_resampler_8(resampler, src, src_channels, pos, start, end, quality);
else if (n == 16)
dumb_reset_resampler_16(resampler, src, src_channels, pos, start, end, quality);
else
dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality);
void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src,
int src_channels, long pos, long start, long end,
int quality) {
if (n == 8)
dumb_reset_resampler_8(resampler, src, src_channels, pos, start, end,
quality);
else if (n == 16)
dumb_reset_resampler_16(resampler, src, src_channels, pos, start, end,
quality);
else
dumb_reset_resampler(resampler, src, src_channels, pos, start, end,
quality);
}
DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, long pos, long start, long end, int quality)
{
if (n == 8)
return dumb_start_resampler_8(src, src_channels, pos, start, end, quality);
else if (n == 16)
return dumb_start_resampler_16(src, src_channels, pos, start, end, quality);
else
return dumb_start_resampler(src, src_channels, pos, start, end, quality);
DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels,
long pos, long start, long end,
int quality) {
if (n == 8)
return dumb_start_resampler_8(src, src_channels, pos, start, end,
quality);
else if (n == 16)
return dumb_start_resampler_16(src, src_channels, pos, start, end,
quality);
else
return dumb_start_resampler(src, src_channels, pos, start, end,
quality);
}
long dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta)
{
if (n == 8)
return dumb_resample_8_1_1(resampler, dst, dst_size, volume, delta);
else if (n == 16)
return dumb_resample_16_1_1(resampler, dst, dst_size, volume, delta);
else
return dumb_resample_1_1(resampler, dst, dst_size, volume, delta);
long dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst,
long dst_size, DUMB_VOLUME_RAMP_INFO *volume,
float delta) {
if (n == 8)
return dumb_resample_8_1_1(resampler, dst, dst_size, volume, delta);
else if (n == 16)
return dumb_resample_16_1_1(resampler, dst, dst_size, volume, delta);
else
return dumb_resample_1_1(resampler, dst, dst_size, volume, delta);
}
long dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
{
if (n == 8)
return dumb_resample_8_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
else if (n == 16)
return dumb_resample_16_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
else
return dumb_resample_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
long dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst,
long dst_size, DUMB_VOLUME_RAMP_INFO *volume_left,
DUMB_VOLUME_RAMP_INFO *volume_right, float delta) {
if (n == 8)
return dumb_resample_8_1_2(resampler, dst, dst_size, volume_left,
volume_right, delta);
else if (n == 16)
return dumb_resample_16_1_2(resampler, dst, dst_size, volume_left,
volume_right, delta);
else
return dumb_resample_1_2(resampler, dst, dst_size, volume_left,
volume_right, delta);
}
long dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
{
if (n == 8)
return dumb_resample_8_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
else if (n == 16)
return dumb_resample_16_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
else
return dumb_resample_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
long dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst,
long dst_size, DUMB_VOLUME_RAMP_INFO *volume_left,
DUMB_VOLUME_RAMP_INFO *volume_right, float delta) {
if (n == 8)
return dumb_resample_8_2_1(resampler, dst, dst_size, volume_left,
volume_right, delta);
else if (n == 16)
return dumb_resample_16_2_1(resampler, dst, dst_size, volume_left,
volume_right, delta);
else
return dumb_resample_2_1(resampler, dst, dst_size, volume_left,
volume_right, delta);
}
long dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
{
if (n == 8)
return dumb_resample_8_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
else if (n == 16)
return dumb_resample_16_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
else
return dumb_resample_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
long dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst,
long dst_size, DUMB_VOLUME_RAMP_INFO *volume_left,
DUMB_VOLUME_RAMP_INFO *volume_right, float delta) {
if (n == 8)
return dumb_resample_8_2_2(resampler, dst, dst_size, volume_left,
volume_right, delta);
else if (n == 16)
return dumb_resample_16_2_2(resampler, dst, dst_size, volume_left,
volume_right, delta);
else
return dumb_resample_2_2(resampler, dst, dst_size, volume_left,
volume_right, delta);
}
void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst)
{
if (n == 8)
dumb_resample_get_current_sample_8_1_1(resampler, volume, dst);
else if (n == 16)
dumb_resample_get_current_sample_16_1_1(resampler, volume, dst);
else
dumb_resample_get_current_sample_1_1(resampler, volume, dst);
void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler,
DUMB_VOLUME_RAMP_INFO *volume,
sample_t *dst) {
if (n == 8)
dumb_resample_get_current_sample_8_1_1(resampler, volume, dst);
else if (n == 16)
dumb_resample_get_current_sample_16_1_1(resampler, volume, dst);
else
dumb_resample_get_current_sample_1_1(resampler, volume, dst);
}
void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
{
if (n == 8)
dumb_resample_get_current_sample_8_1_2(resampler, volume_left, volume_right, dst);
else if (n == 16)
dumb_resample_get_current_sample_16_1_2(resampler, volume_left, volume_right, dst);
else
dumb_resample_get_current_sample_1_2(resampler, volume_left, volume_right, dst);
void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler,
DUMB_VOLUME_RAMP_INFO *volume_left,
DUMB_VOLUME_RAMP_INFO *volume_right,
sample_t *dst) {
if (n == 8)
dumb_resample_get_current_sample_8_1_2(resampler, volume_left,
volume_right, dst);
else if (n == 16)
dumb_resample_get_current_sample_16_1_2(resampler, volume_left,
volume_right, dst);
else
dumb_resample_get_current_sample_1_2(resampler, volume_left,
volume_right, dst);
}
void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
{
if (n == 8)
dumb_resample_get_current_sample_8_2_1(resampler, volume_left, volume_right, dst);
else if (n == 16)
dumb_resample_get_current_sample_16_2_1(resampler, volume_left, volume_right, dst);
else
dumb_resample_get_current_sample_2_1(resampler, volume_left, volume_right, dst);
void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler,
DUMB_VOLUME_RAMP_INFO *volume_left,
DUMB_VOLUME_RAMP_INFO *volume_right,
sample_t *dst) {
if (n == 8)
dumb_resample_get_current_sample_8_2_1(resampler, volume_left,
volume_right, dst);
else if (n == 16)
dumb_resample_get_current_sample_16_2_1(resampler, volume_left,
volume_right, dst);
else
dumb_resample_get_current_sample_2_1(resampler, volume_left,
volume_right, dst);
}
void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
{
if (n == 8)
dumb_resample_get_current_sample_8_2_2(resampler, volume_left, volume_right, dst);
else if (n == 16)
dumb_resample_get_current_sample_16_2_2(resampler, volume_left, volume_right, dst);
else
dumb_resample_get_current_sample_2_2(resampler, volume_left, volume_right, dst);
void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler,
DUMB_VOLUME_RAMP_INFO *volume_left,
DUMB_VOLUME_RAMP_INFO *volume_right,
sample_t *dst) {
if (n == 8)
dumb_resample_get_current_sample_8_2_2(resampler, volume_left,
volume_right, dst);
else if (n == 16)
dumb_resample_get_current_sample_16_2_2(resampler, volume_left,
volume_right, dst);
else
dumb_resample_get_current_sample_2_2(resampler, volume_left,
volume_right, dst);
}
void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler)
{
if (n == 8)
dumb_end_resampler_8(resampler);
else if (n == 16)
dumb_end_resampler_16(resampler);
else
dumb_end_resampler(resampler);
void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler) {
if (n == 8)
dumb_end_resampler_8(resampler);
else if (n == 16)
dumb_end_resampler_16(resampler);
else
dumb_end_resampler(resampler);
}

View file

@ -42,214 +42,246 @@
* FIXME: these comments are somewhat out of date now.
*/
void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, int src_channels, long pos, long start, long end, int quality)
{
int i;
resampler->src = src;
resampler->pos = pos;
resampler->subpos = 0;
resampler->start = start;
resampler->end = end;
resampler->dir = 1;
resampler->pickup = NULL;
resampler->pickup_data = NULL;
if (quality < 0)
{
resampler->quality = 0;
}
else if (quality > DUMB_RQ_N_LEVELS - 1)
{
resampler->quality = DUMB_RQ_N_LEVELS - 1;
}
else
{
resampler->quality = quality;
}
for (i = 0; i < src_channels*3; i++) resampler->X[i] = 0;
resampler->overshot = -1;
resampler->fir_resampler_ratio = 0;
resampler_clear(resampler->fir_resampler[0]);
resampler_clear(resampler->fir_resampler[1]);
resampler_set_quality(resampler->fir_resampler[0], resampler->quality);
resampler_set_quality(resampler->fir_resampler[1], resampler->quality);
void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src,
int src_channels, long pos, long start, long end,
int quality) {
int i;
resampler->src = src;
resampler->pos = pos;
resampler->subpos = 0;
resampler->start = start;
resampler->end = end;
resampler->dir = 1;
resampler->pickup = NULL;
resampler->pickup_data = NULL;
if (quality < 0) {
resampler->quality = 0;
} else if (quality > DUMB_RQ_N_LEVELS - 1) {
resampler->quality = DUMB_RQ_N_LEVELS - 1;
} else {
resampler->quality = quality;
}
for (i = 0; i < src_channels * 3; i++)
resampler->X[i] = 0;
resampler->overshot = -1;
resampler->fir_resampler_ratio = 0;
resampler_clear(resampler->fir_resampler[0]);
resampler_clear(resampler->fir_resampler[1]);
resampler_set_quality(resampler->fir_resampler[0], resampler->quality);
resampler_set_quality(resampler->fir_resampler[1], resampler->quality);
}
DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, long start, long end, int quality)
{
DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler));
if (!resampler) return NULL;
dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality);
return resampler;
DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos,
long start, long end, int quality) {
DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler));
if (!resampler)
return NULL;
dumb_reset_resampler(resampler, src, src_channels, pos, start, end,
quality);
return resampler;
}
#define UPDATE_VOLUME( pvol, vol ) { \
if (pvol) { \
vol##r += vol##d; \
if ((vol##d < 0 && vol##r <= vol##t) || \
(vol##d > 0 && vol##r >= vol##t)) { \
pvol->volume = pvol->target; \
if ( pvol->declick_stage == 0 || \
pvol->declick_stage >= 3) \
pvol->declick_stage++; \
pvol = NULL; \
vol = vol##t * vol##m; \
} else { \
vol = vol##r * vol##m; \
} \
} \
}
#define UPDATE_VOLUME(pvol, vol) \
{ \
if (pvol) { \
vol##r += vol##d; \
if ((vol##d < 0 && vol##r <= vol##t) || \
(vol##d > 0 && vol##r >= vol##t)) { \
pvol->volume = pvol->target; \
if (pvol->declick_stage == 0 || pvol->declick_stage >= 3) \
pvol->declick_stage++; \
pvol = NULL; \
vol = vol##t * vol##m; \
} else { \
vol = vol##r * vol##m; \
} \
} \
}
/* Create mono source resampler. */
#define SUFFIX2 _1
#define SRC_CHANNELS 1
#define DIVIDE_BY_SRC_CHANNELS(x) (x)
#define COPYSRC(dstarray, dstindex, srcarray, srcindex) (dstarray)[dstindex] = (srcarray)[srcindex]
#define COPYSRC2(dstarray, dstindex, condition, srcarray, srcindex) (dstarray)[dstindex] = condition ? (srcarray)[srcindex] : 0
#define MONO_DEST_VOLUME_PARAMETERS DUMB_VOLUME_RAMP_INFO * volume
#define COPYSRC(dstarray, dstindex, srcarray, srcindex) \
(dstarray)[dstindex] = (srcarray)[srcindex]
#define COPYSRC2(dstarray, dstindex, condition, srcarray, srcindex) \
(dstarray)[dstindex] = condition ? (srcarray)[srcindex] : 0
#define MONO_DEST_VOLUME_PARAMETERS DUMB_VOLUME_RAMP_INFO *volume
#define MONO_DEST_VOLUME_VARIABLES vol, volr, vold, volt, volm
#define MONO_DEST_VOLUME_ZEROS 0
#define SET_MONO_DEST_VOLUME_VARIABLES { \
if ( volume ) { \
volr = volume->volume; \
vold = volume->delta; \
volt = volume->target; \
volm = volume->mix; \
vol = volr * volm; \
if ( volr == volt ) volume = NULL; \
} else { \
vol = 0; \
vold = 0; \
volt = 0; \
volm = 0; \
} \
}
#define RETURN_MONO_DEST_VOLUME_VARIABLES if ( volume ) volume->volume = volr
#define SET_MONO_DEST_VOLUME_VARIABLES \
{ \
if (volume) { \
volr = volume->volume; \
vold = volume->delta; \
volt = volume->target; \
volm = volume->mix; \
vol = volr * volm; \
if (volr == volt) \
volume = NULL; \
} else { \
vol = 0; \
volr = 0; \
vold = 0; \
volt = 0; \
volm = 0; \
} \
}
#define RETURN_MONO_DEST_VOLUME_VARIABLES \
if (volume) \
volume->volume = volr
#define MONO_DEST_VOLUMES_ARE_ZERO (vol == 0 && volt == 0)
#define POKE_FIR(offset) { \
resampler_write_sample_float( resampler->fir_resampler[0], FIR(x[offset]) ); \
}
#define MONO_DEST_PEEK_FIR *dst = resampler_get_sample_float( resampler->fir_resampler[0] ) * vol * 16777216.0f
#define MONO_DEST_MIX_FIR { \
*dst++ += resampler_get_sample_float( resampler->fir_resampler[0] ) * vol * 16777216.0f; \
UPDATE_VOLUME( volume, vol ); \
}
#define ADVANCE_FIR resampler_remove_sample( resampler->fir_resampler[0], 1 )
#define STEREO_DEST_PEEK_FIR { \
float sample = resampler_get_sample_float( resampler->fir_resampler[0] ); \
*dst++ = sample * lvol * 16777216.0f; \
*dst++ = sample * rvol * 16777216.0f; \
}
#define STEREO_DEST_MIX_FIR { \
float sample = resampler_get_sample_float( resampler->fir_resampler[0] ); \
*dst++ += sample * lvol * 16777216.0f; \
*dst++ += sample * rvol * 16777216.0f; \
UPDATE_VOLUME( volume_left, lvol ); \
UPDATE_VOLUME( volume_right, rvol ); \
}
#define POKE_FIR(offset) \
{ \
resampler_write_sample_float(resampler->fir_resampler[0], \
FIR(x[offset])); \
}
#define MONO_DEST_PEEK_FIR \
*dst = resampler_get_sample_float(resampler->fir_resampler[0]) * vol * \
16777216.0f
#define MONO_DEST_MIX_FIR \
{ \
*dst++ += resampler_get_sample_float(resampler->fir_resampler[0]) * \
vol * 16777216.0f; \
UPDATE_VOLUME(volume, vol); \
}
#define ADVANCE_FIR resampler_remove_sample(resampler->fir_resampler[0], 1)
#define STEREO_DEST_PEEK_FIR \
{ \
float sample = \
resampler_get_sample_float(resampler->fir_resampler[0]); \
*dst++ = sample * lvol * 16777216.0f; \
*dst++ = sample * rvol * 16777216.0f; \
}
#define STEREO_DEST_MIX_FIR \
{ \
float sample = \
resampler_get_sample_float(resampler->fir_resampler[0]); \
*dst++ += sample * lvol * 16777216.0f; \
*dst++ += sample * rvol * 16777216.0f; \
UPDATE_VOLUME(volume_left, lvol); \
UPDATE_VOLUME(volume_right, rvol); \
}
#include "resamp2.inc"
/* Create stereo source resampler. */
#define SUFFIX2 _2
#define SRC_CHANNELS 2
#define DIVIDE_BY_SRC_CHANNELS(x) ((x) >> 1)
#define COPYSRC(dstarray, dstindex, srcarray, srcindex) { \
(dstarray)[(dstindex)*2] = (srcarray)[(srcindex)*2]; \
(dstarray)[(dstindex)*2+1] = (srcarray)[(srcindex)*2+1]; \
}
#define COPYSRC2(dstarray, dstindex, condition, srcarray, srcindex) { \
if (condition) { \
(dstarray)[(dstindex)*2] = (srcarray)[(srcindex)*2]; \
(dstarray)[(dstindex)*2+1] = (srcarray)[(srcindex)*2+1]; \
} else { \
(dstarray)[(dstindex)*2] = 0; \
(dstarray)[(dstindex)*2+1] = 0; \
} \
}
#define COPYSRC(dstarray, dstindex, srcarray, srcindex) \
{ \
(dstarray)[(dstindex)*2] = (srcarray)[(srcindex)*2]; \
(dstarray)[(dstindex)*2 + 1] = (srcarray)[(srcindex)*2 + 1]; \
}
#define COPYSRC2(dstarray, dstindex, condition, srcarray, srcindex) \
{ \
if (condition) { \
(dstarray)[(dstindex)*2] = (srcarray)[(srcindex)*2]; \
(dstarray)[(dstindex)*2 + 1] = (srcarray)[(srcindex)*2 + 1]; \
} else { \
(dstarray)[(dstindex)*2] = 0; \
(dstarray)[(dstindex)*2 + 1] = 0; \
} \
}
#define MONO_DEST_VOLUME_PARAMETERS DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right
#define MONO_DEST_VOLUME_VARIABLES lvol, lvolr, lvold, lvolt, lvolm, rvol, rvolr, rvold, rvolt, rvolm
#define MONO_DEST_VOLUME_PARAMETERS \
DUMB_VOLUME_RAMP_INFO *volume_left, DUMB_VOLUME_RAMP_INFO *volume_right
#define MONO_DEST_VOLUME_VARIABLES \
lvol, lvolr, lvold, lvolt, lvolm, rvol, rvolr, rvold, rvolt, rvolm
#define MONO_DEST_VOLUME_ZEROS 0, 0
#define SET_MONO_DEST_VOLUME_VARIABLES { \
if ( volume_left ) { \
lvolr = volume_left->volume; \
lvold = volume_left->delta; \
lvolt = volume_left->target; \
lvolm = volume_left->mix; \
lvol = lvolr * lvolm; \
if ( lvolr == lvolt ) volume_left = NULL; \
} else { \
lvol = 0; \
lvold = 0; \
lvolt = 0; \
lvolm = 0; \
} \
if ( volume_right ) { \
rvolr = volume_right->volume; \
rvold = volume_right->delta; \
rvolt = volume_right->target; \
rvolm = volume_right->mix; \
rvol = rvolr * rvolm; \
if ( rvolr == rvolt ) volume_right = NULL; \
} else { \
rvol = 0; \
rvold = 0; \
rvolt = 0; \
rvolm = 0; \
} \
}
#define RETURN_MONO_DEST_VOLUME_VARIABLES { \
if ( volume_left ) volume_left->volume = lvolr; \
if ( volume_right ) volume_right->volume = rvolr; \
}
#define MONO_DEST_VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
#define POKE_FIR(offset) { \
resampler_write_sample_float( resampler->fir_resampler[0], FIR(x[(offset)*2+0]) ); \
resampler_write_sample_float( resampler->fir_resampler[1], FIR(x[(offset)*2+1]) ); \
}
#define MONO_DEST_PEEK_FIR { \
*dst = (resampler_get_sample_float( resampler->fir_resampler[0] ) * lvol + \
resampler_get_sample_float( resampler->fir_resampler[1] ) * rvol) * 16777216.0f; \
}
#define MONO_DEST_MIX_FIR { \
*dst++ += (resampler_get_sample_float( resampler->fir_resampler[0] ) * lvol + \
resampler_get_sample_float( resampler->fir_resampler[1] ) * rvol) * 16777216.0f; \
UPDATE_VOLUME( volume_left, lvol ); \
UPDATE_VOLUME( volume_right, rvol ); \
}
#define ADVANCE_FIR { \
resampler_remove_sample( resampler->fir_resampler[0], 1 ); \
resampler_remove_sample( resampler->fir_resampler[1], 1 ); \
}
#define STEREO_DEST_PEEK_FIR { \
*dst++ = resampler_get_sample_float( resampler->fir_resampler[0] ) * lvol * 16777216.0f; \
*dst++ = resampler_get_sample_float( resampler->fir_resampler[1] ) * rvol * 16777216.0f; \
}
#define STEREO_DEST_MIX_FIR { \
*dst++ += resampler_get_sample_float( resampler->fir_resampler[0] ) * lvol * 16777216.0f; \
*dst++ += resampler_get_sample_float( resampler->fir_resampler[1] ) * rvol * 16777216.0f; \
UPDATE_VOLUME( volume_left, lvol ); \
UPDATE_VOLUME( volume_right, rvol ); \
}
#define SET_MONO_DEST_VOLUME_VARIABLES \
{ \
if (volume_left) { \
lvolr = volume_left->volume; \
lvold = volume_left->delta; \
lvolt = volume_left->target; \
lvolm = volume_left->mix; \
lvol = lvolr * lvolm; \
if (lvolr == lvolt) \
volume_left = NULL; \
} else { \
lvol = 0; \
lvolr = 0; \
lvold = 0; \
lvolt = 0; \
lvolm = 0; \
} \
if (volume_right) { \
rvolr = volume_right->volume; \
rvold = volume_right->delta; \
rvolt = volume_right->target; \
rvolm = volume_right->mix; \
rvol = rvolr * rvolm; \
if (rvolr == rvolt) \
volume_right = NULL; \
} else { \
rvol = 0; \
rvolr = 0; \
rvold = 0; \
rvolt = 0; \
rvolm = 0; \
} \
}
#define RETURN_MONO_DEST_VOLUME_VARIABLES \
{ \
if (volume_left) \
volume_left->volume = lvolr; \
if (volume_right) \
volume_right->volume = rvolr; \
}
#define MONO_DEST_VOLUMES_ARE_ZERO \
(lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
#define POKE_FIR(offset) \
{ \
resampler_write_sample_float(resampler->fir_resampler[0], \
FIR(x[(offset)*2 + 0])); \
resampler_write_sample_float(resampler->fir_resampler[1], \
FIR(x[(offset)*2 + 1])); \
}
#define MONO_DEST_PEEK_FIR \
{ \
*dst = \
(resampler_get_sample_float(resampler->fir_resampler[0]) * lvol + \
resampler_get_sample_float(resampler->fir_resampler[1]) * rvol) * \
16777216.0f; \
}
#define MONO_DEST_MIX_FIR \
{ \
*dst++ += \
(resampler_get_sample_float(resampler->fir_resampler[0]) * lvol + \
resampler_get_sample_float(resampler->fir_resampler[1]) * rvol) * \
16777216.0f; \
UPDATE_VOLUME(volume_left, lvol); \
UPDATE_VOLUME(volume_right, rvol); \
}
#define ADVANCE_FIR \
{ \
resampler_remove_sample(resampler->fir_resampler[0], 1); \
resampler_remove_sample(resampler->fir_resampler[1], 1); \
}
#define STEREO_DEST_PEEK_FIR \
{ \
*dst++ = resampler_get_sample_float(resampler->fir_resampler[0]) * \
lvol * 16777216.0f; \
*dst++ = resampler_get_sample_float(resampler->fir_resampler[1]) * \
rvol * 16777216.0f; \
}
#define STEREO_DEST_MIX_FIR \
{ \
*dst++ += resampler_get_sample_float(resampler->fir_resampler[0]) * \
lvol * 16777216.0f; \
*dst++ += resampler_get_sample_float(resampler->fir_resampler[1]) * \
rvol * 16777216.0f; \
UPDATE_VOLUME(volume_left, lvol); \
UPDATE_VOLUME(volume_right, rvol); \
}
#include "resamp2.inc"
void dumb_end_resampler(DUMB_RESAMPLER *resampler)
{
if (resampler)
free(resampler);
void dumb_end_resampler(DUMB_RESAMPLER *resampler) {
if (resampler)
free(resampler);
}
#undef FIR
#undef SRCBITS
#undef SRCTYPE

File diff suppressed because it is too large Load diff

View file

@ -3,83 +3,86 @@
#include <stdlib.h>
struct riff * riff_parse( DUMBFILE * f, long offset, long size, unsigned proper )
{
unsigned stream_size;
struct riff * stream;
struct riff *riff_parse(DUMBFILE *f, long offset, long size, unsigned proper) {
unsigned stream_size;
struct riff *stream;
if ( size < 8 ) return 0;
if (size < 8)
return 0;
if ( dumbfile_seek(f, offset, DFS_SEEK_SET) ) return 0;
if ( dumbfile_mgetl(f) != DUMB_ID('R','I','F','F') ) return 0;
if (dumbfile_seek(f, offset, DFS_SEEK_SET))
return 0;
if (dumbfile_mgetl(f) != DUMB_ID('R', 'I', 'F', 'F'))
return 0;
stream_size = (int) dumbfile_igetl(f);
if ( stream_size + 8 > size ) return 0;
if ( stream_size < 4 ) return 0;
stream_size = (int)dumbfile_igetl(f);
if (stream_size + 8 > size)
return 0;
if (stream_size < 4)
return 0;
stream = (struct riff *) malloc( sizeof( struct riff ) );
if ( ! stream ) return 0;
stream = (struct riff *)malloc(sizeof(struct riff));
if (!stream)
return 0;
stream->type = (int) dumbfile_mgetl(f);
stream->chunk_count = 0;
stream->chunks = 0;
stream->type = (int)dumbfile_mgetl(f);
stream->chunk_count = 0;
stream->chunks = 0;
stream_size -= 4;
stream_size -= 4;
while ( stream_size && !dumbfile_error(f) )
{
struct riff_chunk * chunk;
if ( stream_size < 8 ) break;
stream->chunks = ( struct riff_chunk * ) realloc( stream->chunks, ( stream->chunk_count + 1 ) * sizeof( struct riff_chunk ) );
if ( ! stream->chunks ) break;
chunk = stream->chunks + stream->chunk_count;
chunk->type = (int) dumbfile_mgetl(f);
chunk->size = (int) dumbfile_igetl(f);
while (stream_size && !dumbfile_error(f)) {
struct riff_chunk *chunk;
if (stream_size < 8)
break;
stream->chunks = (struct riff_chunk *)realloc(
stream->chunks,
(stream->chunk_count + 1) * sizeof(struct riff_chunk));
if (!stream->chunks)
break;
chunk = stream->chunks + stream->chunk_count;
chunk->type = (int)dumbfile_mgetl(f);
chunk->size = (int)dumbfile_igetl(f);
chunk->offset = dumbfile_pos(f);
stream_size -= 8;
if ( stream_size < chunk->size ) break;
if ( chunk->type == DUMB_ID('R','I','F','F') )
{
chunk->nested = riff_parse( f, chunk->offset - 8, chunk->size + 8, proper );
if ( ! chunk->nested ) break;
}
else
{
stream_size -= 8;
if (stream_size < chunk->size)
break;
if (chunk->type == DUMB_ID('R', 'I', 'F', 'F')) {
chunk->nested =
riff_parse(f, chunk->offset - 8, chunk->size + 8, proper);
if (!chunk->nested)
break;
} else {
chunk->nested = 0;
}
}
dumbfile_seek(f, chunk->offset + chunk->size, DFS_SEEK_SET);
stream_size -= chunk->size;
if ( proper && ( chunk->size & 1 ) )
{
stream_size -= chunk->size;
if (proper && (chunk->size & 1)) {
dumbfile_skip(f, 1);
-- stream_size;
}
++stream->chunk_count;
}
if ( stream_size )
{
riff_free( stream );
stream = 0;
}
--stream_size;
}
++stream->chunk_count;
}
return stream;
if (stream_size) {
riff_free(stream);
stream = 0;
}
return stream;
}
void riff_free( struct riff * stream )
{
if ( stream )
{
if ( stream->chunks )
{
unsigned i;
for ( i = 0; i < stream->chunk_count; ++i )
{
struct riff_chunk * chunk = stream->chunks + i;
if ( chunk->nested ) riff_free( chunk->nested );
}
free( stream->chunks );
}
free( stream );
}
void riff_free(struct riff *stream) {
if (stream) {
if (stream->chunks) {
unsigned i;
for (i = 0; i < stream->chunk_count; ++i) {
struct riff_chunk *chunk = stream->chunks + i;
if (chunk->nested)
riff_free(chunk->nested);
}
free(stream->chunks);
}
free(stream);
}
}

View file

@ -20,45 +20,24 @@
#include <stdlib.h>
#include "dumb.h"
/* DEPRECATED */
sample_t **create_sample_buffer(int n_channels, long length)
{
int i;
sample_t **samples = malloc(n_channels * sizeof(*samples));
if (!samples) return NULL;
samples[0] = malloc(n_channels * length * sizeof(*samples[0]));
if (!samples[0]) {
free(samples);
return NULL;
}
for (i = 1; i < n_channels; i++) samples[i] = samples[i-1] + length;
return samples;
sample_t **allocate_sample_buffer(int n_channels, long length) {
int i;
sample_t **samples = malloc(((n_channels + 1) >> 1) * sizeof(*samples));
if (!samples)
return NULL;
samples[0] = malloc(n_channels * length * sizeof(*samples[0]));
if (!samples[0]) {
free(samples);
return NULL;
}
for (i = 1; i<(n_channels + 1)>> 1; i++)
samples[i] = samples[i - 1] + length * 2;
return samples;
}
sample_t **allocate_sample_buffer(int n_channels, long length)
{
int i;
sample_t **samples = malloc(((n_channels + 1) >> 1) * sizeof(*samples));
if (!samples) return NULL;
samples[0] = malloc(n_channels * length * sizeof(*samples[0]));
if (!samples[0]) {
free(samples);
return NULL;
}
for (i = 1; i < (n_channels + 1) >> 1; i++) samples[i] = samples[i-1] + length*2;
return samples;
}
void destroy_sample_buffer(sample_t **samples)
{
if (samples) {
free(samples[0]);
free(samples);
}
void destroy_sample_buffer(sample_t **samples) {
if (samples) {
free(samples[0]);
free(samples);
}
}

View file

@ -20,10 +20,6 @@
#include <string.h>
#include "dumb.h"
void dumb_silence(sample_t *samples, long length)
{
memset(samples, 0, length * sizeof(*samples));
void dumb_silence(sample_t *samples, long length) {
memset(samples, 0, length * sizeof(*samples));
}

View file

@ -21,131 +21,93 @@
#include "dumb.h"
typedef struct dumb_stdfile
{
FILE * file;
long size;
typedef struct dumb_stdfile {
FILE *file;
dumb_off_t size;
} dumb_stdfile;
static void *dumb_stdfile_open(const char *filename)
{
dumb_stdfile * file = ( dumb_stdfile * ) malloc( sizeof(dumb_stdfile) );
if ( !file ) return 0;
static void *dumb_stdfile_open(const char *filename) {
dumb_stdfile *file = (dumb_stdfile *)malloc(sizeof(dumb_stdfile));
if (!file)
return 0;
file->file = fopen(filename, "rb");
if ( !file->file )
{
free( file );
if (!file->file) {
free(file);
return 0;
}
fseek(file->file, 0, SEEK_END);
file->size = ftell(file->file);
if (file->size < 0) {
fclose(file->file);
free(file);
return 0;
}
fseek(file->file, 0, SEEK_SET);
return file;
}
static int dumb_stdfile_skip(void *f, long n)
{
dumb_stdfile * file = ( dumb_stdfile * ) f;
static int dumb_stdfile_skip(void *f, dumb_off_t n) {
dumb_stdfile *file = (dumb_stdfile *)f;
return fseek(file->file, n, SEEK_CUR);
}
static int dumb_stdfile_getc(void *f)
{
dumb_stdfile * file = ( dumb_stdfile * ) f;
static int dumb_stdfile_getc(void *f) {
dumb_stdfile *file = (dumb_stdfile *)f;
return fgetc(file->file);
}
static long dumb_stdfile_getnc(char *ptr, long n, void *f)
{
dumb_stdfile * file = ( dumb_stdfile * ) f;
static dumb_ssize_t dumb_stdfile_getnc(char *ptr, size_t n, void *f) {
dumb_stdfile *file = (dumb_stdfile *)f;
return fread(ptr, 1, n, file->file);
}
static void dumb_stdfile_close(void *f)
{
dumb_stdfile * file = ( dumb_stdfile * ) f;
static void dumb_stdfile_close(void *f) {
dumb_stdfile *file = (dumb_stdfile *)f;
fclose(file->file);
free(f);
}
static void dumb_stdfile_noclose(void *f) { free(f); }
static void dumb_stdfile_noclose(void *f)
{
free(f);
}
static int dumb_stdfile_seek(void *f, long n)
{
dumb_stdfile * file = ( dumb_stdfile * ) f;
static int dumb_stdfile_seek(void *f, dumb_off_t n) {
dumb_stdfile *file = (dumb_stdfile *)f;
return fseek(file->file, n, SEEK_SET);
}
static long dumb_stdfile_get_size(void *f)
{
dumb_stdfile * file = ( dumb_stdfile * ) f;
static dumb_off_t dumb_stdfile_get_size(void *f) {
dumb_stdfile *file = (dumb_stdfile *)f;
return file->size;
}
static const DUMBFILE_SYSTEM stdfile_dfs = {
&dumb_stdfile_open,
&dumb_stdfile_skip,
&dumb_stdfile_getc,
&dumb_stdfile_getnc,
&dumb_stdfile_close,
&dumb_stdfile_seek,
&dumb_stdfile_get_size
};
&dumb_stdfile_open, &dumb_stdfile_skip, &dumb_stdfile_getc,
&dumb_stdfile_getnc, &dumb_stdfile_close, &dumb_stdfile_seek,
&dumb_stdfile_get_size};
void dumb_register_stdfiles(void) { register_dumbfile_system(&stdfile_dfs); }
static const DUMBFILE_SYSTEM stdfile_dfs_leave_open = {NULL,
&dumb_stdfile_skip,
&dumb_stdfile_getc,
&dumb_stdfile_getnc,
&dumb_stdfile_noclose,
&dumb_stdfile_seek,
&dumb_stdfile_get_size};
void dumb_register_stdfiles(void)
{
register_dumbfile_system(&stdfile_dfs);
}
static const DUMBFILE_SYSTEM stdfile_dfs_leave_open = {
NULL,
&dumb_stdfile_skip,
&dumb_stdfile_getc,
&dumb_stdfile_getnc,
&dumb_stdfile_noclose,
&dumb_stdfile_seek,
&dumb_stdfile_get_size
};
DUMBFILE *dumbfile_open_stdfile(FILE *p)
{
dumb_stdfile * file = ( dumb_stdfile * ) malloc( sizeof(dumb_stdfile) );
DUMBFILE *d;
if ( !file ) return 0;
DUMBFILE *dumbfile_open_stdfile(FILE *p) {
dumb_stdfile *file = (dumb_stdfile *)malloc(sizeof(dumb_stdfile));
DUMBFILE *d;
if (!file)
return 0;
file->file = p;
fseek(p, 0, SEEK_END);
file->size = ftell(p);
if (file->size < 0) {
free(file);
return 0;
}
fseek(p, 0, SEEK_SET);
d = dumbfile_open_ex(file, &stdfile_dfs_leave_open);
return d;
return d;
}

View file

@ -2,174 +2,179 @@
#include <string.h>
/*
Structures which contain the play times of each pattern and row combination in the song,
not guaranteed to be valid for the whole song until the loop status is no longer zero.
The initial count and restart count will both be zero on song start, then both will be
incremented until the song loops. Restart count will be reset to zero on loop for all
rows which have a time equal to or greater than the loop start point, so time keeping
functions will know which timestamp the song is currently located at.
/*
Structures which contain the play times of each pattern and row combination
in the song, not guaranteed to be valid for the whole song until the loop
status is no longer zero. The initial count and restart count will both be
zero on song start, then both will be incremented until the song loops.
Restart count will be reset to zero on loop for all rows which have a time
equal to or greater than the loop start point, so time keeping functions will
know which timestamp the song is currently located at.
Timestamp lists are guaranteed to be allocated in blocks of 16 timestamps at a time.
*/
Timestamp lists are guaranteed to be allocated in blocks of 16 timestamps at
a time.
*/
/*
We don't need full timekeeping because the player loop only wants the first play time
of the loop start order/row. We also don't really want full timekeeping because it
involves a lot of memory allocations, which is also slow.
*/
/*
We don't need full timekeeping because the player loop only wants the first
play time of the loop start order/row. We also don't really want full
timekeeping because it involves a lot of memory allocations, which is also
slow.
*/
#undef FULL_TIMEKEEPING
typedef struct DUMB_IT_ROW_TIME
{
unsigned int count, restart_count;
typedef struct DUMB_IT_ROW_TIME {
unsigned int count, restart_count;
#ifndef FULL_TIMEKEEPING
LONG_LONG first_time;
LONG_LONG first_time;
#else
LONG_LONG * times;
LONG_LONG *times;
#endif
} DUMB_IT_ROW_TIME;
void * timekeeping_array_create(size_t size)
{
size_t * _size = (size_t *) calloc( 1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * size );
if ( _size ) {
*_size = size;
}
return _size;
void *timekeeping_array_create(size_t size) {
size_t *_size =
(size_t *)calloc(1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * size);
if (_size) {
*_size = size;
}
return _size;
}
void timekeeping_array_destroy(void * array)
{
void timekeeping_array_destroy(void *array) {
#ifdef FULL_TIMEKEEPING
size_t i;
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
size_t i;
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
for (i = 0; i < *size; i++) {
if (s[i].times) free(s[i].times);
}
for (i = 0; i < *size; i++) {
if (s[i].times)
free(s[i].times);
}
#endif
free(array);
}
void * timekeeping_array_dup(void * array)
{
size_t i;
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
size_t * new_size = (size_t *) calloc( 1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * *size );
if ( new_size ) {
DUMB_IT_ROW_TIME * new_s = (DUMB_IT_ROW_TIME *)(new_size + 1);
void *timekeeping_array_dup(void *array) {
size_t i;
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
size_t *new_size =
(size_t *)calloc(1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * *size);
if (new_size) {
DUMB_IT_ROW_TIME *new_s = (DUMB_IT_ROW_TIME *)(new_size + 1);
*new_size = *size;
*new_size = *size;
for (i = 0; i < *size; i++) {
new_s[i].count = s[i].count;
new_s[i].restart_count = s[i].restart_count;
for (i = 0; i < *size; i++) {
new_s[i].count = s[i].count;
new_s[i].restart_count = s[i].restart_count;
#ifndef FULL_TIMEKEEPING
new_s[i].first_time = s[i].first_time;
new_s[i].first_time = s[i].first_time;
#else
if ( s[i].times ) {
size_t time_count = ( s[i].count + 15 ) & ~15;
new_s[i].times = (LONG_LONG *) malloc( sizeof(LONG_LONG) * time_count );
if ( new_s[i].times == (void *)0 ) {
timekeeping_array_destroy( new_size );
return (void *) 0;
}
memcpy( new_s[i].times, s[i].times, sizeof(LONG_LONG) * s[i].count );
}
if (s[i].times) {
size_t time_count = (s[i].count + 15) & ~15;
new_s[i].times =
(LONG_LONG *)malloc(sizeof(LONG_LONG) * time_count);
if (new_s[i].times == (void *)0) {
timekeeping_array_destroy(new_size);
return (void *)0;
}
memcpy(new_s[i].times, s[i].times,
sizeof(LONG_LONG) * s[i].count);
}
#endif
}
}
}
}
return new_size;
return new_size;
}
void timekeeping_array_reset(void * array, size_t loop_start)
{
size_t i;
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
void timekeeping_array_reset(void *array, size_t loop_start) {
size_t i;
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
DUMB_IT_ROW_TIME * s_loop_start = s + loop_start;
LONG_LONG loop_start_time;
DUMB_IT_ROW_TIME *s_loop_start = s + loop_start;
LONG_LONG loop_start_time;
if ( loop_start >= *size || s_loop_start->count < 1 ) return;
if (loop_start >= *size || s_loop_start->count < 1)
return;
#ifndef FULL_TIMEKEEPING
loop_start_time = s_loop_start->first_time;
loop_start_time = s_loop_start->first_time;
#else
loop_start_time = s_loop_start->times[0];
loop_start_time = s_loop_start->times[0];
#endif
for ( i = 0; i < *size; i++ ) {
for (i = 0; i < *size; i++) {
#ifndef FULL_TIMEKEEPING
if ( s[i].count && s[i].first_time >= loop_start_time ) {
if (s[i].count && s[i].first_time >= loop_start_time) {
#else
if ( s[i].count && s[i].times[0] >= loop_start_time ) {
if (s[i].count && s[i].times[0] >= loop_start_time) {
#endif
s[i].restart_count = 0;
}
}
s[i].restart_count = 0;
}
}
}
void timekeeping_array_push(void * array, size_t index, LONG_LONG time)
{
void timekeeping_array_push(void *array, size_t index, LONG_LONG time) {
#ifdef FULL_TIMEKEEPING
size_t i;
size_t i;
size_t time_count;
#endif
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
if (index >= *size) return;
if (index >= *size)
return;
#ifndef FULL_TIMEKEEPING
if ( !s[index].count++ )
s[index].first_time = time;
if (!s[index].count++)
s[index].first_time = time;
#else
time_count = ( s[index].count + 16 ) & ~15;
time_count = (s[index].count + 16) & ~15;
s[index].times = (LONG_LONG *) realloc( s[index].times, sizeof(LONG_LONG) * time_count );
s[index].times =
(LONG_LONG *)realloc(s[index].times, sizeof(LONG_LONG) * time_count);
s[index].times[s[index].count++] = time;
s[index].times[s[index].count++] = time;
#endif
}
void timekeeping_array_bump(void * array, size_t index)
{
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
void timekeeping_array_bump(void *array, size_t index) {
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
if (index >= *size) return;
if (index >= *size)
return;
s[index].restart_count++;
s[index].restart_count++;
}
unsigned int timekeeping_array_get_count(void * array, size_t index)
{
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
unsigned int timekeeping_array_get_count(void *array, size_t index) {
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
if (index >= *size) return 0;
if (index >= *size)
return 0;
return s[index].count;
return s[index].count;
}
LONG_LONG timekeeping_array_get_item(void * array, size_t index)
{
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
LONG_LONG timekeeping_array_get_item(void *array, size_t index) {
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
if (index >= *size || s[index].restart_count >= s[index].count) return 0;
if (index >= *size || s[index].restart_count >= s[index].count)
return 0;
#ifndef FULL_TIMEKEEPING
return s[index].first_time;
return s[index].first_time;
#else
return s[index].times[s[index].restart_count];
return s[index].times[s[index].restart_count];
#endif
}

View file

@ -20,24 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_it_quick(): loads an IT file into a DUH struct, returning a
* pointer to the DUH struct. When you have finished with it, you must pass
* the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_it_quick(const char *filename)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_it_quick(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_it_quick(f);
duh = dumb_read_it_quick(f);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_load_it(const char *filename)
{
DUH *duh = dumb_load_it_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_it(const char *filename) {
DUH *duh = dumb_load_it_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,230 +20,150 @@
#include "dumb.h"
#include "internal/it.h"
int dumb_it_default_panning_separation = 25;
DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh)
{
return duh_get_raw_sigdata(duh, -1, SIGTYPE_IT);
DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh) {
return duh_get_raw_sigdata(duh, -1, SIGTYPE_IT);
}
const unsigned char *dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd)
{
return sd ? sd->song_message : NULL;
const unsigned char *dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd) {
return sd ? sd->song_message : NULL;
}
int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd)
{
return sd ? sd->n_orders : 0;
int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd) {
return sd ? sd->n_orders : 0;
}
int dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd)
{
return sd ? sd->n_samples : 0;
int dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd) {
return sd ? sd->n_samples : 0;
}
int dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd)
{
return sd ? sd->n_instruments : 0;
int dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd) {
return sd ? sd->n_instruments : 0;
}
const unsigned char *dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i)
{
ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples);
return sd->sample[i].name;
const unsigned char *dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i) {
ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples);
return sd->sample[i].name;
}
const unsigned char *dumb_it_sd_get_sample_filename(DUMB_IT_SIGDATA *sd, int i)
{
ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples);
return sd->sample[i].filename;
const unsigned char *dumb_it_sd_get_sample_filename(DUMB_IT_SIGDATA *sd,
int i) {
ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples);
return sd->sample[i].filename;
}
const unsigned char *dumb_it_sd_get_instrument_name(DUMB_IT_SIGDATA *sd, int i)
{
ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments);
return sd->instrument[i].name;
const unsigned char *dumb_it_sd_get_instrument_name(DUMB_IT_SIGDATA *sd,
int i) {
ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments);
return sd->instrument[i].name;
}
const unsigned char *dumb_it_sd_get_instrument_filename(DUMB_IT_SIGDATA *sd, int i)
{
ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments);
return sd->instrument[i].filename;
const unsigned char *dumb_it_sd_get_instrument_filename(DUMB_IT_SIGDATA *sd,
int i) {
ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments);
return sd->instrument[i].filename;
}
int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd)
{
return sd ? sd->global_volume : 0;
int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd) {
return sd ? sd->global_volume : 0;
}
void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv)
{
if (sd) sd->global_volume = gv;
void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv) {
if (sd)
sd->global_volume = gv;
}
int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd)
{
return sd ? sd->mixing_volume : 0;
int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd) {
return sd ? sd->mixing_volume : 0;
}
void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv)
{
if (sd) sd->mixing_volume = mv;
void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv) {
if (sd)
sd->mixing_volume = mv;
}
int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd)
{
return sd ? sd->speed : 0;
int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd) {
return sd ? sd->speed : 0;
}
void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed)
{
if (sd) sd->speed = speed;
void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed) {
if (sd)
sd->speed = speed;
}
int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd)
{
return sd ? sd->tempo : 0;
int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd) {
return sd ? sd->tempo : 0;
}
void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo)
{
if (sd) sd->tempo = tempo;
void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo) {
if (sd)
sd->tempo = tempo;
}
int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel)
{
ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS);
return sd ? sd->channel_volume[channel] : 0;
int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel) {
ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS);
return sd ? sd->channel_volume[channel] : 0;
}
void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, int volume)
{
ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS);
if (sd) sd->channel_volume[channel] = volume;
void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel,
int volume) {
ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS);
if (sd)
sd->channel_volume[channel] = volume;
}
int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr)
{
return sr ? sr->order : -1;
int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr) {
return sr ? sr->order : -1;
}
int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr)
{
return sr ? sr->row : -1;
int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr) {
return sr ? sr->row : -1;
}
int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr)
{
return sr ? sr->globalvolume : 0;
int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr) {
return sr ? sr->globalvolume : 0;
}
void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv)
{
if (sr) sr->globalvolume = gv;
void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv) {
if (sr)
sr->globalvolume = gv;
}
int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr) { return sr ? sr->tempo : 0; }
int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr)
{
return sr ? sr->tempo : 0;
void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo) {
if (sr)
sr->tempo = tempo;
}
int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr) { return sr ? sr->speed : 0; }
void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo)
{
if (sr) sr->tempo = tempo;
void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed) {
if (sr)
sr->speed = speed;
}
int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr)
{
return sr ? sr->speed : 0;
int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel) {
return sr ? sr->channel[channel].channelvolume : 0;
}
void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed)
{
if (sr) sr->speed = speed;
void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel,
int volume) {
if (sr)
sr->channel[channel].channelvolume = volume;
}
int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel)
{
return sr ? sr->channel[channel].channelvolume : 0;
void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel,
int muted) {
if (sr) {
if (muted)
sr->channel[channel].flags |= IT_CHANNEL_MUTED;
else
sr->channel[channel].flags &= ~IT_CHANNEL_MUTED;
}
}
void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume)
{
if (sr) sr->channel[channel].channelvolume = volume;
}
void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted)
{
if (sr) {
if (muted)
sr->channel[channel].flags |= IT_CHANNEL_MUTED;
else
sr->channel[channel].flags &= ~IT_CHANNEL_MUTED;
}
}
int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel)
{
return sr ? (sr->channel[channel].flags & IT_CHANNEL_MUTED) != 0 : 0;
int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel) {
return sr ? (sr->channel[channel].flags & IT_CHANNEL_MUTED) != 0 : 0;
}

View file

@ -17,47 +17,45 @@
* \__/
*/
#include <stdlib.h>
#include "dumb.h"
#include "internal/it.h"
/* This function ensures that any pattern mentioned in the order table but
* not present in the pattern table is treated as an empty 64 rows pattern.
* This is done by adding such a dummy pattern at the end of the pattern
* table, and redirect invalid orders to it.
* Patterns 254 and 255 are left untouched, unless the signal is an XM.
*/
int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata)
{
int i;
int found_some = 0;
int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata) {
int i;
int found_some = 0;
int first_invalid = sigdata->n_patterns;
int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253;
int first_invalid = sigdata->n_patterns;
int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253;
for (i = 0; i < sigdata->n_orders; i++) {
if (sigdata->order[i] >= first_invalid && sigdata->order[i] <= last_invalid) {
sigdata->order[i] = sigdata->n_patterns;
found_some = 1;
}
}
for (i = 0; i < sigdata->n_orders; i++) {
if (sigdata->order[i] >= first_invalid &&
sigdata->order[i] <= last_invalid) {
sigdata->order[i] = sigdata->n_patterns;
found_some = 1;
}
}
if (found_some) {
IT_PATTERN *new_pattern = realloc(sigdata->pattern, sizeof(*sigdata->pattern) * (sigdata->n_patterns + 1));
if (!new_pattern)
return -1;
new_pattern[sigdata->n_patterns].n_rows = 64;
new_pattern[sigdata->n_patterns].n_entries = 0;
new_pattern[sigdata->n_patterns].entry = NULL;
sigdata->pattern = new_pattern;
sigdata->n_patterns++;
}
if (found_some) {
IT_PATTERN *new_pattern =
realloc(sigdata->pattern,
sizeof(*sigdata->pattern) * (sigdata->n_patterns + 1));
if (!new_pattern)
return -1;
return 0;
new_pattern[sigdata->n_patterns].n_rows = 64;
new_pattern[sigdata->n_patterns].n_entries = 0;
new_pattern[sigdata->n_patterns].entry = NULL;
sigdata->pattern = new_pattern;
sigdata->n_patterns++;
}
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_read_it(DUMBFILE *f)
{
DUH *duh = dumb_read_it_quick(f);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_read_it(DUMBFILE *f) {
DUH *duh = dumb_read_it_quick(f);
dumb_it_do_initial_runthrough(duh);
return duh;
}

File diff suppressed because it is too large Load diff

View file

@ -22,51 +22,48 @@
#include "dumb.h"
#include "internal/it.h"
void _dumb_it_unload_sigdata(sigdata_t *vsigdata) {
if (vsigdata) {
DUMB_IT_SIGDATA *sigdata = vsigdata;
int n;
if (sigdata->song_message)
free(sigdata->song_message);
void _dumb_it_unload_sigdata(sigdata_t *vsigdata)
{
if (vsigdata) {
DUMB_IT_SIGDATA *sigdata = vsigdata;
int n;
if (sigdata->order)
free(sigdata->order);
if (sigdata->song_message)
free(sigdata->song_message);
if (sigdata->instrument)
free(sigdata->instrument);
if (sigdata->order)
free(sigdata->order);
if (sigdata->sample) {
for (n = 0; n < sigdata->n_samples; n++)
if (sigdata->sample[n].data)
free(sigdata->sample[n].data);
if (sigdata->instrument)
free(sigdata->instrument);
free(sigdata->sample);
}
if (sigdata->sample) {
for (n = 0; n < sigdata->n_samples; n++)
if (sigdata->sample[n].data)
free(sigdata->sample[n].data);
if (sigdata->pattern) {
for (n = 0; n < sigdata->n_patterns; n++)
if (sigdata->pattern[n].entry)
free(sigdata->pattern[n].entry);
free(sigdata->pattern);
}
free(sigdata->sample);
}
if (sigdata->midi)
free(sigdata->midi);
if (sigdata->pattern) {
for (n = 0; n < sigdata->n_patterns; n++)
if (sigdata->pattern[n].entry)
free(sigdata->pattern[n].entry);
free(sigdata->pattern);
}
{
IT_CHECKPOINT *checkpoint = sigdata->checkpoint;
while (checkpoint) {
IT_CHECKPOINT *next = checkpoint->next;
_dumb_it_end_sigrenderer(checkpoint->sigrenderer);
free(checkpoint);
checkpoint = next;
}
}
if (sigdata->midi)
free(sigdata->midi);
{
IT_CHECKPOINT *checkpoint = sigdata->checkpoint;
while (checkpoint) {
IT_CHECKPOINT *next = checkpoint->next;
_dumb_it_end_sigrenderer(checkpoint->sigrenderer);
free(checkpoint);
checkpoint = next;
}
}
free(vsigdata);
}
free(vsigdata);
}
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_669_quick(): loads a 669 file into a DUH struct, returning a
* pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_669_quick(const char *filename)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_669_quick(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_669_quick(f);
duh = dumb_read_669_quick(f);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -20,15 +20,12 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_669(): loads a 669 file into a DUH struct, returning a pointer
* to the DUH struct. When you have finished with it, you must pass the
* pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_669(const char *filename)
{
DUH *duh = dumb_load_669_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_669(const char *filename) {
DUH *duh = dumb_load_669_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_amf_quick(): loads a AMF file into a DUH struct, returning a
* pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_amf_quick(const char *filename)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_amf_quick(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_amf_quick(f);
duh = dumb_read_amf_quick(f);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -20,15 +20,12 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_amf(): loads a AMF file into a DUH struct, returning a pointer
* to the DUH struct. When you have finished with it, you must pass the
* pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_amf(const char *filename)
{
DUH *duh = dumb_load_amf_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_amf(const char *filename) {
DUH *duh = dumb_load_amf_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,19 +20,16 @@
#include "dumb.h"
#include "internal/it.h"
DUH *dumb_load_any_quick(const char *filename, int restrict_, int subsong) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_any_quick(const char *filename, int restrict_, int subsong)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_any_quick(f, restrict_, subsong);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_load_any(const char *filename, int restrict_, int subsong)
{
DUH *dumb_load_any(const char *filename, int restrict_, int subsong) {
DUH *duh = dumb_load_any_quick(filename, restrict_, subsong);
dumb_it_do_initial_runthrough(duh);
return duh;
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_asy_quick(): loads a AMF file into a DUH struct, returning a
* pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_asy_quick(const char *filename)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_asy_quick(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_asy_quick(f);
duh = dumb_read_asy_quick(f);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -20,15 +20,12 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_asy(): loads a AMF file into a DUH struct, returning a pointer
* to the DUH struct. When you have finished with it, you must pass the
* pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_asy(const char *filename)
{
DUH *duh = dumb_load_asy_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_asy(const char *filename) {
DUH *duh = dumb_load_asy_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_mod_quick(): loads a MOD file into a DUH struct, returning a
* pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_mod_quick(const char *filename, int restrict_)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_mod_quick(const char *filename, int restrict_) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_mod_quick(f, restrict_);
duh = dumb_read_mod_quick(f, restrict_);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_load_mod(const char *filename, int restrict_)
{
DUH *duh = dumb_load_mod_quick(filename, restrict_);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_mod(const char *filename, int restrict_) {
DUH *duh = dumb_load_mod_quick(filename, restrict_);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_mtm_quick(): loads a MTM file into a DUH struct, returning a
* pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_mtm_quick(const char *filename)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_mtm_quick(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_mtm_quick(f);
duh = dumb_read_mtm_quick(f);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -20,15 +20,12 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_mtm(): loads a MTM file into a DUH struct, returning a pointer
* to the DUH struct. When you have finished with it, you must pass the
* pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_mtm(const char *filename)
{
DUH *duh = dumb_load_mtm_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_mtm(const char *filename) {
DUH *duh = dumb_load_mtm_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_okt_quick(): loads an OKT file into a DUH struct, returning a
* pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_okt_quick(const char *filename)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_okt_quick(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_okt_quick(f);
duh = dumb_read_okt_quick(f);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_load_okt(const char *filename)
{
DUH *duh = dumb_load_okt_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_okt(const char *filename) {
DUH *duh = dumb_load_okt_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,24 +20,21 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_old_psm_quick(): loads an old PSM file into a DUH struct,
* returning a pointer to the DUH struct. When you have finished with it,
* you must pass the pointer to unload_duh() so that the memory can be
* freed.
*/
DUH *dumb_load_old_psm_quick(const char *filename)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_old_psm_quick(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_old_psm_quick(f);
duh = dumb_read_old_psm_quick(f);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -20,15 +20,12 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_old_psm(): loads an old PSM file into a DUH struct, returning
* a pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_old_psm(const char *filename)
{
DUH *duh = dumb_load_old_psm_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_old_psm(const char *filename) {
DUH *duh = dumb_load_old_psm_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_psm_quick(): loads a PSM file into a DUH struct, returning a
* pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_psm_quick(const char *filename, int subsong)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_psm_quick(const char *filename, int subsong) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_psm_quick(f, subsong);
duh = dumb_read_psm_quick(f, subsong);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -20,15 +20,12 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_psm(): loads a PSM file into a DUH struct, returning a pointer
* to the DUH struct. When you have finished with it, you must pass the
* pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_psm(const char *filename, int subsong)
{
DUH *duh = dumb_load_psm_quick(filename, subsong);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_psm(const char *filename, int subsong) {
DUH *duh = dumb_load_psm_quick(filename, subsong);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_ptm_quick(): loads a PTM file into a DUH struct, returning a
* pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_ptm_quick(const char *filename)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_ptm_quick(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_ptm_quick(f);
duh = dumb_read_ptm_quick(f);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -20,15 +20,12 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_ptm(): loads a PTM file into a DUH struct, returning a pointer
* to the DUH struct. When you have finished with it, you must pass the
* pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_ptm(const char *filename)
{
DUH *duh = dumb_load_ptm_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_ptm(const char *filename) {
DUH *duh = dumb_load_ptm_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_riff_quick(): loads a RIFF file into a DUH struct, returning
* a pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH * dumb_load_riff_quick( const char *filename )
{
DUH * duh;
DUMBFILE * f = dumbfile_open( filename );
DUH *dumb_load_riff_quick(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if ( ! f )
return NULL;
if (!f)
return NULL;
duh = dumb_read_riff_quick( f );
duh = dumb_read_riff_quick(f);
dumbfile_close( f );
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_load_riff(const char *filename)
{
DUH *duh = dumb_load_riff_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_riff(const char *filename) {
DUH *duh = dumb_load_riff_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_s3m_quick(): loads an S3M file into a DUH struct, returning
* a pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_s3m_quick(const char *filename)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_s3m_quick(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_s3m_quick(f);
duh = dumb_read_s3m_quick(f);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_load_s3m(const char *filename)
{
DUH *duh = dumb_load_s3m_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_s3m(const char *filename) {
DUH *duh = dumb_load_s3m_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_stm_quick(): loads an STM file into a DUH struct, returning a
* pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_stm_quick(const char *filename)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_stm_quick(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_stm_quick(f);
duh = dumb_read_stm_quick(f);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_load_stm(const char *filename)
{
DUH *duh = dumb_load_stm_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_stm(const char *filename) {
DUH *duh = dumb_load_stm_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -20,23 +20,20 @@
#include "dumb.h"
#include "internal/it.h"
/* dumb_load_xm_quick(): loads an XM file into a DUH struct, returning a
* pointer to the DUH struct. When you have finished with it, you must
* pass the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_load_xm_quick(const char *filename)
{
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
DUH *dumb_load_xm_quick(const char *filename) {
DUH *duh;
DUMBFILE *f = dumbfile_open(filename);
if (!f)
return NULL;
if (!f)
return NULL;
duh = dumb_read_xm_quick(f);
duh = dumb_read_xm_quick(f);
dumbfile_close(f);
dumbfile_close(f);
return duh;
return duh;
}

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_load_xm(const char *filename)
{
DUH *duh = dumb_load_xm_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_load_xm(const char *filename) {
DUH *duh = dumb_load_xm_quick(filename);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -17,109 +17,158 @@
* \__/
*/
#include <stdlib.h>
#include <string.h>
#include "dumb.h"
#include "internal/it.h"
void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry)
{
if (effect >= PTM_N_EFFECTS)
return;
void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry) {
if (effect >= PTM_N_EFFECTS)
return;
/* Linearisation of the effect number... */
if (effect == PTM_E) {
effect = PTM_EBASE + HIGH(value);
value = LOW(value);
}
/* Linearisation of the effect number... */
if (effect == PTM_E) {
effect = PTM_EBASE + HIGH(value);
value = LOW(value);
}
/* convert effect */
entry->mask |= IT_ENTRY_EFFECT;
switch (effect) {
/* convert effect */
entry->mask |= IT_ENTRY_EFFECT;
switch (effect) {
case PTM_APPREGIO: effect = IT_ARPEGGIO; break;
case PTM_PORTAMENTO_UP: effect = IT_PORTAMENTO_UP; break;
case PTM_PORTAMENTO_DOWN: effect = IT_PORTAMENTO_DOWN; break;
case PTM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break;
case PTM_VIBRATO: effect = IT_VIBRATO; break;
case PTM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break;
case PTM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break;
case PTM_TREMOLO: effect = IT_TREMOLO; break;
case PTM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break;
case PTM_VOLUME_SLIDE: effect = IT_VOLUME_SLIDE; break;
case PTM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break;
case PTM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break;
case PTM_PATTERN_BREAK: effect = IT_BREAK_TO_ROW; break;
case PTM_SET_GLOBAL_VOLUME: effect = IT_SET_GLOBAL_VOLUME; break;
case PTM_RETRIGGER: effect = IT_RETRIGGER_NOTE; break;
case PTM_FINE_VIBRATO: effect = IT_FINE_VIBRATO; break;
case PTM_APPREGIO:
effect = IT_ARPEGGIO;
break;
case PTM_PORTAMENTO_UP:
effect = IT_PORTAMENTO_UP;
break;
case PTM_PORTAMENTO_DOWN:
effect = IT_PORTAMENTO_DOWN;
break;
case PTM_TONE_PORTAMENTO:
effect = IT_TONE_PORTAMENTO;
break;
case PTM_VIBRATO:
effect = IT_VIBRATO;
break;
case PTM_VOLSLIDE_TONEPORTA:
effect = IT_VOLSLIDE_TONEPORTA;
break;
case PTM_VOLSLIDE_VIBRATO:
effect = IT_VOLSLIDE_VIBRATO;
break;
case PTM_TREMOLO:
effect = IT_TREMOLO;
break;
case PTM_SAMPLE_OFFSET:
effect = IT_SET_SAMPLE_OFFSET;
break;
case PTM_VOLUME_SLIDE:
effect = IT_VOLUME_SLIDE;
break;
case PTM_POSITION_JUMP:
effect = IT_JUMP_TO_ORDER;
break;
case PTM_SET_CHANNEL_VOLUME:
effect = IT_SET_CHANNEL_VOLUME;
break;
case PTM_PATTERN_BREAK:
effect = IT_BREAK_TO_ROW;
break;
case PTM_SET_GLOBAL_VOLUME:
effect = IT_SET_GLOBAL_VOLUME;
break;
case PTM_RETRIGGER:
effect = IT_RETRIGGER_NOTE;
break;
case PTM_FINE_VIBRATO:
effect = IT_FINE_VIBRATO;
break;
/* TODO properly */
case PTM_NOTE_SLIDE_UP: effect = IT_PTM_NOTE_SLIDE_UP; break;
case PTM_NOTE_SLIDE_DOWN: effect = IT_PTM_NOTE_SLIDE_DOWN; break;
case PTM_NOTE_SLIDE_UP_RETRIG: effect = IT_PTM_NOTE_SLIDE_UP_RETRIG; break;
case PTM_NOTE_SLIDE_DOWN_RETRIG: effect = IT_PTM_NOTE_SLIDE_DOWN_RETRIG; break;
/* TODO properly */
case PTM_NOTE_SLIDE_UP:
effect = IT_PTM_NOTE_SLIDE_UP;
break;
case PTM_NOTE_SLIDE_DOWN:
effect = IT_PTM_NOTE_SLIDE_DOWN;
break;
case PTM_NOTE_SLIDE_UP_RETRIG:
effect = IT_PTM_NOTE_SLIDE_UP_RETRIG;
break;
case PTM_NOTE_SLIDE_DOWN_RETRIG:
effect = IT_PTM_NOTE_SLIDE_DOWN_RETRIG;
break;
case PTM_SET_TEMPO_BPM:
effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
break;
case PTM_SET_TEMPO_BPM:
effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
break;
case PTM_EBASE+PTM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break; /** TODO */
case PTM_EBASE+PTM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break;
case PTM_EBASE+PTM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break;
case PTM_EBASE+PTM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break;
case PTM_EBASE+PTM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break;
case PTM_EBASE+PTM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break;
case PTM_EBASE + PTM_E_SET_FINETUNE:
effect = SBASE + IT_S_FINETUNE;
break; /** TODO */
case PTM_EBASE + PTM_E_SET_LOOP:
effect = SBASE + IT_S_PATTERN_LOOP;
break;
case PTM_EBASE + PTM_E_NOTE_CUT:
effect = SBASE + IT_S_DELAYED_NOTE_CUT;
break;
case PTM_EBASE + PTM_E_NOTE_DELAY:
effect = SBASE + IT_S_NOTE_DELAY;
break;
case PTM_EBASE + PTM_E_PATTERN_DELAY:
effect = SBASE + IT_S_PATTERN_DELAY;
break;
case PTM_EBASE + PTM_E_SET_PANNING:
effect = SBASE + IT_S_SET_PAN;
break;
case PTM_EBASE+PTM_E_FINE_VOLSLIDE_UP:
effect = IT_VOLUME_SLIDE;
value = EFFECT_VALUE(value, 0xF);
break;
case PTM_EBASE + PTM_E_FINE_VOLSLIDE_UP:
effect = IT_VOLUME_SLIDE;
value = EFFECT_VALUE(value, 0xF);
break;
case PTM_EBASE + PTM_E_FINE_VOLSLIDE_DOWN:
effect = IT_VOLUME_SLIDE;
value = EFFECT_VALUE(0xF, value);
break;
case PTM_EBASE + PTM_E_FINE_VOLSLIDE_DOWN:
effect = IT_VOLUME_SLIDE;
value = EFFECT_VALUE(0xF, value);
break;
case PTM_EBASE + PTM_E_FINE_PORTA_UP:
effect = IT_PORTAMENTO_UP;
value = EFFECT_VALUE(0xF, value);
break;
case PTM_EBASE + PTM_E_FINE_PORTA_UP:
effect = IT_PORTAMENTO_UP;
value = EFFECT_VALUE(0xF, value);
break;
case PTM_EBASE + PTM_E_FINE_PORTA_DOWN:
effect = IT_PORTAMENTO_DOWN;
value = EFFECT_VALUE(0xF, value);
break;
case PTM_EBASE + PTM_E_FINE_PORTA_DOWN:
effect = IT_PORTAMENTO_DOWN;
value = EFFECT_VALUE(0xF, value);
break;
case PTM_EBASE + PTM_E_RETRIG_NOTE:
effect = IT_XM_RETRIGGER_NOTE;
value = EFFECT_VALUE(0, value);
break;
case PTM_EBASE + PTM_E_RETRIG_NOTE:
effect = IT_XM_RETRIGGER_NOTE;
value = EFFECT_VALUE(0, value);
break;
case PTM_EBASE + PTM_E_SET_VIBRATO_CONTROL:
effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM;
value &= ~4; /** TODO: value&4 -> don't retrig wave */
break;
case PTM_EBASE + PTM_E_SET_VIBRATO_CONTROL:
effect = SBASE + IT_S_SET_VIBRATO_WAVEFORM;
value &= ~4; /** TODO: value&4 -> don't retrig wave */
break;
case PTM_EBASE + PTM_E_SET_TREMOLO_CONTROL:
effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM;
value &= ~4; /** TODO: value&4 -> don't retrig wave */
break;
case PTM_EBASE + PTM_E_SET_TREMOLO_CONTROL:
effect = SBASE + IT_S_SET_TREMOLO_WAVEFORM;
value &= ~4; /** TODO: value&4 -> don't retrig wave */
break;
default:
/* user effect (often used in demos for synchronisation) */
entry->mask &= ~IT_ENTRY_EFFECT;
}
default:
/* user effect (often used in demos for synchronisation) */
entry->mask &= ~IT_ENTRY_EFFECT;
}
/* Inverse linearisation... */
if (effect >= SBASE && effect < SBASE+16) {
value = EFFECT_VALUE(effect-SBASE, value);
effect = IT_S;
}
/* Inverse linearisation... */
if (effect >= SBASE && effect < SBASE + 16) {
value = EFFECT_VALUE(effect - SBASE, value);
effect = IT_S;
}
entry->effect = effect;
entry->effectvalue = value;
entry->effect = effect;
entry->effectvalue = value;
}

View file

@ -24,102 +24,108 @@
#include "dumb.h"
#include "internal/it.h"
static int it_669_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int tempo,
int breakpoint, unsigned char *buffer,
int *used_channels) {
int pos;
int channel;
int row;
IT_ENTRY *entry;
static int it_669_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int tempo, int breakpoint, unsigned char *buffer, int * used_channels)
{
int pos;
int channel;
int row;
IT_ENTRY *entry;
pattern->n_rows = 64;
pattern->n_rows = 64;
if (dumbfile_getnc((char *)buffer, 64 * 3 * 8, f) < 64 * 3 * 8)
return -1;
return -1;
/* compute number of entries */
pattern->n_entries = 64 + 1; /* Account for the row end markers, speed command */
if (breakpoint < 63) pattern->n_entries++; /* and break to row 0 */
/* compute number of entries */
pattern->n_entries =
64 + 1; /* Account for the row end markers, speed command */
if (breakpoint < 63)
pattern->n_entries++; /* and break to row 0 */
pos = 0;
for (row = 0; row < 64; row++) {
for (channel = 0; channel < 8; channel++) {
if (buffer[pos+0] != 0xFF || buffer[pos+2] != 0xFF)
pattern->n_entries++;
pos += 3;
}
}
pos = 0;
for (row = 0; row < 64; row++) {
for (channel = 0; channel < 8; channel++) {
if (buffer[pos + 0] != 0xFF || buffer[pos + 2] != 0xFF)
pattern->n_entries++;
pos += 3;
}
}
pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
if (!pattern->entry)
return -1;
pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
if (!pattern->entry)
return -1;
if (breakpoint == 63) breakpoint++;
if (breakpoint == 63)
breakpoint++;
entry = pattern->entry;
entry = pattern->entry;
entry->channel = 8;
entry->mask = IT_ENTRY_EFFECT;
entry->effect = IT_SET_SPEED;
entry->effectvalue = tempo;
entry++;
entry->channel = 8;
entry->mask = IT_ENTRY_EFFECT;
entry->effect = IT_SET_SPEED;
entry->effectvalue = tempo;
entry++;
pos = 0;
for (row = 0; row < 64; row++) {
pos = 0;
for (row = 0; row < 64; row++) {
if (row == breakpoint) {
entry->channel = 8;
entry->mask = IT_ENTRY_EFFECT;
entry->effect = IT_BREAK_TO_ROW;
entry->effectvalue = 0;
entry++;
}
if (row == breakpoint) {
entry->channel = 8;
entry->mask = IT_ENTRY_EFFECT;
entry->effect = IT_BREAK_TO_ROW;
entry->effectvalue = 0;
entry++;
}
for (channel = 0; channel < 8; channel++) {
if (buffer[pos+0] != 0xFF || buffer[pos+2] != 0xFF) {
entry->channel = channel;
entry->mask = 0;
for (channel = 0; channel < 8; channel++) {
if (buffer[pos + 0] != 0xFF || buffer[pos + 2] != 0xFF) {
entry->channel = channel;
entry->mask = 0;
if (buffer[pos+0] < 0xFE) {
entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT;
entry->note = (buffer[pos+0] >> 2) + 36;
entry->instrument = (((buffer[pos+0] << 4) | (buffer[pos+1] >> 4)) & 0x3F) + 1;
}
if (buffer[pos+0] <= 0xFE) {
entry->mask |= IT_ENTRY_VOLPAN;
entry->volpan = ((buffer[pos+1] & 15) << 6) / 15;
if (*used_channels < channel + 1) *used_channels = channel + 1;
}
if (buffer[pos+2] != 0xFF) {
entry->mask |= IT_ENTRY_EFFECT;
entry->effectvalue = buffer[pos+2] & 15;
switch (buffer[pos+2] >> 4) {
case 0:
entry->effect = IT_PORTAMENTO_UP;
break;
case 1:
entry->effect = IT_PORTAMENTO_DOWN;
break;
case 2:
entry->effect = IT_TONE_PORTAMENTO;
break;
case 3:
entry->effect = IT_S;
entry->effectvalue += IT_S_FINETUNE * 16 + 8;
break;
case 4:
entry->effect = IT_VIBRATO;
// XXX speed unknown
entry->effectvalue |= 0x10;
break;
case 5:
if (entry->effectvalue) {
entry->effect = IT_SET_SPEED;
} else {
entry->mask &= ~IT_ENTRY_EFFECT;
}
break;
if (buffer[pos + 0] < 0xFE) {
entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT;
entry->note = (buffer[pos + 0] >> 2) + 36;
entry->instrument =
(((buffer[pos + 0] << 4) | (buffer[pos + 1] >> 4)) &
0x3F) +
1;
}
if (buffer[pos + 0] <= 0xFE) {
entry->mask |= IT_ENTRY_VOLPAN;
entry->volpan = ((buffer[pos + 1] & 15) << 6) / 15;
if (*used_channels < channel + 1)
*used_channels = channel + 1;
}
if (buffer[pos + 2] != 0xFF) {
entry->mask |= IT_ENTRY_EFFECT;
entry->effectvalue = buffer[pos + 2] & 15;
switch (buffer[pos + 2] >> 4) {
case 0:
entry->effect = IT_PORTAMENTO_UP;
break;
case 1:
entry->effect = IT_PORTAMENTO_DOWN;
break;
case 2:
entry->effect = IT_TONE_PORTAMENTO;
break;
case 3:
entry->effect = IT_S;
entry->effectvalue += IT_S_FINETUNE * 16 + 8;
break;
case 4:
entry->effect = IT_VIBRATO;
// XXX speed unknown
entry->effectvalue |= 0x10;
break;
case 5:
if (entry->effectvalue) {
entry->effect = IT_SET_SPEED;
} else {
entry->mask &= ~IT_ENTRY_EFFECT;
}
break;
#if 0
/* dunno about this, really... */
case 6:
@ -134,315 +140,312 @@ static int it_669_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int tempo, int
}
break;
#endif
default:
entry->mask &= ~IT_ENTRY_EFFECT;
break;
}
if (*used_channels < channel + 1) *used_channels = channel + 1;
}
default:
entry->mask &= ~IT_ENTRY_EFFECT;
break;
}
if (*used_channels < channel + 1)
*used_channels = channel + 1;
}
entry++;
}
pos += 3;
}
IT_SET_END_ROW(entry);
entry++;
}
entry++;
}
pos += 3;
}
IT_SET_END_ROW(entry);
entry++;
}
return 0;
return 0;
}
static int it_669_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
{
static int it_669_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) {
dumbfile_getnc((char *)sample->name, 13, f);
sample->name[13] = 0;
sample->name[13] = 0;
sample->filename[0] = 0;
sample->filename[0] = 0;
sample->length = dumbfile_igetl(f);
sample->loop_start = dumbfile_igetl(f);
sample->loop_end = dumbfile_igetl(f);
sample->length = dumbfile_igetl(f);
sample->loop_start = dumbfile_igetl(f);
sample->loop_end = dumbfile_igetl(f);
if (dumbfile_error(f))
return -1;
if (dumbfile_error(f))
return -1;
if (sample->length <= 0) {
sample->flags = 0;
return 0;
}
if (sample->length <= 0) {
sample->flags = 0;
return 0;
}
sample->flags = IT_SAMPLE_EXISTS;
sample->flags = IT_SAMPLE_EXISTS;
sample->global_volume = 64;
sample->default_volume = 64;
sample->global_volume = 64;
sample->default_volume = 64;
sample->default_pan = 0;
sample->C5_speed = 8363;
// the above line might be wrong
sample->default_pan = 0;
sample->C5_speed = 8363;
// the above line might be wrong
if ((sample->loop_end > sample->length) && !(sample->loop_start))
sample->loop_end = 0;
if ((sample->loop_end > sample->length) && !(sample->loop_start))
sample->loop_end = 0;
if (sample->loop_end > sample->length)
sample->loop_end = sample->length;
if (sample->loop_end > sample->length)
sample->loop_end = sample->length;
if (sample->loop_end - sample->loop_start > 2)
sample->flags |= IT_SAMPLE_LOOP;
if (sample->loop_end - sample->loop_start > 2)
sample->flags |= IT_SAMPLE_LOOP;
sample->vibrato_speed = 0;
sample->vibrato_depth = 0;
sample->vibrato_rate = 0;
sample->vibrato_waveform = 0; // do we have to set _all_ these?
sample->finetune = 0;
sample->max_resampling_quality = -1;
sample->vibrato_speed = 0;
sample->vibrato_depth = 0;
sample->vibrato_rate = 0;
sample->vibrato_waveform = 0; // do we have to set _all_ these?
sample->finetune = 0;
sample->max_resampling_quality = -1;
return 0;
return 0;
}
static int it_669_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f) {
long i;
long truncated_size;
/* let's get rid of the sample data coming after the end of the loop */
if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
truncated_size = sample->length - sample->loop_end;
sample->length = sample->loop_end;
} else {
truncated_size = 0;
}
static int it_669_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f)
{
long i;
long truncated_size;
sample->data = malloc(sample->length);
/* let's get rid of the sample data coming after the end of the loop */
if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
truncated_size = sample->length - sample->loop_end;
sample->length = sample->loop_end;
} else {
truncated_size = 0;
}
if (!sample->data)
return -1;
sample->data = malloc(sample->length);
if (sample->length) {
i = dumbfile_getnc(sample->data, sample->length, f);
if (!sample->data)
return -1;
if (i < sample->length) {
// return -1;
// ficking truncated files
if (i <= 0) {
sample->flags = 0;
return 0;
}
sample->length = i;
if (sample->loop_end > i)
sample->loop_end = i;
} else {
/* skip truncated data */
dumbfile_skip(f, truncated_size);
// Should we be truncating it?
if (dumbfile_error(f))
return -1;
}
if (sample->length)
{
i = dumbfile_getnc(sample->data, sample->length, f);
if (i < sample->length) {
//return -1;
// ficking truncated files
if (i <= 0) {
sample->flags = 0;
return 0;
}
sample->length = i;
if (sample->loop_end > i) sample->loop_end = i;
} else {
/* skip truncated data */
dumbfile_skip(f, truncated_size);
// Should we be truncating it?
if (dumbfile_error(f))
return -1;
}
for (i = 0; i < sample->length; i++)
((signed char *)sample->data)[i] ^= 0x80;
}
for (i = 0; i < sample->length; i++)
((signed char *)sample->data)[i] ^= 0x80;
}
return 0;
return 0;
}
static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int *ext) {
DUMB_IT_SIGDATA *sigdata;
int n_channels;
int i;
unsigned char tempolist[128];
unsigned char breaklist[128];
static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int * ext)
{
DUMB_IT_SIGDATA *sigdata;
int n_channels;
int i;
unsigned char tempolist[128];
unsigned char breaklist[128];
i = dumbfile_igetw(f);
if (i != 0x6669 && i != 0x4E4A)
return NULL;
i = dumbfile_igetw(f);
if (i != 0x6669 && i != 0x4E4A) return NULL;
*ext = (i == 0x4E4A);
*ext = (i == 0x4E4A);
sigdata = malloc(sizeof(*sigdata));
if (!sigdata) {
return NULL;
}
sigdata = malloc(sizeof(*sigdata));
if (!sigdata) {
return NULL;
}
if (dumbfile_getnc((char *)sigdata->name, 36, f) < 36) {
free(sigdata);
return NULL;
}
sigdata->name[36] = 0;
free(sigdata);
return NULL;
}
sigdata->name[36] = 0;
sigdata->order = NULL;
sigdata->instrument = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
sigdata->sample = NULL;
sigdata->order = NULL;
sigdata->instrument = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
sigdata->sample = NULL;
sigdata->n_instruments = 0;
sigdata->n_instruments = 0;
sigdata->song_message = malloc(72 + 2 + 1);
if (!sigdata->song_message) {
free(sigdata);
return NULL;
}
sigdata->song_message = malloc(72 + 2 + 1);
if (!sigdata->song_message) {
free(sigdata);
return NULL;
}
if (dumbfile_getnc((char *)sigdata->song_message, 36, f) < 36) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->song_message[36] = 13;
sigdata->song_message[36 + 1] = 10;
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->song_message[36] = 13;
sigdata->song_message[36 + 1] = 10;
if (dumbfile_getnc((char *)sigdata->song_message + 38, 36, f) < 36) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->song_message[38 + 36] = 0;
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->song_message[38 + 36] = 0;
sigdata->n_samples = dumbfile_getc(f);
sigdata->n_patterns = dumbfile_getc(f);
sigdata->restart_position = dumbfile_getc(f);
sigdata->n_samples = dumbfile_getc(f);
sigdata->n_patterns = dumbfile_getc(f);
sigdata->restart_position = dumbfile_getc(f);
if ((sigdata->n_samples) > 64 || (sigdata->n_patterns > 128)) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if ((sigdata->n_samples) > 64 || (sigdata->n_patterns > 128)) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->order = malloc(128); /* We may need to scan the extra ones! */
if (!sigdata->order) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->order = malloc(128); /* We may need to scan the extra ones! */
if (!sigdata->order) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (dumbfile_getnc((char *)sigdata->order, 128, f) < 128) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (i = 0; i < 128; i++) {
if (sigdata->order[i] == 255) break;
if (sigdata->order[i] >= sigdata->n_patterns) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
if (!i) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->n_orders = i;
for (i = 0; i < 128; i++) {
if (sigdata->order[i] == 255)
break;
if (sigdata->order[i] >= sigdata->n_patterns) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
if (!i) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->n_orders = i;
if (dumbfile_getnc((char *)tempolist, 128, f) < 128) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (dumbfile_getnc((char *)breaklist, 128, f) < 128) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
if (!sigdata->sample) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
if (!sigdata->sample) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (i = 0; i < sigdata->n_samples; i++)
sigdata->sample[i].data = NULL;
for (i = 0; i < sigdata->n_samples; i++)
sigdata->sample[i].data = NULL;
for (i = 0; i < sigdata->n_samples; i++) {
if (it_669_read_sample_header(&sigdata->sample[i], f)) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
for (i = 0; i < sigdata->n_samples; i++) {
if (it_669_read_sample_header(&sigdata->sample[i], f)) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
/* May as well try to save a tiny bit of memory. */
if (sigdata->n_orders < 128) {
unsigned char *order = realloc(sigdata->order, sigdata->n_orders);
if (order) sigdata->order = order;
}
/* May as well try to save a tiny bit of memory. */
if (sigdata->n_orders < 128) {
unsigned char *order = realloc(sigdata->order, sigdata->n_orders);
if (order)
sigdata->order = order;
}
sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
if (!sigdata->pattern) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (i = 0; i < sigdata->n_patterns; i++)
sigdata->pattern[i].entry = NULL;
sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
if (!sigdata->pattern) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (i = 0; i < sigdata->n_patterns; i++)
sigdata->pattern[i].entry = NULL;
n_channels = 0;
n_channels = 0;
/* Read in the patterns */
{
unsigned char *buffer = malloc(64 * 3 * 8); /* 64 rows * 3 bytes * 8 channels */
if (!buffer) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (i = 0; i < sigdata->n_patterns; i++) {
if (it_669_read_pattern(&sigdata->pattern[i], f, tempolist[i], breaklist[i], buffer, &n_channels) != 0) {
free(buffer);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
free(buffer);
}
/* Read in the patterns */
{
unsigned char *buffer =
malloc(64 * 3 * 8); /* 64 rows * 3 bytes * 8 channels */
if (!buffer) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (i = 0; i < sigdata->n_patterns; i++) {
if (it_669_read_pattern(&sigdata->pattern[i], f, tempolist[i],
breaklist[i], buffer, &n_channels) != 0) {
free(buffer);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
free(buffer);
}
sigdata->n_pchannels = n_channels;
sigdata->n_pchannels = n_channels;
/* And finally, the sample data */
for (i = 0; i < sigdata->n_samples; i++) {
if (it_669_read_sample_data(&sigdata->sample[i], f)) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
/* And finally, the sample data */
for (i = 0; i < sigdata->n_samples; i++) {
if (it_669_read_sample_data(&sigdata->sample[i], f)) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
/* Now let's initialise the remaining variables, and we're done! */
sigdata->flags = IT_OLD_EFFECTS | IT_LINEAR_SLIDES | IT_STEREO | IT_WAS_A_669;
/* Now let's initialise the remaining variables, and we're done! */
sigdata->flags =
IT_OLD_EFFECTS | IT_LINEAR_SLIDES | IT_STEREO | IT_WAS_A_669;
sigdata->global_volume = 128;
sigdata->mixing_volume = 48;
sigdata->speed = 4;
sigdata->tempo = 78;
sigdata->pan_separation = 128;
sigdata->global_volume = 128;
sigdata->mixing_volume = 48;
sigdata->speed = 4;
sigdata->tempo = 78;
sigdata->pan_separation = 128;
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
for (i = 0; i < DUMB_IT_N_CHANNELS; i += 2) {
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[i+0] = 32 + sep;
sigdata->channel_pan[i+1] = 32 - sep;
}
for (i = 0; i < DUMB_IT_N_CHANNELS; i += 2) {
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[i + 0] = 32 + sep;
sigdata->channel_pan[i + 1] = 32 - sep;
}
_dumb_it_fix_invalid_orders(sigdata);
_dumb_it_fix_invalid_orders(sigdata);
return sigdata;
return sigdata;
}
DUH *dumb_read_669_quick(DUMBFILE *f) {
sigdata_t *sigdata;
int ext;
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
DUH *dumb_read_669_quick(DUMBFILE *f)
{
sigdata_t *sigdata;
int ext;
sigdata = it_669_load_sigdata(f, &ext);
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
if (!sigdata)
return NULL;
sigdata = it_669_load_sigdata(f, &ext);
if (!sigdata)
return NULL;
{
const char *tag[2][2];
tag[0][0] = "TITLE";
{
const char *tag[2][2];
tag[0][0] = "TITLE";
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
tag[1][0] = "FORMAT";
tag[1][1] = ext ? "669 Extended" : "669";
return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
}
tag[1][0] = "FORMAT";
tag[1][1] = ext ? "669 Extended" : "669";
return make_duh(-1, 2, (const char *const(*)[2])tag, 1, &descptr,
&sigdata);
}
}

View file

@ -1,29 +1,26 @@
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
* | | | | | | || ||\ /| |
* | | | | | | || || \/ | | ' ' '
* | | | | | | || || | | . .
* | |_/ / \ \__// || | |
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
* / \
* / . \
* read6692.c - Code to read a 669 Composer module / / \ \
* from an open file, and do an initial | < / \_
* run-through. | \/ /\ /
* By Chris Moeller. \_ / > /
* | \ / /
* | ' /
* \__/
*/
#include "dumb.h"
DUH *dumb_read_669(DUMBFILE *f)
{
DUH *duh = dumb_read_669_quick(f);
dumb_it_do_initial_runthrough(duh);
return duh;
}
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
* | | | | | | || ||\ /| |
* | | | | | | || || \/ | | ' ' '
* | | | | | | || || | | . .
* | |_/ / \ \__// || | |
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
* / \
* / . \
* read6692.c - Code to read a 669 Composer module / / \ \
* from an open file, and do an initial | < / \_
* run-through. | \/ /\ /
* By Chris Moeller. \_ / > /
* | \ / /
* | ' /
* \__/
*/
#include "dumb.h"
DUH *dumb_read_669(DUMBFILE *f) {
DUH *duh = dumb_read_669_quick(f);
dumb_it_do_initial_runthrough(duh);
return duh;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_read_amf(DUMBFILE *f)
{
DUH *duh = dumb_read_amf_quick(f);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_read_amf(DUMBFILE *f) {
DUH *duh = dumb_read_amf_quick(f);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -1,132 +1,103 @@
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
* | | | | | | || ||\ /| |
* | | | | | | || || \/ | | ' ' '
* | | | | | | || || | | . .
* | |_/ / \ \__// || | |
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
* / \
* / . \
* readany.c - Code to detect and read any of the / / \ \
* module formats supported by DUMB. | < / \_
* | \/ /\ /
* By Chris Moeller. \_ / > /
* | \ / /
* | ' /
* \__/
*/
#include <stdlib.h>
#include <string.h>
#include "dumb.h"
#ifdef _MSC_VER
#define strnicmp _strnicmp
#else
#if defined(unix) || defined(__unix__) || defined(__unix)
#include <strings.h>
#endif
#define strnicmp strncasecmp
#endif
enum { maximum_signature_size = 0x30 };
DUH *dumb_read_any_quick(DUMBFILE *f, int restrict_, int subsong)
{
unsigned char signature[ maximum_signature_size ];
unsigned long signature_size;
DUH * duh = NULL;
/* signature_size = dumbfile_get_size(f); */
signature_size = dumbfile_getnc( (char *)signature, maximum_signature_size, f );
dumbfile_seek( f, 0, DFS_SEEK_SET );
if (signature_size >= 4 &&
signature[0] == 'I' && signature[1] == 'M' &&
signature[2] == 'P' && signature[3] == 'M')
{
duh = dumb_read_it_quick( f );
}
else if (signature_size >= 17 && !memcmp(signature, "Extended Module: ", 17))
{
duh = dumb_read_xm_quick( f );
}
else if (signature_size >= 0x30 &&
signature[0x2C] == 'S' && signature[0x2D] == 'C' &&
signature[0x2E] == 'R' && signature[0x2F] == 'M')
{
duh = dumb_read_s3m_quick( f );
}
else if (signature_size >= 30 &&
/*signature[28] == 0x1A &&*/ signature[29] == 2 &&
( ! strnicmp( ( const char * ) signature + 20, "!Scream!", 8 ) ||
! strnicmp( ( const char * ) signature + 20, "BMOD2STM", 8 ) ||
! strnicmp( ( const char * ) signature + 20, "WUZAMOD!", 8 ) ) )
{
duh = dumb_read_stm_quick( f );
}
else if (signature_size >= 2 &&
((signature[0] == 0x69 && signature[1] == 0x66) ||
(signature[0] == 0x4A && signature[1] == 0x4E)))
{
duh = dumb_read_669_quick( f );
}
else if (signature_size >= 0x30 &&
signature[0x2C] == 'P' && signature[0x2D] == 'T' &&
signature[0x2E] == 'M' && signature[0x2F] == 'F')
{
duh = dumb_read_ptm_quick( f );
}
else if (signature_size >= 4 &&
signature[0] == 'P' && signature[1] == 'S' &&
signature[2] == 'M' && signature[3] == ' ')
{
duh = dumb_read_psm_quick( f, subsong );
}
else if (signature_size >= 4 &&
signature[0] == 'P' && signature[1] == 'S' &&
signature[2] == 'M' && signature[3] == 254)
{
duh = dumb_read_old_psm_quick( f );
}
else if (signature_size >= 3 &&
signature[0] == 'M' && signature[1] == 'T' &&
signature[2] == 'M')
{
duh = dumb_read_mtm_quick( f );
}
else if ( signature_size >= 4 &&
signature[0] == 'R' && signature[1] == 'I' &&
signature[2] == 'F' && signature[3] == 'F')
{
duh = dumb_read_riff_quick( f );
}
else if ( signature_size >= 24 &&
!memcmp( signature, "ASYLUM Music Format", 19 ) &&
!memcmp( signature + 19, " V1.0", 5 ) )
{
duh = dumb_read_asy_quick( f );
}
else if ( signature_size >= 3 &&
signature[0] == 'A' && signature[1] == 'M' &&
signature[2] == 'F')
{
duh = dumb_read_amf_quick( f );
}
else if ( signature_size >= 8 &&
!memcmp( signature, "OKTASONG", 8 ) )
{
duh = dumb_read_okt_quick( f );
}
if ( !duh )
{
dumbfile_seek( f, 0, DFS_SEEK_SET );
duh = dumb_read_mod_quick( f, restrict_ );
}
return duh;
}
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
* | | | | | | || ||\ /| |
* | | | | | | || || \/ | | ' ' '
* | | | | | | || || | | . .
* | |_/ / \ \__// || | |
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
* / \
* / . \
* readany.c - Code to detect and read any of the / / \ \
* module formats supported by DUMB. | < / \_
* | \/ /\ /
* By Chris Moeller. \_ / > /
* | \ / /
* | ' /
* \__/
*/
#include <stdlib.h>
#include <string.h>
#include "dumb.h"
#ifdef _MSC_VER
#define strnicmp _strnicmp
#else
#if defined(unix) || defined(__unix__) || defined(__unix)
#include <strings.h>
#endif
#define strnicmp strncasecmp
#endif
enum { maximum_signature_size = 0x30 };
DUH *dumb_read_any_quick(DUMBFILE *f, int restrict_, int subsong) {
unsigned char signature[maximum_signature_size];
unsigned long signature_size;
DUH *duh = NULL;
/* signature_size = dumbfile_get_size(f); */
signature_size =
dumbfile_getnc((char *)signature, maximum_signature_size, f);
dumbfile_seek(f, 0, DFS_SEEK_SET);
if (signature_size >= 4 && signature[0] == 'I' && signature[1] == 'M' &&
signature[2] == 'P' && signature[3] == 'M') {
duh = dumb_read_it_quick(f);
} else if (signature_size >= 17 &&
!memcmp(signature, "Extended Module: ", 17)) {
duh = dumb_read_xm_quick(f);
} else if (signature_size >= 0x30 && signature[0x2C] == 'S' &&
signature[0x2D] == 'C' && signature[0x2E] == 'R' &&
signature[0x2F] == 'M') {
duh = dumb_read_s3m_quick(f);
} else if (signature_size >= 30 &&
/*signature[28] == 0x1A &&*/ signature[29] == 2 &&
(!strnicmp((const char *)signature + 20, "!Scream!", 8) ||
!strnicmp((const char *)signature + 20, "BMOD2STM", 8) ||
!strnicmp((const char *)signature + 20, "WUZAMOD!", 8))) {
duh = dumb_read_stm_quick(f);
} else if (signature_size >= 2 &&
((signature[0] == 0x69 && signature[1] == 0x66) ||
(signature[0] == 0x4A && signature[1] == 0x4E))) {
duh = dumb_read_669_quick(f);
} else if (signature_size >= 0x30 && signature[0x2C] == 'P' &&
signature[0x2D] == 'T' && signature[0x2E] == 'M' &&
signature[0x2F] == 'F') {
duh = dumb_read_ptm_quick(f);
} else if (signature_size >= 4 && signature[0] == 'P' &&
signature[1] == 'S' && signature[2] == 'M' &&
signature[3] == ' ') {
duh = dumb_read_psm_quick(f, subsong);
} else if (signature_size >= 4 && signature[0] == 'P' &&
signature[1] == 'S' && signature[2] == 'M' &&
signature[3] == 254) {
duh = dumb_read_old_psm_quick(f);
} else if (signature_size >= 3 && signature[0] == 'M' &&
signature[1] == 'T' && signature[2] == 'M') {
duh = dumb_read_mtm_quick(f);
} else if (signature_size >= 4 && signature[0] == 'R' &&
signature[1] == 'I' && signature[2] == 'F' &&
signature[3] == 'F') {
duh = dumb_read_riff_quick(f);
} else if (signature_size >= 24 &&
!memcmp(signature, "ASYLUM Music Format", 19) &&
!memcmp(signature + 19, " V1.0", 5)) {
duh = dumb_read_asy_quick(f);
} else if (signature_size >= 3 && signature[0] == 'A' &&
signature[1] == 'M' && signature[2] == 'F') {
duh = dumb_read_amf_quick(f);
} else if (signature_size >= 8 && !memcmp(signature, "OKTASONG", 8)) {
duh = dumb_read_okt_quick(f);
}
if (!duh) {
dumbfile_seek(f, 0, DFS_SEEK_SET);
duh = dumb_read_mod_quick(f, restrict_);
}
return duh;
}

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_read_any(DUMBFILE *f, int restrict_, int subsong)
{
DUH *dumb_read_any(DUMBFILE *f, int restrict_, int subsong) {
DUH *duh = dumb_read_any_quick(f, restrict_, subsong);
dumb_it_do_initial_runthrough(duh);
return duh;
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -24,316 +24,318 @@
#include "dumb.h"
#include "internal/it.h"
static int it_asy_read_pattern(IT_PATTERN *pattern, DUMBFILE *f,
unsigned char *buffer) {
int pos;
int channel;
int row;
IT_ENTRY *entry;
pattern->n_rows = 64;
static int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer )
{
int pos;
int channel;
int row;
IT_ENTRY *entry;
if (dumbfile_getnc((char *)buffer, 64 * 8 * 4, f) != 64 * 8 * 4)
return -1;
pattern->n_rows = 64;
/* compute number of entries */
pattern->n_entries = 64; /* Account for the row end markers */
pos = 0;
for (row = 0; row < 64; ++row) {
for (channel = 0; channel < 8; ++channel) {
if (buffer[pos + 0] | buffer[pos + 1] | buffer[pos + 2] |
buffer[pos + 3])
++pattern->n_entries;
pos += 4;
}
}
if ( dumbfile_getnc( (char *) buffer, 64 * 8 * 4, f ) != 64 * 8 * 4 )
return -1;
pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
if (!pattern->entry)
return -1;
/* compute number of entries */
pattern->n_entries = 64; /* Account for the row end markers */
pos = 0;
for ( row = 0; row < 64; ++row ) {
for ( channel = 0; channel < 8; ++channel ) {
if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] )
++pattern->n_entries;
pos += 4;
}
}
entry = pattern->entry;
pos = 0;
for (row = 0; row < 64; ++row) {
for (channel = 0; channel < 8; ++channel) {
if (buffer[pos + 0] | buffer[pos + 1] | buffer[pos + 2] |
buffer[pos + 3]) {
entry->channel = channel;
entry->mask = 0;
pattern->entry = malloc( pattern->n_entries * sizeof( *pattern->entry ) );
if ( !pattern->entry )
return -1;
entry = pattern->entry;
pos = 0;
for ( row = 0; row < 64; ++row ) {
for ( channel = 0; channel < 8; ++channel ) {
if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) {
entry->channel = channel;
entry->mask = 0;
if ( buffer[ pos + 0 ] && buffer[ pos + 0 ] < 96 ) {
entry->note = buffer[ pos + 0 ];
entry->mask |= IT_ENTRY_NOTE;
}
if ( buffer[ pos + 1 ] && buffer[ pos + 1 ] <= 64 ) {
entry->instrument = buffer[ pos + 1 ];
entry->mask |= IT_ENTRY_INSTRUMENT;
}
_dumb_it_xm_convert_effect( buffer[ pos + 2 ], buffer[ pos + 3 ], entry, 1 );
// fixup
switch ( entry->effect ) {
case IT_SET_PANNING:
entry->effectvalue <<= 1;
break;
if (buffer[pos + 0] && buffer[pos + 0] < 96) {
entry->note = buffer[pos + 0];
entry->mask |= IT_ENTRY_NOTE;
}
if ( entry->mask ) ++entry;
}
pos += 4;
}
IT_SET_END_ROW( entry );
++entry;
}
if (buffer[pos + 1] && buffer[pos + 1] <= 64) {
entry->instrument = buffer[pos + 1];
entry->mask |= IT_ENTRY_INSTRUMENT;
}
pattern->n_entries = (int)(entry - pattern->entry);
_dumb_it_xm_convert_effect(buffer[pos + 2], buffer[pos + 3],
entry, 1);
return 0;
// fixup
switch (entry->effect) {
case IT_SET_PANNING:
entry->effectvalue <<= 1;
break;
}
if (entry->mask)
++entry;
}
pos += 4;
}
IT_SET_END_ROW(entry);
++entry;
}
pattern->n_entries = (int)(entry - pattern->entry);
return 0;
}
static int it_asy_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) {
int finetune, key_offset;
/**
21 22 Chars Sample 1 name. If the name is not a full
22 chars in length, it will be null
terminated.
static int it_asy_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f )
{
int finetune, key_offset;
If
the sample name begins with a '#' character (ASCII $23 (35)) then this is
assumed not to be an instrument name, and is probably a message.
*/
dumbfile_getnc((char *)sample->name, 22, f);
sample->name[22] = 0;
/**
21 22 Chars Sample 1 name. If the name is not a full
22 chars in length, it will be null
terminated.
sample->filename[0] = 0;
If
the sample name begins with a '#' character (ASCII $23 (35)) then this is
assumed not to be an instrument name, and is probably a message.
*/
dumbfile_getnc( (char *) sample->name, 22, f );
sample->name[22] = 0;
/** Each finetune step changes the note 1/8th of a semitone. */
finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
sample->default_volume =
dumbfile_getc(f); // Should we be setting global_volume to this instead?
sample->global_volume = 64;
if (sample->default_volume > 64)
sample->default_volume = 64;
key_offset = (signed char)dumbfile_getc(f); /* base key offset */
sample->length = dumbfile_igetl(f);
sample->loop_start = dumbfile_igetl(f);
sample->loop_end = sample->loop_start + dumbfile_igetl(f);
sample->filename[0] = 0;
if (sample->length <= 0) {
sample->flags = 0;
return 0;
}
/** Each finetune step changes the note 1/8th of a semitone. */
finetune = ( signed char ) ( dumbfile_getc( f ) << 4 ) >> 4; /* signed nibble */
sample->default_volume = dumbfile_getc( f ); // Should we be setting global_volume to this instead?
sample->global_volume = 64;
if ( sample->default_volume > 64 ) sample->default_volume = 64;
key_offset = ( signed char ) dumbfile_getc( f ); /* base key offset */
sample->length = dumbfile_igetl( f );
sample->loop_start = dumbfile_igetl( f );
sample->loop_end = sample->loop_start + dumbfile_igetl( f );
sample->flags = IT_SAMPLE_EXISTS;
if ( sample->length <= 0 ) {
sample->flags = 0;
return 0;
}
sample->default_pan = 0;
sample->C5_speed =
(int)(AMIGA_CLOCK / 214.0 *
pow(DUMB_SEMITONE_BASE, key_offset)); //( long )( 16726.0 * pow(
// DUMB_PITCH_BASE, finetune
//* 32 ) );
sample->finetune = finetune * 32;
// the above line might be wrong
sample->flags = IT_SAMPLE_EXISTS;
if ((sample->loop_end - sample->loop_start > 2) &&
(sample->loop_end <= sample->length))
sample->flags |= IT_SAMPLE_LOOP;
sample->default_pan = 0;
sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 * pow( DUMB_SEMITONE_BASE, key_offset ) );//( long )( 16726.0 * pow( DUMB_PITCH_BASE, finetune * 32 ) );
sample->finetune = finetune * 32;
// the above line might be wrong
sample->vibrato_speed = 0;
sample->vibrato_depth = 0;
sample->vibrato_rate = 0;
sample->vibrato_waveform = 0; // do we have to set _all_ these?
sample->max_resampling_quality = -1;
if ( ( sample->loop_end - sample->loop_start > 2 ) && ( sample->loop_end <= sample->length ) )
sample->flags |= IT_SAMPLE_LOOP;
sample->vibrato_speed = 0;
sample->vibrato_depth = 0;
sample->vibrato_rate = 0;
sample->vibrato_waveform = 0; // do we have to set _all_ these?
sample->max_resampling_quality = -1;
return dumbfile_error(f);
return dumbfile_error(f);
}
static int it_asy_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f) {
long truncated_size;
/* let's get rid of the sample data coming after the end of the loop */
if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
truncated_size = sample->length - sample->loop_end;
sample->length = sample->loop_end;
} else {
truncated_size = 0;
}
static int it_asy_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f )
{
long truncated_size;
sample->data = malloc(sample->length);
/* let's get rid of the sample data coming after the end of the loop */
if ( ( sample->flags & IT_SAMPLE_LOOP ) && sample->loop_end < sample->length ) {
truncated_size = sample->length - sample->loop_end;
sample->length = sample->loop_end;
} else {
truncated_size = 0;
}
if (!sample->data)
return -1;
sample->data = malloc( sample->length );
if (sample->length)
dumbfile_getnc(sample->data, sample->length, f);
if ( !sample->data )
return -1;
dumbfile_skip(f, truncated_size);
if ( sample->length )
dumbfile_getnc( sample->data, sample->length, f );
dumbfile_skip( f, truncated_size );
return dumbfile_error( f );
return dumbfile_error(f);
}
static DUMB_IT_SIGDATA *it_asy_load_sigdata(DUMBFILE *f) {
DUMB_IT_SIGDATA *sigdata;
int i;
static const char sig_part[] = "ASYLUM Music Format";
static const char sig_rest[] =
" V1.0"; /* whee, string space optimization with format type below */
static DUMB_IT_SIGDATA *it_asy_load_sigdata(DUMBFILE *f)
{
DUMB_IT_SIGDATA *sigdata;
int i;
char signature[32];
static const char sig_part[] = "ASYLUM Music Format";
static const char sig_rest[] = " V1.0"; /* whee, string space optimization with format type below */
if (dumbfile_getnc(signature, 32, f) != 32 ||
memcmp(signature, sig_part, 19) ||
memcmp(signature + 19, sig_rest, 5)) {
return NULL;
}
char signature [32];
sigdata = malloc(sizeof(*sigdata));
if (!sigdata) {
return NULL;
}
if ( dumbfile_getnc( signature, 32, f ) != 32 ||
memcmp( signature, sig_part, 19 ) ||
memcmp( signature + 19, sig_rest, 5 ) ) {
return NULL;
}
sigdata->speed = dumbfile_getc(f); /* XXX seems to fit the files I have */
sigdata->tempo = dumbfile_getc(f); /* ditto */
sigdata->n_samples = dumbfile_getc(f); /* ditto */
sigdata->n_patterns = dumbfile_getc(f);
sigdata->n_orders = dumbfile_getc(f);
sigdata->restart_position = dumbfile_getc(f);
sigdata = malloc(sizeof(*sigdata));
if (!sigdata) {
return NULL;
}
if (dumbfile_error(f) || !sigdata->n_samples || sigdata->n_samples > 64 ||
!sigdata->n_patterns || !sigdata->n_orders) {
free(sigdata);
return NULL;
}
sigdata->speed = dumbfile_getc( f ); /* XXX seems to fit the files I have */
sigdata->tempo = dumbfile_getc( f ); /* ditto */
sigdata->n_samples = dumbfile_getc( f ); /* ditto */
sigdata->n_patterns = dumbfile_getc( f );
sigdata->n_orders = dumbfile_getc( f );
sigdata->restart_position = dumbfile_getc( f );
if (sigdata->restart_position > sigdata->n_orders) /* XXX */
sigdata->restart_position = 0;
if ( dumbfile_error( f ) || !sigdata->n_samples || sigdata->n_samples > 64 || !sigdata->n_patterns ||
!sigdata->n_orders ) {
free( sigdata );
return NULL;
}
sigdata->order = malloc(sigdata->n_orders);
if (!sigdata->order) {
free(sigdata);
return NULL;
}
if ( sigdata->restart_position > sigdata->n_orders ) /* XXX */
sigdata->restart_position = 0;
if (dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f) !=
sigdata->n_orders ||
dumbfile_skip(f, 256 - sigdata->n_orders)) {
free(sigdata->order);
free(sigdata);
return NULL;
}
sigdata->order = malloc( sigdata->n_orders );
if ( !sigdata->order ) {
free( sigdata );
return NULL;
}
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
if (!sigdata->sample) {
free(sigdata->order);
free(sigdata);
return NULL;
}
if ( dumbfile_getnc( (char *) sigdata->order, sigdata->n_orders, f ) != sigdata->n_orders ||
dumbfile_skip( f, 256 - sigdata->n_orders ) ) {
free( sigdata->order );
free( sigdata );
return NULL;
}
sigdata->song_message = NULL;
sigdata->instrument = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
if ( !sigdata->sample ) {
free( sigdata->order );
free( sigdata );
return NULL;
}
sigdata->n_instruments = 0;
sigdata->song_message = NULL;
sigdata->instrument = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
for (i = 0; i < sigdata->n_samples; ++i)
sigdata->sample[i].data = NULL;
sigdata->n_instruments = 0;
for (i = 0; i < sigdata->n_samples; ++i) {
if (it_asy_read_sample_header(&sigdata->sample[i], f)) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
for ( i = 0; i < sigdata->n_samples; ++i )
sigdata->sample[i].data = NULL;
if (dumbfile_skip(f, 37 * (64 - sigdata->n_samples))) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for ( i = 0; i < sigdata->n_samples; ++i ) {
if ( it_asy_read_sample_header( &sigdata->sample[i], f ) ) {
_dumb_it_unload_sigdata( sigdata );
return NULL;
}
}
sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
if (!sigdata->pattern) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (i = 0; i < sigdata->n_patterns; ++i)
sigdata->pattern[i].entry = NULL;
if ( dumbfile_skip( f, 37 * ( 64 - sigdata->n_samples ) ) ) {
_dumb_it_unload_sigdata( sigdata );
return NULL;
}
/* Read in the patterns */
{
unsigned char *buffer =
malloc(64 * 8 * 4); /* 64 rows * 8 channels * 4 bytes */
if (!buffer) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (i = 0; i < sigdata->n_patterns; ++i) {
if (it_asy_read_pattern(&sigdata->pattern[i], f, buffer) != 0) {
free(buffer);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
free(buffer);
}
sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
if ( !sigdata->pattern ) {
_dumb_it_unload_sigdata( sigdata );
return NULL;
}
for (i = 0; i < sigdata->n_patterns; ++i)
sigdata->pattern[i].entry = NULL;
/* And finally, the sample data */
for (i = 0; i < sigdata->n_samples; ++i) {
if (it_asy_read_sample_data(&sigdata->sample[i], f)) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
/* Read in the patterns */
{
unsigned char *buffer = malloc( 64 * 8 * 4 ); /* 64 rows * 8 channels * 4 bytes */
if ( !buffer ) {
_dumb_it_unload_sigdata( sigdata );
return NULL;
}
for ( i = 0; i < sigdata->n_patterns; ++i ) {
if ( it_asy_read_pattern( &sigdata->pattern[i], f, buffer ) != 0 ) {
free( buffer );
_dumb_it_unload_sigdata( sigdata );
return NULL;
}
}
free( buffer );
}
/* Now let's initialise the remaining variables, and we're done! */
sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS |
IT_COMPATIBLE_GXX | IT_STEREO;
/* And finally, the sample data */
for ( i = 0; i < sigdata->n_samples; ++i ) {
if ( it_asy_read_sample_data( &sigdata->sample[i], f ) ) {
_dumb_it_unload_sigdata( sigdata );
return NULL;
}
}
sigdata->global_volume = 128;
sigdata->mixing_volume = 48;
sigdata->pan_separation = 128;
/* Now let's initialise the remaining variables, and we're done! */
sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
sigdata->n_pchannels = 8;
sigdata->global_volume = 128;
sigdata->mixing_volume = 48;
sigdata->pan_separation = 128;
sigdata->name[0] = 0;
sigdata->n_pchannels = 8;
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
sigdata->name[0] = 0;
for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[i + 0] = 32 - sep;
sigdata->channel_pan[i + 1] = 32 + sep;
sigdata->channel_pan[i + 2] = 32 + sep;
sigdata->channel_pan[i + 3] = 32 - sep;
}
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
_dumb_it_fix_invalid_orders(sigdata);
for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[i+0] = 32 - sep;
sigdata->channel_pan[i+1] = 32 + sep;
sigdata->channel_pan[i+2] = 32 + sep;
sigdata->channel_pan[i+3] = 32 - sep;
}
_dumb_it_fix_invalid_orders(sigdata);
return sigdata;
return sigdata;
}
DUH *dumb_read_asy_quick(DUMBFILE *f) {
sigdata_t *sigdata;
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
DUH *dumb_read_asy_quick(DUMBFILE *f)
{
sigdata_t *sigdata;
sigdata = it_asy_load_sigdata(f);
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
if (!sigdata)
return NULL;
sigdata = it_asy_load_sigdata(f);
if (!sigdata)
return NULL;
{
const char *tag[2][2];
tag[0][0] = "TITLE";
{
const char *tag[2][2];
tag[0][0] = "TITLE";
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
tag[1][0] = "FORMAT";
tag[1][1] = "ASYLUM Music Format";
return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
}
tag[1][0] = "FORMAT";
tag[1][1] = "ASYLUM Music Format";
return make_duh(-1, 2, (const char *const(*)[2])tag, 1, &descptr,
&sigdata);
}
}

View file

@ -24,360 +24,367 @@
#include "internal/it.h"
#include "internal/riff.h"
static int it_riff_dsmf_process_sample( IT_SAMPLE * sample, DUMBFILE * f, int len )
{
int flags;
static int it_riff_dsmf_process_sample(IT_SAMPLE *sample, DUMBFILE *f,
int len) {
int flags;
dumbfile_getnc( (char *) sample->filename, 13, f );
sample->filename[ 14 ] = 0;
flags = dumbfile_igetw( f );
sample->default_volume = dumbfile_getc( f );
sample->length = dumbfile_igetl( f );
sample->loop_start = dumbfile_igetl( f );
sample->loop_end = dumbfile_igetl( f );
dumbfile_skip( f, 32 - 28 );
sample->C5_speed = dumbfile_igetw( f ) * 2;
dumbfile_skip( f, 36 - 34 );
dumbfile_getnc( (char *) sample->name, 28, f );
sample->name[ 28 ] = 0;
dumbfile_getnc((char *)sample->filename, 13, f);
sample->filename[14] = 0;
/*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] )
return -1;*/
flags = dumbfile_igetw(f);
sample->default_volume = dumbfile_getc(f);
sample->length = dumbfile_igetl(f);
sample->loop_start = dumbfile_igetl(f);
sample->loop_end = dumbfile_igetl(f);
dumbfile_skip(f, 32 - 28);
sample->C5_speed = dumbfile_igetw(f) * 2;
dumbfile_skip(f, 36 - 34);
dumbfile_getnc((char *)sample->name, 28, f);
sample->name[28] = 0;
if ( ! sample->length ) {
sample->flags &= ~IT_SAMPLE_EXISTS;
return 0;
}
/*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] )
return -1;*/
/*if ( flags & ~( 2 | 1 ) )
return -1;*/
if (!sample->length) {
sample->flags &= ~IT_SAMPLE_EXISTS;
return 0;
}
if ( sample->length + 64 > len )
return -1;
/*if ( flags & ~( 2 | 1 ) )
return -1;*/
sample->flags = IT_SAMPLE_EXISTS;
if (sample->length + 64 > len)
return -1;
sample->default_pan = 0;
sample->global_volume = 64;
sample->vibrato_speed = 0;
sample->vibrato_depth = 0;
sample->vibrato_rate = 0;
sample->vibrato_waveform = IT_VIBRATO_SINE;
sample->finetune = 0;
sample->max_resampling_quality = -1;
sample->flags = IT_SAMPLE_EXISTS;
if ( flags & 1 )
{
if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) &&
((unsigned int)sample->loop_start < (unsigned int)sample->loop_end))
{
sample->length = sample->loop_end;
sample->flags |= IT_SAMPLE_LOOP;
if ( flags & 0x10 ) sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
}
}
sample->default_pan = 0;
sample->global_volume = 64;
sample->vibrato_speed = 0;
sample->vibrato_depth = 0;
sample->vibrato_rate = 0;
sample->vibrato_waveform = IT_VIBRATO_SINE;
sample->finetune = 0;
sample->max_resampling_quality = -1;
sample->data = malloc( sample->length );
if ( ! sample->data )
return -1;
if (flags & 1) {
if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) &&
((unsigned int)sample->loop_start <
(unsigned int)sample->loop_end)) {
sample->length = sample->loop_end;
sample->flags |= IT_SAMPLE_LOOP;
if (flags & 0x10)
sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
}
}
dumbfile_getnc( sample->data, sample->length, f );
sample->data = malloc(sample->length);
if (!sample->data)
return -1;
if ( ! ( flags & 2 ) )
{
for ( flags = 0; flags < sample->length; ++flags )
( ( signed char * ) sample->data ) [ flags ] ^= 0x80;
}
dumbfile_getnc(sample->data, sample->length, f);
return 0;
if (!(flags & 2)) {
for (flags = 0; flags < sample->length; ++flags)
((signed char *)sample->data)[flags] ^= 0x80;
}
return 0;
}
static int it_riff_dsmf_process_pattern( IT_PATTERN * pattern, DUMBFILE * f, int len )
{
static int it_riff_dsmf_process_pattern(IT_PATTERN *pattern, DUMBFILE *f,
int len) {
int length, row;
unsigned flags;
unsigned flags;
long start, end;
int p, q, r;
IT_ENTRY * entry;
IT_ENTRY *entry;
length = dumbfile_igetw( f );
if ( length > len ) return -1;
length = dumbfile_igetw(f);
if (length > len)
return -1;
len = length - 2;
len = length - 2;
pattern->n_rows = 64;
pattern->n_entries = 64;
pattern->n_rows = 64;
pattern->n_entries = 64;
row = 0;
row = 0;
start = dumbfile_pos( f );
start = dumbfile_pos(f);
end = start + len;
while ( (row < 64) && !dumbfile_error( f ) && (dumbfile_pos( f ) < end) ) {
p = dumbfile_getc( f );
if ( ! p ) {
++ row;
continue;
}
while ((row < 64) && !dumbfile_error(f) && (dumbfile_pos(f) < end)) {
p = dumbfile_getc(f);
if (!p) {
++row;
continue;
}
flags = p & 0xF0;
if (flags) {
++ pattern->n_entries;
if (flags & 0x80) dumbfile_skip( f, 1 );
if (flags & 0x40) dumbfile_skip( f, 1 );
if (flags & 0x20) dumbfile_skip( f, 1 );
if (flags & 0x10) dumbfile_skip( f, 2 );
}
}
if (flags) {
++pattern->n_entries;
if (flags & 0x80)
dumbfile_skip(f, 1);
if (flags & 0x40)
dumbfile_skip(f, 1);
if (flags & 0x20)
dumbfile_skip(f, 1);
if (flags & 0x10)
dumbfile_skip(f, 2);
}
}
if ( pattern->n_entries == 64 ) return 0;
if (pattern->n_entries == 64)
return 0;
pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) );
if ( ! pattern->entry ) return -1;
pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
if (!pattern->entry)
return -1;
entry = pattern->entry;
entry = pattern->entry;
row = 0;
row = 0;
if ( dumbfile_seek( f, start, DFS_SEEK_SET ) ) return -1;
if (dumbfile_seek(f, start, DFS_SEEK_SET))
return -1;
while ( ( row < 64 ) && !dumbfile_error( f ) && ( dumbfile_pos( f ) < end ) )
{
p = dumbfile_getc( f );
if ( ! p )
{
IT_SET_END_ROW( entry );
++ entry;
++ row;
continue;
}
while ((row < 64) && !dumbfile_error(f) && (dumbfile_pos(f) < end)) {
p = dumbfile_getc(f);
if (!p) {
IT_SET_END_ROW(entry);
++entry;
++row;
continue;
}
flags = p;
entry->channel = flags & 0x0F;
entry->mask = 0;
entry->channel = flags & 0x0F;
entry->mask = 0;
if ( flags & 0xF0 )
{
if ( flags & 0x80 )
{
q = dumbfile_getc( f );
if ( q )
{
entry->mask |= IT_ENTRY_NOTE;
if (flags & 0xF0) {
if (flags & 0x80) {
q = dumbfile_getc(f);
if (q) {
entry->mask |= IT_ENTRY_NOTE;
entry->note = q - 1;
}
}
}
}
if ( flags & 0x40 )
{
q = dumbfile_getc( f );
if ( q )
{
entry->mask |= IT_ENTRY_INSTRUMENT;
if (flags & 0x40) {
q = dumbfile_getc(f);
if (q) {
entry->mask |= IT_ENTRY_INSTRUMENT;
entry->instrument = q;
}
}
}
}
if ( flags & 0x20 )
{
entry->mask |= IT_ENTRY_VOLPAN;
entry->volpan = dumbfile_getc( f );
}
if (flags & 0x20) {
entry->mask |= IT_ENTRY_VOLPAN;
entry->volpan = dumbfile_getc(f);
}
if ( flags & 0x10 )
{
q = dumbfile_getc( f );
r = dumbfile_getc( f );
_dumb_it_xm_convert_effect( q, r, entry, 0 );
}
if (flags & 0x10) {
q = dumbfile_getc(f);
r = dumbfile_getc(f);
_dumb_it_xm_convert_effect(q, r, entry, 0);
}
if (entry->mask) entry++;
}
}
if (entry->mask)
entry++;
}
}
while ( row < 64 )
{
IT_SET_END_ROW( entry );
++ entry;
++ row;
}
while (row < 64) {
IT_SET_END_ROW(entry);
++entry;
++row;
}
pattern->n_entries = entry - pattern->entry;
if ( ! pattern->n_entries ) return -1;
pattern->n_entries = (int)((long)entry - (long)pattern->entry);
if (!pattern->n_entries)
return -1;
return 0;
return 0;
}
static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( DUMBFILE * f, struct riff * stream )
{
DUMB_IT_SIGDATA *sigdata;
static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata(DUMBFILE *f,
struct riff *stream) {
DUMB_IT_SIGDATA *sigdata;
int n, o, found;
int n, o, found;
if ( ! stream ) goto error;
if (!stream)
goto error;
if ( stream->type != DUMB_ID( 'D', 'S', 'M', 'F' ) ) goto error;
if (stream->type != DUMB_ID('D', 'S', 'M', 'F'))
goto error;
sigdata = malloc(sizeof(*sigdata));
if ( ! sigdata ) goto error;
sigdata = malloc(sizeof(*sigdata));
if (!sigdata)
goto error;
sigdata->n_patterns = 0;
sigdata->n_samples = 0;
sigdata->name[0] = 0;
sigdata->n_patterns = 0;
sigdata->n_samples = 0;
sigdata->name[0] = 0;
found = 0;
found = 0;
for ( n = 0; (unsigned)n < stream->chunk_count; ++n )
{
struct riff_chunk * c = stream->chunks + n;
switch( c->type )
{
case DUMB_ID( 'S' ,'O' ,'N' ,'G' ):
/* initialization data */
if ( ( found ) || ( c->size < 192 ) ) goto error_sd;
found = 1;
break;
for (n = 0; (unsigned)n < stream->chunk_count; ++n) {
struct riff_chunk *c = stream->chunks + n;
switch (c->type) {
case DUMB_ID('S', 'O', 'N', 'G'):
/* initialization data */
if ((found) || (c->size < 192))
goto error_sd;
found = 1;
break;
case DUMB_ID( 'P', 'A', 'T', 'T' ):
++ sigdata->n_patterns;
break;
case DUMB_ID('P', 'A', 'T', 'T'):
++sigdata->n_patterns;
break;
case DUMB_ID( 'I', 'N', 'S', 'T' ):
++ sigdata->n_samples;
break;
}
}
case DUMB_ID('I', 'N', 'S', 'T'):
++sigdata->n_samples;
break;
}
}
if ( !found || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd;
if (!found || !sigdata->n_samples || !sigdata->n_patterns)
goto error_sd;
if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd;
if (sigdata->n_samples > 255 || sigdata->n_patterns > 255)
goto error_sd;
sigdata->song_message = NULL;
sigdata->order = NULL;
sigdata->instrument = NULL;
sigdata->sample = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
sigdata->song_message = NULL;
sigdata->order = NULL;
sigdata->instrument = NULL;
sigdata->sample = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
sigdata->mixing_volume = 48;
sigdata->pan_separation = 128;
sigdata->mixing_volume = 48;
sigdata->pan_separation = 128;
sigdata->n_instruments = 0;
sigdata->n_orders = 0;
sigdata->restart_position = 0;
sigdata->n_instruments = 0;
sigdata->n_orders = 0;
sigdata->restart_position = 0;
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[n ] = 32 - sep;
sigdata->channel_pan[n+1] = 32 + sep;
sigdata->channel_pan[n+2] = 32 + sep;
sigdata->channel_pan[n+3] = 32 - sep;
}
for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[n] = 32 - sep;
sigdata->channel_pan[n + 1] = 32 + sep;
sigdata->channel_pan[n + 2] = 32 + sep;
sigdata->channel_pan[n + 3] = 32 - sep;
}
for ( n = 0; (unsigned)n < stream->chunk_count; ++n )
{
struct riff_chunk * c = stream->chunks + n;
switch ( c->type )
{
case DUMB_ID( 'S', 'O', 'N', 'G' ):
if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd;
dumbfile_getnc( (char *) sigdata->name, 28, f );
sigdata->name[ 28 ] = 0;
sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
dumbfile_skip( f, 36 - 28 );
sigdata->n_orders = dumbfile_igetw( f );
//sigdata->n_samples = ptr[ 38 ] | ( ptr[ 39 ] << 8 ); // whatever
//sigdata->n_patterns = ptr[ 40 ] | ( ptr[ 41 ] << 8 );
dumbfile_skip( f, 42 - 38 );
sigdata->n_pchannels = dumbfile_igetw( f );
sigdata->global_volume = dumbfile_getc( f );
sigdata->mixing_volume = dumbfile_getc( f );
sigdata->speed = dumbfile_getc( f );
sigdata->tempo = dumbfile_getc( f );
for (n = 0; (unsigned)n < stream->chunk_count; ++n) {
struct riff_chunk *c = stream->chunks + n;
switch (c->type) {
case DUMB_ID('S', 'O', 'N', 'G'):
if (dumbfile_seek(f, c->offset, DFS_SEEK_SET))
goto error_usd;
dumbfile_getnc((char *)sigdata->name, 28, f);
sigdata->name[28] = 0;
sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
dumbfile_skip(f, 36 - 28);
sigdata->n_orders = dumbfile_igetw(f);
// sigdata->n_samples = ptr[ 38 ] | ( ptr[ 39 ] << 8 ); // whatever
// sigdata->n_patterns = ptr[ 40 ] | ( ptr[ 41 ] << 8 );
dumbfile_skip(f, 42 - 38);
sigdata->n_pchannels = dumbfile_igetw(f);
sigdata->global_volume = dumbfile_getc(f);
sigdata->mixing_volume = dumbfile_getc(f);
sigdata->speed = dumbfile_getc(f);
sigdata->tempo = dumbfile_getc(f);
for ( o = 0; o < 16; ++o )
{
sigdata->channel_pan[ o ] = dumbfile_getc( f ) / 2;
}
for (o = 0; o < 16; ++o) {
sigdata->channel_pan[o] = dumbfile_getc(f) / 2;
}
sigdata->order = malloc( 128 );
if ( ! sigdata->order ) goto error_usd;
dumbfile_getnc( (char *) sigdata->order, 128, f );
sigdata->order = malloc(128);
if (!sigdata->order)
goto error_usd;
dumbfile_getnc((char *)sigdata->order, 128, f);
break;
}
}
break;
}
}
sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
if ( ! sigdata->pattern ) goto error_usd;
for ( n = 0; n < sigdata->n_patterns; ++n )
sigdata->pattern[ n ].entry = NULL;
sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
if (!sigdata->pattern)
goto error_usd;
for (n = 0; n < sigdata->n_patterns; ++n)
sigdata->pattern[n].entry = NULL;
sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
if ( ! sigdata->sample ) goto error_usd;
for ( n = 0; n < sigdata->n_samples; ++n )
{
IT_SAMPLE * sample = sigdata->sample + n;
sample->data = NULL;
}
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
if (!sigdata->sample)
goto error_usd;
for (n = 0; n < sigdata->n_samples; ++n) {
IT_SAMPLE *sample = sigdata->sample + n;
sample->data = NULL;
}
sigdata->n_samples = 0;
sigdata->n_patterns = 0;
sigdata->n_samples = 0;
sigdata->n_patterns = 0;
for ( n = 0; (unsigned)n < stream->chunk_count; ++n )
{
struct riff_chunk * c = stream->chunks + n;
switch ( c->type )
{
case DUMB_ID( 'P', 'A', 'T', 'T' ):
if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd;
if ( it_riff_dsmf_process_pattern( sigdata->pattern + sigdata->n_patterns, f, c->size ) ) goto error_usd;
++ sigdata->n_patterns;
break;
for (n = 0; (unsigned)n < stream->chunk_count; ++n) {
struct riff_chunk *c = stream->chunks + n;
switch (c->type) {
case DUMB_ID('P', 'A', 'T', 'T'):
if (dumbfile_seek(f, c->offset, DFS_SEEK_SET))
goto error_usd;
if (it_riff_dsmf_process_pattern(
sigdata->pattern + sigdata->n_patterns, f, c->size))
goto error_usd;
++sigdata->n_patterns;
break;
case DUMB_ID( 'I', 'N', 'S', 'T' ):
if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd;
if ( it_riff_dsmf_process_sample( sigdata->sample + sigdata->n_samples, f, c->size ) ) goto error_usd;
++ sigdata->n_samples;
break;
}
}
case DUMB_ID('I', 'N', 'S', 'T'):
if (dumbfile_seek(f, c->offset, DFS_SEEK_SET))
goto error_usd;
if (it_riff_dsmf_process_sample(
sigdata->sample + sigdata->n_samples, f, c->size))
goto error_usd;
++sigdata->n_samples;
break;
}
}
_dumb_it_fix_invalid_orders( sigdata );
_dumb_it_fix_invalid_orders(sigdata);
return sigdata;
return sigdata;
error_usd:
_dumb_it_unload_sigdata( sigdata );
goto error;
_dumb_it_unload_sigdata(sigdata);
goto error;
error_sd:
free( sigdata );
free(sigdata);
error:
return NULL;
return NULL;
}
DUH *dumb_read_riff_dsmf( DUMBFILE * f, struct riff * stream )
{
sigdata_t *sigdata;
DUH *dumb_read_riff_dsmf(DUMBFILE *f, struct riff *stream) {
sigdata_t *sigdata;
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
sigdata = it_riff_dsmf_load_sigdata( f, stream );
sigdata = it_riff_dsmf_load_sigdata(f, stream);
if (!sigdata)
return NULL;
if (!sigdata)
return NULL;
{
const char *tag[2][2];
tag[0][0] = "TITLE";
{
const char *tag[2][2];
tag[0][0] = "TITLE";
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
tag[1][0] = "FORMAT";
tag[1][1] = "RIFF DSMF";
return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
}
tag[1][0] = "FORMAT";
tag[1][1] = "RIFF DSMF";
return make_duh(-1, 2, (const char *const(*)[2])tag, 1, &descptr,
&sigdata);
}
}

File diff suppressed because it is too large Load diff

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_read_mod(DUMBFILE *f, int restrict_)
{
DUH *duh = dumb_read_mod_quick(f, restrict_);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_read_mod(DUMBFILE *f, int restrict_) {
DUH *duh = dumb_read_mod_quick(f, restrict_);
dumb_it_do_initial_runthrough(duh);
return duh;
}

View file

@ -24,407 +24,432 @@
#include "dumb.h"
#include "internal/it.h"
size_t strlen_max(const char * ptr, size_t max)
{
const char * end, * start;
if (ptr==0) return 0;
start = ptr;
end = ptr + max;
while(ptr < end && *ptr) ptr++;
return ptr - start;
size_t strlen_max(const char *ptr, size_t max) {
const char *end, *start;
if (ptr == 0)
return 0;
start = ptr;
end = ptr + max;
while (ptr < end && *ptr)
ptr++;
return ptr - start;
}
static int it_mtm_assemble_pattern(IT_PATTERN *pattern, const unsigned char * track, const unsigned short * sequence, int n_rows)
{
int n, o, note, sample;
const unsigned char * t;
IT_ENTRY * entry;
static int it_mtm_assemble_pattern(IT_PATTERN *pattern,
const unsigned char *track,
const unsigned short *sequence, int n_rows) {
int n, o, note, sample;
const unsigned char *t;
IT_ENTRY *entry;
pattern->n_rows = n_rows;
pattern->n_entries = n_rows;
pattern->n_rows = n_rows;
pattern->n_entries = n_rows;
for (n = 0; n < 32; n++) {
if (sequence[n]) {
t = &track[192 * (sequence[n] - 1)];
for (o = 0; o < n_rows; o++) {
if (t[0] || t[1] || t[2]) pattern->n_entries++;
t += 3;
}
}
}
for (n = 0; n < 32; n++) {
if (sequence[n]) {
t = &track[192 * (sequence[n] - 1)];
for (o = 0; o < n_rows; o++) {
if (t[0] || t[1] || t[2])
pattern->n_entries++;
t += 3;
}
}
}
entry = malloc(pattern->n_entries * sizeof(*entry));
if (!entry) return -1;
pattern->entry = entry;
entry = malloc(pattern->n_entries * sizeof(*entry));
if (!entry)
return -1;
pattern->entry = entry;
for (n = 0; n < n_rows; n++) {
for (o = 0; o < 32; o++) {
if (sequence[o]) {
t = &track[192 * (sequence[o] - 1) + (n * 3)];
if (t[0] || t[1] || t[2]) {
entry->channel = o;
entry->mask = 0;
note = t[0] >> 2;
sample = ((t[0] << 4) | (t[1] >> 4)) & 0x3F;
for (n = 0; n < n_rows; n++) {
for (o = 0; o < 32; o++) {
if (sequence[o]) {
t = &track[192 * (sequence[o] - 1) + (n * 3)];
if (t[0] || t[1] || t[2]) {
entry->channel = o;
entry->mask = 0;
note = t[0] >> 2;
sample = ((t[0] << 4) | (t[1] >> 4)) & 0x3F;
if (note) {
entry->mask |= IT_ENTRY_NOTE;
entry->note = note + 24;
}
if (note) {
entry->mask |= IT_ENTRY_NOTE;
entry->note = note + 24;
}
if (sample) {
entry->mask |= IT_ENTRY_INSTRUMENT;
entry->instrument = sample;
}
if (sample) {
entry->mask |= IT_ENTRY_INSTRUMENT;
entry->instrument = sample;
}
_dumb_it_xm_convert_effect(t[1] & 0xF, t[2], entry, 1);
_dumb_it_xm_convert_effect(t[1] & 0xF, t[2], entry, 1);
if (entry->mask) entry++;
}
}
}
IT_SET_END_ROW(entry);
entry++;
}
if (entry->mask)
entry++;
}
}
}
IT_SET_END_ROW(entry);
entry++;
}
pattern->n_entries = (int)(entry - pattern->entry);
pattern->n_entries = (int)(entry - pattern->entry);
return 0;
return 0;
}
static int it_mtm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f, int * skip_bytes)
{
int finetune, flags;
static int it_mtm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f,
int *skip_bytes) {
int finetune, flags;
dumbfile_getnc((char *)sample->name, 22, f);
sample->name[22] = 0;
sample->name[22] = 0;
sample->filename[0] = 0;
sample->filename[0] = 0;
sample->length = dumbfile_igetl(f);
sample->loop_start = dumbfile_igetl(f);
sample->loop_end = dumbfile_igetl(f);
finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
sample->global_volume = 64;
sample->default_volume = dumbfile_getc(f);
sample->length = dumbfile_igetl(f);
sample->loop_start = dumbfile_igetl(f);
sample->loop_end = dumbfile_igetl(f);
finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
sample->global_volume = 64;
sample->default_volume = dumbfile_getc(f);
flags = dumbfile_getc(f);
flags = dumbfile_getc(f);
if (sample->length <= 0) {
sample->flags = 0;
return 0;
}
if (sample->length <= 0) {
sample->flags = 0;
return 0;
}
sample->flags = IT_SAMPLE_EXISTS;
sample->flags = IT_SAMPLE_EXISTS;
*skip_bytes = 0;
if (flags & 1) {
*skip_bytes = sample->length & 1;
sample->flags |= IT_SAMPLE_16BIT;
sample->length >>= 1;
sample->loop_start >>= 1;
sample->loop_end >>= 1;
}
*skip_bytes = 0;
if (flags & 1) {
*skip_bytes = sample->length & 1;
sample->flags |= IT_SAMPLE_16BIT;
sample->length >>= 1;
sample->loop_start >>= 1;
sample->loop_end >>= 1;
}
sample->default_pan = 0;
sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
sample->finetune = finetune * 32;
// the above line might be wrong
sample->default_pan = 0;
sample->C5_speed =
(int)(AMIGA_CLOCK /
214.0); //(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
sample->finetune = finetune * 32;
// the above line might be wrong
if (sample->loop_end > sample->length)
sample->loop_end = sample->length;
if (sample->loop_end > sample->length)
sample->loop_end = sample->length;
if (sample->loop_end - sample->loop_start > 2)
sample->flags |= IT_SAMPLE_LOOP;
if (sample->loop_end - sample->loop_start > 2)
sample->flags |= IT_SAMPLE_LOOP;
sample->vibrato_speed = 0;
sample->vibrato_depth = 0;
sample->vibrato_rate = 0;
sample->vibrato_waveform = 0; // do we have to set _all_ these?
sample->max_resampling_quality = -1;
sample->vibrato_speed = 0;
sample->vibrato_depth = 0;
sample->vibrato_rate = 0;
sample->vibrato_waveform = 0; // do we have to set _all_ these?
sample->max_resampling_quality = -1;
return dumbfile_error(f);
return dumbfile_error(f);
}
static int it_mtm_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f, int skip_bytes)
{
long i;
long truncated_size;
long bytes_per_sample;
static int it_mtm_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f,
int skip_bytes) {
long i;
long truncated_size;
long bytes_per_sample;
/* let's get rid of the sample data coming after the end of the loop */
if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
truncated_size = sample->length - sample->loop_end;
sample->length = sample->loop_end;
} else {
truncated_size = 0;
}
bytes_per_sample = (sample->flags & IT_SAMPLE_16BIT) ? 2 : 1;
/* let's get rid of the sample data coming after the end of the loop */
if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
truncated_size = sample->length - sample->loop_end;
sample->length = sample->loop_end;
} else {
truncated_size = 0;
}
sample->data = malloc(sample->length * bytes_per_sample);
bytes_per_sample = (sample->flags & IT_SAMPLE_16BIT) ? 2 : 1;
if (!sample->data)
return -1;
sample->data = malloc(sample->length * bytes_per_sample);
dumbfile_getnc((char *)sample->data, sample->length * bytes_per_sample, f);
dumbfile_skip(f, truncated_size * bytes_per_sample);
dumbfile_skip(f, skip_bytes);
if (!sample->data)
return -1;
if (dumbfile_error(f))
return -1;
dumbfile_getnc((char *)sample->data, sample->length * bytes_per_sample, f);
dumbfile_skip(f, truncated_size * bytes_per_sample);
dumbfile_skip(f, skip_bytes);
if (bytes_per_sample == 1)
for (i = 0; i < sample->length; i++)
((signed char *)sample->data)[i] ^= 0x80;
if (dumbfile_error(f))
return -1;
return 0;
if (bytes_per_sample == 1)
for (i = 0; i < sample->length; i++)
((signed char *)sample->data)[i] ^= 0x80;
return 0;
}
static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int * version)
{
DUMB_IT_SIGDATA *sigdata;
static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int *version) {
DUMB_IT_SIGDATA *sigdata;
int n, o, n_tracks, l_comment, n_rows, n_channels;
int n, o, n_tracks, l_comment, n_rows, n_channels;
unsigned char * track;
unsigned char *track;
unsigned short * sequence;
unsigned short *sequence;
char * comment;
int * skip_bytes;
char *comment;
if (dumbfile_getc(f) != 'M' ||
dumbfile_getc(f) != 'T' ||
dumbfile_getc(f) != 'M') goto error;
int *skip_bytes;
*version = dumbfile_getc(f);
if (dumbfile_getc(f) != 'M' || dumbfile_getc(f) != 'T' ||
dumbfile_getc(f) != 'M')
goto error;
sigdata = malloc(sizeof(*sigdata));
if (!sigdata) goto error;
*version = dumbfile_getc(f);
sigdata = malloc(sizeof(*sigdata));
if (!sigdata)
goto error;
dumbfile_getnc((char *)sigdata->name, 20, f);
sigdata->name[20] = 0;
sigdata->name[20] = 0;
n_tracks = dumbfile_igetw(f);
sigdata->n_patterns = dumbfile_getc(f) + 1;
sigdata->n_orders = dumbfile_getc(f) + 1;
l_comment = dumbfile_igetw(f);
sigdata->n_samples = dumbfile_getc(f);
//if (dumbfile_getc(f)) goto error_sd;
dumbfile_getc(f);
n_rows = dumbfile_getc(f);
n_channels = dumbfile_getc(f);
n_tracks = dumbfile_igetw(f);
sigdata->n_patterns = dumbfile_getc(f) + 1;
sigdata->n_orders = dumbfile_getc(f) + 1;
l_comment = dumbfile_igetw(f);
sigdata->n_samples = dumbfile_getc(f);
// if (dumbfile_getc(f)) goto error_sd;
dumbfile_getc(f);
n_rows = dumbfile_getc(f);
n_channels = dumbfile_getc(f);
if (dumbfile_error(f) ||
(n_tracks <= 0) ||
(sigdata->n_samples <= 0) ||
(n_rows <= 0 || n_rows > 64) ||
(n_channels <= 0 || n_channels > 32)) goto error_sd;
if (dumbfile_error(f) || (n_tracks <= 0) || (sigdata->n_samples <= 0) ||
(n_rows <= 0 || n_rows > 64) || (n_channels <= 0 || n_channels > 32))
goto error_sd;
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
if (dumbfile_getnc((char *)sigdata->channel_pan, 32, f) < 32) goto error_sd;
if (dumbfile_getnc((char *)sigdata->channel_pan, 32, f) < 32)
goto error_sd;
for (n = 0; n < 32; n++) {
if (sigdata->channel_pan[n] <= 15) {
sigdata->channel_pan[n] -= (sigdata->channel_pan[n] & 8) >> 3;
sigdata->channel_pan[n] = (sigdata->channel_pan[n] * 32) / 7;
} else {
sigdata->channel_volume[n] = 0;
sigdata->channel_pan[n] = 7;
}
}
for (n = 0; n < 32; n++) {
if (sigdata->channel_pan[n] <= 15) {
sigdata->channel_pan[n] -= (sigdata->channel_pan[n] & 8) >> 3;
sigdata->channel_pan[n] = (sigdata->channel_pan[n] * 32) / 7;
} else {
sigdata->channel_volume[n] = 0;
sigdata->channel_pan[n] = 7;
}
}
for (n = 32; n < DUMB_IT_N_CHANNELS; n += 4) {
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[n ] = 32 - sep;
sigdata->channel_pan[n+1] = 32 + sep;
sigdata->channel_pan[n+2] = 32 + sep;
sigdata->channel_pan[n+3] = 32 - sep;
}
for (n = 32; n < DUMB_IT_N_CHANNELS; n += 4) {
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[n] = 32 - sep;
sigdata->channel_pan[n + 1] = 32 + sep;
sigdata->channel_pan[n + 2] = 32 + sep;
sigdata->channel_pan[n + 3] = 32 - sep;
}
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
if (!sigdata->sample) goto error_sd;
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
if (!sigdata->sample)
goto error_sd;
sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_STEREO | IT_OLD_EFFECTS |
IT_COMPATIBLE_GXX;
sigdata->global_volume = 128;
sigdata->mixing_volume = 48;
sigdata->speed = 6;
sigdata->tempo = 125;
sigdata->pan_separation = 128;
sigdata->global_volume = 128;
sigdata->mixing_volume = 48;
sigdata->speed = 6;
sigdata->tempo = 125;
sigdata->pan_separation = 128;
sigdata->song_message = NULL;
sigdata->order = NULL;
sigdata->instrument = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
sigdata->song_message = NULL;
sigdata->order = NULL;
sigdata->instrument = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
sigdata->n_instruments = 0;
sigdata->n_instruments = 0;
sigdata->restart_position = 0;
sigdata->n_pchannels = n_channels;
for (n = 0; n < sigdata->n_samples; n++)
sigdata->sample[n].data = NULL;
sigdata->restart_position = 0;
sigdata->n_pchannels = n_channels;
skip_bytes = calloc(sizeof(int), sigdata->n_samples);
if (!skip_bytes) goto error_usd;
for (n = 0; n < sigdata->n_samples; n++) {
if (it_mtm_read_sample_header(&sigdata->sample[n], f, skip_bytes + n)) goto error_sb;
}
for (n = 0; n < sigdata->n_samples; n++)
sigdata->sample[n].data = NULL;
sigdata->order = malloc(sigdata->n_orders);
if (!sigdata->order) goto error_sb;
skip_bytes = calloc(sizeof(int), sigdata->n_samples);
if (!skip_bytes)
goto error_usd;
if (dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_sb;
if (sigdata->n_orders < 128)
if (dumbfile_skip(f, 128 - sigdata->n_orders)) goto error_sb;
for (n = 0; n < sigdata->n_samples; n++) {
if (it_mtm_read_sample_header(&sigdata->sample[n], f, skip_bytes + n))
goto error_sb;
}
track = malloc(192 * n_tracks);
if (!track) goto error_sb;
sigdata->order = malloc(sigdata->n_orders);
if (!sigdata->order)
goto error_sb;
if (dumbfile_getnc((char *)track, 192 * n_tracks, f) < 192 * n_tracks) goto error_ft;
if (dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f) <
sigdata->n_orders)
goto error_sb;
if (sigdata->n_orders < 128)
if (dumbfile_skip(f, 128 - sigdata->n_orders))
goto error_sb;
sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
if (!sigdata->pattern) goto error_ft;
for (n = 0; n < sigdata->n_patterns; n++)
sigdata->pattern[n].entry = NULL;
track = malloc(192 * n_tracks);
if (!track)
goto error_sb;
sequence = malloc(sigdata->n_patterns * 32 * sizeof(*sequence));
if (!sequence) goto error_ft;
if (dumbfile_getnc((char *)track, 192 * n_tracks, f) < 192 * n_tracks)
goto error_ft;
for (n = 0; n < sigdata->n_patterns; n++) {
for (o = 0; o < 32; o++) {
sequence[(n * 32) + o] = dumbfile_igetw(f);
if (sequence[(n * 32) + o] > n_tracks)
{
//goto error_fs;
// illegal track number, silence instead of rejecting the file
sequence[(n * 32) + o] = 0;
}
}
}
sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
if (!sigdata->pattern)
goto error_ft;
for (n = 0; n < sigdata->n_patterns; n++)
sigdata->pattern[n].entry = NULL;
for (n = 0; n < sigdata->n_patterns; n++) {
if (it_mtm_assemble_pattern(&sigdata->pattern[n], track, &sequence[n * 32], n_rows)) goto error_fs;
}
sequence = malloc(sigdata->n_patterns * 32 * sizeof(*sequence));
if (!sequence)
goto error_ft;
if (l_comment) {
comment = malloc(l_comment);
if (!comment) goto error_fs;
if (dumbfile_getnc(comment, l_comment, f) < l_comment) goto error_fc;
for (n = 0; n < sigdata->n_patterns; n++) {
for (o = 0; o < 32; o++) {
sequence[(n * 32) + o] = dumbfile_igetw(f);
if (sequence[(n * 32) + o] > n_tracks) {
// goto error_fs;
// illegal track number, silence instead of rejecting the file
sequence[(n * 32) + o] = 0;
}
}
}
/* Time for annoying "logic", yes. We want each line which has text,
* and each blank line in between all the valid lines.
*/
for (n = 0; n < sigdata->n_patterns; n++) {
if (it_mtm_assemble_pattern(&sigdata->pattern[n], track,
&sequence[n * 32], n_rows))
goto error_fs;
}
/* Find last actual line. */
for (o = -1, n = 0; n < l_comment; n += 40) {
if (comment[n]) o = n;
}
if (l_comment) {
comment = malloc(l_comment);
if (!comment)
goto error_fs;
if (dumbfile_getnc(comment, l_comment, f) < l_comment)
goto error_fc;
if (o >= 0) {
/* Time for annoying "logic", yes. We want each line which has text,
* and each blank line in between all the valid lines.
*/
int l, m;
/* Find last actual line. */
for (o = -1, n = 0; n < l_comment; n += 40) {
if (comment[n])
o = n;
}
for (l = 0, n = 0; n <= o; n += 40) {
int maxlen = l_comment - n;
l += strlen_max(&comment[n], maxlen > 40 ? 40 : maxlen) + 2;
}
if (o >= 0) {
l -= 1;
int l, m;
sigdata->song_message = malloc(l);
if (!sigdata->song_message) goto error_fc;
for (l = 0, n = 0; n <= o; n += 40) {
int maxlen = l_comment - n;
l += strlen_max(&comment[n], maxlen > 40 ? 40 : maxlen) + 2;
}
for (m = 0, n = 0; n <= o; n += 40) {
int maxlen = l_comment - n;
int p = (int) strlen_max(&comment[n], maxlen > 40 ? 40 : maxlen);
if (p) {
memcpy(sigdata->song_message + m, &comment[n], p);
m += p;
}
if (l - m > 1) {
sigdata->song_message[m++] = 13;
sigdata->song_message[m++] = 10;
}
}
sigdata->song_message[m] = 0;
}
l -= 1;
free(comment);
}
sigdata->song_message = malloc(l);
if (!sigdata->song_message)
goto error_fc;
for (n = 0; n < sigdata->n_samples; n++) {
if (it_mtm_read_sample_data(&sigdata->sample[n], f, skip_bytes[n])) goto error_fs;
}
_dumb_it_fix_invalid_orders(sigdata);
for (m = 0, n = 0; n <= o; n += 40) {
int maxlen = l_comment - n;
int p = (int)strlen_max(&comment[n], maxlen > 40 ? 40 : maxlen);
if (p) {
memcpy(sigdata->song_message + m, &comment[n], p);
m += p;
}
if (l - m > 1) {
sigdata->song_message[m++] = 13;
sigdata->song_message[m++] = 10;
}
}
free(sequence);
free(track);
free(skip_bytes);
sigdata->song_message[m] = 0;
}
return sigdata;
free(comment);
}
for (n = 0; n < sigdata->n_samples; n++) {
if (it_mtm_read_sample_data(&sigdata->sample[n], f, skip_bytes[n]))
goto error_fs;
}
_dumb_it_fix_invalid_orders(sigdata);
free(sequence);
free(track);
free(skip_bytes);
return sigdata;
error_fc:
free(comment);
free(comment);
error_fs:
free(sequence);
free(sequence);
error_ft:
free(track);
free(track);
error_sb:
free(skip_bytes);
free(skip_bytes);
error_usd:
_dumb_it_unload_sigdata(sigdata);
return NULL;
_dumb_it_unload_sigdata(sigdata);
return NULL;
error_sd:
free(sigdata);
free(sigdata);
error:
return NULL;
return NULL;
}
static char hexdigit(int in)
{
if (in < 10) return in + '0';
else return in + 'A' - 10;
static char hexdigit(int in) {
if (in < 10)
return in + '0';
else
return in + 'A' - 10;
}
DUH *dumb_read_mtm_quick(DUMBFILE *f)
{
sigdata_t *sigdata;
int ver;
DUH *dumb_read_mtm_quick(DUMBFILE *f) {
sigdata_t *sigdata;
int ver;
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
sigdata = it_mtm_load_sigdata(f, &ver);
sigdata = it_mtm_load_sigdata(f, &ver);
if (!sigdata)
return NULL;
if (!sigdata)
return NULL;
{
char version[16];
const char *tag[2][2];
tag[0][0] = "TITLE";
{
char version[16];
const char *tag[2][2];
tag[0][0] = "TITLE";
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
tag[1][0] = "FORMAT";
version[0] = 'M';
version[1] = 'T';
version[2] = 'M';
version[3] = ' ';
version[4] = 'v';
version[5] = hexdigit(ver >> 4);
version[6] = '.';
version[7] = hexdigit(ver & 15);
version[8] = 0;
tag[1][1] = (const char *) &version;
return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
}
tag[1][0] = "FORMAT";
version[0] = 'M';
version[1] = 'T';
version[2] = 'M';
version[3] = ' ';
version[4] = 'v';
version[5] = hexdigit(ver >> 4);
version[6] = '.';
version[7] = hexdigit(ver & 15);
version[8] = 0;
tag[1][1] = (const char *)&version;
return make_duh(-1, 2, (const char *const(*)[2])tag, 1, &descptr,
&sigdata);
}
}

View file

@ -24,535 +24,579 @@
#include "dumb.h"
#include "internal/it.h"
static int it_okt_read_pattern(IT_PATTERN *pattern, const unsigned char *data,
int length, int n_channels) {
int pos;
int channel;
int row;
int n_rows;
IT_ENTRY *entry;
if (length < 2)
return -1;
static int it_okt_read_pattern(IT_PATTERN *pattern, const unsigned char *data, int length, int n_channels)
{
int pos;
int channel;
int row;
int n_rows;
IT_ENTRY *entry;
n_rows = (data[0] << 8) | data[1];
if (!n_rows)
n_rows = 64;
if (length < 2) return -1;
if (length < 2 + (n_rows * n_channels * 4))
return -1;
n_rows = (data[0] << 8) | data[1];
if (!n_rows) n_rows = 64;
pattern->n_rows = n_rows;
if (length < 2 + (n_rows * n_channels * 4)) return -1;
/* compute number of entries */
pattern->n_entries = n_rows; /* Account for the row end markers */
pos = 2;
for (row = 0; row < pattern->n_rows; row++) {
for (channel = 0; channel < n_channels; channel++) {
if (data[pos + 0] | data[pos + 2])
pattern->n_entries++;
pos += 4;
}
}
pattern->n_rows = n_rows;
pattern->entry =
(IT_ENTRY *)malloc(pattern->n_entries * sizeof(*pattern->entry));
if (!pattern->entry)
return -1;
/* compute number of entries */
pattern->n_entries = n_rows; /* Account for the row end markers */
pos = 2;
for (row = 0; row < pattern->n_rows; row++) {
for (channel = 0; channel < n_channels; channel++) {
if (data[pos+0] | data[pos+2])
pattern->n_entries++;
pos += 4;
}
}
entry = pattern->entry;
pos = 2;
for (row = 0; row < n_rows; row++) {
for (channel = 0; channel < n_channels; channel++) {
if (data[pos + 0] | data[pos + 2]) {
entry->channel = channel;
entry->mask = 0;
pattern->entry = (IT_ENTRY *) malloc(pattern->n_entries * sizeof(*pattern->entry));
if (!pattern->entry)
return -1;
if (data[pos + 0] > 0 && data[pos + 0] <= 36) {
entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT;
entry = pattern->entry;
pos = 2;
for (row = 0; row < n_rows; row++) {
for (channel = 0; channel < n_channels; channel++) {
if (data[pos+0] | data[pos+2]) {
entry->channel = channel;
entry->mask = 0;
entry->note = data[pos + 0] + 35;
entry->instrument = data[pos + 1] + 1;
}
if (data[pos+0] > 0 && data[pos+0] <= 36) {
entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT;
entry->effect = 0;
entry->effectvalue = data[pos + 3];
entry->note = data[pos+0] + 35;
entry->instrument = data[pos+1] + 1;
}
switch (data[pos + 2]) {
case 2:
if (data[pos + 3])
entry->effect = IT_PORTAMENTO_DOWN;
break; // XXX code calls this rs_portu, but it's adding to
// the period, which decreases the pitch
case 13:
if (data[pos + 3])
entry->effect = IT_OKT_NOTE_SLIDE_DOWN;
break;
case 21:
if (data[pos + 3])
entry->effect = IT_OKT_NOTE_SLIDE_DOWN_ROW;
break;
entry->effect = 0;
entry->effectvalue = data[pos+3];
case 1:
if (data[pos + 3])
entry->effect = IT_PORTAMENTO_UP;
break; // XXX same deal here, increasing the pitch
case 17:
if (data[pos + 3])
entry->effect = IT_OKT_NOTE_SLIDE_UP;
break;
case 30:
if (data[pos + 3])
entry->effect = IT_OKT_NOTE_SLIDE_UP_ROW;
break;
switch (data[pos+2]) {
case 2: if (data[pos+3]) entry->effect = IT_PORTAMENTO_DOWN; break; // XXX code calls this rs_portu, but it's adding to the period, which decreases the pitch
case 13: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_DOWN; break;
case 21: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_DOWN_ROW; break;
case 10:
if (data[pos + 3])
entry->effect = IT_OKT_ARPEGGIO_3;
break;
case 11:
if (data[pos + 3])
entry->effect = IT_OKT_ARPEGGIO_4;
break;
case 12:
if (data[pos + 3])
entry->effect = IT_OKT_ARPEGGIO_5;
break;
case 1: if (data[pos+3]) entry->effect = IT_PORTAMENTO_UP; break; // XXX same deal here, increasing the pitch
case 17: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_UP; break;
case 30: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_UP_ROW; break;
case 15:
entry->effect = IT_S;
entry->effectvalue =
EFFECT_VALUE(IT_S_SET_FILTER, data[pos + 3] & 0x0F);
break;
case 10: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_3; break;
case 11: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_4; break;
case 12: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_5; break;
case 25:
entry->effect = IT_JUMP_TO_ORDER;
break;
case 15: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_SET_FILTER, data[pos+3] & 0x0F); break;
case 27:
entry->note = IT_NOTE_OFF;
entry->mask |= IT_ENTRY_NOTE;
break;
case 25: entry->effect = IT_JUMP_TO_ORDER; break;
case 28:
entry->effect = IT_SET_SPEED;
break;
case 27: entry->note = IT_NOTE_OFF; entry->mask |= IT_ENTRY_NOTE; break;
case 31:
if (data[pos + 3] <= 0x40)
entry->effect = IT_SET_CHANNEL_VOLUME;
else if (data[pos + 3] <= 0x50) {
entry->effect = IT_OKT_VOLUME_SLIDE_DOWN;
entry->effectvalue = data[pos + 3] - 0x40;
} else if (data[pos + 3] <= 0x60) {
entry->effect = IT_OKT_VOLUME_SLIDE_UP;
entry->effectvalue = data[pos + 3] - 0x50;
} else if (data[pos + 3] <= 0x70) {
entry->effect = IT_OKT_VOLUME_SLIDE_DOWN;
entry->effectvalue = data[pos + 3] - 0x50;
} else if (data[pos + 3] <= 0x80) {
entry->effect = IT_OKT_VOLUME_SLIDE_UP;
entry->effectvalue = data[pos + 3] - 0x60;
}
break;
}
case 28: entry->effect = IT_SET_SPEED; break;
if (entry->effect)
entry->mask |= IT_ENTRY_EFFECT;
case 31:
if ( data[pos+3] <= 0x40 ) entry->effect = IT_SET_CHANNEL_VOLUME;
else if ( data[pos+3] <= 0x50 ) { entry->effect = IT_OKT_VOLUME_SLIDE_DOWN; entry->effectvalue = data[pos+3] - 0x40; }
else if ( data[pos+3] <= 0x60 ) { entry->effect = IT_OKT_VOLUME_SLIDE_UP; entry->effectvalue = data[pos+3] - 0x50; }
else if ( data[pos+3] <= 0x70 ) { entry->effect = IT_OKT_VOLUME_SLIDE_DOWN; entry->effectvalue = data[pos+3] - 0x50; }
else if ( data[pos+3] <= 0x80 ) { entry->effect = IT_OKT_VOLUME_SLIDE_UP; entry->effectvalue = data[pos+3] - 0x60; }
break;
}
entry++;
}
pos += 4;
}
IT_SET_END_ROW(entry);
entry++;
}
if ( entry->effect ) entry->mask |= IT_ENTRY_EFFECT;
entry++;
}
pos += 4;
}
IT_SET_END_ROW(entry);
entry++;
}
return 0;
return 0;
}
static void it_okt_read_sample_header(IT_SAMPLE *sample,
const unsigned char *data) {
int loop_start, loop_length;
memcpy(sample->name, data, 20);
sample->name[20] = 0;
static void it_okt_read_sample_header(IT_SAMPLE *sample, const unsigned char * data)
{
int loop_start, loop_length;
sample->filename[0] = 0;
memcpy(sample->name, data, 20);
sample->name[20] = 0;
sample->length =
(data[20] << 24) | (data[21] << 16) | (data[22] << 8) | data[23];
sample->global_volume = 64;
sample->default_volume = data[29];
loop_start = ((data[24] << 8) | data[25]) << 1;
loop_length = ((data[26] << 8) | data[27]) << 1;
sample->sus_loop_start = loop_start;
sample->sus_loop_end = loop_start + loop_length;
sample->filename[0] = 0;
if (sample->length <= 0) {
sample->flags = 0;
return;
}
sample->length = (data[20] << 24) | (data[21] << 16) | (data[22] << 8) | data[23];
sample->global_volume = 64;
sample->default_volume = data[29];
loop_start = ((data[24] << 8) | data[25]) << 1;
loop_length = ((data[26] << 8) | data[27]) << 1;
sample->sus_loop_start = loop_start;
sample->sus_loop_end = loop_start + loop_length;
sample->flags = IT_SAMPLE_EXISTS;
if (sample->length <= 0) {
sample->flags = 0;
return;
}
sample->default_pan = 0;
sample->C5_speed =
(int)(AMIGA_CLOCK /
214.0); //(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
sample->finetune = 0;
sample->flags = IT_SAMPLE_EXISTS;
if (sample->sus_loop_end > sample->length)
sample->sus_loop_end = sample->length;
sample->default_pan = 0;
sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 ); //(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
sample->finetune = 0;
if (loop_length > 2)
sample->flags |= IT_SAMPLE_SUS_LOOP;
if (sample->sus_loop_end > sample->length)
sample->sus_loop_end = sample->length;
if (loop_length > 2)
sample->flags |= IT_SAMPLE_SUS_LOOP;
sample->vibrato_speed = 0;
sample->vibrato_depth = 0;
sample->vibrato_rate = 0;
sample->vibrato_waveform = 0; // do we have to set _all_ these?
sample->max_resampling_quality = -1;
sample->vibrato_speed = 0;
sample->vibrato_depth = 0;
sample->vibrato_rate = 0;
sample->vibrato_waveform = 0; // do we have to set _all_ these?
sample->max_resampling_quality = -1;
}
static int it_okt_read_sample_data(IT_SAMPLE *sample, const char *data,
int length) {
if (length && sample->length) {
if (length < sample->length) {
sample->length = length;
if (length < sample->sus_loop_end)
sample->sus_loop_end = length;
}
sample->data = malloc(length);
static int it_okt_read_sample_data(IT_SAMPLE *sample, const char * data, int length)
{
if (length && sample->length) {
if (length < sample->length) {
sample->length = length;
if (length < sample->sus_loop_end) sample->sus_loop_end = length;
}
if (!sample->data)
return -1;
sample->data = malloc(length);
memcpy(sample->data, data, length);
}
if (!sample->data)
return -1;
memcpy(sample->data, data, length);
}
return 0;
return 0;
}
typedef struct IFF_CHUNK IFF_CHUNK;
typedef struct IFF_CHUNKED IFF_CHUNKED;
struct IFF_CHUNK
{
unsigned type;
unsigned char * data;
unsigned size;
struct IFF_CHUNK {
unsigned type;
unsigned char *data;
unsigned size;
};
struct IFF_CHUNKED
{
unsigned chunk_count;
IFF_CHUNK * chunks;
struct IFF_CHUNKED {
unsigned chunk_count;
IFF_CHUNK *chunks;
};
static IFF_CHUNKED *dumbfile_read_okt(DUMBFILE *f) {
IFF_CHUNKED *mod = (IFF_CHUNKED *)malloc(sizeof(*mod));
if (!mod)
return NULL;
mod->chunk_count = 0;
mod->chunks = 0;
static IFF_CHUNKED *dumbfile_read_okt(DUMBFILE *f)
{
IFF_CHUNKED *mod = (IFF_CHUNKED *) malloc(sizeof(*mod));
if (!mod) return NULL;
for (;;) {
long bytes_read;
IFF_CHUNK *chunk = (IFF_CHUNK *)realloc(
mod->chunks, (mod->chunk_count + 1) * sizeof(IFF_CHUNK));
if (!chunk) {
if (mod->chunks)
free(mod->chunks);
free(mod);
return NULL;
}
mod->chunks = chunk;
chunk += mod->chunk_count;
mod->chunk_count = 0;
mod->chunks = 0;
bytes_read = dumbfile_mgetl(f);
if (bytes_read < 0)
break;
for (;;)
{
long bytes_read;
IFF_CHUNK * chunk = ( IFF_CHUNK * ) realloc( mod->chunks, ( mod->chunk_count + 1 ) * sizeof( IFF_CHUNK ) );
if ( !chunk )
{
if ( mod->chunks ) free( mod->chunks );
free( mod );
return NULL;
}
mod->chunks = chunk;
chunk += mod->chunk_count;
chunk->type = (unsigned int)bytes_read;
chunk->size = (unsigned int)dumbfile_mgetl(f);
bytes_read = dumbfile_mgetl( f );
if ( bytes_read < 0 ) break;
if (dumbfile_error(f))
break;
chunk->type = bytes_read;
chunk->size = dumbfile_mgetl( f );
chunk->data = (unsigned char *)malloc(chunk->size);
if (!chunk->data) {
free(mod->chunks);
free(mod);
return NULL;
}
if ( dumbfile_error( f ) ) break;
bytes_read = dumbfile_getnc((char *)chunk->data, chunk->size, f);
if (bytes_read < chunk->size) {
if (bytes_read <= 0) {
free(chunk->data);
break;
} else {
chunk->size = (unsigned int)bytes_read;
mod->chunk_count++;
break;
}
}
chunk->data = (unsigned char *) malloc( chunk->size );
if ( !chunk->data )
{
free( mod->chunks );
free( mod );
return NULL;
}
mod->chunk_count++;
}
bytes_read = dumbfile_getnc( ( char * ) chunk->data, chunk->size, f );
if ( bytes_read < chunk->size )
{
if ( bytes_read <= 0 ) {
free( chunk->data );
break;
} else {
chunk->size = bytes_read;
mod->chunk_count++;
break;
}
}
if (!mod->chunk_count) {
if (mod->chunks)
free(mod->chunks);
free(mod);
mod = NULL;
}
mod->chunk_count++;
}
if ( !mod->chunk_count ) {
if ( mod->chunks ) free(mod->chunks);
free(mod);
mod = NULL;
}
return mod;
return mod;
}
void free_okt(IFF_CHUNKED * mod)
{
unsigned i;
if (mod)
{
if (mod->chunks)
{
for (i = 0; i < mod->chunk_count; i++)
{
if (mod->chunks[i].data) free(mod->chunks[i].data);
}
free(mod->chunks);
}
free(mod);
}
void free_okt(IFF_CHUNKED *mod) {
unsigned i;
if (mod) {
if (mod->chunks) {
for (i = 0; i < mod->chunk_count; i++) {
if (mod->chunks[i].data)
free(mod->chunks[i].data);
}
free(mod->chunks);
}
free(mod);
}
}
const IFF_CHUNK * get_chunk_by_type(IFF_CHUNKED * mod, unsigned type, unsigned offset)
{
unsigned i;
if (mod)
{
if (mod->chunks)
{
for (i = 0; i < mod->chunk_count; i++)
{
if (mod->chunks[i].type == type)
{
if (!offset) return &mod->chunks[i];
else offset--;
}
}
}
}
return NULL;
const IFF_CHUNK *get_chunk_by_type(IFF_CHUNKED *mod, unsigned type,
unsigned offset) {
unsigned i;
if (mod) {
if (mod->chunks) {
for (i = 0; i < mod->chunk_count; i++) {
if (mod->chunks[i].type == type) {
if (!offset)
return &mod->chunks[i];
else
offset--;
}
}
}
}
return NULL;
}
unsigned get_chunk_count(IFF_CHUNKED *mod, unsigned type)
{
unsigned i, count = 0;
if (mod)
{
if (mod->chunks)
{
for (i = 0; i < mod->chunk_count; i++)
{
if (mod->chunks[i].type == type) count++;
}
}
}
return count;
unsigned get_chunk_count(IFF_CHUNKED *mod, unsigned type) {
unsigned i, count = 0;
if (mod) {
if (mod->chunks) {
for (i = 0; i < mod->chunk_count; i++) {
if (mod->chunks[i].type == type)
count++;
}
}
}
return count;
}
static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f)
{
DUMB_IT_SIGDATA *sigdata;
static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f) {
DUMB_IT_SIGDATA *sigdata;
int n_channels;
int i, j, k, l;
IFF_CHUNKED *mod;
const IFF_CHUNK *chunk;
IFF_CHUNKED *mod;
const IFF_CHUNK *chunk;
char signature[8];
char signature[8];
if (dumbfile_getnc(signature, 8, f) < 8 ||
memcmp(signature, "OKTASONG", 8)) {
return NULL;
}
if (dumbfile_getnc(signature, 8, f) < 8 ||
memcmp(signature, "OKTASONG", 8)) {
return NULL;
}
mod = dumbfile_read_okt(f);
if (!mod)
return NULL;
mod = dumbfile_read_okt(f);
if (!mod)
return NULL;
sigdata = (DUMB_IT_SIGDATA *) malloc(sizeof(*sigdata));
if (!sigdata) {
free_okt(mod);
return NULL;
}
sigdata = (DUMB_IT_SIGDATA *)malloc(sizeof(*sigdata));
if (!sigdata) {
free_okt(mod);
return NULL;
}
sigdata->name[0] = 0;
sigdata->name[0] = 0;
chunk = get_chunk_by_type(mod, DUMB_ID('S','P','E','E'), 0);
if (!chunk || chunk->size < 2) {
free(sigdata);
free_okt(mod);
return NULL;
}
chunk = get_chunk_by_type(mod, DUMB_ID('S', 'P', 'E', 'E'), 0);
if (!chunk || chunk->size < 2) {
free(sigdata);
free_okt(mod);
return NULL;
}
sigdata->speed = (chunk->data[0] << 8) | chunk->data[1];
sigdata->speed = (chunk->data[0] << 8) | chunk->data[1];
chunk = get_chunk_by_type(mod, DUMB_ID('S','A','M','P'), 0);
if (!chunk || chunk->size < 32) {
free(sigdata);
free_okt(mod);
return NULL;
}
chunk = get_chunk_by_type(mod, DUMB_ID('S', 'A', 'M', 'P'), 0);
if (!chunk || chunk->size < 32) {
free(sigdata);
free_okt(mod);
return NULL;
}
sigdata->n_samples = chunk->size / 32;
sigdata->n_samples = chunk->size / 32;
chunk = get_chunk_by_type(mod, DUMB_ID('C','M','O','D'), 0);
if (!chunk || chunk->size < 8) {
free(sigdata);
free_okt(mod);
return NULL;
}
chunk = get_chunk_by_type(mod, DUMB_ID('C', 'M', 'O', 'D'), 0);
if (!chunk || chunk->size < 8) {
free(sigdata);
free_okt(mod);
return NULL;
}
n_channels = 0;
n_channels = 0;
for (i = 0; i < 4; i++) {
j = (chunk->data[i * 2] << 8) | chunk->data[i * 2 + 1];
if (!j) n_channels++;
else if (j == 1) n_channels += 2;
}
for (i = 0; i < 4; i++) {
j = (chunk->data[i * 2] << 8) | chunk->data[i * 2 + 1];
if (!j)
n_channels++;
else if (j == 1)
n_channels += 2;
}
if (!n_channels) {
free(sigdata);
free_okt(mod);
return NULL;
}
if (!n_channels) {
free(sigdata);
free_okt(mod);
return NULL;
}
sigdata->n_pchannels = n_channels;
sigdata->n_pchannels = n_channels;
sigdata->sample = (IT_SAMPLE *) malloc(sigdata->n_samples * sizeof(*sigdata->sample));
if (!sigdata->sample) {
free(sigdata);
free_okt(mod);
return NULL;
}
sigdata->sample =
(IT_SAMPLE *)malloc(sigdata->n_samples * sizeof(*sigdata->sample));
if (!sigdata->sample) {
free(sigdata);
free_okt(mod);
return NULL;
}
sigdata->song_message = NULL;
sigdata->order = NULL;
sigdata->instrument = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
sigdata->song_message = NULL;
sigdata->order = NULL;
sigdata->instrument = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
sigdata->n_instruments = 0;
sigdata->n_instruments = 0;
for (i = 0; i < sigdata->n_samples; i++)
sigdata->sample[i].data = NULL;
for (i = 0; i < sigdata->n_samples; i++)
sigdata->sample[i].data = NULL;
chunk = get_chunk_by_type(mod, DUMB_ID('S','A','M','P'), 0);
chunk = get_chunk_by_type(mod, DUMB_ID('S', 'A', 'M', 'P'), 0);
for (i = 0; i < sigdata->n_samples; i++) {
it_okt_read_sample_header(&sigdata->sample[i], chunk->data + 32 * i);
}
for (i = 0; i < sigdata->n_samples; i++) {
it_okt_read_sample_header(&sigdata->sample[i], chunk->data + 32 * i);
}
sigdata->restart_position = 0;
sigdata->restart_position = 0;
chunk = get_chunk_by_type(mod, DUMB_ID('P','L','E','N'), 0);
if (!chunk || chunk->size < 2) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
chunk = get_chunk_by_type(mod, DUMB_ID('P', 'L', 'E', 'N'), 0);
if (!chunk || chunk->size < 2) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
sigdata->n_orders = (chunk->data[0] << 8) | chunk->data[1];
// what if this is > 128?
sigdata->n_orders = (chunk->data[0] << 8) | chunk->data[1];
// what if this is > 128?
if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
chunk = get_chunk_by_type(mod, DUMB_ID('P','A','T','T'), 0);
chunk = get_chunk_by_type(mod, DUMB_ID('P', 'A', 'T', 'T'), 0);
if (!chunk || chunk->size < (unsigned)sigdata->n_orders) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
sigdata->order = (unsigned char *) malloc(sigdata->n_orders);
if (!sigdata->order) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
sigdata->order = (unsigned char *)malloc(sigdata->n_orders);
if (!sigdata->order) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
memcpy(sigdata->order, chunk->data, sigdata->n_orders);
memcpy(sigdata->order, chunk->data, sigdata->n_orders);
/* Work out how many patterns there are. */
chunk = get_chunk_by_type(mod, DUMB_ID('S','L','E','N'), 0);
if (!chunk || chunk->size < 2) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
/* Work out how many patterns there are. */
chunk = get_chunk_by_type(mod, DUMB_ID('S', 'L', 'E', 'N'), 0);
if (!chunk || chunk->size < 2) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
sigdata->n_patterns = (chunk->data[0] << 8) | chunk->data[1];
sigdata->n_patterns = (chunk->data[0] << 8) | chunk->data[1];
j = get_chunk_count(mod, DUMB_ID('P','B','O','D'));
if (sigdata->n_patterns > j) sigdata->n_patterns = j;
j = get_chunk_count(mod, DUMB_ID('P', 'B', 'O', 'D'));
if (sigdata->n_patterns > j)
sigdata->n_patterns = j;
if (!sigdata->n_patterns) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
if (!sigdata->n_patterns) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
sigdata->pattern = (IT_PATTERN *) malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
if (!sigdata->pattern) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
for (i = 0; i < sigdata->n_patterns; i++)
sigdata->pattern[i].entry = NULL;
sigdata->pattern =
(IT_PATTERN *)malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
if (!sigdata->pattern) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
for (i = 0; i < sigdata->n_patterns; i++)
sigdata->pattern[i].entry = NULL;
/* Read in the patterns */
for (i = 0; i < sigdata->n_patterns; i++) {
chunk = get_chunk_by_type(mod, DUMB_ID('P','B','O','D'), i);
if (it_okt_read_pattern(&sigdata->pattern[i], chunk->data, chunk->size, n_channels) != 0) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
}
/* Read in the patterns */
for (i = 0; i < sigdata->n_patterns; i++) {
chunk = get_chunk_by_type(mod, DUMB_ID('P', 'B', 'O', 'D'), i);
if (it_okt_read_pattern(&sigdata->pattern[i], chunk->data, chunk->size,
n_channels) != 0) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
}
/* And finally, the sample data */
k = get_chunk_count(mod, DUMB_ID('S','B','O','D'));
for (i = 0, j = 0; i < sigdata->n_samples && j < k; i++) {
if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) {
chunk = get_chunk_by_type(mod, DUMB_ID('S','B','O','D'), j);
if (it_okt_read_sample_data(&sigdata->sample[i], (const char *)chunk->data, chunk->size)) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
j++;
}
}
for (; i < sigdata->n_samples; i++) {
sigdata->sample[i].flags = 0;
}
/* And finally, the sample data */
k = get_chunk_count(mod, DUMB_ID('S', 'B', 'O', 'D'));
for (i = 0, j = 0; i < sigdata->n_samples && j < k; i++) {
if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) {
chunk = get_chunk_by_type(mod, DUMB_ID('S', 'B', 'O', 'D'), j);
if (it_okt_read_sample_data(&sigdata->sample[i],
(const char *)chunk->data,
chunk->size)) {
_dumb_it_unload_sigdata(sigdata);
free_okt(mod);
return NULL;
}
j++;
}
}
for (; i < sigdata->n_samples; i++) {
sigdata->sample[i].flags = 0;
}
chunk = get_chunk_by_type(mod, DUMB_ID('C','M','O','D'), 0);
chunk = get_chunk_by_type(mod, DUMB_ID('C', 'M', 'O', 'D'), 0);
for (i = 0, j = 0; i < n_channels && j < 4; j++) {
k = (chunk->data[j * 2] << 8) | chunk->data[j * 2 + 1];
l = (j == 1 || j == 2) ? 48 : 16;
if (k == 0) {
sigdata->channel_pan[i++] = l;
}
else if (k == 1) {
sigdata->channel_pan[i++] = l;
sigdata->channel_pan[i++] = l;
}
}
for (i = 0, j = 0; i < n_channels && j < 4; j++) {
k = (chunk->data[j * 2] << 8) | chunk->data[j * 2 + 1];
l = (j == 1 || j == 2) ? 48 : 16;
if (k == 0) {
sigdata->channel_pan[i++] = l;
} else if (k == 1) {
sigdata->channel_pan[i++] = l;
sigdata->channel_pan[i++] = l;
}
}
free_okt(mod);
free_okt(mod);
/* Now let's initialise the remaining variables, and we're done! */
sigdata->flags = IT_WAS_AN_OKT | IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
/* Now let's initialise the remaining variables, and we're done! */
sigdata->flags = IT_WAS_AN_OKT | IT_WAS_AN_XM | IT_WAS_A_MOD |
IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
sigdata->global_volume = 128;
sigdata->mixing_volume = 48;
/* We want 50 ticks per second; 50/6 row advances per second;
* 50*10=500 row advances per minute; 500/4=125 beats per minute.
*/
sigdata->tempo = 125;
sigdata->pan_separation = 128;
sigdata->global_volume = 128;
sigdata->mixing_volume = 48;
/* We want 50 ticks per second; 50/6 row advances per second;
* 50*10=500 row advances per minute; 500/4=125 beats per minute.
*/
sigdata->tempo = 125;
sigdata->pan_separation = 128;
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
memset(sigdata->channel_pan + n_channels, 32, DUMB_IT_N_CHANNELS - n_channels);
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
memset(sigdata->channel_pan + n_channels, 32,
DUMB_IT_N_CHANNELS - n_channels);
_dumb_it_fix_invalid_orders(sigdata);
_dumb_it_fix_invalid_orders(sigdata);
return sigdata;
return sigdata;
}
DUH *dumb_read_okt_quick(DUMBFILE *f) {
sigdata_t *sigdata;
DUH *dumb_read_okt_quick(DUMBFILE *f)
{
sigdata_t *sigdata;
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
sigdata = it_okt_load_sigdata(f);
if (!sigdata)
return NULL;
if (!sigdata)
return NULL;
{
const char *tag[1][2];
tag[0][0] = "FORMAT";
tag[0][1] = "Oktalyzer";
return make_duh(-1, 1, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
}
{
const char *tag[1][2];
tag[0][0] = "FORMAT";
tag[0][1] = "Oktalyzer";
return make_duh(-1, 1, (const char *const(*)[2])tag, 1, &descptr,
&sigdata);
}
}

View file

@ -19,11 +19,8 @@
#include "dumb.h"
DUH *dumb_read_okt(DUMBFILE *f)
{
DUH *duh = dumb_read_okt_quick(f);
dumb_it_do_initial_runthrough(duh);
return duh;
DUH *dumb_read_okt(DUMBFILE *f) {
DUH *duh = dumb_read_okt_quick(f);
dumb_it_do_initial_runthrough(duh);
return duh;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -24,531 +24,538 @@
#include "dumb.h"
#include "internal/it.h"
static int it_ptm_read_sample_header(IT_SAMPLE *sample, long *offset,
DUMBFILE *f) {
int flags;
static int it_ptm_read_sample_header(IT_SAMPLE *sample, long *offset, DUMBFILE *f)
{
int flags;
flags = dumbfile_getc(f);
flags = dumbfile_getc(f);
dumbfile_getnc((char *)sample->filename, 12, f);
sample->filename[12] = 0;
sample->filename[12] = 0;
sample->default_volume = dumbfile_getc(f);
sample->default_volume = dumbfile_getc(f);
sample->C5_speed = dumbfile_igetw(f) << 1;
sample->C5_speed = dumbfile_igetw(f) << 1;
dumbfile_skip(f, 2); /* segment */
dumbfile_skip(f, 2); /* segment */
*offset = dumbfile_igetl(f);
*offset = dumbfile_igetl(f);
sample->length = dumbfile_igetl(f);
sample->loop_start = dumbfile_igetl(f);
sample->loop_end = dumbfile_igetl(f);
sample->length = dumbfile_igetl(f);
sample->loop_start = dumbfile_igetl(f);
sample->loop_end = dumbfile_igetl(f);
/* GUSBegin, GUSLStart, GUSLEnd, GUSLoop, reserverd */
dumbfile_skip(f, 4+4+4+1+1);
/* GUSBegin, GUSLStart, GUSLEnd, GUSLoop, reserverd */
dumbfile_skip(f, 4 + 4 + 4 + 1 + 1);
dumbfile_getnc((char *)sample->name, 28, f);
sample->name[28] = 0;
sample->name[28] = 0;
/*
if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','S'))
return -1;
*/
/*
if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','S'))
return -1;
*/
/* BLAH! Shit likes to have broken or missing sample IDs */
dumbfile_skip(f, 4);
/* BLAH! Shit likes to have broken or missing sample IDs */
dumbfile_skip(f, 4);
if ((flags & 3) == 0) {
/* Looks like no sample */
sample->flags &= ~IT_SAMPLE_EXISTS;
return dumbfile_error(f);
}
if ((flags & 3) == 0) {
/* Looks like no sample */
sample->flags &= ~IT_SAMPLE_EXISTS;
return dumbfile_error(f);
}
sample->global_volume = 64;
sample->global_volume = 64;
sample->flags = IT_SAMPLE_EXISTS;
if (flags & 4) sample->flags |= IT_SAMPLE_LOOP;
if (flags & 8) sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
sample->flags = IT_SAMPLE_EXISTS;
if (flags & 4)
sample->flags |= IT_SAMPLE_LOOP;
if (flags & 8)
sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
if (flags & 16) {
sample->flags |= IT_SAMPLE_16BIT;
if (flags & 16) {
sample->flags |= IT_SAMPLE_16BIT;
sample->length >>= 1;
sample->loop_start >>= 1;
sample->loop_end >>= 1;
}
sample->length >>= 1;
sample->loop_start >>= 1;
sample->loop_end >>= 1;
}
if (sample->loop_end) sample->loop_end--;
if (sample->loop_end)
sample->loop_end--;
sample->default_pan = 0; // 0 = don't use, or 160 = centre?
sample->default_pan = 0; // 0 = don't use, or 160 = centre?
if (sample->length <= 0)
sample->flags &= ~IT_SAMPLE_EXISTS;
else if (sample->flags & IT_SAMPLE_LOOP) {
if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
sample->flags &= ~IT_SAMPLE_LOOP;
else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
sample->flags &= ~IT_SAMPLE_LOOP;
else
sample->length = sample->loop_end;
}
if (sample->length <= 0)
sample->flags &= ~IT_SAMPLE_EXISTS;
else if (sample->flags & IT_SAMPLE_LOOP) {
if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
sample->flags &= ~IT_SAMPLE_LOOP;
else if ((unsigned int)sample->loop_start >=
(unsigned int)sample->loop_end)
sample->flags &= ~IT_SAMPLE_LOOP;
else
sample->length = sample->loop_end;
}
// Do we need to set all these?
sample->vibrato_speed = 0;
sample->vibrato_depth = 0;
sample->vibrato_rate = 0;
sample->vibrato_waveform = IT_VIBRATO_SINE;
sample->finetune = 0;
sample->max_resampling_quality = -1;
//Do we need to set all these?
sample->vibrato_speed = 0;
sample->vibrato_depth = 0;
sample->vibrato_rate = 0;
sample->vibrato_waveform = IT_VIBRATO_SINE;
sample->finetune = 0;
sample->max_resampling_quality = -1;
return dumbfile_error(f);
return dumbfile_error(f);
}
static int it_ptm_read_byte(DUMBFILE *f)
{
int meh = dumbfile_getc(f);
if (meh < 0) return 0;
return meh;
static int it_ptm_read_byte(DUMBFILE *f) {
int meh = dumbfile_getc(f);
if (meh < 0)
return 0;
return meh;
}
static int it_ptm_read_sample_data(IT_SAMPLE *sample, int last, DUMBFILE *f)
{
long n;
int s;
static int it_ptm_read_sample_data(IT_SAMPLE *sample, int last, DUMBFILE *f) {
long n;
int s;
sample->data = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
if (!sample->data)
return -1;
sample->data =
malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
if (!sample->data)
return -1;
s = 0;
s = 0;
if (sample->flags & IT_SAMPLE_16BIT) {
unsigned char a, b;
for (n = 0; n < sample->length; n++) {
a = s += (signed char) it_ptm_read_byte(f);
b = s += (signed char) it_ptm_read_byte(f);
((short *)sample->data)[n] = a | (b << 8);
}
} else {
for (n = 0; n < sample->length; n++) {
s += (signed char) it_ptm_read_byte(f);
((signed char *)sample->data)[n] = s;
}
}
if (sample->flags & IT_SAMPLE_16BIT) {
unsigned char a, b;
for (n = 0; n < sample->length; n++) {
a = s += (signed char)it_ptm_read_byte(f);
b = s += (signed char)it_ptm_read_byte(f);
((short *)sample->data)[n] = a | (b << 8);
}
} else {
for (n = 0; n < sample->length; n++) {
s += (signed char)it_ptm_read_byte(f);
((signed char *)sample->data)[n] = s;
}
}
if (dumbfile_error(f) && !last)
return -1;
if (dumbfile_error(f) && !last)
return -1;
return 0;
return 0;
}
static int it_ptm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f,
unsigned char *buffer, size_t length) {
int buflen = 0;
int bufpos = 0;
int effect, effectvalue;
IT_ENTRY *entry;
static int it_ptm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int length)
{
int buflen = 0;
int bufpos = 0;
int effect, effectvalue;
unsigned char channel;
IT_ENTRY *entry;
if (!length)
return -1;
unsigned char channel;
pattern->n_rows = 0;
pattern->n_entries = 0;
if (!length)
return -1;
pattern->n_rows = 0;
pattern->n_entries = 0;
/* Read in the pattern data, little by little, and work out how many
* entries we need room for. Sorry, but this is just so funny...
*/
for (;;) {
unsigned char b = buffer[buflen++] = dumbfile_getc(f);
/* Read in the pattern data, little by little, and work out how many
* entries we need room for. Sorry, but this is just so funny...
*/
for (;;) {
unsigned char b = buffer[buflen++] = dumbfile_getc(f);
#if 1
static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5};
channel = b & 31;
b >>= 5;
pattern->n_entries++;
if (b) {
if (buflen + used[b] >= 65536) return -1;
static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5};
channel = b & 31;
b >>= 5;
pattern->n_entries++;
if (b) {
if (buflen + used[b] >= 65536)
return -1;
dumbfile_getnc((char *)buffer + buflen, used[b], f);
buflen += used[b];
} else {
/* End of row */
if (++pattern->n_rows == 64) break;
if (buflen >= 65536) return -1;
}
buflen += used[b];
} else {
/* End of row */
if (++pattern->n_rows == 64)
break;
if (buflen >= 65536)
return -1;
}
#else
if (b == 0) {
/* End of row */
pattern->n_entries++;
if (++pattern->n_rows == 64) break;
if (buflen >= 65536) return -1;
} else {
static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5};
channel = b & 31;
b >>= 5;
if (b) {
pattern->n_entries++;
if (buflen + used[b] >= 65536) return -1;
dumbfile_getnc(buffer + buflen, used[b], f);
buflen += used[b];
}
}
if (b == 0) {
/* End of row */
pattern->n_entries++;
if (++pattern->n_rows == 64)
break;
if (buflen >= 65536)
return -1;
} else {
static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5};
channel = b & 31;
b >>= 5;
if (b) {
pattern->n_entries++;
if (buflen + used[b] >= 65536)
return -1;
dumbfile_getnc(buffer + buflen, used[b], f);
buflen += used[b];
}
}
#endif
/* We have ensured that buflen < 65536 at this point, so it is safe
* to iterate and read at least one more byte without checking.
* However, now would be a good time to check for errors reading from
* the file.
*/
/* We have ensured that buflen < 65536 at this point, so it is safe
* to iterate and read at least one more byte without checking.
* However, now would be a good time to check for errors reading from
* the file.
*/
if (dumbfile_error(f))
return -1;
if (dumbfile_error(f))
return -1;
/* Great. We ran out of data, but there should be data for more rows.
* Fill the rest with null data...
*/
if (buflen >= length && pattern->n_rows < 64)
{
while (pattern->n_rows < 64)
{
if (buflen >= 65536) return -1;
buffer[buflen++] = 0;
pattern->n_entries++;
pattern->n_rows++;
}
break;
}
}
/* Great. We ran out of data, but there should be data for more rows.
* Fill the rest with null data...
*/
if (buflen >= (dumb_ssize_t)length && pattern->n_rows < 64) {
while (pattern->n_rows < 64) {
if (buflen >= 65536)
return -1;
buffer[buflen++] = 0;
pattern->n_entries++;
pattern->n_rows++;
}
break;
}
}
pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
if (!pattern->entry)
return -1;
if (!pattern->entry)
return -1;
entry = pattern->entry;
entry = pattern->entry;
while (bufpos < buflen) {
unsigned char b = buffer[bufpos++];
while (bufpos < buflen) {
unsigned char b = buffer[bufpos++];
if (b == 0)
{
/* End of row */
IT_SET_END_ROW(entry);
entry++;
continue;
}
if (b == 0) {
/* End of row */
IT_SET_END_ROW(entry);
entry++;
continue;
}
channel = b & 31;
channel = b & 31;
if (b & 224) {
entry->mask = 0;
entry->channel = channel;
if (b & 224) {
entry->mask = 0;
entry->channel = channel;
if (b & 32) {
unsigned char n = buffer[bufpos++];
if (n == 254 || (n >= 1 && n <= 120)) {
if (n == 254)
entry->note = IT_NOTE_CUT;
else
entry->note = n - 1;
entry->mask |= IT_ENTRY_NOTE;
}
if (b & 32) {
unsigned char n = buffer[bufpos++];
if (n == 254 || (n >= 1 && n <= 120)) {
if (n == 254)
entry->note = IT_NOTE_CUT;
else
entry->note = n - 1;
entry->mask |= IT_ENTRY_NOTE;
}
entry->instrument = buffer[bufpos++];
if (entry->instrument)
entry->mask |= IT_ENTRY_INSTRUMENT;
}
entry->instrument = buffer[bufpos++];
if (entry->instrument)
entry->mask |= IT_ENTRY_INSTRUMENT;
}
if (b & 64) {
effect = buffer[bufpos++];
effectvalue = buffer[bufpos++];
_dumb_it_ptm_convert_effect(effect, effectvalue, entry);
}
if (b & 64) {
effect = buffer[bufpos++];
effectvalue = buffer[bufpos++];
_dumb_it_ptm_convert_effect(effect, effectvalue, entry);
}
if (b & 128) {
entry->volpan = buffer[bufpos++];
if (entry->volpan <= 64)
entry->mask |= IT_ENTRY_VOLPAN;
}
if (b & 128) {
entry->volpan = buffer[bufpos++];
if (entry->volpan <= 64)
entry->mask |= IT_ENTRY_VOLPAN;
}
entry++;
}
}
entry++;
}
}
ASSERT(entry == pattern->entry + pattern->n_entries);
ASSERT(entry == pattern->entry + pattern->n_entries);
return 0;
return 0;
}
/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */
/** WARNING: this is duplicated in itread.c - also bad practice to use the same
* struct name unless they are unified in a header */
/* Currently we assume the sample data are stored after the sample headers in
* module files. This assumption may be unjustified; let me know if you have
* trouble.
*/
#define PTM_COMPONENT_INSTRUMENT 1
#define PTM_COMPONENT_PATTERN 2
#define PTM_COMPONENT_SAMPLE 3
#define PTM_COMPONENT_PATTERN 2
#define PTM_COMPONENT_SAMPLE 3
typedef struct PTM_COMPONENT
{
unsigned char type;
unsigned char n;
long offset;
}
PTM_COMPONENT;
typedef struct PTM_COMPONENT {
unsigned char type;
unsigned char n;
long offset;
} PTM_COMPONENT;
static int ptm_component_compare(const void *e1, const void *e2)
{
return ((const PTM_COMPONENT *)e1)->offset -
((const PTM_COMPONENT *)e2)->offset;
static int ptm_component_compare(const void *e1, const void *e2) {
return (int)(((const PTM_COMPONENT *)e1)->offset -
((const PTM_COMPONENT *)e2)->offset);
}
static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f) {
DUMB_IT_SIGDATA *sigdata;
PTM_COMPONENT *component;
int n_components = 0;
static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f)
{
DUMB_IT_SIGDATA *sigdata;
int n;
PTM_COMPONENT *component;
int n_components = 0;
unsigned char *buffer;
int n;
sigdata = malloc(sizeof(*sigdata));
if (!sigdata)
return NULL;
unsigned char *buffer;
sigdata = malloc(sizeof(*sigdata));
if (!sigdata) return NULL;
/* Skip song name. */
/* Skip song name. */
dumbfile_getnc((char *)sigdata->name, 28, f);
sigdata->name[28] = 0;
sigdata->name[28] = 0;
if (dumbfile_getc(f) != 0x1A || dumbfile_igetw(f) != 0x203) {
free(sigdata);
return NULL;
}
if (dumbfile_getc(f) != 0x1A || dumbfile_igetw(f) != 0x203) {
free(sigdata);
return NULL;
}
dumbfile_skip(f, 1);
dumbfile_skip(f, 1);
sigdata->song_message = NULL;
sigdata->order = NULL;
sigdata->instrument = NULL;
sigdata->sample = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
sigdata->song_message = NULL;
sigdata->order = NULL;
sigdata->instrument = NULL;
sigdata->sample = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
sigdata->n_orders = dumbfile_igetw(f);
sigdata->n_instruments = 0;
sigdata->n_samples = dumbfile_igetw(f);
sigdata->n_patterns = dumbfile_igetw(f);
sigdata->n_orders = dumbfile_igetw(f);
sigdata->n_instruments = 0;
sigdata->n_samples = dumbfile_igetw(f);
sigdata->n_patterns = dumbfile_igetw(f);
if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 255 || sigdata->n_patterns > 128) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (dumbfile_error(f) || sigdata->n_orders <= 0 ||
sigdata->n_samples > 255 || sigdata->n_patterns > 128) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->n_pchannels = dumbfile_igetw(f);
sigdata->n_pchannels = dumbfile_igetw(f);
if (dumbfile_igetw(f) != 0) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (dumbfile_igetw(f) != 0) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
dumbfile_skip(f, 2);
dumbfile_skip(f, 2);
if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','F')) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (dumbfile_mgetl(f) != DUMB_ID('P', 'T', 'M', 'F')) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
dumbfile_skip(f, 16);
dumbfile_skip(f, 16);
sigdata->order = malloc(sigdata->n_orders);
if (!sigdata->order) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->order = malloc(sigdata->n_orders);
if (!sigdata->order) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (sigdata->n_samples) {
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
if (!sigdata->sample) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (n = 0; n < sigdata->n_samples; n++)
sigdata->sample[n].data = NULL;
}
if (sigdata->n_samples) {
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
if (!sigdata->sample) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (n = 0; n < sigdata->n_samples; n++)
sigdata->sample[n].data = NULL;
}
if (sigdata->n_patterns) {
sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
if (!sigdata->pattern) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (n = 0; n < sigdata->n_patterns; n++)
sigdata->pattern[n].entry = NULL;
}
if (sigdata->n_patterns) {
sigdata->pattern =
malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
if (!sigdata->pattern) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (n = 0; n < sigdata->n_patterns; n++)
sigdata->pattern[n].entry = NULL;
}
/** WARNING: which ones? */
sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_A_PTM;
/** WARNING: which ones? */
sigdata->flags =
IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_A_PTM;
sigdata->global_volume = 128;
sigdata->speed = 6;
sigdata->tempo = 125;
sigdata->mixing_volume = 48;
sigdata->global_volume = 128;
sigdata->speed = 6;
sigdata->tempo = 125;
sigdata->mixing_volume = 48;
/* Panning positions for 32 channels */
{
int i;
for (i = 0; i < 32; i++) {
int c = dumbfile_getc(f);
if (c <= 15) {
sigdata->channel_volume[i] = 64;
sigdata->channel_pan[i] = c;
} else {
/** WARNING: this could be improved if we support channel muting... */
sigdata->channel_volume[i] = 0;
sigdata->channel_pan[i] = 7;
}
}
}
/* Panning positions for 32 channels */
{
int i;
for (i = 0; i < 32; i++) {
int c = dumbfile_getc(f);
if (c <= 15) {
sigdata->channel_volume[i] = 64;
sigdata->channel_pan[i] = c;
} else {
/** WARNING: this could be improved if we support channel
* muting... */
sigdata->channel_volume[i] = 0;
sigdata->channel_pan[i] = 7;
}
}
}
/* Orders, byte each, length = sigdata->n_orders (should be even) */
/* Orders, byte each, length = sigdata->n_orders (should be even) */
dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f);
sigdata->restart_position = 0;
sigdata->restart_position = 0;
component = malloc(768*sizeof(*component));
if (!component) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
component = malloc(768 * sizeof(*component));
if (!component) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (dumbfile_seek(f, 352, DFS_SEEK_SET)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (n = 0; n < sigdata->n_patterns; n++) {
component[n_components].type = PTM_COMPONENT_PATTERN;
component[n_components].n = n;
component[n_components].offset = dumbfile_igetw(f) << 4;
n_components++;
}
for (n = 0; n < sigdata->n_patterns; n++) {
component[n_components].type = PTM_COMPONENT_PATTERN;
component[n_components].n = n;
component[n_components].offset = dumbfile_igetw(f) << 4;
n_components++;
}
if (dumbfile_seek(f, 608, DFS_SEEK_SET)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (n = 0; n < sigdata->n_samples; n++) {
if (it_ptm_read_sample_header(&sigdata->sample[n], &component[n_components].offset, f)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (!(sigdata->sample[n].flags & IT_SAMPLE_EXISTS)) continue;
component[n_components].type = PTM_COMPONENT_SAMPLE;
component[n_components].n = n;
n_components++;
}
for (n = 0; n < sigdata->n_samples; n++) {
if (it_ptm_read_sample_header(&sigdata->sample[n],
&component[n_components].offset, f)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (!(sigdata->sample[n].flags & IT_SAMPLE_EXISTS))
continue;
component[n_components].type = PTM_COMPONENT_SAMPLE;
component[n_components].n = n;
n_components++;
}
qsort(component, n_components, sizeof(PTM_COMPONENT), &ptm_component_compare);
qsort(component, n_components, sizeof(PTM_COMPONENT),
&ptm_component_compare);
{
int i;
for (i = 0; i < 32; i++) {
sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3;
sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7;
if (sigdata->channel_pan[i] > 64) sigdata->channel_pan[i] = 64;
}
}
{
int i;
for (i = 0; i < 32; i++) {
sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3;
sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7;
if (sigdata->channel_pan[i] > 64)
sigdata->channel_pan[i] = 64;
}
}
sigdata->pan_separation = 128;
sigdata->pan_separation = 128;
if (dumbfile_error(f)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (dumbfile_error(f)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
buffer = malloc(65536);
if (!buffer) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
buffer = malloc(65536);
if (!buffer) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (n = 0; n < n_components; n++) {
for (n = 0; n < n_components; n++) {
if (dumbfile_seek(f, component[n].offset, DFS_SEEK_SET)) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
switch (component[n].type) {
switch (component[n].type) {
case PTM_COMPONENT_PATTERN:
if (it_ptm_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
break;
case PTM_COMPONENT_PATTERN:
if (it_ptm_read_pattern(
&sigdata->pattern[component[n].n], f, buffer,
(n + 1 < n_components)
? (component[n + 1].offset - component[n].offset)
: 0)) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
break;
case PTM_COMPONENT_SAMPLE:
if (it_ptm_read_sample_data(&sigdata->sample[component[n].n], (n + 1 == n_components), f)) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
}
case PTM_COMPONENT_SAMPLE:
if (it_ptm_read_sample_data(&sigdata->sample[component[n].n],
(n + 1 == n_components), f)) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
}
free(buffer);
free(component);
free(buffer);
free(component);
_dumb_it_fix_invalid_orders(sigdata);
_dumb_it_fix_invalid_orders(sigdata);
return sigdata;
return sigdata;
}
DUH *dumb_read_ptm_quick(DUMBFILE *f)
{
sigdata_t *sigdata;
DUH *dumb_read_ptm_quick(DUMBFILE *f) {
sigdata_t *sigdata;
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
sigdata = it_ptm_load_sigdata(f);
sigdata = it_ptm_load_sigdata(f);
if (!sigdata)
return NULL;
if (!sigdata)
return NULL;
{
const char *tag[2][2];
tag[0][0] = "TITLE";
{
const char *tag[2][2];
tag[0][0] = "TITLE";
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
tag[1][0] = "FORMAT";
tag[1][1] = "PTM";
return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
}
tag[1][0] = "FORMAT";
tag[1][1] = "PTM";
return make_duh(-1, 2, (const char *const(*)[2])tag, 1, &descptr,
&sigdata);
}
}

View file

@ -21,37 +21,38 @@
#include "internal/it.h"
#include "internal/riff.h"
DUH *dumb_read_riff_amff( DUMBFILE * f, struct riff * stream );
DUH *dumb_read_riff_am( DUMBFILE * f, struct riff * stream );
DUH *dumb_read_riff_dsmf( DUMBFILE * f, struct riff * stream );
DUH *dumb_read_riff_amff(DUMBFILE *f, struct riff *stream);
DUH *dumb_read_riff_am(DUMBFILE *f, struct riff *stream);
DUH *dumb_read_riff_dsmf(DUMBFILE *f, struct riff *stream);
/* dumb_read_riff_quick(): reads a RIFF file into a DUH struct, returning a
* pointer to the DUH struct. When you have finished with it, you must pass
* the pointer to unload_duh() so that the memory can be freed.
*/
DUH *dumb_read_riff_quick( DUMBFILE * f )
{
DUH * duh;
struct riff * stream;
DUH *dumb_read_riff_quick(DUMBFILE *f) {
DUH *duh;
struct riff *stream;
long size;
size = dumbfile_get_size(f);
stream = riff_parse( f, 0, size, 1 );
if ( ! stream ) stream = riff_parse( f, 0, size, 0 );
stream = riff_parse(f, 0, size, 1);
if (!stream)
stream = riff_parse(f, 0, size, 0);
if ( ! stream ) return 0;
if (!stream)
return 0;
if ( stream->type == DUMB_ID( 'A', 'M', ' ', ' ' ) )
duh = dumb_read_riff_am( f, stream );
else if ( stream->type == DUMB_ID( 'A', 'M', 'F', 'F' ) )
duh = dumb_read_riff_amff( f, stream );
else if ( stream->type == DUMB_ID( 'D', 'S', 'M', 'F' ) )
duh = dumb_read_riff_dsmf( f, stream );
else duh = 0;
if (stream->type == DUMB_ID('A', 'M', ' ', ' '))
duh = dumb_read_riff_am(f, stream);
else if (stream->type == DUMB_ID('A', 'M', 'F', 'F'))
duh = dumb_read_riff_amff(f, stream);
else if (stream->type == DUMB_ID('D', 'S', 'M', 'F'))
duh = dumb_read_riff_dsmf(f, stream);
else
duh = 0;
riff_free( stream );
riff_free(stream);
return duh;
return duh;
}

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more