mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-24 02:30:46 +00:00
- made things compile again after updating enet. Also removed the redundant dumb and game_music_emu libraries which just got imported by accident when using other things from GZDoom.
Note: enet uses 'malloc' and 'free' as field names in a struct - this does not work with any compiler using some sort of heap instrumentation that #defines these names! This had to be changed to allow MSVC debug builds to compile again.
This commit is contained in:
parent
63713002b3
commit
2316957026
240 changed files with 36 additions and 65935 deletions
|
@ -166,14 +166,6 @@ target_architecture(DEMOLITION_TARGET_ARCH)
|
|||
# find_package( asmjit )
|
||||
#endif()
|
||||
|
||||
# GME
|
||||
#find_path( GME_INCLUDE_DIR gme/gme.h )
|
||||
#find_library( GME_LIBRARIES gme )
|
||||
#mark_as_advanced( GME_INCLUDE_DIR GME_LIBRARIES )
|
||||
#FIND_PACKAGE_HANDLE_STANDARD_ARGS( GME
|
||||
# REQUIRED_VARS GME_LIBRARIES GME_INCLUDE_DIR
|
||||
#)
|
||||
|
||||
if( MSVC )
|
||||
# Eliminate unreferenced functions and data
|
||||
# Perform identical COMDAT folding
|
||||
|
@ -302,10 +294,8 @@ set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
|
|||
option(FORCE_INTERNAL_ZLIB "Use internal zlib")
|
||||
option(FORCE_INTERNAL_JPEG "Use internal jpeg")
|
||||
option(FORCE_INTERNAL_BZIP2 "Use internal bzip2")
|
||||
option(FORCE_INTERNAL_GME "Use internal gme" ON)
|
||||
mark_as_advanced( FORCE_INTERNAL_GME )
|
||||
option(FORCE_INTERNAL_ASMJIT "Use internal asmjit" ON)
|
||||
mark_as_advanced( FORCE_INTERNAL_ASMJIT )
|
||||
#option(FORCE_INTERNAL_ASMJIT "Use internal asmjit" ON)
|
||||
#mark_as_advanced( FORCE_INTERNAL_ASMJIT )
|
||||
|
||||
if (HAVE_VULKAN)
|
||||
add_subdirectory( libraries/glslang/glslang)
|
||||
|
@ -378,20 +368,7 @@ else()
|
|||
set( BZIP2_LIBRARY bz2 )
|
||||
endif()
|
||||
|
||||
if( GME_FOUND AND NOT FORCE_INTERNAL_GME )
|
||||
message( STATUS "Using system gme library, includes found at ${GME_INCLUDE_DIR}" )
|
||||
else()
|
||||
message( STATUS "Using internal gme library" )
|
||||
# Use MAME as it's balanced emulator: well-accurate, but doesn't eats lot of CPU
|
||||
# Nuked OPN2 is very accurate emulator, but it eats too much CPU for the workflow
|
||||
set( GME_YM2612_EMU "MAME" )
|
||||
add_subdirectory( libraries/game-music-emu )
|
||||
set( GME_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/game-music-emu" )
|
||||
set( GME_LIBRARIES gme )
|
||||
endif()
|
||||
|
||||
set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/lzma/C" )
|
||||
set( ENET_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/enet" )
|
||||
set( GDTOA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/gdtoa" )
|
||||
|
||||
if( NOT CMAKE_CROSSCOMPILING )
|
||||
|
@ -412,9 +389,7 @@ endif()
|
|||
|
||||
add_subdirectory( libraries/lzma )
|
||||
add_subdirectory( tools )
|
||||
add_subdirectory( libraries/dumb )
|
||||
add_subdirectory( libraries/gdtoa )
|
||||
add_subdirectory( libraries/enet )
|
||||
add_subdirectory( wadsrc )
|
||||
add_subdirectory( source )
|
||||
add_subdirectory( source/duke3d )
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
make_release_only()
|
||||
|
||||
include( CheckFunctionExists )
|
||||
include( CheckCXXCompilerFlag )
|
||||
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -DDEBUGMODE=1" )
|
||||
|
||||
if( DEM_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-pointer-sign -Wno-uninitialized" )
|
||||
if( CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.5" )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-but-set-variable" )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Enable fast flag for dumb
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DEM_FASTMATH_FLAG}" )
|
||||
|
||||
CHECK_FUNCTION_EXISTS( itoa ITOA_EXISTS )
|
||||
if( NOT ITOA_EXISTS )
|
||||
add_definitions( -DNEED_ITOA=1 )
|
||||
endif()
|
||||
|
||||
include_directories( include )
|
||||
|
||||
add_library( dumb STATIC
|
||||
src/core/unload.c
|
||||
src/core/rendsig.c
|
||||
src/core/rendduh.c
|
||||
src/core/register.c
|
||||
src/core/readduh.c
|
||||
src/core/rawsig.c
|
||||
src/core/makeduh.c
|
||||
src/core/loadduh.c
|
||||
src/core/dumbfile.c
|
||||
src/core/duhtag.c
|
||||
src/core/duhlen.c
|
||||
src/core/atexit.c
|
||||
src/helpers/stdfile.c
|
||||
src/helpers/silence.c
|
||||
src/helpers/sampbuf.c
|
||||
src/helpers/riff.c
|
||||
src/helpers/resample.c
|
||||
src/helpers/memfile.c
|
||||
src/helpers/clickrem.c
|
||||
src/helpers/barray.c
|
||||
src/it/xmeffect.c
|
||||
src/it/readxm2.c
|
||||
src/it/readxm.c
|
||||
src/it/readstm2.c
|
||||
src/it/readstm.c
|
||||
src/it/reads3m2.c
|
||||
src/it/reads3m.c
|
||||
src/it/readriff.c
|
||||
src/it/readptm.c
|
||||
src/it/readpsm.c
|
||||
src/it/readoldpsm.c
|
||||
src/it/readokt2.c
|
||||
src/it/readokt.c
|
||||
src/it/readmtm.c
|
||||
src/it/readmod2.c
|
||||
src/it/readmod.c
|
||||
src/it/readdsmf.c
|
||||
src/it/readasy.c
|
||||
src/it/readamf2.c
|
||||
src/it/readamf.c
|
||||
src/it/readam.c
|
||||
src/it/read6692.c
|
||||
src/it/read669.c
|
||||
src/it/ptmeffect.c
|
||||
src/it/loadxm2.c
|
||||
src/it/loadxm.c
|
||||
src/it/loadstm2.c
|
||||
src/it/loadstm.c
|
||||
src/it/loads3m2.c
|
||||
src/it/loads3m.c
|
||||
src/it/loadriff2.c
|
||||
src/it/loadriff.c
|
||||
src/it/loadptm2.c
|
||||
src/it/loadptm.c
|
||||
src/it/loadpsm2.c
|
||||
src/it/loadpsm.c
|
||||
src/it/loadoldpsm2.c
|
||||
src/it/loadoldpsm.c
|
||||
src/it/loadokt2.c
|
||||
src/it/loadokt.c
|
||||
src/it/loadmtm2.c
|
||||
src/it/loadmtm.c
|
||||
src/it/loadmod2.c
|
||||
src/it/loadmod.c
|
||||
src/it/loadasy2.c
|
||||
src/it/loadasy.c
|
||||
src/it/loadamf2.c
|
||||
src/it/loadamf.c
|
||||
src/it/load6692.c
|
||||
src/it/load669.c
|
||||
src/it/itunload.c
|
||||
src/it/itrender.c
|
||||
src/it/itread2.c
|
||||
src/it/itread.c
|
||||
src/it/itorder.c
|
||||
src/it/itmisc.c
|
||||
src/it/itload2.c
|
||||
src/it/itload.c
|
||||
src/it/readany.c
|
||||
src/it/loadany2.c
|
||||
src/it/loadany.c
|
||||
src/it/readany2.c
|
||||
src/helpers/resampler.c
|
||||
src/helpers/lpc.c
|
||||
)
|
||||
target_link_libraries( dumb )
|
||||
|
||||
if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
CHECK_CXX_COMPILER_FLAG( -msse DUMB_CAN_USE_SSE )
|
||||
|
||||
if( DUMB_CAN_USE_SSE )
|
||||
set_source_files_properties( src/helpers/resampler.c PROPERTIES COMPILE_FLAGS -msse )
|
||||
endif()
|
||||
endif()
|
|
@ -1,118 +0,0 @@
|
|||
cmake_minimum_required(VERSION 2.8.7)
|
||||
project(libdumb C)
|
||||
|
||||
set(CMAKE_C_FLAGS "-Wall -DDUMB_DECLARE_DEPRECATED -D_USE_SSE -msse -Wno-unused-variable -Wno-unused-but-set-variable")
|
||||
set(CMAKE_C_FLAGS_DEBUG "-ggdb -DDEBUGMODE=1 -D_DEBUG")
|
||||
set(CMAKE_C_FLAGS_RELEASE "-ffast-math -O2 -DNDEBUG")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-ffast-math -g -O2 -DNDEBUG")
|
||||
set(CMAKE_C_FLAGS_MINSIZEREL "-ffast-math -Os -DNDEBUG")
|
||||
|
||||
link_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(../include/)
|
||||
|
||||
SET(SOURCES
|
||||
../src/core/unload.c
|
||||
../src/core/rendsig.c
|
||||
../src/core/rendduh.c
|
||||
../src/core/register.c
|
||||
../src/core/readduh.c
|
||||
../src/core/rawsig.c
|
||||
../src/core/makeduh.c
|
||||
../src/core/loadduh.c
|
||||
../src/core/dumbfile.c
|
||||
../src/core/duhtag.c
|
||||
../src/core/duhlen.c
|
||||
../src/core/atexit.c
|
||||
../src/helpers/stdfile.c
|
||||
../src/helpers/silence.c
|
||||
../src/helpers/sampbuf.c
|
||||
../src/helpers/riff.c
|
||||
../src/helpers/resample.c
|
||||
../src/helpers/memfile.c
|
||||
../src/helpers/clickrem.c
|
||||
../src/helpers/barray.c
|
||||
../src/helpers/tarray.c
|
||||
../src/it/xmeffect.c
|
||||
../src/it/readxm2.c
|
||||
../src/it/readxm.c
|
||||
../src/it/readstm2.c
|
||||
../src/it/readstm.c
|
||||
../src/it/reads3m2.c
|
||||
../src/it/reads3m.c
|
||||
../src/it/readriff.c
|
||||
../src/it/readptm.c
|
||||
../src/it/readpsm.c
|
||||
../src/it/readoldpsm.c
|
||||
../src/it/readokt2.c
|
||||
../src/it/readokt.c
|
||||
../src/it/readmtm.c
|
||||
../src/it/readmod2.c
|
||||
../src/it/readmod.c
|
||||
../src/it/readdsmf.c
|
||||
../src/it/readasy.c
|
||||
../src/it/readamf2.c
|
||||
../src/it/readamf.c
|
||||
../src/it/readam.c
|
||||
../src/it/read6692.c
|
||||
../src/it/read669.c
|
||||
../src/it/ptmeffect.c
|
||||
../src/it/loadxm2.c
|
||||
../src/it/loadxm.c
|
||||
../src/it/loadstm2.c
|
||||
../src/it/loadstm.c
|
||||
../src/it/loads3m2.c
|
||||
../src/it/loads3m.c
|
||||
../src/it/loadriff2.c
|
||||
../src/it/loadriff.c
|
||||
../src/it/loadptm2.c
|
||||
../src/it/loadptm.c
|
||||
../src/it/loadpsm2.c
|
||||
../src/it/loadpsm.c
|
||||
../src/it/loadoldpsm2.c
|
||||
../src/it/loadoldpsm.c
|
||||
../src/it/loadokt2.c
|
||||
../src/it/loadokt.c
|
||||
../src/it/loadmtm2.c
|
||||
../src/it/loadmtm.c
|
||||
../src/it/loadmod2.c
|
||||
../src/it/loadmod.c
|
||||
../src/it/loadasy2.c
|
||||
../src/it/loadasy.c
|
||||
../src/it/loadamf2.c
|
||||
../src/it/loadamf.c
|
||||
../src/it/load6692.c
|
||||
../src/it/load669.c
|
||||
../src/it/itunload.c
|
||||
../src/it/itrender.c
|
||||
../src/it/itread2.c
|
||||
../src/it/itread.c
|
||||
../src/it/itorder.c
|
||||
../src/it/itmisc.c
|
||||
../src/it/itload2.c
|
||||
../src/it/itload.c
|
||||
../src/it/readany.c
|
||||
../src/it/loadany2.c
|
||||
../src/it/loadany.c
|
||||
../src/it/readany2.c
|
||||
../src/helpers/resampler.c
|
||||
../src/helpers/lpc.c
|
||||
)
|
||||
|
||||
set(INSTALL_HEADERS
|
||||
../include/dumb.h
|
||||
)
|
||||
|
||||
add_library(dumb ${SOURCES})
|
||||
set_target_properties(dumb PROPERTIES DEBUG_POSTFIX d)
|
||||
|
||||
# Make sure the dylib install name path is set on OSX so you can include dumb in app bundles
|
||||
IF(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
set_target_properties(dumb PROPERTIES INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib)
|
||||
ENDIF()
|
||||
|
||||
INSTALL(FILES ${INSTALL_HEADERS} DESTINATION include/)
|
||||
INSTALL(TARGETS dumb
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
|
@ -1,30 +0,0 @@
|
|||
Howto build libdumb with cmake
|
||||
==============================
|
||||
|
||||
A quick example
|
||||
---------------
|
||||
|
||||
In libdumb cmake directory (dumb/cmake/), run:
|
||||
```
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_SHARED_LIBS:BOOL=ON ..
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
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=OFF -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.
|
||||
|
||||
Flags
|
||||
-----
|
||||
|
||||
* CMAKE_INSTALL_PREFIX sets the installation path prefix
|
||||
* CMAKE_BUILD_TYPE sets the build type (eg. Release, Debug, RelWithDebInfo, MinSizeRel). Debug libraries will be named libdumbd, release libraries libdumb.
|
||||
* BUILD_SHARED_LIBS selects whether cmake should build dynamic or static library (On=shared, OFF=static)
|
||||
* 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" .`.
|
|
@ -1,811 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* dumb.h - The user header file for DUMB. / / \ \
|
||||
* | < / \_
|
||||
* Include this file in any of your files in | \/ /\ /
|
||||
* which you wish to use the DUMB functions \_ / > /
|
||||
* and variables. | \ / /
|
||||
* | ' /
|
||||
* Allegro users, you will probably want aldumb.h. \__/
|
||||
*/
|
||||
|
||||
#ifndef DUMB_H
|
||||
#define DUMB_H
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_DEBUG) && defined(_MSC_VER)
|
||||
#ifndef _CRTDBG_MAP_ALLOC
|
||||
//#define _CRTDBG_MAP_ALLOC
|
||||
#endif
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define DUMB_MAJOR_VERSION 1
|
||||
#define DUMB_MINOR_VERSION 0
|
||||
#define DUMB_REVISION_VERSION 0
|
||||
|
||||
#define DUMB_VERSION (DUMB_MAJOR_VERSION*10000 + DUMB_MINOR_VERSION*100 + DUMB_REVISION_VERSION)
|
||||
|
||||
#define DUMB_VERSION_STR "1.0.0"
|
||||
|
||||
#define DUMB_NAME "DUMB v" DUMB_VERSION_STR
|
||||
|
||||
#define DUMB_YEAR 2015
|
||||
#define DUMB_MONTH 1
|
||||
#define DUMB_DAY 17
|
||||
|
||||
#define DUMB_YEAR_STR2 "15"
|
||||
#define DUMB_YEAR_STR4 "2015"
|
||||
#define DUMB_MONTH_STR1 "1"
|
||||
#define DUMB_DAY_STR1 "17"
|
||||
|
||||
#if DUMB_MONTH < 10
|
||||
#define DUMB_MONTH_STR2 "0" DUMB_MONTH_STR1
|
||||
#else
|
||||
#define DUMB_MONTH_STR2 DUMB_MONTH_STR1
|
||||
#endif
|
||||
|
||||
#if DUMB_DAY < 10
|
||||
#define DUMB_DAY_STR2 "0" DUMB_DAY_STR1
|
||||
#else
|
||||
#define DUMB_DAY_STR2 DUMB_DAY_STR1
|
||||
#endif
|
||||
|
||||
|
||||
/* WARNING: The month and day were inadvertently swapped in the v0.8 release.
|
||||
* Please do not compare this constant against any date in 2002. In
|
||||
* any case, DUMB_VERSION is probably more useful for this purpose.
|
||||
*/
|
||||
#define DUMB_DATE (DUMB_YEAR*10000 + DUMB_MONTH*100 + DUMB_DAY)
|
||||
|
||||
#define DUMB_DATE_STR DUMB_DAY_STR1 "." DUMB_MONTH_STR1 "." DUMB_YEAR_STR4
|
||||
|
||||
|
||||
#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)))
|
||||
|
||||
#undef ABS
|
||||
#define ABS(x) (((x) >= 0) ? (x) : (-(x)))
|
||||
|
||||
|
||||
#ifdef DEBUGMODE
|
||||
|
||||
#ifndef ASSERT
|
||||
#include <assert.h>
|
||||
#define ASSERT(n) assert(n)
|
||||
#endif
|
||||
#ifndef TRACE
|
||||
// it would be nice if this did actually trace ...
|
||||
#define TRACE 1 ? (void)0 : (void)printf
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifndef ASSERT
|
||||
#define ASSERT(n)
|
||||
#endif
|
||||
#ifndef TRACE
|
||||
#define TRACE 1 ? (void)0 : (void)printf
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define DUMB_ID(a,b,c,d) (((unsigned int)(a) << 24) | \
|
||||
((unsigned int)(b) << 16) | \
|
||||
((unsigned int)(c) << 8) | \
|
||||
((unsigned int)(d) ))
|
||||
|
||||
|
||||
#ifdef __DOS__
|
||||
typedef long int32;
|
||||
typedef unsigned long uint32;
|
||||
typedef signed long sint32;
|
||||
#else
|
||||
typedef int int32;
|
||||
typedef unsigned int uint32;
|
||||
typedef signed int sint32;
|
||||
#endif
|
||||
|
||||
#define CDECL
|
||||
#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
|
||||
#undef CDECL
|
||||
#define CDECL __cdecl
|
||||
#elif defined __sgi
|
||||
#define LONG_LONG long long
|
||||
#else
|
||||
#error 64-bit integer type unknown
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 301 /* GCC 3.1+ */
|
||||
#ifndef DUMB_DECLARE_DEPRECATED
|
||||
#define DUMB_DECLARE_DEPRECATED
|
||||
#endif
|
||||
#define DUMB_DEPRECATED __attribute__((__deprecated__))
|
||||
#else
|
||||
#define DUMB_DEPRECATED
|
||||
#endif
|
||||
|
||||
#define DUMBEXPORT CDECL
|
||||
#define DUMBCALLBACK CDECL
|
||||
|
||||
/* Basic Sample Type. Normal range is -0x800000 to 0x7FFFFF. */
|
||||
|
||||
typedef int sample_t;
|
||||
|
||||
|
||||
/* Library Clean-up Management */
|
||||
|
||||
int dumb_atexit(void (*proc)(void));
|
||||
|
||||
void dumb_exit(void);
|
||||
|
||||
|
||||
/* File Input Functions */
|
||||
|
||||
typedef struct DUMBFILE_SYSTEM
|
||||
{
|
||||
void *(DUMBCALLBACK *open)(const char *filename);
|
||||
int (DUMBCALLBACK *skip)(void *f, long n);
|
||||
int (DUMBCALLBACK *getc)(void *f);
|
||||
int32 (DUMBCALLBACK *getnc)(char *ptr, int32 n, void *f);
|
||||
void (DUMBCALLBACK *close)(void *f);
|
||||
int (DUMBCALLBACK *seek)(void *f, long n);
|
||||
long (DUMBCALLBACK *get_size)(void *f);
|
||||
}
|
||||
DUMBFILE_SYSTEM;
|
||||
|
||||
typedef struct DUMBFILE DUMBFILE;
|
||||
|
||||
void DUMBEXPORT register_dumbfile_system(const DUMBFILE_SYSTEM *dfs);
|
||||
|
||||
DUMBFILE *DUMBEXPORT dumbfile_open(const char *filename);
|
||||
DUMBFILE *DUMBEXPORT dumbfile_open_ex(void *file, const DUMBFILE_SYSTEM *dfs);
|
||||
|
||||
int32 DUMBEXPORT dumbfile_pos(DUMBFILE *f);
|
||||
int DUMBEXPORT dumbfile_skip(DUMBFILE *f, long n);
|
||||
|
||||
#define DFS_SEEK_SET 0
|
||||
#define DFS_SEEK_CUR 1
|
||||
#define DFS_SEEK_END 2
|
||||
|
||||
int DUMBEXPORT dumbfile_seek(DUMBFILE *f, long n, int origin);
|
||||
|
||||
int32 DUMBEXPORT dumbfile_get_size(DUMBFILE *f);
|
||||
|
||||
int DUMBEXPORT dumbfile_getc(DUMBFILE *f);
|
||||
|
||||
int DUMBEXPORT dumbfile_igetw(DUMBFILE *f);
|
||||
int DUMBEXPORT dumbfile_mgetw(DUMBFILE *f);
|
||||
|
||||
int32 DUMBEXPORT dumbfile_igetl(DUMBFILE *f);
|
||||
int32 DUMBEXPORT dumbfile_mgetl(DUMBFILE *f);
|
||||
|
||||
uint32 DUMBEXPORT dumbfile_cgetul(DUMBFILE *f);
|
||||
sint32 DUMBEXPORT dumbfile_cgetsl(DUMBFILE *f);
|
||||
|
||||
int32 DUMBEXPORT dumbfile_getnc(char *ptr, int32 n, DUMBFILE *f);
|
||||
|
||||
int DUMBEXPORT dumbfile_error(DUMBFILE *f);
|
||||
int DUMBEXPORT dumbfile_close(DUMBFILE *f);
|
||||
|
||||
|
||||
/* stdio File Input Module */
|
||||
|
||||
void DUMBEXPORT dumb_register_stdfiles(void);
|
||||
|
||||
DUMBFILE *DUMBEXPORT dumbfile_open_stdfile(FILE *p);
|
||||
|
||||
|
||||
/* Memory File Input Module */
|
||||
|
||||
DUMBFILE *DUMBEXPORT dumbfile_open_memory(const char *data, int32 size);
|
||||
|
||||
|
||||
/* DUH Management */
|
||||
|
||||
typedef struct DUH DUH;
|
||||
|
||||
#define DUH_SIGNATURE DUMB_ID('D','U','H','!')
|
||||
|
||||
void DUMBEXPORT unload_duh(DUH *duh);
|
||||
|
||||
DUH *DUMBEXPORT load_duh(const char *filename);
|
||||
DUH *DUMBEXPORT read_duh(DUMBFILE *f);
|
||||
|
||||
int32 DUMBEXPORT duh_get_length(DUH *duh);
|
||||
|
||||
const char *DUMBEXPORT duh_get_tag(DUH *duh, const char *key);
|
||||
|
||||
/* Signal Rendering Functions */
|
||||
|
||||
typedef struct DUH_SIGRENDERER DUH_SIGRENDERER;
|
||||
|
||||
DUH_SIGRENDERER *DUMBEXPORT duh_start_sigrenderer(DUH *duh, int sig, int n_channels, int32 pos);
|
||||
|
||||
#ifdef DUMB_DECLARE_DEPRECATED
|
||||
typedef void (*DUH_SIGRENDERER_CALLBACK)(void *data, sample_t **samples, int n_channels, int32 length);
|
||||
/* This is deprecated, but is not marked as such because GCC tends to
|
||||
* complain spuriously when the typedef is used later. See comments below.
|
||||
*/
|
||||
|
||||
void duh_sigrenderer_set_callback(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
DUH_SIGRENDERER_CALLBACK callback, void *data
|
||||
) DUMB_DEPRECATED;
|
||||
/* The 'callback' argument's type has changed for const-correctness. See the
|
||||
* DUH_SIGRENDERER_CALLBACK definition just above. Also note that the samples
|
||||
* in the buffer are now 256 times as large; the normal range is -0x800000 to
|
||||
* 0x7FFFFF. The function has been renamed partly because its functionality
|
||||
* has changed slightly and partly so that its name is more meaningful. The
|
||||
* new one is duh_sigrenderer_set_analyser_callback(), and the typedef for
|
||||
* the function pointer has also changed, from DUH_SIGRENDERER_CALLBACK to
|
||||
* DUH_SIGRENDERER_ANALYSER_CALLBACK. (If you wanted to use this callback to
|
||||
* apply a DSP effect, don't worry; there is a better way of doing this. It
|
||||
* is undocumented, so contact me and I shall try to help. Contact details
|
||||
* are in readme.txt.)
|
||||
*/
|
||||
|
||||
typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, int32 length);
|
||||
/* This is deprecated, but is not marked as such because GCC tends to
|
||||
* complain spuriously when the typedef is used later. See comments below.
|
||||
*/
|
||||
|
||||
void duh_sigrenderer_set_analyser_callback(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data
|
||||
) DUMB_DEPRECATED;
|
||||
/* This is deprecated because the meaning of the 'samples' parameter in the
|
||||
* callback needed to change. For stereo applications, the array used to be
|
||||
* indexed with samples[channel][pos]. It is now indexed with
|
||||
* samples[0][pos*2+channel]. Mono sample data are still indexed with
|
||||
* samples[0][pos]. The array is still 2D because samples will probably only
|
||||
* ever be interleaved in twos. In order to fix your code, adapt it to the
|
||||
* new sample layout and then call
|
||||
* duh_sigrenderer_set_sample_analyser_callback below instead of this
|
||||
* function.
|
||||
*/
|
||||
#endif
|
||||
|
||||
typedef void (*DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, int32 length);
|
||||
|
||||
void duh_sigrenderer_set_sample_analyser_callback(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data
|
||||
);
|
||||
|
||||
int DUMBEXPORT duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);
|
||||
int32 DUMBEXPORT duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer);
|
||||
|
||||
void DUMBEXPORT duh_sigrenderer_set_sigparam(DUH_SIGRENDERER *sigrenderer, unsigned char id, int32 value);
|
||||
|
||||
#ifdef DUMB_DECLARE_DEPRECATED
|
||||
int32 duh_sigrenderer_get_samples(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
float volume, float delta,
|
||||
int32 size, sample_t **samples
|
||||
) DUMB_DEPRECATED;
|
||||
/* The sample format has changed, so if you were using this function,
|
||||
* you should switch to duh_sigrenderer_generate_samples() and change
|
||||
* how you interpret the samples array. See the comments for
|
||||
* duh_sigrenderer_set_analyser_callback().
|
||||
*/
|
||||
#endif
|
||||
|
||||
int32 DUMBEXPORT duh_sigrenderer_generate_samples(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
double volume, double delta,
|
||||
int32 size, sample_t **samples
|
||||
);
|
||||
|
||||
void DUMBEXPORT duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples);
|
||||
|
||||
void DUMBEXPORT duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer);
|
||||
|
||||
|
||||
/* DUH Rendering Functions */
|
||||
|
||||
int32 DUMBEXPORT duh_render(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
int bits, int unsign,
|
||||
float volume, float delta,
|
||||
int32 size, void *sptr
|
||||
);
|
||||
|
||||
#ifdef DUMB_DECLARE_DEPRECATED
|
||||
|
||||
int32 duh_render_signal(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
float volume, float delta,
|
||||
int32 size, sample_t **samples
|
||||
) DUMB_DEPRECATED;
|
||||
/* Please use duh_sigrenderer_generate_samples(), and see the
|
||||
* comments for the deprecated duh_sigrenderer_get_samples() too.
|
||||
*/
|
||||
|
||||
typedef DUH_SIGRENDERER DUH_RENDERER DUMB_DEPRECATED;
|
||||
/* Please use DUH_SIGRENDERER instead of DUH_RENDERER. */
|
||||
|
||||
DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, int32 pos) DUMB_DEPRECATED;
|
||||
/* Please use duh_start_sigrenderer() instead. Pass 0 for 'sig'. */
|
||||
|
||||
int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
|
||||
int32 duh_renderer_get_position(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
|
||||
/* Please use the duh_sigrenderer_*() equivalents of these two functions. */
|
||||
|
||||
void duh_end_renderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
|
||||
/* Please use duh_end_sigrenderer() instead. */
|
||||
|
||||
DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer) DUMB_DEPRECATED;
|
||||
DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
|
||||
DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
|
||||
/* These functions have become no-ops that just return the parameter.
|
||||
* So, for instance, replace
|
||||
* duh_renderer_encapsulate_sigrenderer(my_sigrenderer)
|
||||
* with
|
||||
* my_sigrenderer
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Impulse Tracker Support */
|
||||
|
||||
extern int dumb_it_max_to_mix;
|
||||
|
||||
typedef struct DUMB_IT_SIGDATA DUMB_IT_SIGDATA;
|
||||
typedef struct DUMB_IT_SIGRENDERER DUMB_IT_SIGRENDERER;
|
||||
|
||||
DUMB_IT_SIGDATA *DUMBEXPORT duh_get_it_sigdata(DUH *duh);
|
||||
DUH_SIGRENDERER *DUMBEXPORT duh_encapsulate_it_sigrenderer(DUMB_IT_SIGRENDERER *it_sigrenderer, int n_channels, int32 pos);
|
||||
DUMB_IT_SIGRENDERER *DUMBEXPORT duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer);
|
||||
|
||||
int DUMBEXPORT dumb_it_trim_silent_patterns(DUH * duh);
|
||||
|
||||
typedef int (*dumb_scan_callback)(void *, int, int32);
|
||||
int DUMBEXPORT dumb_it_scan_for_playable_orders(DUMB_IT_SIGDATA *sigdata, dumb_scan_callback callback, void * callback_data);
|
||||
|
||||
DUH_SIGRENDERER *DUMBEXPORT dumb_it_start_at_order(DUH *duh, int n_channels, int startorder);
|
||||
|
||||
enum
|
||||
{
|
||||
DUMB_IT_RAMP_NONE = 0,
|
||||
DUMB_IT_RAMP_ONOFF_ONLY = 1,
|
||||
DUMB_IT_RAMP_FULL = 2
|
||||
};
|
||||
|
||||
void DUMBEXPORT dumb_it_set_ramp_style(DUMB_IT_SIGRENDERER * sigrenderer, int ramp_style);
|
||||
|
||||
void DUMBEXPORT dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (DUMBCALLBACK *callback)(void *data), void *data);
|
||||
void DUMBEXPORT dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (DUMBCALLBACK *callback)(void *data), void *data);
|
||||
void DUMBEXPORT dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (DUMBCALLBACK *callback)(void *data, int channel, unsigned char midi_byte), void *data);
|
||||
void DUMBEXPORT dumb_it_set_global_volume_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (DUMBCALLBACK *callback)(void *data), void *data);
|
||||
|
||||
int DUMBCALLBACK dumb_it_callback_terminate(void *data);
|
||||
int DUMBCALLBACK dumb_it_callback_midi_block(void *data, int channel, unsigned char midi_byte);
|
||||
|
||||
/* dumb_*_mod*: restrict_ |= 1-Don't read 15 sample files / 2-Use old pattern counting method */
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_it(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_xm(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_s3m(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_stm(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_mod(const char *filename, int restrict_);
|
||||
DUH *DUMBEXPORT dumb_load_ptm(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_669(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_psm(const char *filename, int subsong);
|
||||
DUH *DUMBEXPORT dumb_load_old_psm(const char * filename);
|
||||
DUH *DUMBEXPORT dumb_load_mtm(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_riff(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_asy(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_amf(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_okt(const char *filename);
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_it(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_xm(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_s3m(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_stm(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_mod(DUMBFILE *f, int restrict_);
|
||||
DUH *DUMBEXPORT dumb_read_ptm(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_669(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_psm(DUMBFILE *f, int subsong);
|
||||
DUH *DUMBEXPORT dumb_read_old_psm(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_mtm(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_riff(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_asy(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_amf(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_okt(DUMBFILE *f);
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_it_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_xm_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_s3m_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_stm_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_mod_quick(const char *filename, int restrict_);
|
||||
DUH *DUMBEXPORT dumb_load_ptm_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_669_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_psm_quick(const char *filename, int subsong);
|
||||
DUH *DUMBEXPORT dumb_load_old_psm_quick(const char * filename);
|
||||
DUH *DUMBEXPORT dumb_load_mtm_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_riff_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_asy_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_amf_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_okt_quick(const char *filename);
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_it_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_xm_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_s3m_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_stm_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_mod_quick(DUMBFILE *f, int restrict_);
|
||||
DUH *DUMBEXPORT dumb_read_ptm_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_669_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_psm_quick(DUMBFILE *f, int subsong);
|
||||
DUH *DUMBEXPORT dumb_read_old_psm_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_mtm_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_riff_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_asy_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_amf_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_okt_quick(DUMBFILE *f);
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_any_quick(DUMBFILE *f, int restrict_, int subsong);
|
||||
DUH *DUMBEXPORT dumb_read_any(DUMBFILE *f, int restrict_, int subsong);
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_any_quick(const char *filename, int restrict_, int subsong);
|
||||
DUH *DUMBEXPORT dumb_load_any(const char *filename, int restrict_, int subsong);
|
||||
|
||||
int32 DUMBEXPORT dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder);
|
||||
void DUMBEXPORT dumb_it_do_initial_runthrough(DUH *duh);
|
||||
|
||||
int DUMBEXPORT dumb_get_psm_subsong_count(DUMBFILE *f);
|
||||
|
||||
const unsigned char *DUMBEXPORT dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd);
|
||||
|
||||
int DUMBEXPORT dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd);
|
||||
int DUMBEXPORT dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd);
|
||||
int DUMBEXPORT dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd);
|
||||
|
||||
const unsigned char *DUMBEXPORT dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i);
|
||||
const unsigned char *DUMBEXPORT dumb_it_sd_get_sample_filename(DUMB_IT_SIGDATA *sd, int i);
|
||||
const unsigned char *DUMBEXPORT dumb_it_sd_get_instrument_name(DUMB_IT_SIGDATA *sd, int i);
|
||||
const unsigned char *DUMBEXPORT dumb_it_sd_get_instrument_filename(DUMB_IT_SIGDATA *sd, int i);
|
||||
|
||||
int DUMBEXPORT dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd);
|
||||
void DUMBEXPORT dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv);
|
||||
|
||||
int DUMBEXPORT dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd);
|
||||
void DUMBEXPORT dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv);
|
||||
|
||||
int DUMBEXPORT dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd);
|
||||
void DUMBEXPORT dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed);
|
||||
|
||||
int DUMBEXPORT dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd);
|
||||
void DUMBEXPORT dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo);
|
||||
|
||||
int DUMBEXPORT dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel);
|
||||
void DUMBEXPORT dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, int volume);
|
||||
|
||||
int DUMBEXPORT dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr);
|
||||
int DUMBEXPORT dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr);
|
||||
|
||||
int DUMBEXPORT dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr);
|
||||
void DUMBEXPORT dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv);
|
||||
|
||||
int DUMBEXPORT dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr);
|
||||
void DUMBEXPORT dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo);
|
||||
|
||||
int DUMBEXPORT dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr);
|
||||
void DUMBEXPORT dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed);
|
||||
|
||||
#define DUMB_IT_N_CHANNELS 64
|
||||
#define DUMB_IT_N_NNA_CHANNELS 192
|
||||
#define DUMB_IT_TOTAL_CHANNELS (DUMB_IT_N_CHANNELS + DUMB_IT_N_NNA_CHANNELS)
|
||||
|
||||
/* Channels passed to any of these functions are 0-based */
|
||||
int DUMBEXPORT dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel);
|
||||
void DUMBEXPORT dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume);
|
||||
|
||||
int DUMBEXPORT dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel);
|
||||
void DUMBEXPORT dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted);
|
||||
|
||||
typedef struct DUMB_IT_CHANNEL_STATE DUMB_IT_CHANNEL_STATE;
|
||||
|
||||
struct DUMB_IT_CHANNEL_STATE
|
||||
{
|
||||
int channel; /* 0-based; meaningful for NNA channels */
|
||||
int sample; /* 1-based; 0 if nothing playing, then other fields undef */
|
||||
int freq; /* in Hz */
|
||||
float volume; /* 1.0 maximum; affected by ALL factors, inc. mixing vol */
|
||||
unsigned char pan; /* 0-64, 100 for surround */
|
||||
signed char subpan; /* use (pan + subpan/256.0f) or ((pan<<8)+subpan) */
|
||||
unsigned char filter_cutoff; /* 0-127 cutoff=127 AND resonance=0 */
|
||||
unsigned char filter_subcutoff; /* 0-255 -> no filters (subcutoff */
|
||||
unsigned char filter_resonance; /* 0-127 always 0 in this case) */
|
||||
/* subcutoff only changes from zero if filter envelopes are in use. The
|
||||
* calculation (filter_cutoff + filter_subcutoff/256.0f) gives a more
|
||||
* accurate filter cutoff measurement as a float. It would often be more
|
||||
* useful to use a scaled int such as ((cutoff<<8) + subcutoff).
|
||||
*/
|
||||
};
|
||||
|
||||
/* Values of 64 or more will access NNA channels here. */
|
||||
void DUMBEXPORT dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel, DUMB_IT_CHANNEL_STATE *state);
|
||||
|
||||
|
||||
/* Signal Design Helper Values */
|
||||
|
||||
/* Use pow(DUMB_SEMITONE_BASE, n) to get the 'delta' value to transpose up by
|
||||
* n semitones. To transpose down, use negative n.
|
||||
*/
|
||||
#define DUMB_SEMITONE_BASE 1.059463094359295309843105314939748495817
|
||||
|
||||
/* Use pow(DUMB_QUARTERTONE_BASE, n) to get the 'delta' value to transpose up
|
||||
* by n quartertones. To transpose down, use negative n.
|
||||
*/
|
||||
#define DUMB_QUARTERTONE_BASE 1.029302236643492074463779317738953977823
|
||||
|
||||
/* Use pow(DUMB_PITCH_BASE, n) to get the 'delta' value to transpose up by n
|
||||
* units. In this case, 256 units represent one semitone; 3072 units
|
||||
* represent one octave. These units are used by the sequence signal (SEQU).
|
||||
*/
|
||||
#define DUMB_PITCH_BASE 1.000225659305069791926712241547647863626
|
||||
|
||||
|
||||
/* Signal Design Function Types */
|
||||
|
||||
typedef void sigdata_t;
|
||||
typedef void sigrenderer_t;
|
||||
|
||||
typedef sigdata_t *(*DUH_LOAD_SIGDATA)(DUH *duh, DUMBFILE *file);
|
||||
|
||||
typedef sigrenderer_t *(*DUH_START_SIGRENDERER)(
|
||||
DUH *duh,
|
||||
sigdata_t *sigdata,
|
||||
int n_channels,
|
||||
int32 pos
|
||||
);
|
||||
|
||||
typedef void (*DUH_SIGRENDERER_SET_SIGPARAM)(
|
||||
sigrenderer_t *sigrenderer,
|
||||
unsigned char id, int32 value
|
||||
);
|
||||
|
||||
typedef int32 (*DUH_SIGRENDERER_GENERATE_SAMPLES)(
|
||||
sigrenderer_t *sigrenderer,
|
||||
double volume, double delta,
|
||||
int32 size, sample_t **samples
|
||||
);
|
||||
|
||||
typedef void (*DUH_SIGRENDERER_GET_CURRENT_SAMPLE)(
|
||||
sigrenderer_t *sigrenderer,
|
||||
double volume,
|
||||
sample_t *samples
|
||||
);
|
||||
|
||||
typedef void (*DUH_END_SIGRENDERER)(sigrenderer_t *sigrenderer);
|
||||
|
||||
typedef void (*DUH_UNLOAD_SIGDATA)(sigdata_t *sigdata);
|
||||
|
||||
|
||||
/* Signal Design Function Registration */
|
||||
|
||||
typedef struct DUH_SIGTYPE_DESC
|
||||
{
|
||||
int32 type;
|
||||
DUH_LOAD_SIGDATA load_sigdata;
|
||||
DUH_START_SIGRENDERER start_sigrenderer;
|
||||
DUH_SIGRENDERER_SET_SIGPARAM sigrenderer_set_sigparam;
|
||||
DUH_SIGRENDERER_GENERATE_SAMPLES sigrenderer_generate_samples;
|
||||
DUH_SIGRENDERER_GET_CURRENT_SAMPLE sigrenderer_get_current_sample;
|
||||
DUH_END_SIGRENDERER end_sigrenderer;
|
||||
DUH_UNLOAD_SIGDATA unload_sigdata;
|
||||
}
|
||||
DUH_SIGTYPE_DESC;
|
||||
|
||||
void DUMBEXPORT dumb_register_sigtype(DUH_SIGTYPE_DESC *desc);
|
||||
|
||||
|
||||
// Decide where to put these functions; new heading?
|
||||
|
||||
sigdata_t *DUMBEXPORT duh_get_raw_sigdata(DUH *duh, int sig, int32 type);
|
||||
|
||||
DUH_SIGRENDERER *DUMBEXPORT duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, int32 pos);
|
||||
sigrenderer_t *DUMBEXPORT duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, int32 type);
|
||||
|
||||
int DUMBEXPORT duh_add_signal(DUH *duh, DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata);
|
||||
|
||||
|
||||
/* Standard Signal Types */
|
||||
|
||||
//void dumb_register_sigtype_sample(void);
|
||||
|
||||
|
||||
/* Sample Buffer Allocation Helpers */
|
||||
|
||||
#ifdef DUMB_DECLARE_DEPRECATED
|
||||
sample_t **create_sample_buffer(int n_channels, int32 length) DUMB_DEPRECATED;
|
||||
/* DUMB has been changed to interleave stereo samples. Use
|
||||
* allocate_sample_buffer() instead, and see the comments for
|
||||
* duh_sigrenderer_set_analyser_callback().
|
||||
*/
|
||||
#endif
|
||||
sample_t **DUMBEXPORT allocate_sample_buffer(int n_channels, int32 length);
|
||||
void DUMBEXPORT destroy_sample_buffer(sample_t **samples);
|
||||
|
||||
|
||||
/* Silencing Helper */
|
||||
|
||||
void DUMBEXPORT dumb_silence(sample_t *samples, int32 length);
|
||||
|
||||
|
||||
/* Click Removal Helpers */
|
||||
|
||||
typedef struct DUMB_CLICK_REMOVER DUMB_CLICK_REMOVER;
|
||||
|
||||
DUMB_CLICK_REMOVER *DUMBEXPORT dumb_create_click_remover(void);
|
||||
void DUMBEXPORT dumb_record_click(DUMB_CLICK_REMOVER *cr, int32 pos, sample_t step);
|
||||
void DUMBEXPORT dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, int32 length, int step, double halflife);
|
||||
sample_t DUMBEXPORT dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr);
|
||||
void DUMBEXPORT dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr);
|
||||
|
||||
DUMB_CLICK_REMOVER **DUMBEXPORT dumb_create_click_remover_array(int n);
|
||||
void DUMBEXPORT dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, int32 pos, sample_t *step);
|
||||
void DUMBEXPORT dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, int32 pos, sample_t *step);
|
||||
void DUMBEXPORT dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, int32 length, double halflife);
|
||||
void DUMBEXPORT dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr, sample_t *offset);
|
||||
void DUMBEXPORT dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr);
|
||||
|
||||
|
||||
/* Resampling Helpers */
|
||||
|
||||
#define DUMB_RQ_ALIASING 0
|
||||
#define DUMB_LQ_LINEAR 1
|
||||
#define DUMB_LQ_CUBIC 2
|
||||
|
||||
#define DUMB_RQ_BLEP 3
|
||||
#define DUMB_RQ_LINEAR 4
|
||||
#define DUMB_RQ_BLAM 5
|
||||
#define DUMB_RQ_CUBIC 6
|
||||
#define DUMB_RQ_FIR 7
|
||||
#define DUMB_RQ_N_LEVELS 8
|
||||
|
||||
/* Subtract quality above by this to convert to resampler.c's quality */
|
||||
#define DUMB_RESAMPLER_BASE 2
|
||||
|
||||
extern int dumb_resampling_quality; /* This specifies the default */
|
||||
void DUMBEXPORT dumb_it_set_resampling_quality(DUMB_IT_SIGRENDERER * sigrenderer, int quality); /* This overrides it */
|
||||
|
||||
typedef struct DUMB_RESAMPLER DUMB_RESAMPLER;
|
||||
|
||||
typedef struct DUMB_VOLUME_RAMP_INFO DUMB_VOLUME_RAMP_INFO;
|
||||
|
||||
typedef void (*DUMB_RESAMPLE_PICKUP)(DUMB_RESAMPLER *resampler, void *data);
|
||||
|
||||
struct DUMB_RESAMPLER
|
||||
{
|
||||
void *src;
|
||||
int32 pos;
|
||||
int subpos;
|
||||
int32 start, end;
|
||||
int dir;
|
||||
DUMB_RESAMPLE_PICKUP pickup;
|
||||
void *pickup_data;
|
||||
int quality;
|
||||
/* Everything below this point is internal: do not use. */
|
||||
union {
|
||||
sample_t x24[3*2];
|
||||
short x16[3*2];
|
||||
signed char x8[3*2];
|
||||
} x;
|
||||
int overshot;
|
||||
double fir_resampler_ratio;
|
||||
void* fir_resampler[2];
|
||||
};
|
||||
|
||||
struct DUMB_VOLUME_RAMP_INFO
|
||||
{
|
||||
float volume;
|
||||
float delta;
|
||||
float target;
|
||||
float mix;
|
||||
unsigned char declick_stage;
|
||||
};
|
||||
|
||||
void dumb_reset_resampler(DUMB_RESAMPLER *resampler, sample_t *src, int src_channels, int32 pos, int32 start, int32 end, int quality);
|
||||
DUMB_RESAMPLER *dumb_start_resampler(sample_t *src, int src_channels, int32 pos, int32 start, int32 end, int quality);
|
||||
//int32 dumb_resample_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume, double delta);
|
||||
int32 dumb_resample_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta);
|
||||
//int32 dumb_resample_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta);
|
||||
int32 dumb_resample_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta);
|
||||
//void dumb_resample_get_current_sample_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
|
||||
void dumb_resample_get_current_sample_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
|
||||
//void dumb_resample_get_current_sample_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
|
||||
void dumb_resample_get_current_sample_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
|
||||
void dumb_end_resampler(DUMB_RESAMPLER *resampler);
|
||||
|
||||
void dumb_reset_resampler_16(DUMB_RESAMPLER *resampler, short *src, int src_channels, int32 pos, int32 start, int32 end, int quality);
|
||||
DUMB_RESAMPLER *dumb_start_resampler_16(short *src, int src_channels, int32 pos, int32 start, int32 end, int quality);
|
||||
//int32 dumb_resample_16_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume, double delta);
|
||||
int32 dumb_resample_16_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta);
|
||||
//int32 dumb_resample_16_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta);
|
||||
int32 dumb_resample_16_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta);
|
||||
//void dumb_resample_get_current_sample_16_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
|
||||
void dumb_resample_get_current_sample_16_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
|
||||
//void dumb_resample_get_current_sample_16_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
|
||||
void dumb_resample_get_current_sample_16_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
|
||||
void dumb_end_resampler_16(DUMB_RESAMPLER *resampler);
|
||||
|
||||
void dumb_reset_resampler_8(DUMB_RESAMPLER *resampler, signed char *src, int src_channels, int32 pos, int32 start, int32 end, int quality);
|
||||
DUMB_RESAMPLER *dumb_start_resampler_8(signed char *src, int src_channels, int32 pos, int32 start, int32 end, int quality);
|
||||
//int32 dumb_resample_8_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume, double delta);
|
||||
int32 dumb_resample_8_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta);
|
||||
//int32 dumb_resample_8_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta);
|
||||
int32 dumb_resample_8_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta);
|
||||
//void dumb_resample_get_current_sample_8_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
|
||||
void dumb_resample_get_current_sample_8_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
|
||||
//void dumb_resample_get_current_sample_8_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
|
||||
void dumb_resample_get_current_sample_8_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
|
||||
void dumb_end_resampler_8(DUMB_RESAMPLER *resampler);
|
||||
|
||||
void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, int32 pos, int32 start, int32 end, int quality);
|
||||
DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, int32 pos, int32 start, int32 end, int quality);
|
||||
//int32 dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume, double delta);
|
||||
int32 dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta);
|
||||
//int32 dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta);
|
||||
int32 dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta);
|
||||
//void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *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);
|
||||
//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);
|
||||
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);
|
||||
void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler);
|
||||
|
||||
/* This sets the default panning separation for hard panned formats,
|
||||
or for formats with default panning information. This must be set
|
||||
before using any readers or loaders, and is not really thread safe. */
|
||||
|
||||
extern int dumb_it_default_panning_separation; /* in percent, default 25 */
|
||||
|
||||
/* DUH Construction */
|
||||
|
||||
DUH *make_duh(
|
||||
int32 length,
|
||||
int n_tags,
|
||||
const char *const tag[][2],
|
||||
int n_signals,
|
||||
DUH_SIGTYPE_DESC *desc[],
|
||||
sigdata_t *sigdata[]
|
||||
);
|
||||
|
||||
void DUMBEXPORT duh_set_length(DUH *duh, int32 length);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* DUMB_H */
|
|
@ -1,27 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* internal/aldumb.h - The internal header file / / \ \
|
||||
* for DUMB with Allegro. | < / \_
|
||||
* | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#ifndef INTERNAL_ALDUMB_H
|
||||
#define INTERNAL_ALDUMB_H
|
||||
|
||||
|
||||
void _dat_unload_duh(void *duh);
|
||||
|
||||
|
||||
#endif /* INTERNAL_DUMB_H */
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef _B_ARRAY_H_
|
||||
#define _B_ARRAY_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef BARRAY_DECORATE
|
||||
#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_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);
|
||||
|
||||
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_merge(void * array, void * source, size_t offset);
|
||||
void bit_array_mask(void * array, void * source, size_t offset);
|
||||
|
||||
#endif
|
|
@ -1,61 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* internal/dumb.h - DUMB's internal declarations. / / \ \
|
||||
* | < / \_
|
||||
* This header file provides access to the | \/ /\ /
|
||||
* internal structure of DUMB, and is liable \_ / > /
|
||||
* to change, mutate or cease to exist at any | \ / /
|
||||
* moment. Include it at your own peril. | ' /
|
||||
* \__/
|
||||
* ...
|
||||
*
|
||||
* Seriously. You don't need access to anything in this file. All right, you
|
||||
* probably do actually. But if you use it, you will be relying on a specific
|
||||
* version of DUMB, so please check DUMB_VERSION defined in dumb.h. Please
|
||||
* contact the authors so that we can provide a public API for what you need.
|
||||
*/
|
||||
|
||||
#ifndef INTERNAL_DUMB_H
|
||||
#define INTERNAL_DUMB_H
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
||||
struct DUH
|
||||
{
|
||||
int32 length;
|
||||
|
||||
int n_tags;
|
||||
char *(*tag)[2];
|
||||
|
||||
int n_signals;
|
||||
DUH_SIGNAL **signal;
|
||||
};
|
||||
|
||||
|
||||
DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(int32 type);
|
||||
|
||||
|
||||
#endif /* INTERNAL_DUMB_H */
|
|
@ -1,13 +0,0 @@
|
|||
#ifndef DUMBFILE_H
|
||||
#define DUMBFILE_H
|
||||
|
||||
#include "../dumb.h"
|
||||
|
||||
struct DUMBFILE
|
||||
{
|
||||
const DUMBFILE_SYSTEM *dfs;
|
||||
void *file;
|
||||
long pos;
|
||||
};
|
||||
|
||||
#endif // DUMBFILE_H
|
|
@ -1,914 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* internal/it.h - Internal stuff for IT playback / / \ \
|
||||
* and MOD/XM/S3M conversion. | < / \_
|
||||
* | \/ /\ /
|
||||
* This header file provides access to the \_ / > /
|
||||
* internal structure of DUMB, and is liable | \ / /
|
||||
* to change, mutate or cease to exist at any | ' /
|
||||
* moment. Include it at your own peril. \__/
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* Seriously. You don't need access to anything in this file. All right, you
|
||||
* probably do actually. But if you use it, you will be relying on a specific
|
||||
* version of DUMB, so please check DUMB_VERSION defined in dumb.h. Please
|
||||
* contact the authors so that we can provide a public API for what you need.
|
||||
*/
|
||||
|
||||
#ifndef INTERNAL_IT_H
|
||||
#define INTERNAL_IT_H
|
||||
|
||||
|
||||
#define BIT_ARRAY_BULLSHIT
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "barray.h"
|
||||
|
||||
|
||||
/** TO DO: THINK ABOUT THE FOLLOWING:
|
||||
|
||||
sigdata->flags & IT_COMPATIBLE_GXX
|
||||
|
||||
Bit 5: On = Link Effect G's memory with Effect E/F. Also
|
||||
Gxx with an instrument present will cause the
|
||||
envelopes to be retriggered. If you change a
|
||||
sample on a row with Gxx, it'll adjust the
|
||||
frequency of the current note according to:
|
||||
|
||||
NewFrequency = OldFrequency * NewC5 / OldC5;
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* These #defines are TEMPORARY. They are used to write alternative code to
|
||||
* handle ambiguities in the format specification. The correct code in each
|
||||
* case will be determined most likely by experimentation.
|
||||
*/
|
||||
//#define STEREO_SAMPLES_COUNT_AS_TWO
|
||||
#define INVALID_ORDERS_END_SONG
|
||||
#define SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP
|
||||
#define VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
|
||||
|
||||
|
||||
|
||||
#define SIGTYPE_IT DUMB_ID('I', 'T', ' ', ' ')
|
||||
|
||||
#define IT_SIGNATURE DUMB_ID('I', 'M', 'P', 'M')
|
||||
#define IT_INSTRUMENT_SIGNATURE DUMB_ID('I', 'M', 'P', 'I')
|
||||
#define IT_SAMPLE_SIGNATURE DUMB_ID('I', 'M', 'P', 'S')
|
||||
|
||||
// olivier sux
|
||||
#define IT_MPTX_SIGNATURE DUMB_ID('X', 'T', 'P', 'M')
|
||||
#define IT_INSM_SIGNATURE DUMB_ID('M', 'S', 'N', 'I')
|
||||
|
||||
|
||||
/* This is divided by the tempo times 256 to get the interval between ticks.
|
||||
*/
|
||||
#define TICK_TIME_DIVIDEND (65536 * 5 * 128)
|
||||
|
||||
|
||||
|
||||
/* I'm not going to try to explain this, because I didn't derive it very
|
||||
* formally ;)
|
||||
*/
|
||||
/* #define AMIGA_DIVISOR ((float)(4.0 * 14317056.0)) */
|
||||
/* I believe the following one to be more accurate. */
|
||||
//#define AMIGA_DIVISOR ((float)(8.0 * 7159090.5))
|
||||
#define AMIGA_CLOCK 3546895
|
||||
#define AMIGA_DIVISOR ((float)(16.0 * AMIGA_CLOCK))
|
||||
|
||||
|
||||
|
||||
typedef struct IT_MIDI IT_MIDI;
|
||||
typedef struct IT_FILTER_STATE IT_FILTER_STATE;
|
||||
typedef struct IT_ENVELOPE IT_ENVELOPE;
|
||||
typedef struct IT_INSTRUMENT IT_INSTRUMENT;
|
||||
typedef struct IT_SAMPLE IT_SAMPLE;
|
||||
typedef struct IT_ENTRY IT_ENTRY;
|
||||
typedef struct IT_PATTERN IT_PATTERN;
|
||||
typedef struct IT_PLAYING_ENVELOPE IT_PLAYING_ENVELOPE;
|
||||
typedef struct IT_PLAYING IT_PLAYING;
|
||||
typedef struct IT_CHANNEL IT_CHANNEL;
|
||||
typedef struct IT_CHECKPOINT IT_CHECKPOINT;
|
||||
typedef struct IT_CALLBACKS IT_CALLBACKS;
|
||||
|
||||
|
||||
|
||||
struct IT_MIDI
|
||||
{
|
||||
unsigned char SFmacro[16][16]; // read these from 0x120
|
||||
unsigned char SFmacrolen[16];
|
||||
unsigned short SFmacroz[16]; /* Bitfield; bit 0 set = z in first position */
|
||||
unsigned char Zmacro[128][16]; // read these from 0x320
|
||||
unsigned char Zmacrolen[128];
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct IT_FILTER_STATE
|
||||
{
|
||||
sample_t currsample, prevsample;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define IT_ENVELOPE_ON 1
|
||||
#define IT_ENVELOPE_LOOP_ON 2
|
||||
#define IT_ENVELOPE_SUSTAIN_LOOP 4
|
||||
#define IT_ENVELOPE_CARRY 8
|
||||
#define IT_ENVELOPE_PITCH_IS_FILTER 128
|
||||
|
||||
struct IT_ENVELOPE
|
||||
{
|
||||
unsigned char flags;
|
||||
unsigned char n_nodes;
|
||||
unsigned char loop_start;
|
||||
unsigned char loop_end;
|
||||
unsigned char sus_loop_start;
|
||||
unsigned char sus_loop_end;
|
||||
signed char node_y[25];
|
||||
unsigned short node_t[25];
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define NNA_NOTE_CUT 0
|
||||
#define NNA_NOTE_CONTINUE 1
|
||||
#define NNA_NOTE_OFF 2
|
||||
#define NNA_NOTE_FADE 3
|
||||
|
||||
#define DCT_OFF 0
|
||||
#define DCT_NOTE 1
|
||||
#define DCT_SAMPLE 2
|
||||
#define DCT_INSTRUMENT 3
|
||||
|
||||
#define DCA_NOTE_CUT 0
|
||||
#define DCA_NOTE_OFF 1
|
||||
#define DCA_NOTE_FADE 2
|
||||
|
||||
struct IT_INSTRUMENT
|
||||
{
|
||||
unsigned char name[27];
|
||||
unsigned char filename[14];
|
||||
|
||||
int fadeout;
|
||||
|
||||
IT_ENVELOPE volume_envelope;
|
||||
IT_ENVELOPE pan_envelope;
|
||||
IT_ENVELOPE pitch_envelope;
|
||||
|
||||
unsigned char new_note_action;
|
||||
unsigned char dup_check_type;
|
||||
unsigned char dup_check_action;
|
||||
signed char pp_separation;
|
||||
unsigned char pp_centre;
|
||||
unsigned char global_volume;
|
||||
unsigned char default_pan;
|
||||
unsigned char random_volume;
|
||||
unsigned char random_pan;
|
||||
|
||||
unsigned char filter_cutoff;
|
||||
unsigned char filter_resonance;
|
||||
|
||||
unsigned char map_note[120];
|
||||
unsigned short map_sample[120];
|
||||
|
||||
//int output;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define IT_SAMPLE_EXISTS 1
|
||||
#define IT_SAMPLE_16BIT 2
|
||||
#define IT_SAMPLE_STEREO 4
|
||||
#define IT_SAMPLE_LOOP 16
|
||||
#define IT_SAMPLE_SUS_LOOP 32
|
||||
#define IT_SAMPLE_PINGPONG_LOOP 64
|
||||
#define IT_SAMPLE_PINGPONG_SUS_LOOP 128
|
||||
|
||||
#define IT_VIBRATO_SINE 0
|
||||
#define IT_VIBRATO_SAWTOOTH 1
|
||||
#define IT_VIBRATO_SQUARE 2
|
||||
#define IT_VIBRATO_RANDOM 3
|
||||
#define IT_VIBRATO_XM_SQUARE 4
|
||||
#define IT_VIBRATO_RAMP_DOWN 5
|
||||
#define IT_VIBRATO_RAMP_UP 6
|
||||
|
||||
struct IT_SAMPLE
|
||||
{
|
||||
unsigned char name[35];
|
||||
unsigned char filename[15];
|
||||
unsigned char flags;
|
||||
unsigned char global_volume;
|
||||
unsigned char default_volume;
|
||||
unsigned char default_pan;
|
||||
/* default_pan:
|
||||
* 0-255 for XM
|
||||
* ignored for MOD
|
||||
* otherwise, 0-64, and add 128 to enable
|
||||
*/
|
||||
|
||||
int32 length;
|
||||
int32 loop_start;
|
||||
int32 loop_end;
|
||||
int32 C5_speed;
|
||||
int32 sus_loop_start;
|
||||
int32 sus_loop_end;
|
||||
|
||||
unsigned char vibrato_speed;
|
||||
unsigned char vibrato_depth;
|
||||
unsigned char vibrato_rate;
|
||||
unsigned char vibrato_waveform;
|
||||
|
||||
signed short finetune;
|
||||
|
||||
void *data;
|
||||
|
||||
int max_resampling_quality;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define IT_ENTRY_NOTE 1
|
||||
#define IT_ENTRY_INSTRUMENT 2
|
||||
#define IT_ENTRY_VOLPAN 4
|
||||
#define IT_ENTRY_EFFECT 8
|
||||
|
||||
#define IT_SET_END_ROW(entry) ((entry)->channel = 255)
|
||||
#define IT_IS_END_ROW(entry) ((entry)->channel >= DUMB_IT_N_CHANNELS)
|
||||
|
||||
#define IT_NOTE_OFF 255
|
||||
#define IT_NOTE_CUT 254
|
||||
|
||||
#define IT_ENVELOPE_SHIFT 8
|
||||
|
||||
#define IT_SURROUND 100
|
||||
#define IT_IS_SURROUND(pan) ((pan) > 64)
|
||||
#define IT_IS_SURROUND_SHIFTED(pan) ((pan) > 64 << IT_ENVELOPE_SHIFT)
|
||||
|
||||
#define IT_SET_SPEED 1
|
||||
#define IT_JUMP_TO_ORDER 2
|
||||
#define IT_BREAK_TO_ROW 3
|
||||
#define IT_VOLUME_SLIDE 4
|
||||
#define IT_PORTAMENTO_DOWN 5
|
||||
#define IT_PORTAMENTO_UP 6
|
||||
#define IT_TONE_PORTAMENTO 7
|
||||
#define IT_VIBRATO 8
|
||||
#define IT_TREMOR 9
|
||||
#define IT_ARPEGGIO 10
|
||||
#define IT_VOLSLIDE_VIBRATO 11
|
||||
#define IT_VOLSLIDE_TONEPORTA 12
|
||||
#define IT_SET_CHANNEL_VOLUME 13
|
||||
#define IT_CHANNEL_VOLUME_SLIDE 14
|
||||
#define IT_SET_SAMPLE_OFFSET 15
|
||||
#define IT_PANNING_SLIDE 16
|
||||
#define IT_RETRIGGER_NOTE 17
|
||||
#define IT_TREMOLO 18
|
||||
#define IT_S 19
|
||||
#define IT_SET_SONG_TEMPO 20
|
||||
#define IT_FINE_VIBRATO 21
|
||||
#define IT_SET_GLOBAL_VOLUME 22
|
||||
#define IT_GLOBAL_VOLUME_SLIDE 23
|
||||
#define IT_SET_PANNING 24
|
||||
#define IT_PANBRELLO 25
|
||||
#define IT_MIDI_MACRO 26 //see MIDI.TXT
|
||||
|
||||
/* Some effects needed for XM compatibility */
|
||||
#define IT_XM_PORTAMENTO_DOWN 27
|
||||
#define IT_XM_PORTAMENTO_UP 28
|
||||
#define IT_XM_FINE_VOLSLIDE_DOWN 29
|
||||
#define IT_XM_FINE_VOLSLIDE_UP 30
|
||||
#define IT_XM_RETRIGGER_NOTE 31
|
||||
#define IT_XM_KEY_OFF 32
|
||||
#define IT_XM_SET_ENVELOPE_POSITION 33
|
||||
|
||||
/* More effects needed for PTM compatibility */
|
||||
#define IT_PTM_NOTE_SLIDE_DOWN 34
|
||||
#define IT_PTM_NOTE_SLIDE_UP 35
|
||||
#define IT_PTM_NOTE_SLIDE_DOWN_RETRIG 36
|
||||
#define IT_PTM_NOTE_SLIDE_UP_RETRIG 37
|
||||
|
||||
/* More effects needed for OKT compatibility */
|
||||
#define IT_OKT_NOTE_SLIDE_DOWN 38
|
||||
#define IT_OKT_NOTE_SLIDE_DOWN_ROW 39
|
||||
#define IT_OKT_NOTE_SLIDE_UP 40
|
||||
#define IT_OKT_NOTE_SLIDE_UP_ROW 41
|
||||
#define IT_OKT_ARPEGGIO_3 42
|
||||
#define IT_OKT_ARPEGGIO_4 43
|
||||
#define IT_OKT_ARPEGGIO_5 44
|
||||
#define IT_OKT_VOLUME_SLIDE_DOWN 45
|
||||
#define IT_OKT_VOLUME_SLIDE_UP 46
|
||||
|
||||
#define IT_N_EFFECTS 47
|
||||
|
||||
/* These represent the top nibble of the command value. */
|
||||
#define IT_S_SET_FILTER 0 /* Greyed out in IT... */
|
||||
#define IT_S_SET_GLISSANDO_CONTROL 1 /* Greyed out in IT... */
|
||||
#define IT_S_FINETUNE 2 /* Greyed out in IT... */
|
||||
#define IT_S_SET_VIBRATO_WAVEFORM 3
|
||||
#define IT_S_SET_TREMOLO_WAVEFORM 4
|
||||
#define IT_S_SET_PANBRELLO_WAVEFORM 5
|
||||
#define IT_S_FINE_PATTERN_DELAY 6
|
||||
#define IT_S7 7
|
||||
#define IT_S_SET_PAN 8
|
||||
#define IT_S_SET_SURROUND_SOUND 9
|
||||
#define IT_S_SET_HIGH_OFFSET 10
|
||||
#define IT_S_PATTERN_LOOP 11
|
||||
#define IT_S_DELAYED_NOTE_CUT 12
|
||||
#define IT_S_NOTE_DELAY 13
|
||||
#define IT_S_PATTERN_DELAY 14
|
||||
#define IT_S_SET_MIDI_MACRO 15
|
||||
|
||||
/*
|
||||
S0x Set filter
|
||||
S1x Set glissando control
|
||||
S2x Set finetune
|
||||
|
||||
|
||||
S3x Set vibrato waveform to type x
|
||||
S4x Set tremelo waveform to type x
|
||||
S5x Set panbrello waveform to type x
|
||||
Waveforms for commands S3x, S4x and S5x:
|
||||
0: Sine wave
|
||||
1: Ramp down
|
||||
2: Square wave
|
||||
3: Random wave
|
||||
S6x Pattern delay for x ticks
|
||||
S70 Past note cut
|
||||
S71 Past note off
|
||||
S72 Past note fade
|
||||
S73 Set NNA to note cut
|
||||
S74 Set NNA to continue
|
||||
S75 Set NNA to note off
|
||||
S76 Set NNA to note fade
|
||||
S77 Turn off volume envelope
|
||||
S78 Turn on volume envelope
|
||||
S79 Turn off panning envelope
|
||||
S7A Turn on panning envelope
|
||||
S7B Turn off pitch envelope
|
||||
S7C Turn on pitch envelope
|
||||
S8x Set panning position
|
||||
S91 Set surround sound
|
||||
SAy Set high value of sample offset yxx00h
|
||||
SB0 Set loopback point
|
||||
SBx Loop x times to loopback point
|
||||
SCx Note cut after x ticks
|
||||
SDx Note delay for x ticks
|
||||
SEx Pattern delay for x rows
|
||||
SFx Set parameterised MIDI Macro
|
||||
*/
|
||||
|
||||
struct IT_ENTRY
|
||||
{
|
||||
unsigned char channel; /* End of row if channel >= DUMB_IT_N_CHANNELS */
|
||||
unsigned char mask;
|
||||
unsigned char note;
|
||||
unsigned char instrument;
|
||||
unsigned char volpan;
|
||||
unsigned char effect;
|
||||
unsigned char effectvalue;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct IT_PATTERN
|
||||
{
|
||||
int n_rows;
|
||||
int n_entries;
|
||||
IT_ENTRY *entry;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define IT_STEREO 1
|
||||
#define IT_USE_INSTRUMENTS 4
|
||||
#define IT_LINEAR_SLIDES 8 /* If not set, use Amiga slides */
|
||||
#define IT_OLD_EFFECTS 16
|
||||
#define IT_COMPATIBLE_GXX 32
|
||||
|
||||
/* Make sure IT_WAS_AN_XM and IT_WAS_A_MOD aren't set accidentally */
|
||||
#define IT_REAL_FLAGS 63
|
||||
|
||||
#define IT_WAS_AN_XM 64 /* Set for both XMs and MODs */
|
||||
#define IT_WAS_A_MOD 128
|
||||
|
||||
#define IT_WAS_AN_S3M 256
|
||||
|
||||
#define IT_WAS_A_PTM 512
|
||||
|
||||
#define IT_WAS_A_669 1024
|
||||
|
||||
#define IT_WAS_AN_OKT 2048
|
||||
|
||||
#define IT_WAS_AN_STM 4096
|
||||
|
||||
#define IT_WAS_PROCESSED 8192 /* Will be set the first time a sigdata passes through a sigrenderer */
|
||||
|
||||
#define IT_ORDER_END 255
|
||||
#define IT_ORDER_SKIP 254
|
||||
|
||||
struct DUMB_IT_SIGDATA
|
||||
{
|
||||
unsigned char name[65];
|
||||
|
||||
unsigned char *song_message;
|
||||
|
||||
int n_orders;
|
||||
int n_instruments;
|
||||
int n_samples;
|
||||
int n_patterns;
|
||||
int n_pchannels;
|
||||
|
||||
int flags;
|
||||
|
||||
int global_volume;
|
||||
int mixing_volume;
|
||||
int speed;
|
||||
int tempo;
|
||||
int pan_separation;
|
||||
|
||||
unsigned char channel_pan[DUMB_IT_N_CHANNELS];
|
||||
unsigned char channel_volume[DUMB_IT_N_CHANNELS];
|
||||
|
||||
unsigned char *order;
|
||||
unsigned char restart_position; /* for XM compatiblity */
|
||||
|
||||
IT_INSTRUMENT *instrument;
|
||||
IT_SAMPLE *sample;
|
||||
IT_PATTERN *pattern;
|
||||
|
||||
IT_MIDI *midi;
|
||||
|
||||
IT_CHECKPOINT *checkpoint;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct IT_PLAYING_ENVELOPE
|
||||
{
|
||||
int next_node;
|
||||
int tick;
|
||||
int value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define IT_PLAYING_BACKGROUND 1
|
||||
#define IT_PLAYING_SUSTAINOFF 2
|
||||
#define IT_PLAYING_FADING 4
|
||||
#define IT_PLAYING_DEAD 8
|
||||
#define IT_PLAYING_REVERSE 16
|
||||
|
||||
struct IT_PLAYING
|
||||
{
|
||||
int flags;
|
||||
|
||||
int resampling_quality;
|
||||
|
||||
IT_CHANNEL *channel;
|
||||
IT_SAMPLE *sample;
|
||||
IT_INSTRUMENT *instrument;
|
||||
IT_INSTRUMENT *env_instrument;
|
||||
|
||||
unsigned short sampnum;
|
||||
unsigned char instnum;
|
||||
|
||||
unsigned char declick_stage;
|
||||
|
||||
float float_volume[2];
|
||||
float ramp_volume[2];
|
||||
float ramp_delta[2];
|
||||
|
||||
unsigned char channel_volume;
|
||||
|
||||
unsigned char volume;
|
||||
unsigned short pan;
|
||||
|
||||
signed char volume_offset, panning_offset;
|
||||
|
||||
unsigned char note;
|
||||
|
||||
unsigned char enabled_envelopes;
|
||||
|
||||
unsigned char filter_cutoff;
|
||||
unsigned char filter_resonance;
|
||||
|
||||
unsigned short true_filter_cutoff; /* These incorporate the filter envelope, and will not */
|
||||
unsigned char true_filter_resonance; /* be changed if they would be set to 127<<8 and 0. */
|
||||
|
||||
unsigned char vibrato_speed;
|
||||
unsigned char vibrato_depth;
|
||||
unsigned char vibrato_n; /* May be specified twice: volpan & effect. */
|
||||
unsigned char vibrato_time;
|
||||
unsigned char vibrato_waveform;
|
||||
|
||||
unsigned char tremolo_speed;
|
||||
unsigned char tremolo_depth;
|
||||
unsigned char tremolo_time;
|
||||
unsigned char tremolo_waveform;
|
||||
|
||||
unsigned char panbrello_speed;
|
||||
unsigned char panbrello_depth;
|
||||
unsigned char panbrello_time;
|
||||
unsigned char panbrello_waveform;
|
||||
signed char panbrello_random;
|
||||
|
||||
unsigned char sample_vibrato_time;
|
||||
unsigned char sample_vibrato_waveform;
|
||||
int sample_vibrato_depth; /* Starts at rate?0:depth, increases by rate */
|
||||
|
||||
int slide;
|
||||
float delta;
|
||||
int finetune;
|
||||
|
||||
IT_PLAYING_ENVELOPE volume_envelope;
|
||||
IT_PLAYING_ENVELOPE pan_envelope;
|
||||
IT_PLAYING_ENVELOPE pitch_envelope;
|
||||
|
||||
int fadeoutcount;
|
||||
|
||||
IT_FILTER_STATE filter_state[2]; /* Left and right */
|
||||
|
||||
DUMB_RESAMPLER resampler;
|
||||
|
||||
/* time_lost is used to emulate Impulse Tracker's sample looping
|
||||
* characteristics. When time_lost is added to pos, the result represents
|
||||
* the position in the theoretical version of the sample where all loops
|
||||
* have been expanded. If this is stored, the resampling helpers will
|
||||
* safely convert it for use with new loop boundaries. The situation is
|
||||
* slightly more complicated if dir == -1 when the change takes place; we
|
||||
* must reflect pos off the loop end point and set dir to 1 before
|
||||
* proceeding.
|
||||
*/
|
||||
int32 time_lost;
|
||||
|
||||
//int output;
|
||||
|
||||
IT_PLAYING *next;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define IT_CHANNEL_MUTED 1
|
||||
|
||||
#define IT_ENV_VOLUME 1
|
||||
#define IT_ENV_PANNING 2
|
||||
#define IT_ENV_PITCH 4
|
||||
|
||||
struct IT_CHANNEL
|
||||
{
|
||||
int flags;
|
||||
|
||||
unsigned char volume;
|
||||
signed char volslide;
|
||||
signed char xm_volslide;
|
||||
signed char panslide;
|
||||
|
||||
/* xm_volslide is used for volume slides done in the volume column in an
|
||||
* XM file, since it seems the volume column slide is applied first,
|
||||
* followed by clamping, followed by the effects column slide. IT does
|
||||
* not exhibit this behaviour, so xm_volslide is maintained at zero.
|
||||
*/
|
||||
|
||||
unsigned char pan;
|
||||
unsigned short truepan;
|
||||
|
||||
unsigned char channelvolume;
|
||||
signed char channelvolslide;
|
||||
|
||||
unsigned char instrument;
|
||||
unsigned char note;
|
||||
|
||||
unsigned char SFmacro;
|
||||
|
||||
unsigned char filter_cutoff;
|
||||
unsigned char filter_resonance;
|
||||
|
||||
unsigned char key_off_count;
|
||||
unsigned char note_cut_count;
|
||||
unsigned char note_delay_count;
|
||||
IT_ENTRY *note_delay_entry;
|
||||
|
||||
unsigned char new_note_action;
|
||||
|
||||
unsigned char const* arpeggio_table;
|
||||
signed char arpeggio_offsets[3];
|
||||
|
||||
int arpeggio_shift;
|
||||
unsigned char retrig;
|
||||
unsigned char xm_retrig;
|
||||
int retrig_tick;
|
||||
|
||||
unsigned char tremor;
|
||||
unsigned char tremor_time; /* Bit 6 set if note on; bit 7 set if tremor active. */
|
||||
|
||||
unsigned char vibrato_waveform;
|
||||
unsigned char tremolo_waveform;
|
||||
unsigned char panbrello_waveform;
|
||||
|
||||
int portamento;
|
||||
int toneporta;
|
||||
int toneslide;
|
||||
unsigned char toneslide_tick, last_toneslide_tick, ptm_toneslide, ptm_last_toneslide, okt_toneslide;
|
||||
unsigned char destnote;
|
||||
unsigned char toneslide_retrig;
|
||||
|
||||
unsigned char glissando;
|
||||
|
||||
/** WARNING - for neatness, should one or both of these be in the IT_PLAYING struct? */
|
||||
unsigned short sample;
|
||||
unsigned char truenote;
|
||||
|
||||
unsigned char midi_state;
|
||||
|
||||
signed char lastvolslide;
|
||||
unsigned char lastDKL;
|
||||
unsigned char lastEF; /* Doubles as last portamento up for XM files */
|
||||
unsigned char lastG;
|
||||
unsigned char lastHspeed;
|
||||
unsigned char lastHdepth;
|
||||
unsigned char lastRspeed;
|
||||
unsigned char lastRdepth;
|
||||
unsigned char lastYspeed;
|
||||
unsigned char lastYdepth;
|
||||
unsigned char lastI;
|
||||
unsigned char lastJ; /* Doubles as last portamento down for XM files */
|
||||
unsigned char lastN;
|
||||
unsigned char lastO;
|
||||
unsigned char high_offset;
|
||||
unsigned char lastP;
|
||||
unsigned char lastQ;
|
||||
unsigned char lastS;
|
||||
unsigned char pat_loop_row;
|
||||
unsigned char pat_loop_count;
|
||||
unsigned char pat_loop_end_row; /* Used to catch infinite pattern loops */
|
||||
unsigned char lastW;
|
||||
|
||||
unsigned char xm_lastE1;
|
||||
unsigned char xm_lastE2;
|
||||
unsigned char xm_lastEA;
|
||||
unsigned char xm_lastEB;
|
||||
unsigned char xm_lastX1;
|
||||
unsigned char xm_lastX2;
|
||||
|
||||
unsigned char inv_loop_delay;
|
||||
unsigned char inv_loop_speed;
|
||||
int inv_loop_offset;
|
||||
|
||||
IT_PLAYING *playing;
|
||||
|
||||
#ifdef BIT_ARRAY_BULLSHIT
|
||||
void * played_patjump;
|
||||
int played_patjump_order;
|
||||
#endif
|
||||
|
||||
//int output;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct DUMB_IT_SIGRENDERER
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
|
||||
int n_channels;
|
||||
|
||||
int resampling_quality;
|
||||
|
||||
unsigned char globalvolume;
|
||||
signed char globalvolslide;
|
||||
|
||||
int tempo;
|
||||
signed char temposlide;
|
||||
|
||||
IT_CHANNEL channel[DUMB_IT_N_CHANNELS];
|
||||
|
||||
IT_PLAYING *playing[DUMB_IT_N_NNA_CHANNELS];
|
||||
|
||||
int tick;
|
||||
int speed;
|
||||
int rowcount;
|
||||
|
||||
int order; /* Set to -1 if the song is terminated by a callback. */
|
||||
int row;
|
||||
int processorder;
|
||||
int processrow;
|
||||
int breakrow;
|
||||
|
||||
int restart_position;
|
||||
|
||||
int n_rows;
|
||||
|
||||
IT_ENTRY *entry_start;
|
||||
IT_ENTRY *entry;
|
||||
IT_ENTRY *entry_end;
|
||||
|
||||
int32 time_left; /* Time before the next tick is processed */
|
||||
int sub_time_left;
|
||||
|
||||
DUMB_CLICK_REMOVER **click_remover;
|
||||
|
||||
IT_CALLBACKS *callbacks;
|
||||
|
||||
#ifdef BIT_ARRAY_BULLSHIT
|
||||
/* bit array, which rows are played, only checked by pattern break or loop commands */
|
||||
void * played;
|
||||
#endif
|
||||
|
||||
int32 gvz_time;
|
||||
int gvz_sub_time;
|
||||
|
||||
int ramp_style;
|
||||
|
||||
//int max_output;
|
||||
|
||||
IT_PLAYING *free_playing;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct IT_CHECKPOINT
|
||||
{
|
||||
IT_CHECKPOINT *next;
|
||||
int32 time;
|
||||
DUMB_IT_SIGRENDERER *sigrenderer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct IT_CALLBACKS
|
||||
{
|
||||
int (DUMBCALLBACK *loop)(void *data);
|
||||
void *loop_data;
|
||||
/* Return 1 to prevent looping; the music will terminate abruptly. If you
|
||||
* want to make the music stop but allow samples to fade (beware, as they
|
||||
* might not fade at all!), use dumb_it_sr_set_speed() and set the speed
|
||||
* to 0. Note that xm_speed_zero() will not be called if you set the
|
||||
* speed manually, and also that this will work for IT and S3M files even
|
||||
* though the music can't stop in this way by itself.
|
||||
*/
|
||||
|
||||
int (DUMBCALLBACK *xm_speed_zero)(void *data);
|
||||
void *xm_speed_zero_data;
|
||||
/* Return 1 to terminate the mod, without letting samples fade. */
|
||||
|
||||
int (DUMBCALLBACK *midi)(void *data, int channel, unsigned char byte);
|
||||
void *midi_data;
|
||||
/* Return 1 to prevent DUMB from subsequently interpreting the MIDI bytes
|
||||
* itself. In other words, return 1 if the Zxx macros in an IT file are
|
||||
* controlling filters and shouldn't be.
|
||||
*/
|
||||
|
||||
int (DUMBCALLBACK *global_volume_zero)(void *data);
|
||||
void *global_volume_zero_data;
|
||||
/* Return 1 to terminate the module when global volume is set to zero. */
|
||||
};
|
||||
|
||||
|
||||
|
||||
void _dumb_it_end_sigrenderer(sigrenderer_t *sigrenderer);
|
||||
void _dumb_it_unload_sigdata(sigdata_t *vsigdata);
|
||||
|
||||
extern DUH_SIGTYPE_DESC _dumb_sigtype_it;
|
||||
|
||||
|
||||
|
||||
#define XM_APPREGIO 0
|
||||
#define XM_PORTAMENTO_UP 1
|
||||
#define XM_PORTAMENTO_DOWN 2
|
||||
#define XM_TONE_PORTAMENTO 3
|
||||
#define XM_VIBRATO 4
|
||||
#define XM_VOLSLIDE_TONEPORTA 5
|
||||
#define XM_VOLSLIDE_VIBRATO 6
|
||||
#define XM_TREMOLO 7
|
||||
#define XM_SET_PANNING 8
|
||||
#define XM_SAMPLE_OFFSET 9
|
||||
#define XM_VOLUME_SLIDE 10 /* A */
|
||||
#define XM_POSITION_JUMP 11 /* B */
|
||||
#define XM_SET_CHANNEL_VOLUME 12 /* C */
|
||||
#define XM_PATTERN_BREAK 13 /* D */
|
||||
#define XM_E 14 /* E */
|
||||
#define XM_SET_TEMPO_BPM 15 /* F */
|
||||
#define XM_SET_GLOBAL_VOLUME 16 /* G */
|
||||
#define XM_GLOBAL_VOLUME_SLIDE 17 /* H */
|
||||
#define XM_KEY_OFF 20 /* K (undocumented) */
|
||||
#define XM_SET_ENVELOPE_POSITION 21 /* L */
|
||||
#define XM_PANNING_SLIDE 25 /* P */
|
||||
#define XM_MULTI_RETRIG 27 /* R */
|
||||
#define XM_TREMOR 29 /* T */
|
||||
#define XM_X 33 /* X */
|
||||
#define XM_N_EFFECTS (10+26)
|
||||
|
||||
#define XM_E_SET_FILTER 0x0
|
||||
#define XM_E_FINE_PORTA_UP 0x1
|
||||
#define XM_E_FINE_PORTA_DOWN 0x2
|
||||
#define XM_E_SET_GLISSANDO_CONTROL 0x3
|
||||
#define XM_E_SET_VIBRATO_CONTROL 0x4
|
||||
#define XM_E_SET_FINETUNE 0x5
|
||||
#define XM_E_SET_LOOP 0x6
|
||||
#define XM_E_SET_TREMOLO_CONTROL 0x7
|
||||
#define XM_E_SET_PANNING 0x8
|
||||
#define XM_E_RETRIG_NOTE 0x9
|
||||
#define XM_E_FINE_VOLSLIDE_UP 0xA
|
||||
#define XM_E_FINE_VOLSLIDE_DOWN 0xB
|
||||
#define XM_E_NOTE_CUT 0xC
|
||||
#define XM_E_NOTE_DELAY 0xD
|
||||
#define XM_E_PATTERN_DELAY 0xE
|
||||
#define XM_E_SET_MIDI_MACRO 0xF
|
||||
|
||||
#define XM_X_EXTRAFINE_PORTA_UP 1
|
||||
#define XM_X_EXTRAFINE_PORTA_DOWN 2
|
||||
|
||||
/* To make my life a bit simpler during conversion, effect E:xy is converted
|
||||
* to effect number EBASE+x:y. The same applies to effect X, and IT's S. That
|
||||
* way, these effects can be manipulated like regular effects.
|
||||
*/
|
||||
#define EBASE (XM_N_EFFECTS)
|
||||
#define XBASE (EBASE+16)
|
||||
#define SBASE (IT_N_EFFECTS)
|
||||
|
||||
#define EFFECT_VALUE(x, y) (((x)<<4)|(y))
|
||||
#define HIGH(v) ((v)>>4)
|
||||
#define LOW(v) ((v)&0x0F)
|
||||
#define SET_HIGH(v, x) v = (((x)<<4)|((v)&0x0F))
|
||||
#define SET_LOW(v, y) v = (((v)&0xF0)|(y))
|
||||
#define BCD_TO_NORMAL(v) (HIGH(v)*10+LOW(v))
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
unsigned char **_dumb_malloc2(int w, int h);
|
||||
void _dumb_free2(unsigned char **line);
|
||||
#endif
|
||||
|
||||
void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry, int mod);
|
||||
int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata);
|
||||
|
||||
|
||||
#define PTM_APPREGIO 0
|
||||
#define PTM_PORTAMENTO_UP 1
|
||||
#define PTM_PORTAMENTO_DOWN 2
|
||||
#define PTM_TONE_PORTAMENTO 3
|
||||
#define PTM_VIBRATO 4
|
||||
#define PTM_VOLSLIDE_TONEPORTA 5
|
||||
#define PTM_VOLSLIDE_VIBRATO 6
|
||||
#define PTM_TREMOLO 7
|
||||
#define PTM_SAMPLE_OFFSET 9
|
||||
#define PTM_VOLUME_SLIDE 10 /* A */
|
||||
#define PTM_POSITION_JUMP 11 /* B */
|
||||
#define PTM_SET_CHANNEL_VOLUME 12 /* C */
|
||||
#define PTM_PATTERN_BREAK 13 /* D */
|
||||
#define PTM_E 14 /* E */
|
||||
#define PTM_SET_TEMPO_BPM 15 /* F */
|
||||
#define PTM_SET_GLOBAL_VOLUME 16 /* G */
|
||||
#define PTM_RETRIGGER 17 /* H */
|
||||
#define PTM_FINE_VIBRATO 18 /* I */
|
||||
#define PTM_NOTE_SLIDE_UP 19 /* J */
|
||||
#define PTM_NOTE_SLIDE_DOWN 20 /* K */
|
||||
#define PTM_NOTE_SLIDE_UP_RETRIG 21 /* L */
|
||||
#define PTM_NOTE_SLIDE_DOWN_RETRIG 22 /* M */
|
||||
#define PTM_N_EFFECTS 23
|
||||
|
||||
#define PTM_E_FINE_PORTA_DOWN 0x1
|
||||
#define PTM_E_FINE_PORTA_UP 0x2
|
||||
#define PTM_E_SET_VIBRATO_CONTROL 0x4
|
||||
#define PTM_E_SET_FINETUNE 0x5
|
||||
#define PTM_E_SET_LOOP 0x6
|
||||
#define PTM_E_SET_TREMOLO_CONTROL 0x7
|
||||
#define PTM_E_SET_PANNING 0x8
|
||||
#define PTM_E_RETRIG_NOTE 0x9
|
||||
#define PTM_E_FINE_VOLSLIDE_UP 0xA
|
||||
#define PTM_E_FINE_VOLSLIDE_DOWN 0xB
|
||||
#define PTM_E_NOTE_CUT 0xC
|
||||
#define PTM_E_NOTE_DELAY 0xD
|
||||
#define PTM_E_PATTERN_DELAY 0xE
|
||||
|
||||
/* To make my life a bit simpler during conversion, effect E:xy is converted
|
||||
* to effect number EBASE+x:y. The same applies to effect X, and IT's S. That
|
||||
* way, these effects can be manipulated like regular effects.
|
||||
*/
|
||||
#define PTM_EBASE (PTM_N_EFFECTS)
|
||||
|
||||
void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry);
|
||||
|
||||
int32 _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f);
|
||||
|
||||
void _dumb_it_interleave_stereo_sample(IT_SAMPLE *sample);
|
||||
|
||||
/* Calling either of these is optional */
|
||||
void _dumb_init_cubic();
|
||||
#ifdef _USE_SSE
|
||||
void _dumb_init_sse();
|
||||
#endif
|
||||
|
||||
#endif /* INTERNAL_IT_H */
|
|
@ -1,30 +0,0 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function: LPC low level routines
|
||||
last mod: $Id: lpc.h 16037 2009-05-26 21:10:58Z xiphmont $
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#ifndef _V_LPC_H_
|
||||
#define _V_LPC_H_
|
||||
|
||||
/* simple linear scale LPC code */
|
||||
extern float vorbis_lpc_from_data(float *data,float *lpc,int n,int m);
|
||||
|
||||
extern void vorbis_lpc_predict(float *coeff,float *prime,int m,
|
||||
float *data,long n);
|
||||
|
||||
struct DUMB_IT_SIGDATA;
|
||||
extern void dumb_it_add_lpc(struct DUMB_IT_SIGDATA *sigdata);
|
||||
|
||||
#endif
|
|
@ -1,36 +0,0 @@
|
|||
#ifndef INTERNAL_MULSC_H
|
||||
#define INTERNAL_MULSC_H
|
||||
|
||||
#if !defined(_MSC_VER) || !defined(_M_IX86) || _MSC_VER >= 1800
|
||||
//#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 MULSCA(a, b) ((int)((LONG_LONG)((a) << 4) * (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))
|
||||
#else
|
||||
/* VC++ calls __allmull and __allshr for the above math. I don't know why.
|
||||
* [Need to check if this still applies to recent versions of the compiler.] */
|
||||
static __forceinline unsigned long long MULLL(int a, int b)
|
||||
{
|
||||
__asm mov eax,a
|
||||
__asm imul b
|
||||
}
|
||||
static __forceinline int MULSCV (int a, int b)
|
||||
{
|
||||
#ifndef _DEBUG
|
||||
union { unsigned long long q; struct { int l, h; }; } val;
|
||||
val.q = MULLL(a,b);
|
||||
return val.h;
|
||||
#else
|
||||
__asm mov eax,a
|
||||
__asm imul b
|
||||
__asm mov eax,edx
|
||||
#endif
|
||||
}
|
||||
#define MULSCA(a, b) MULSCV((a) << 4, b)
|
||||
#define MULSC(a, b) MULSCV((a) << 4, (b) << 12)
|
||||
#define MULSC16(a, b) MULSCV((a) << 12, (b) << 12)
|
||||
#endif
|
||||
|
||||
#endif /* INTERNAL_MULSC_H */
|
|
@ -1,58 +0,0 @@
|
|||
#ifndef _RESAMPLER_H_
|
||||
#define _RESAMPLER_H_
|
||||
|
||||
// Ugglay
|
||||
#ifdef RESAMPLER_DECORATE
|
||||
#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_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_delete(void *);
|
||||
void * resampler_dup(const void *);
|
||||
void resampler_dup_inplace(void *, const void *);
|
||||
|
||||
enum
|
||||
{
|
||||
RESAMPLER_QUALITY_MIN = 0,
|
||||
RESAMPLER_QUALITY_ZOH = 0,
|
||||
RESAMPLER_QUALITY_BLEP = 1,
|
||||
RESAMPLER_QUALITY_LINEAR = 2,
|
||||
RESAMPLER_QUALITY_BLAM = 3,
|
||||
RESAMPLER_QUALITY_CUBIC = 4,
|
||||
RESAMPLER_QUALITY_SINC = 5,
|
||||
RESAMPLER_QUALITY_MAX = 5
|
||||
};
|
||||
|
||||
void resampler_set_quality(void *, int quality);
|
||||
|
||||
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_set_rate( void *, double new_factor );
|
||||
int resampler_ready(void *);
|
||||
void resampler_clear(void *);
|
||||
int resampler_get_sample_count(void *);
|
||||
int resampler_get_sample(void *);
|
||||
float resampler_get_sample_float(void *);
|
||||
void resampler_remove_sample(void *, int decay);
|
||||
|
||||
#endif
|
|
@ -1,24 +0,0 @@
|
|||
#ifndef RIFF_H
|
||||
#define RIFF_H
|
||||
|
||||
struct riff;
|
||||
|
||||
struct riff_chunk
|
||||
{
|
||||
unsigned type;
|
||||
int32 offset;
|
||||
unsigned size;
|
||||
struct riff * nested;
|
||||
};
|
||||
|
||||
struct riff
|
||||
{
|
||||
unsigned type;
|
||||
unsigned chunk_count;
|
||||
struct riff_chunk * chunks;
|
||||
};
|
||||
|
||||
struct riff * riff_parse( DUMBFILE * f, int32 offset, int32 size, unsigned proper );
|
||||
void riff_free( struct riff * );
|
||||
|
||||
#endif
|
|
@ -1,113 +0,0 @@
|
|||
/* Copyright (C) 2002 Jean-Marc Valin */
|
||||
/**
|
||||
@file stack_alloc.h
|
||||
@brief Temporary memory allocation on stack
|
||||
*/
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the Xiph.org Foundation nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef STACK_ALLOC_H
|
||||
#define STACK_ALLOC_H
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <malloc.h>
|
||||
#else
|
||||
# ifdef HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def ALIGN(stack, size)
|
||||
*
|
||||
* Aligns the stack to a 'size' boundary
|
||||
*
|
||||
* @param stack Stack
|
||||
* @param size New size boundary
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def PUSH(stack, size, type)
|
||||
*
|
||||
* Allocates 'size' elements of type 'type' on the stack
|
||||
*
|
||||
* @param stack Stack
|
||||
* @param size Number of elements
|
||||
* @param type Type of element
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def VARDECL(var)
|
||||
*
|
||||
* Declare variable on stack
|
||||
*
|
||||
* @param var Variable to declare
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def ALLOC(var, size, type)
|
||||
*
|
||||
* Allocate 'size' elements of 'type' on stack
|
||||
*
|
||||
* @param var Name of variable to allocate
|
||||
* @param size Number of elements
|
||||
* @param type Type of element
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_VALGRIND
|
||||
|
||||
#include <valgrind/memcheck.h>
|
||||
|
||||
#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))))
|
||||
|
||||
#else
|
||||
|
||||
#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))))
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(VAR_ARRAYS)
|
||||
#define VARDECL(var)
|
||||
#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))
|
||||
#else
|
||||
#define VARDECL(var) var
|
||||
#define ALLOC(var, size, type) var = PUSH(stack, size, type)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
|
@ -1,87 +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.
|
||||
|
||||
8. Take the number stated as introducing this clause. Multiply it by two,
|
||||
then subtract four. Now insert a '+' between the two digits and evaluate
|
||||
the resulting sum. Call the result 'x'. If you have not yet concluded that
|
||||
every numbered clause in this licence whose ordinal number is strictly
|
||||
greater than 'x' (with the exception of the present clause) is null and
|
||||
void, Debian, then you are hereby informed that laughter is good for one's
|
||||
health and you are warmly suggested to do it. By the way, Clauses 4, 5 and
|
||||
6 are null and void. Incidentally, I like Kubuntu. The work you guys do is
|
||||
awesome. (Lawyers, on the other hand ...)
|
||||
|
||||
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.
|
3
libraries/dumb/prj/.gitignore
vendored
3
libraries/dumb/prj/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
dumb-build-Desktop-Release
|
||||
dumb-build-Desktop-Debug
|
||||
*.user
|
|
@ -1,128 +0,0 @@
|
|||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2012-12-22T16:33:53
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT -= core gui
|
||||
|
||||
TARGET = dumb
|
||||
TEMPLATE = lib
|
||||
CONFIG += staticlib
|
||||
|
||||
DEFINES += _USE_SSE
|
||||
|
||||
INCLUDEPATH += ../../include
|
||||
|
||||
QMAKE_CFLAGS += -msse
|
||||
|
||||
SOURCES += \
|
||||
../../src/core/unload.c \
|
||||
../../src/core/rendsig.c \
|
||||
../../src/core/rendduh.c \
|
||||
../../src/core/register.c \
|
||||
../../src/core/readduh.c \
|
||||
../../src/core/rawsig.c \
|
||||
../../src/core/makeduh.c \
|
||||
../../src/core/loadduh.c \
|
||||
../../src/core/dumbfile.c \
|
||||
../../src/core/duhtag.c \
|
||||
../../src/core/duhlen.c \
|
||||
../../src/core/atexit.c \
|
||||
../../src/helpers/stdfile.c \
|
||||
../../src/helpers/silence.c \
|
||||
../../src/helpers/sampbuf.c \
|
||||
../../src/helpers/riff.c \
|
||||
../../src/helpers/resample.c \
|
||||
../../src/helpers/memfile.c \
|
||||
../../src/helpers/clickrem.c \
|
||||
../../src/helpers/barray.c \
|
||||
../../src/it/xmeffect.c \
|
||||
../../src/it/readxm2.c \
|
||||
../../src/it/readxm.c \
|
||||
../../src/it/readstm2.c \
|
||||
../../src/it/readstm.c \
|
||||
../../src/it/reads3m2.c \
|
||||
../../src/it/reads3m.c \
|
||||
../../src/it/readriff.c \
|
||||
../../src/it/readptm.c \
|
||||
../../src/it/readpsm.c \
|
||||
../../src/it/readoldpsm.c \
|
||||
../../src/it/readokt2.c \
|
||||
../../src/it/readokt.c \
|
||||
../../src/it/readmtm.c \
|
||||
../../src/it/readmod2.c \
|
||||
../../src/it/readmod.c \
|
||||
../../src/it/readdsmf.c \
|
||||
../../src/it/readasy.c \
|
||||
../../src/it/readamf2.c \
|
||||
../../src/it/readamf.c \
|
||||
../../src/it/readam.c \
|
||||
../../src/it/read6692.c \
|
||||
../../src/it/read669.c \
|
||||
../../src/it/ptmeffect.c \
|
||||
../../src/it/loadxm2.c \
|
||||
../../src/it/loadxm.c \
|
||||
../../src/it/loadstm2.c \
|
||||
../../src/it/loadstm.c \
|
||||
../../src/it/loads3m2.c \
|
||||
../../src/it/loads3m.c \
|
||||
../../src/it/loadriff2.c \
|
||||
../../src/it/loadriff.c \
|
||||
../../src/it/loadptm2.c \
|
||||
../../src/it/loadptm.c \
|
||||
../../src/it/loadpsm2.c \
|
||||
../../src/it/loadpsm.c \
|
||||
../../src/it/loadoldpsm2.c \
|
||||
../../src/it/loadoldpsm.c \
|
||||
../../src/it/loadokt2.c \
|
||||
../../src/it/loadokt.c \
|
||||
../../src/it/loadmtm2.c \
|
||||
../../src/it/loadmtm.c \
|
||||
../../src/it/loadmod2.c \
|
||||
../../src/it/loadmod.c \
|
||||
../../src/it/loadasy2.c \
|
||||
../../src/it/loadasy.c \
|
||||
../../src/it/loadamf2.c \
|
||||
../../src/it/loadamf.c \
|
||||
../../src/it/load6692.c \
|
||||
../../src/it/load669.c \
|
||||
../../src/it/itunload.c \
|
||||
../../src/it/itrender.c \
|
||||
../../src/it/itread2.c \
|
||||
../../src/it/itread.c \
|
||||
../../src/it/itorder.c \
|
||||
../../src/it/itmisc.c \
|
||||
../../src/it/itload2.c \
|
||||
../../src/it/itload.c \
|
||||
../../src/it/readany.c \
|
||||
../../src/it/loadany2.c \
|
||||
../../src/it/loadany.c \
|
||||
../../src/it/readany2.c \
|
||||
../../src/helpers/sinc_resampler.c \
|
||||
../../src/helpers/lpc.c
|
||||
|
||||
HEADERS += \
|
||||
../../include/dumb.h \
|
||||
../../include/internal/riff.h \
|
||||
../../include/internal/it.h \
|
||||
../../include/internal/dumb.h \
|
||||
../../include/internal/barray.h \
|
||||
../../include/internal/aldumb.h \
|
||||
../../include/internal/sinc_resampler.h \
|
||||
../../include/internal/stack_alloc.h \
|
||||
../../include/internal/lpc.h \
|
||||
../../include/internal/dumbfile.h
|
||||
unix:!symbian {
|
||||
maemo5 {
|
||||
target.path = /opt/usr/lib
|
||||
} else {
|
||||
target.path = /usr/lib
|
||||
}
|
||||
INSTALLS += target
|
||||
}
|
||||
|
||||
OTHER_FILES += \
|
||||
../../src/helpers/resample.inc \
|
||||
../../src/helpers/resamp3.inc \
|
||||
../../src/helpers/resamp2.inc
|
|
@ -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
|
|
@ -1,561 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* release.txt - Release notes for DUMB. / / \ \
|
||||
* | < / \_
|
||||
* | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
|
||||
*******************************************
|
||||
*** DUMB 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,
|
||||
loading of text fields in the module files, and faster load functions for
|
||||
projects that don't need to seek within the module or know its length.
|
||||
Additionally, Chad Austin has contributed a dumb2wav tool for converting
|
||||
modules to .wav files and updated the Visual Studio 6 project files to
|
||||
compile all the examples as well as the library. Users of Unix-like systems
|
||||
will be pleased to know that on Chad's suggestion I have made the build
|
||||
system cope with variables such as $HOME or ${HOME} in the prefix.
|
||||
|
||||
Chad has also contributed an Autotools build system, but neither of us
|
||||
recommends its use. The Autotools are an evil black box, we haven't quite
|
||||
managed to get it right, and goodness help you if it happens not to work for
|
||||
you. The files are available in a separate download if you absolutely need
|
||||
them. Notice that that download is almost twice as large as the rest of DUMB!
|
||||
|
||||
Maybe we'll do SCons next time.
|
||||
|
||||
Thanks to Chad for all his work. Chad is the author of Audiere, a portable
|
||||
sound library which has started using DUMB for its module playback! Wahoo!
|
||||
|
||||
http://audiere.sf.net/
|
||||
|
||||
There are three main optimisations that went into the mixing loops.
|
||||
|
||||
First, I downloaded ModPlugXMMS and had a peek at the mixing code, which is
|
||||
Public Domain. It uses look-up tables for the cubic mixing. I pinched the
|
||||
idea, and that sped DUMB's cubic (best quality) resamplers up by a factor of
|
||||
two or three.
|
||||
|
||||
Secondly, the samples loaded from the file are now kept in 8-bit or 16-bit
|
||||
format, whereas previously they were being converted to 24-bit-in-32-bit on
|
||||
loading. This means the samples occupy a half or a quarter of the memory they
|
||||
used to occupy. It also had the side-effect of speeding up the mixing loops,
|
||||
but it meant I had to duplicate the resampling code. (It is all done with
|
||||
macros in the source code, but it becomes two copies on the binary level.)
|
||||
|
||||
Secondly, stereo samples and stereo mixing buffers are now kept in
|
||||
interleaved format, where previously the two channels were done separately to
|
||||
keep the code simpler. This change has made the library quite a bit bigger,
|
||||
but has made the code run almost twice as fast for stereo output (tested for
|
||||
modules whose samples are mostly mono)!
|
||||
|
||||
DUMB is now as fast as ModPlugXMMS on my system.
|
||||
|
||||
Some people have also commented that DUMB seems to take a long time loading
|
||||
files. This is because immediately upon loading the file it runs the playback
|
||||
engine over it up as far as the point of first loop, taking snapshots at 30-
|
||||
second intervals to be used as references for fast seeking and finally
|
||||
storing the playback time. Of course, most games don't need this. You can now
|
||||
skip it by calling the _quick versions of the dumb_load_*(), dumb_read_*() or
|
||||
dumb_register_dat_*() functions. Should you need the data later, you can call
|
||||
dumb_it_do_initial_runthrough() to calculate it. Please note that this cannot
|
||||
currently be done safely from a concurrent thread while the music is playing.
|
||||
|
||||
As mentioned, DUMB loads the text fields in module files now. You can
|
||||
retrieve the song title with duh_get_tag(). Sample names and file names and
|
||||
instrument names and filenames, and the song message for IT files, are
|
||||
available with a call to duh_get_it_sigdata() and various dumb_it_sd_*()
|
||||
functions. Please note that text fields added as extensions by ModPlug
|
||||
Tracker are not supported.
|
||||
|
||||
DUMB's timing is ever so slightly more accurate. This is hardly noticeable,
|
||||
but it has meant that the length computed will increase very slightly.
|
||||
|
||||
There are many small playback fixes in this release:
|
||||
|
||||
* The Lxx effect in XM files (set envelope position) is now supported.
|
||||
|
||||
* Pattern looping is now correct for XM files. Bizarrely, an ordinary pattern
|
||||
loop whose start point isn't the first row seems to cause the next pattern
|
||||
to start at the row corresponding to the loop start point. That must have
|
||||
been a headache for people creating XM files! Nevertheless, DUMB now
|
||||
emulates this behaviour. If you have an XM file that was written in a
|
||||
tracker other than Fast Tracker II and breaks in DUMB, you can get around
|
||||
it by putting a D00 effect (break to row 0) right at the end of the pattern
|
||||
containing the loop.
|
||||
|
||||
* XM pattern looping can be infinite. DUMB should detect this and call the
|
||||
loop callback when it happens. Specifically, it has a loop counter for each
|
||||
channel, so each time it sets or decrements that counter, it remembers the
|
||||
loop end point for that channel. When the loop terminates, the loop end
|
||||
point is reset to 0. If the loop end point ever decreases during a loop,
|
||||
the loop callback is called. If anyone manages to get around this check and
|
||||
prevent DUMB from calling the callback, please let me know and send me an
|
||||
illustrative XM file!
|
||||
|
||||
* For IT files, notes are now removed from channels if they have faded out,
|
||||
even if they are still in the foreground. After this has happened, a row
|
||||
with a note and Gxx (tone portamento) specified will cause a new note to
|
||||
start playing, which is what Impulse Tracker does in this scenario.
|
||||
(Normally, Gxx prevents the new note from playing and instead causes the
|
||||
old note to start sliding towards the new note.)
|
||||
|
||||
* If a tone portamento command occurred when no note was playing, the effect
|
||||
value wasn't stored. This has been fixed. Thanks to Maim from #trax on
|
||||
EFnet for discovering this bug.
|
||||
|
||||
* DUMB now treats the parameter to the undocumented XM key off effect Kxx as
|
||||
a delay, consistent with Fast Tracker II's behaviour. It has also been made
|
||||
not to clear the note, so a subsequent volume command will restore it, as
|
||||
in Fast Tracker II.
|
||||
|
||||
* DUMB used to process the first row when you created the
|
||||
DUMB_IT_SIGRENDERER. This happened before you had a chance to install any
|
||||
callbacks. If an F00 effect occurred on the first row, the music would stop
|
||||
immediately and the xm_speed_zero callback would be called if it were
|
||||
present. Unfortunately, it wasn't present, and the algorithm for
|
||||
calculating the length subsequently went into an endless loop while waiting
|
||||
for it. Worse still, the same algorithm accumulated data for fast seeking,
|
||||
and never stopped, so it pretty quickly consumed all the resources. DUMB
|
||||
will now not process the first row until you first request some samples,
|
||||
provided you pass zero for pos. Of course, any MOD or XM file with F00 in
|
||||
the very first row won't do much anyway, but such files won't crash the
|
||||
library now.
|
||||
|
||||
* There was a subtle bug that affected a few XM files. For instruments with
|
||||
no associated samples, the array mapping notes to samples is uninitialised.
|
||||
This became a problem if such instruments were then used, which does happen
|
||||
sometimes. On many systems, memory is initialised to zero when first given
|
||||
to a program (for security reasons), so the problem didn't come up most of
|
||||
the time. However, on platforms like DOS where memory isn't initialised, or
|
||||
in programs that reuse memory later on (this includes the XMMS plug-in with
|
||||
which I discovered the bug), a rogue note would occasionally play. This has
|
||||
now been fixed.
|
||||
|
||||
* DUMB's envelope handling for IT files was subtly wrong. Upon note off, it
|
||||
stopped obeying the sustain loop points one tick too early. Notes were
|
||||
often shorter than they should have been, and in pathological cases a whole
|
||||
extra iteration of the sustain loop section might have been skipped. The
|
||||
envelope code has now been rewritten. Thanks go to Allefant for Valgrinding
|
||||
the new code!
|
||||
|
||||
Finally, there were two build problems in the last version, which were fixed
|
||||
in the download marked with -fixed. They are of course correct in this
|
||||
version. For the record:
|
||||
|
||||
* The make/config.bat file, responsible for generating make/config.txt, wrote
|
||||
a crucial line to the wrong place, causing it to be left out of the file.
|
||||
As a result, the makefile would fail to install everything for Allegro
|
||||
users, and enter infinite recursion for other users. This applied to people
|
||||
using DJGPP and MinGW.
|
||||
|
||||
* DUMB's Makefile was supposed to install the example programs on Unix-based
|
||||
platforms, but it wasn't doing. The fix was to edit Makefile and change the
|
||||
one occurrence of $COMSPEC to $(COMSPEC).
|
||||
|
||||
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 ***
|
||||
******************************************
|
||||
|
||||
Yes, there really has been a release. This is not a day-late April fools'
|
||||
joke.
|
||||
|
||||
DUMB's full name has changed! The old "Dedicated Universal Music
|
||||
Bastardisation" was rather silly, and not much more than a forced attempt at
|
||||
finding words beginning with D, U, M and B. I spent weeks and weeks browsing
|
||||
dictionaries and hopelessly asking others for bright ideas, until the
|
||||
brilliant Chris "Kitty Cat" Robinson came up with "Dynamic". I decided to
|
||||
keep the U as Universal, since a DUH struct can hold digital music in any
|
||||
format. Now all that remained was the B, but it didn't take me long to come
|
||||
up with Bibliotheque, which, despite looking French, is indeed considered an
|
||||
English word by Oxford English Dictionary Online, to which my university has
|
||||
a subscription. So there you have it - the name now makes sense.
|
||||
|
||||
The two most significant additions to the project would have to be the new
|
||||
thread safety (with an important restriction, detailed in docs/dumb.txt), and
|
||||
the new build system. The silly 'makeall' and 'makecore' scripts are gone. If
|
||||
you are a GCC user, all you need do now is run 'make' and 'make install', as
|
||||
for other projects. You don't even have to run a 'fix' script any more! There
|
||||
are some caveats, which are covered in readme.txt. If you use Microsoft
|
||||
Visual C++ 6, you no longer need to obtain GCC and GNU Make - there is a
|
||||
project file just for you.
|
||||
|
||||
Huge thanks go to Steve Terry for testing on Windows XP - about five times -
|
||||
and to lillo for testing on BeOS and Mac OS X. Thanks also to X-G for testing
|
||||
on a Windows system that has consistently posed problems for DUMB's old
|
||||
makefiles.
|
||||
|
||||
There was a bug whereby al_poll_duh() would sometimes cause the music to
|
||||
resume playing if you called it after al_pause_duh(). Whether this was DUMB's
|
||||
fault for misusing Allegro's API, or a bug in Allegro, is unclear, but this
|
||||
release makes it work.
|
||||
|
||||
In one of my projects, I found that my AL_DUH_PLAYER stopped playing when
|
||||
there were lots of other sound effects. In order to fix this, I programmed
|
||||
DUMB to set the priority of the stream's voice to 255, the maximum. I also
|
||||
added al_duh_set_priority(), so you can set the priority yourself if you need
|
||||
to.
|
||||
|
||||
The resampling code has undergone a transformation. The bad news is that the
|
||||
linear average code is no longer in use. The good news is that where DUMB's
|
||||
resamplers used to require three extra samples' worth of memory to be
|
||||
allocated and initialised, it now copes with just the sample data. And it
|
||||
does a very good job at bouncing off loop points and otherwise hurtling
|
||||
around the sample. The resampling code is considerably more complicated, but
|
||||
the code that uses the resamplers is considerably simpler - and if you
|
||||
noticed a slight click in some bidirectionally looping samples, you'll be
|
||||
pleased to know that that click is gone!
|
||||
|
||||
I have also devoted some effort to optimisation. It seemed hopeless for a
|
||||
while, but then I actually figured out a way of making it faster AND more
|
||||
accurate at the same time! DUMB is now quite a bit faster than it was, and it
|
||||
mixes not with 16-bit precision, but with 24-bit precision. (It used 32-bit
|
||||
integers all along, but the difference is that it now makes use of 256 times
|
||||
as much of the integer's range.)
|
||||
|
||||
There have been the usual improvements to playback. The last release occurred
|
||||
rather too soon after I had fixed the XM effect memories; EAx and EBx, fine
|
||||
volume ramps, had been neglected. These are now handled properly.
|
||||
|
||||
In previous versions of DUMB, muted channels in IT were actually played with
|
||||
surround sound panning (where the right-hand channel is inverted). This has
|
||||
been fixed, so muted channels will really be muted now.
|
||||
|
||||
There were also some subtle problems with the way DUMB handled New Note
|
||||
Actions for IT files. It turned out that, in all releases of DUMB so far,
|
||||
pitch, filter and panning envelopes and sample vibrato were not being
|
||||
processed for any note that was forced into the background by a new note on
|
||||
the same channel! This only affected IT files. Not only has this been fixed,
|
||||
but envelope interpolation is much more accurate. Long trailing envelope-
|
||||
driven fade-outs sound a lot better now!
|
||||
|
||||
Since panning and filter envelopes are more precise, extra fields have been
|
||||
added to the DUMB_IT_CHANNEL_STATE struct, used by
|
||||
dumb_it_sr_get_channel_state(). These fields hold the 'decimal' parts of the
|
||||
pan and filter cut-off. See dumb.txt for details.
|
||||
|
||||
Mxx (set channel volume) now correctly only modifies the last note played on
|
||||
the channel, not any previous notes that have been forced into the background
|
||||
by New Note Actions, and filter effect processing is now closer to what
|
||||
Impulse Tracker does.
|
||||
|
||||
The XM loader was slightly flawed and could crash on files containing samples
|
||||
with out-of-range loop points. One such file was given to me. This has been
|
||||
fixed.
|
||||
|
||||
Finally, the legal stuff. Julien Cugniere has been added to the list of
|
||||
copyright owners. He deserves it, for all the work he did on the XM support!
|
||||
And the licence has been changed. You are no longer required to include a
|
||||
link to DUMB in a project that uses DUMB; the reasons for this relaxation are
|
||||
explained in licence.txt. However, the request is still there ...
|
||||
|
||||
As usual, enjoy!
|
||||
|
||||
|
||||
**********************************************
|
||||
*** DUMB v0.9.1, released 19 December 2002 ***
|
||||
**********************************************
|
||||
|
||||
Hi again! Lots to say this time, so I shall cut right to the chase.
|
||||
|
||||
DUMB now supports Impulse Tracker's low-pass resonant filters! Huge thanks go
|
||||
to Jeffrey Lim, author of Impulse Tracker, for giving me what information he
|
||||
still had regarding the algorithm; to cut a long story short, modifying
|
||||
ModPlug Tracker's source code (which is in the Public Domain) led to an
|
||||
algorithm whose output matched Impulse Tracker's perfectly.
|
||||
|
||||
Please note that ModPlug Tracker's filters as they stand do not match Impulse
|
||||
Tracker's, and I have no interest in supporting ModPlug Tracker's variant
|
||||
(especially not the integer rounding problems). Please see docs/modplug.txt,
|
||||
new in this release, for details.
|
||||
|
||||
Thanks also go to Fatso Huuskonen for motivating me to add filter support,
|
||||
and providing me with several great IT files to test it with!
|
||||
|
||||
The other important feature added for this release is click removal. Up until
|
||||
now, DUMB has generated clicks when cutting notes, starting samples in the
|
||||
middle, and so on. This version of DUMB will remove any such clicks. Note
|
||||
that DUMB does not use volume ramps to accomplish this; the algorithm will
|
||||
not take the bite out of the music!
|
||||
|
||||
In other news, DUMB now supports sample vibrato for IT files, and instrument
|
||||
vibrato for XM files. A slight bug in New Note Action handling for IT files
|
||||
has been fixed; Note Fade will not break the sustain loops of the sample and
|
||||
envelope, as it did before. Tremor handling (Ixy) had a strange bug in it,
|
||||
which has been fixed.
|
||||
|
||||
Support for XM files has been greatly enhanced. The XM envelope handling new
|
||||
in the last release contained a huge bug, resulting in notes seeming not to
|
||||
stop when they should; this has been fixed. Some XM files crashed DUMB, while
|
||||
others failed to load; these problems have been solved. Effect memories now
|
||||
work properly for XM and MOD files, to the best of my knowledge. Some other
|
||||
differences between IT and XM have been accounted for, most notably the
|
||||
Retrigger Note effects, Rxy and E9x.
|
||||
|
||||
DUMB's sound quality and accuracy are not the only areas that have been
|
||||
enhanced. The API has been expanded, at last. You can now detect when a
|
||||
module loops, or make it play through just once. You can ask DUMB to inform
|
||||
you every time it generates some samples; this is useful for visualisation.
|
||||
For IT files, you can intercept the MIDI messages generated by Zxx macros,
|
||||
enabling you to synchronise your game with the music to some extent. (There
|
||||
is no such method for XM, S3M or MOD files yet; sorry. Also note that the
|
||||
function will be called before you actually hear the sound; I cannot improve
|
||||
this until DUMB has its own sound drivers, which won't be for a while.) You
|
||||
can query the current order and row. Finally, operations like changing the
|
||||
speed and tempo are now possible, and you can query the playback state on
|
||||
each channel.
|
||||
|
||||
Some parts of DUMB's API have been deprecated. Simple programs that use
|
||||
Allegro will be unaffected, but if you get some compiler warnings or errors,
|
||||
please review docs/deprec.txt. This file explains why those parts of the API
|
||||
were deprecated, and tells you how to adapt your code; the changes you need
|
||||
to make are straightforward. Sorry for the inconvenience.
|
||||
|
||||
For various reasons, I have made DUMB's makefiles use different compiler
|
||||
flags depending on your GCC version (unless you are using MSVC). There is no
|
||||
elegant way of getting the makefiles to detect when GCC is upgraded. If you
|
||||
upgrade GCC, you should execute 'make clean' in order to make DUMB detect the
|
||||
GCC version again. Otherwise you may get some annoying error messages. (It is
|
||||
wise to do this in any case, so that all the object files are built with the
|
||||
same GCC version.)
|
||||
|
||||
DUMB's example players have been unified into a single player called
|
||||
'dumbplay'. The player has been enhanced to display messages when the music
|
||||
loops, and when XM and MOD files freeze (effect F00; more information on this
|
||||
in docs/howto.txt).
|
||||
|
||||
Finally, as noted on DUMB's website, the release notes from the last release
|
||||
were inaccurate. It has been verified that DUMBOGG v0.5 does still work with
|
||||
that release, and still works with this release. The esoteric DUMBOGG v0.6
|
||||
has not been created yet, since DUMBOGG v0.5 still works.
|
||||
|
||||
Please scroll down and read through the indented paragraphs in the notes for
|
||||
the last release; they are relevant for this release too.
|
||||
|
||||
That's all folks! Until next time.
|
||||
|
||||
|
||||
*******************************************
|
||||
*** DUMB 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
|
||||
played back. Most notably, handling of tone portamento in IT files has been
|
||||
improved a lot, and XM envelopes are now processed correctly.
|
||||
|
||||
The other major change is that DUMB now does a dummy run through each module
|
||||
on loading. It stores the playback state at thirty-second intervals. It stops
|
||||
when the module first loops, and then stores the playback time. This results
|
||||
in a slightly longer load time and a greater memory overhead, but seeking is
|
||||
faster (to any point before the module first loops) and the length is
|
||||
calculated! duh_get_length() will return this and is now documented in
|
||||
docs/howto.txt and docs/dumb.txt.
|
||||
|
||||
DUMB's build process has been changed to use 'mingw' wherever it used
|
||||
'mingw32' before; some directories have been renamed, and the 'fix' command
|
||||
you had to run for MinGW has been changed from 'fix mingw32' to 'fix mingw'.
|
||||
|
||||
Last time, I directed you to scroll down and read the notes from a past
|
||||
release, but ignore this point, and that point applies to something else, and
|
||||
so on. Did anyone do so? Well, if you're reading this at all, you probably
|
||||
did. Nevertheless, this time I shall be much less confusing and restate any
|
||||
relevant information. So the least you can do is read it!
|
||||
|
||||
- If your program ever aborts with exit code 37 while loading an IT file,
|
||||
PLEASE LET ME KNOW! The IT file in question has a stereo compressed sample
|
||||
in it, and the format is unspecified for this case (Impulse Tracker itself
|
||||
doesn't use stereo samples at all). I will need the IT file in question,
|
||||
and any information you can give me about how the IT file was created (e.g.
|
||||
what program). (If you don't get to see an exit code, let me know anyway.)
|
||||
|
||||
- If your program ever outputs a line resembling "Inst 01 Env: 0,64 8,32
|
||||
15,48" to stderr while loading an IT file, PLEASE LET ME KNOW! You have an
|
||||
old IT file (saved by an Impulse Tracker version older than 2.00), and
|
||||
support for such files is STILL untested.
|
||||
|
||||
- Not all parts of DUMB's API are documented yet. You will find some
|
||||
functions in dumb.h which are not listed in docs/dumb.txt; the reason is
|
||||
that these functions still need work and will probably change. If you
|
||||
really, really want to use them, talk to me first (IRC EFnet #dumb is a
|
||||
good place for this; see readme.txt for details on using IRC). I intend to
|
||||
finalise and document the whole of DUMB's API for Version 1.0.
|
||||
|
||||
There have been some changes to the naming conventions in DUMB's undocumented
|
||||
API. DUMBOGG v0.5 will not work with this and subsequent releases of DUMB;
|
||||
please upgrade to DUMBOGG v0.6. These changes should not break anything in
|
||||
your own code, since you didn't use those parts of the API, did you ;)
|
||||
|
||||
There is still a great deal of work to be done before DUMB's API can be
|
||||
finalised, and thus it will be a while before DUMB v1.0 comes out. It should
|
||||
be worth the wait. In the meantime, there will be 0.9.x releases with
|
||||
additional functionality, improved playback, and possibly support for some
|
||||
extra file formats.
|
||||
|
||||
Finally I should like to offer an apology; there is a strong possibility that
|
||||
some of DUMB's official API will change in the near future. There will not be
|
||||
any drastic changes, and the corresponding changes to your source code will
|
||||
be simple enough. If I didn't make these changes, DUMB's API would start to
|
||||
become limited, or messy, or both, so it's for the better. I apologise in
|
||||
advance for this.
|
||||
|
||||
Now scroll down and read the notes for the first r... oh wait, we already did
|
||||
that. I guess that's it then. You can stop reading now.
|
||||
|
||||
Right after you've read this.
|
||||
|
||||
And this.
|
||||
|
||||
Off you go.
|
||||
|
||||
Bye.
|
||||
|
||||
|
||||
********************************************
|
||||
*** DUMB 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
|
||||
in aldumb.h, so code would compile, but there would be an unresolved symbol
|
||||
at the linking stage. This has been fixed.
|
||||
|
||||
Platforms other than Unix did not have a working 'make veryclean' target;
|
||||
this has been fixed. In addition, the makefiles now use 'xcopy' instead of
|
||||
'copy', since on some systems GNU Make seems to have trouble calling commands
|
||||
built in to the shell.
|
||||
|
||||
Contrary to the errata that was on the DUMB website, the makeall.sh and
|
||||
makecore.sh scripts actually DID install in /usr. This has now been
|
||||
corrected, and regardless of whether you use these scripts or call make
|
||||
directly, the files will now be installed to /usr/local by default.
|
||||
|
||||
The XM loader used to treat stereo samples as mono samples with the data for
|
||||
the right channel positioned after the data for the left channel. This
|
||||
generally resulted in an unwanted echo effect. This has been fixed.
|
||||
|
||||
When playing XM files, specifying an invalid instrument would cause an old
|
||||
note on that channel to come back (roughly speaking). Fast Tracker 2 does not
|
||||
exhibit this behaviour. This has been fixed.
|
||||
|
||||
The GCC makefiles used -mpentium, which is deprecated in gcc 3.x. This was
|
||||
generating warnings, and has now been fixed.
|
||||
|
||||
In XM files, the length of a sample is stored in bytes. DUMB was assuming
|
||||
that the length of a 16-bit sample would be even. I had two XM files where
|
||||
this was not the case, and DUMB was unable to load them. This has been fixed.
|
||||
|
||||
In order to accommodate the extra part of the version number,
|
||||
DUMB_REVISION_VERSION has been added. DUMB_VERSION has also been added in
|
||||
order to facilitate checking if the version of DUMB installed is sufficient.
|
||||
See docs/dumb.txt for details.
|
||||
|
||||
As a last-minute fix, the XM "Break to row" effect is now loaded properly. It
|
||||
was necessary to convert from binary-coded decimal to hexadecimal (those who
|
||||
have experience with Fast Tracker 2 will know what I mean). In short, this
|
||||
means the effect will now work properly when breaking to row 10 or greater.
|
||||
|
||||
DUMB v0.8 had faulty release date constants; DUMB_MONTH and DUMB_DAY were
|
||||
swapped! For this reason, DUMB_DATE should not be compared against any date
|
||||
in 2002. This note has been added to docs/dumb.txt and also to dumb.h.
|
||||
|
||||
Please scroll to the end and read the release notes for the first version,
|
||||
DUMB v0.7. Most of them apply equally to this release. However, the
|
||||
non-portable code was rewritten for DUMB v0.8, so that point does not apply.
|
||||
The point about length not being calculated also applies to XM files.
|
||||
|
||||
Enjoy :)
|
||||
|
||||
|
||||
****************************************
|
||||
*** DUMB v0.8, released 14 June 2002 ***
|
||||
****************************************
|
||||
|
||||
Welcome to the second release of DUMB!
|
||||
|
||||
In addition to these notes, please read below the release notes for the
|
||||
previous version, DUMB v0.7. Most of them apply equally to this release.
|
||||
However, the non-portable code has been rewritten; DUMB should now port to
|
||||
big-endian platforms.
|
||||
|
||||
The main improvement in this release of DUMB is the support for XM files.
|
||||
Enormous thanks go to Julien Cugniere for working on this while I had to
|
||||
revise for my exams!
|
||||
|
||||
There was a mistake in the makefiles in the last release. The debugging
|
||||
Allegro interface library was mistakenly named libaldmbd.a instead of
|
||||
libaldmd.a, meaning you had to compile with -laldmbd, contrary to what the
|
||||
docs said. Apologies to everyone who lost sleep trying to work out what was
|
||||
wrong! The reason for using libaldmd.a is to maintain compatibility with
|
||||
plain DOS, where filenames are limited to eight characters (plus a three-
|
||||
letter extension). The makefiles have now been changed to match the
|
||||
information in the docs, so you may have to alter your project files
|
||||
accordingly.
|
||||
|
||||
The example programs were faulty, and crashed on Windows if they were unable
|
||||
to load the file. It was also difficult to work out how to exit them (you had
|
||||
to click the taskbar button that didn't have a window, then press a key).
|
||||
They have been improved in both these respects.
|
||||
|
||||
I have now added a docs/faq.txt file (Frequently Asked Questions), which is
|
||||
based on problems and misconceptions people have had with the first release.
|
||||
Please refer to it before contacting me with problems.
|
||||
|
||||
Thanks to networm for touching up the Unix makefile and writing the
|
||||
instructions on using it.
|
||||
|
||||
Incidentally, today (Friday 14 June) is the Robinson College May Ball at
|
||||
Cambridge Uni. God knows why it's called a May Ball if it's in June. I'm not
|
||||
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 ***
|
||||
****************************************
|
||||
|
||||
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
|
||||
features that aren't documented in docs/dumb.txt, the library should be rock
|
||||
solid and you should be able to upgrade more or less without problems.
|
||||
|
||||
Here are some notes on this release:
|
||||
|
||||
- There is some non-portable code in this release of DUMB. It is likely that
|
||||
the library will fail to load IT files with compressed samples on
|
||||
big-endian machines such as the Apple Macintosh.
|
||||
|
||||
- If your program ever aborts with exit code 37 while loading an IT file,
|
||||
PLEASE LET ME KNOW! The IT file in question has a stereo compressed sample
|
||||
in it, and the format is unspecified for this case (Impulse Tracker itself
|
||||
doesn't use stereo samples at all). I will need the IT file in question,
|
||||
and any information you can give me about how the IT file was created (e.g.
|
||||
what program). (If you don't get to see an exit code, let me know anyway.)
|
||||
|
||||
- If your program ever outputs a line resembling "Inst 01 Env: 0,64 8,32
|
||||
15,48" to stderr while loading an IT file, PLEASE LET ME KNOW! You have an
|
||||
old IT file (saved by an Impulse Tracker version older than 2.00), and
|
||||
support for such files is untested.
|
||||
|
||||
- The length of IT and S3M files is not currently calculated. It is just set
|
||||
to ten minutes.
|
|
@ -1,71 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* atexit.c - Library Clean-up Management. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/dumb.h"
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
dap = malloc(sizeof(*dap));
|
||||
|
||||
if (!dap)
|
||||
return -1;
|
||||
|
||||
dap->next = dumb_atexit_proc;
|
||||
dap->proc = proc;
|
||||
dumb_atexit_proc = dap;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* duhlen.c - Functions to set and return the / / \ \
|
||||
* length of a DUH. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* Note that the length of a DUH is a constant | ' /
|
||||
* stored in the DUH struct and in the DUH disk \__/
|
||||
* format. It will be calculated on loading for
|
||||
* other formats in which the length is not explicitly stored. Also note that
|
||||
* it does not necessarily correspond to the length of time for which the DUH
|
||||
* will generate samples. Rather it represents a suitable point for a player
|
||||
* such as Winamp to stop, and in any good DUH it will allow for any final
|
||||
* flourish to fade out and be appreciated.
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/dumb.h"
|
||||
|
||||
|
||||
|
||||
int32 DUMBEXPORT duh_get_length(DUH *duh)
|
||||
{
|
||||
return duh ? duh->length : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT duh_set_length(DUH *duh, int32 length)
|
||||
{
|
||||
if (duh)
|
||||
duh->length = length;
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* duhtag.c - Function to return the tags stored / / \ \
|
||||
* in a DUH struct (typically author | < / \_
|
||||
* information). | \/ /\ /
|
||||
* \_ / > /
|
||||
* By entheh. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/dumb.h"
|
||||
|
||||
|
||||
|
||||
const char *DUMBEXPORT 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;
|
||||
}
|
|
@ -1,418 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* dumbfile.c - Hookable, strictly sequential / / \ \
|
||||
* file input functions. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
static const DUMBFILE_SYSTEM *the_dfs = NULL;
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include "internal/dumbfile.h"
|
||||
|
||||
|
||||
|
||||
DUMBFILE *DUMBEXPORT dumbfile_open(const char *filename)
|
||||
{
|
||||
DUMBFILE *f;
|
||||
|
||||
ASSERT(the_dfs);
|
||||
|
||||
f = (DUMBFILE *) malloc(sizeof(*f));
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
f->dfs = the_dfs;
|
||||
|
||||
f->file = (*the_dfs->open)(filename);
|
||||
|
||||
if (!f->file) {
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f->pos = 0;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUMBFILE *DUMBEXPORT dumbfile_open_ex(void *file, const DUMBFILE_SYSTEM *dfs)
|
||||
{
|
||||
DUMBFILE *f;
|
||||
|
||||
ASSERT(dfs);
|
||||
ASSERT(dfs->getc);
|
||||
ASSERT(file);
|
||||
|
||||
f = (DUMBFILE *) malloc(sizeof(*f));
|
||||
|
||||
if (!f) {
|
||||
if (dfs->close)
|
||||
(*dfs->close)(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f->dfs = dfs;
|
||||
f->file = file;
|
||||
|
||||
f->pos = 0;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32 DUMBEXPORT dumbfile_pos(DUMBFILE *f)
|
||||
{
|
||||
ASSERT(f);
|
||||
|
||||
return f->pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumbfile_skip(DUMBFILE *f, long n)
|
||||
{
|
||||
int rv;
|
||||
|
||||
ASSERT(f);
|
||||
ASSERT(n >= 0);
|
||||
|
||||
if (f->pos < 0)
|
||||
return -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumbfile_getc(DUMBFILE *f)
|
||||
{
|
||||
int rv;
|
||||
|
||||
ASSERT(f);
|
||||
|
||||
if (f->pos < 0)
|
||||
return -1;
|
||||
|
||||
rv = (*f->dfs->getc)(f->file);
|
||||
|
||||
if (rv < 0) {
|
||||
f->pos = -1;
|
||||
return rv;
|
||||
}
|
||||
|
||||
f->pos++;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumbfile_igetw(DUMBFILE *f)
|
||||
{
|
||||
int l, h;
|
||||
|
||||
ASSERT(f);
|
||||
|
||||
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;
|
||||
|
||||
return l | (h << 8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumbfile_mgetw(DUMBFILE *f)
|
||||
{
|
||||
int l, h;
|
||||
|
||||
ASSERT(f);
|
||||
|
||||
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;
|
||||
|
||||
return l | (h << 8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32 DUMBEXPORT dumbfile_igetl(DUMBFILE *f)
|
||||
{
|
||||
uint32 rv, b;
|
||||
|
||||
ASSERT(f);
|
||||
|
||||
if (f->pos < 0)
|
||||
return -1;
|
||||
|
||||
rv = (*f->dfs->getc)(f->file);
|
||||
if ((sint32)rv < 0) {
|
||||
f->pos = -1;
|
||||
return rv;
|
||||
}
|
||||
|
||||
b = (*f->dfs->getc)(f->file);
|
||||
if ((sint32)b < 0) {
|
||||
f->pos = -1;
|
||||
return b;
|
||||
}
|
||||
rv |= b << 8;
|
||||
|
||||
b = (*f->dfs->getc)(f->file);
|
||||
if ((sint32)b < 0) {
|
||||
f->pos = -1;
|
||||
return b;
|
||||
}
|
||||
rv |= b << 16;
|
||||
|
||||
b = (*f->dfs->getc)(f->file);
|
||||
if ((sint32)b < 0) {
|
||||
f->pos = -1;
|
||||
return b;
|
||||
}
|
||||
rv |= b << 24;
|
||||
|
||||
f->pos += 4;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32 DUMBEXPORT dumbfile_mgetl(DUMBFILE *f)
|
||||
{
|
||||
uint32 rv, b;
|
||||
|
||||
ASSERT(f);
|
||||
|
||||
if (f->pos < 0)
|
||||
return -1;
|
||||
|
||||
rv = (*f->dfs->getc)(f->file);
|
||||
if ((sint32)rv < 0) {
|
||||
f->pos = -1;
|
||||
return rv;
|
||||
}
|
||||
rv <<= 24;
|
||||
|
||||
b = (*f->dfs->getc)(f->file);
|
||||
if ((sint32)b < 0) {
|
||||
f->pos = -1;
|
||||
return b;
|
||||
}
|
||||
rv |= b << 16;
|
||||
|
||||
b = (*f->dfs->getc)(f->file);
|
||||
if ((sint32)b < 0) {
|
||||
f->pos = -1;
|
||||
return b;
|
||||
}
|
||||
rv |= b << 8;
|
||||
|
||||
b = (*f->dfs->getc)(f->file);
|
||||
if ((sint32)b < 0) {
|
||||
f->pos = -1;
|
||||
return b;
|
||||
}
|
||||
rv |= b;
|
||||
|
||||
f->pos += 4;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32 DUMBEXPORT dumbfile_cgetul(DUMBFILE *f)
|
||||
{
|
||||
uint32 rv = 0;
|
||||
int v;
|
||||
|
||||
do {
|
||||
v = dumbfile_getc(f);
|
||||
|
||||
if (v < 0)
|
||||
return v;
|
||||
|
||||
rv <<= 7;
|
||||
rv |= v & 0x7F;
|
||||
} while (v & 0x80);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
sint32 DUMBEXPORT dumbfile_cgetsl(DUMBFILE *f)
|
||||
{
|
||||
uint32 rv = dumbfile_cgetul(f);
|
||||
|
||||
if (f->pos < 0)
|
||||
return rv;
|
||||
|
||||
return (rv >> 1) | (rv << 31);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32 DUMBEXPORT dumbfile_getnc(char *ptr, int32 n, DUMBFILE *f)
|
||||
{
|
||||
int32 rv;
|
||||
|
||||
ASSERT(f);
|
||||
ASSERT(n >= 0);
|
||||
|
||||
if (f->pos < 0)
|
||||
return -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT 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;
|
||||
}
|
||||
f->pos = n;
|
||||
return (*f->dfs->seek)(f->file, n);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32 DUMBEXPORT dumbfile_get_size(DUMBFILE *f)
|
||||
{
|
||||
return (*f->dfs->get_size)(f->file);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumbfile_error(DUMBFILE *f)
|
||||
{
|
||||
ASSERT(f);
|
||||
|
||||
return f->pos < 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumbfile_close(DUMBFILE *f)
|
||||
{
|
||||
int rv;
|
||||
|
||||
ASSERT(f);
|
||||
|
||||
rv = f->pos < 0;
|
||||
|
||||
if (f->dfs->close)
|
||||
(*f->dfs->close)(f->file);
|
||||
|
||||
free(f);
|
||||
|
||||
return rv;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadduh.c - Code to read a DUH from a file, / / \ \
|
||||
* opening and closing the file for | < / \_
|
||||
* you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By entheh. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT load_duh(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = read_duh(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* makeduh.c - Function to construct a DUH from / / \ \
|
||||
* its components. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
|
||||
signal = malloc(sizeof(*signal));
|
||||
|
||||
if (!signal) {
|
||||
if (desc->unload_sigdata)
|
||||
if (sigdata)
|
||||
(*desc->unload_sigdata)(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
signal->desc = desc;
|
||||
signal->sigdata = sigdata;
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUH *make_duh(
|
||||
int32 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->signal = malloc(n_signals * sizeof(*duh->signal));
|
||||
|
||||
if (!duh->signal) {
|
||||
free(duh);
|
||||
duh = 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;
|
||||
}
|
||||
|
||||
duh->n_tags = 0;
|
||||
duh->tag = NULL;
|
||||
|
||||
fail = 0;
|
||||
|
||||
for (i = 0; i < n_signals; i++) {
|
||||
duh->signal[i] = make_signal(desc[i], sigdata[i]);
|
||||
if (!duh->signal[i])
|
||||
fail = 1;
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
unload_duh(duh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
duh->length = length;
|
||||
|
||||
{
|
||||
int mem = n_tags * 2; /* account for NUL terminators here */
|
||||
char *ptr;
|
||||
|
||||
for (i = 0; i < n_tags; i++)
|
||||
mem += (int)(strlen(tags[i][0]) + strlen(tags[i][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;
|
||||
}
|
||||
|
||||
int DUMBEXPORT duh_add_signal(DUH *duh, DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata)
|
||||
{
|
||||
DUH_SIGNAL **signal;
|
||||
|
||||
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;
|
||||
|
||||
memmove( signal + 1, signal, duh->n_signals * sizeof( *signal ) );
|
||||
duh->n_signals++;
|
||||
|
||||
signal[ 0 ] = make_signal( desc, sigdata );
|
||||
if ( !signal[ 0 ] ) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* rawsig.c - Function to retrieve raw signal / / \ \
|
||||
* data from a DUH provided you know | < / \_
|
||||
* what type of signal it is. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By entheh. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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 *DUMBEXPORT duh_get_raw_sigdata(DUH *duh, int sig, int32 type)
|
||||
{
|
||||
int i;
|
||||
DUH_SIGNAL *signal;
|
||||
|
||||
if (!duh) return NULL;
|
||||
|
||||
if ( sig >= 0 )
|
||||
{
|
||||
if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readduh.c - Code to read a DUH from an open / / \ \
|
||||
* file. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/dumb.h"
|
||||
|
||||
|
||||
|
||||
static DUH_SIGNAL *read_signal(DUH *duh, DUMBFILE *f)
|
||||
{
|
||||
DUH_SIGNAL *signal;
|
||||
int32 type;
|
||||
|
||||
signal = malloc(sizeof(*signal));
|
||||
|
||||
if (!signal)
|
||||
return NULL;
|
||||
|
||||
type = dumbfile_mgetl(f);
|
||||
if (dumbfile_error(f)) {
|
||||
free(signal);
|
||||
return 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* read_duh(): reads a DUH from an already open DUMBFILE, and returns its
|
||||
* pointer, or null on error. The file is not closed.
|
||||
*/
|
||||
DUH *DUMBEXPORT read_duh(DUMBFILE *f)
|
||||
{
|
||||
DUH *duh;
|
||||
int i;
|
||||
|
||||
if (dumbfile_mgetl(f) != DUH_SIGNATURE)
|
||||
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->n_signals = 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* register.c - Signal type registration. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
|
||||
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
|
||||
* signal's behaviour is defined by four functions, whose pointers you pass
|
||||
* here. See the documentation for details.
|
||||
*
|
||||
* 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 DUMBEXPORT 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);
|
||||
|
||||
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));
|
||||
|
||||
if (!desc_link)
|
||||
return;
|
||||
|
||||
desc_link->next = NULL;
|
||||
sigtype_desc_tail = &desc_link->next;
|
||||
|
||||
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(int32 type)
|
||||
{
|
||||
DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
|
||||
|
||||
while (desc_link && desc_link->desc->type != type)
|
||||
desc_link = desc_link->next;
|
||||
|
||||
return desc_link ? desc_link->desc : NULL;
|
||||
}
|
|
@ -1,184 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* rendduh.c - Functions for rendering a DUH into / / \ \
|
||||
* an end-user sample format. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#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 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); \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#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); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* DEPRECATED */
|
||||
DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, int32 pos)
|
||||
{
|
||||
return duh_start_sigrenderer(duh, 0, n_channels, pos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32 DUMBEXPORT duh_render(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
int bits, int unsign,
|
||||
float volume, float delta,
|
||||
int32 size, void *sptr
|
||||
)
|
||||
{
|
||||
int32 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* DEPRECATED */
|
||||
int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr)
|
||||
{
|
||||
return duh_sigrenderer_get_n_channels(dr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* DEPRECATED */
|
||||
int32 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;
|
||||
}
|
|
@ -1,348 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* rendsig.c - Wrappers to render samples from / / \ \
|
||||
* the signals in a DUH. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/dumb.h"
|
||||
|
||||
|
||||
|
||||
struct DUH_SIGRENDERER
|
||||
{
|
||||
DUH_SIGTYPE_DESC *desc;
|
||||
|
||||
sigrenderer_t *sigrenderer;
|
||||
|
||||
int n_channels;
|
||||
|
||||
int32 pos;
|
||||
int subpos;
|
||||
|
||||
DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback;
|
||||
void *callback_data;
|
||||
};
|
||||
|
||||
|
||||
|
||||
DUH_SIGRENDERER *DUMBEXPORT duh_start_sigrenderer(DUH *duh, int sig, int n_channels, int32 pos)
|
||||
{
|
||||
DUH_SIGRENDERER *sigrenderer;
|
||||
|
||||
DUH_SIGNAL *signal;
|
||||
DUH_START_SIGRENDERER proc;
|
||||
|
||||
/* [RH] Mono destination mixers are disabled. */
|
||||
if (n_channels != 2)
|
||||
return NULL;
|
||||
|
||||
if (!duh)
|
||||
return NULL;
|
||||
|
||||
if ((unsigned int)sig >= (unsigned int)duh->n_signals)
|
||||
return NULL;
|
||||
|
||||
signal = duh->signal[sig];
|
||||
if (!signal)
|
||||
return NULL;
|
||||
|
||||
sigrenderer = malloc(sizeof(*sigrenderer));
|
||||
if (!sigrenderer)
|
||||
return NULL;
|
||||
|
||||
sigrenderer->desc = signal->desc;
|
||||
|
||||
proc = sigrenderer->desc->start_sigrenderer;
|
||||
|
||||
if (proc) {
|
||||
duh->signal[sig] = NULL;
|
||||
sigrenderer->sigrenderer = (*proc)(duh, signal->sigdata, n_channels, pos);
|
||||
duh->signal[sig] = signal;
|
||||
|
||||
if (!sigrenderer->sigrenderer) {
|
||||
free(sigrenderer);
|
||||
return NULL;
|
||||
}
|
||||
} else
|
||||
sigrenderer->sigrenderer = NULL;
|
||||
|
||||
sigrenderer->n_channels = n_channels;
|
||||
|
||||
sigrenderer->pos = pos;
|
||||
sigrenderer->subpos = 0;
|
||||
|
||||
sigrenderer->callback = NULL;
|
||||
|
||||
return sigrenderer;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DUMB_DECLARE_DEPRECATED
|
||||
#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");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer)
|
||||
{
|
||||
return sigrenderer ? sigrenderer->n_channels : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32 DUMBEXPORT duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer)
|
||||
{
|
||||
return sigrenderer ? sigrenderer->pos : -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT duh_sigrenderer_set_sigparam(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
unsigned char id, int32 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 = %d 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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32 DUMBEXPORT duh_sigrenderer_generate_samples(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
double volume, double delta,
|
||||
int32 size, sample_t **samples
|
||||
)
|
||||
{
|
||||
int32 rendered;
|
||||
LONG_LONG t;
|
||||
|
||||
if (!sigrenderer) return 0;
|
||||
|
||||
rendered = (*sigrenderer->desc->sigrenderer_generate_samples)
|
||||
(sigrenderer->sigrenderer, volume, delta, size, samples);
|
||||
|
||||
if (rendered) {
|
||||
if (sigrenderer->callback)
|
||||
(*sigrenderer->callback)(sigrenderer->callback_data,
|
||||
(const sample_t *const *)samples, sigrenderer->n_channels, rendered);
|
||||
|
||||
t = sigrenderer->subpos + (LONG_LONG)(delta * 65536.0 + 0.5) * rendered;
|
||||
|
||||
sigrenderer->pos += (int32)(t >> 16);
|
||||
sigrenderer->subpos = (int)t & 65535;
|
||||
}
|
||||
|
||||
return rendered;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* DEPRECATED */
|
||||
int32 duh_sigrenderer_get_samples(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
float volume, float delta,
|
||||
int32 size, sample_t **samples
|
||||
)
|
||||
{
|
||||
sample_t **s;
|
||||
int32 rendered;
|
||||
int32 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* DEPRECATED */
|
||||
int32 duh_render_signal(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
float volume, float delta,
|
||||
int32 size, sample_t **samples
|
||||
)
|
||||
{
|
||||
sample_t **s;
|
||||
int32 rendered;
|
||||
int32 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT 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 DUMBEXPORT duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer)
|
||||
{
|
||||
if (sigrenderer) {
|
||||
if (sigrenderer->desc->end_sigrenderer)
|
||||
if (sigrenderer->sigrenderer)
|
||||
(*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
|
||||
|
||||
free(sigrenderer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUH_SIGRENDERER *DUMBEXPORT duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, int32 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 *DUMBEXPORT duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, int32 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
|
||||
// the function at all. Who would want to keep an IT_SIGRENDERER (for
|
||||
// instance) without keeping the DUH_SIGRENDERER?
|
||||
sigrenderer_t *duh_decompose_to_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, int32 type)
|
||||
{
|
||||
if (sigrenderer && sigrenderer->desc->type == type) {
|
||||
|
||||
|
||||
|
||||
if (sigrenderer) {
|
||||
if (sigrenderer->desc->end_sigrenderer)
|
||||
if (sigrenderer->sigrenderer)
|
||||
(*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
|
||||
|
||||
free(sigrenderer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return sigrenderer->sigrenderer;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
|
@ -1,64 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* unload.c - Code to free a DUH from memory. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
|
||||
free(signal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* unload_duh(): destroys a DUH struct. You must call this for every DUH
|
||||
* struct created, when you've finished with it.
|
||||
*/
|
||||
void DUMBEXPORT unload_duh(DUH *duh)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (duh) {
|
||||
if (duh->signal) {
|
||||
for (i = 0; i < duh->n_signals; i++)
|
||||
destroy_signal(duh->signal[i]);
|
||||
|
||||
free(duh->signal);
|
||||
}
|
||||
|
||||
if (duh->tag) {
|
||||
if (duh->tag[0][0])
|
||||
free(duh->tag[0][0]);
|
||||
free(duh->tag);
|
||||
}
|
||||
|
||||
free(duh);
|
||||
}
|
||||
}
|
|
@ -1,189 +0,0 @@
|
|||
#include "internal/barray.h"
|
||||
|
||||
#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_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_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_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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
size_t i;
|
||||
for (i = bit; i < *size && i < bit + count; ++i)
|
||||
ptr[i >> 3] &= ~(1U << (i & 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,306 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* clickrem.c - Click removal helpers. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
typedef struct DUMB_CLICK DUMB_CLICK;
|
||||
|
||||
|
||||
struct DUMB_CLICK_REMOVER
|
||||
{
|
||||
DUMB_CLICK *click;
|
||||
int n_clicks;
|
||||
|
||||
int offset;
|
||||
|
||||
DUMB_CLICK *free_clicks;
|
||||
};
|
||||
|
||||
|
||||
struct DUMB_CLICK
|
||||
{
|
||||
DUMB_CLICK *next;
|
||||
int32 pos;
|
||||
sample_t step;
|
||||
};
|
||||
|
||||
|
||||
static DUMB_CLICK *alloc_click(DUMB_CLICK_REMOVER *cr)
|
||||
{
|
||||
if (cr->free_clicks != NULL)
|
||||
{
|
||||
DUMB_CLICK *click = cr->free_clicks;
|
||||
cr->free_clicks = click->next;
|
||||
return click;
|
||||
}
|
||||
return malloc(sizeof(DUMB_CLICK));
|
||||
}
|
||||
|
||||
static void free_click(DUMB_CLICK_REMOVER *cr, DUMB_CLICK *cl)
|
||||
{
|
||||
cl->next = cr->free_clicks;
|
||||
cr->free_clicks = cl;
|
||||
}
|
||||
|
||||
DUMB_CLICK_REMOVER *DUMBEXPORT dumb_create_click_remover(void)
|
||||
{
|
||||
DUMB_CLICK_REMOVER *cr = malloc(sizeof(*cr));
|
||||
if (!cr) return NULL;
|
||||
|
||||
cr->click = NULL;
|
||||
cr->n_clicks = 0;
|
||||
|
||||
cr->offset = 0;
|
||||
cr->free_clicks = NULL;
|
||||
|
||||
return cr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_record_click(DUMB_CLICK_REMOVER *cr, int32 pos, sample_t step)
|
||||
{
|
||||
DUMB_CLICK *click;
|
||||
|
||||
ASSERT(pos >= 0);
|
||||
|
||||
if (!cr || !step) return;
|
||||
|
||||
if (pos == 0) {
|
||||
cr->offset -= step;
|
||||
return;
|
||||
}
|
||||
|
||||
click = alloc_click(cr);
|
||||
if (!click) return;
|
||||
|
||||
click->pos = pos;
|
||||
click->step = step;
|
||||
|
||||
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;
|
||||
|
||||
/* Split the list into two */
|
||||
c1 = click;
|
||||
cp = &c1;
|
||||
for (i = 0; i < n_clicks; i += 2) cp = &(*cp)->next;
|
||||
c2 = *cp;
|
||||
*cp = NULL;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, int32 length, int step, double halflife)
|
||||
{
|
||||
DUMB_CLICK *click;
|
||||
int32 pos = 0;
|
||||
int offset;
|
||||
int factor;
|
||||
|
||||
if (!cr) return;
|
||||
|
||||
factor = (int)floor(pow(0.5, 1.0/halflife) * (1U << 31));
|
||||
|
||||
click = dumb_click_mergesort(cr->click, cr->n_clicks);
|
||||
cr->click = NULL;
|
||||
cr->n_clicks = 0;
|
||||
|
||||
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(cr, 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
sample_t DUMBEXPORT dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr)
|
||||
{
|
||||
return cr ? cr->offset : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT 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;
|
||||
}
|
||||
click = cr->free_clicks;
|
||||
while (click) {
|
||||
DUMB_CLICK *next = click->next;
|
||||
free(click);
|
||||
click = next;
|
||||
}
|
||||
free(cr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUMB_CLICK_REMOVER **DUMBEXPORT 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 DUMBEXPORT dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, int32 pos, sample_t *step)
|
||||
{
|
||||
if (cr) {
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
dumb_record_click(cr[i], pos, step[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, int32 pos, sample_t *step)
|
||||
{
|
||||
if (cr) {
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
dumb_record_click(cr[i], pos, -step[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, int32 length, double 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 DUMBEXPORT 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 DUMBEXPORT 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);
|
||||
}
|
||||
}
|
|
@ -1,320 +0,0 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
|
||||
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function: LPC low level routines
|
||||
last mod: $Id: lpc.c 16227 2009-07-08 06:58:46Z xiphmont $
|
||||
|
||||
********************************************************************/
|
||||
|
||||
/* Some of these routines (autocorrelator, LPC coefficient estimator)
|
||||
are derived from code written by Jutta Degener and Carsten Bormann;
|
||||
thus we include their copyright below. The entirety of this file
|
||||
is freely redistributable on the condition that both of these
|
||||
copyright notices are preserved without modification. */
|
||||
|
||||
/* Preserved Copyright: *********************************************/
|
||||
|
||||
/* Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
|
||||
Technische Universita"t Berlin
|
||||
|
||||
Any use of this software is permitted provided that this notice is not
|
||||
removed and that neither the authors nor the Technische Universita"t
|
||||
Berlin are deemed to have made any representations as to the
|
||||
suitability of this software for any purpose nor are held responsible
|
||||
for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR
|
||||
THIS SOFTWARE.
|
||||
|
||||
As a matter of courtesy, the authors request to be informed about uses
|
||||
this software has found, about bugs in this software, and about any
|
||||
improvements that may be of general interest.
|
||||
|
||||
Berlin, 28.11.1994
|
||||
Jutta Degener
|
||||
Carsten Bormann
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "internal/stack_alloc.h"
|
||||
#include "internal/lpc.h"
|
||||
|
||||
/* Autocorrelation LPC coeff generation algorithm invented by
|
||||
N. Levinson in 1947, modified by J. Durbin in 1959. */
|
||||
|
||||
/* Input : n elements of time doamin data
|
||||
Output: m lpc coefficients, excitation energy */
|
||||
|
||||
float vorbis_lpc_from_data(float *data,float *lpci,int n,int m){
|
||||
double *aut=alloca(sizeof(*aut)*(m+1));
|
||||
double *lpc=alloca(sizeof(*lpc)*(m));
|
||||
double error;
|
||||
double epsilon;
|
||||
int 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
/* 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];
|
||||
|
||||
/* we need the error value to know how big an impulse to hit the
|
||||
filter with later */
|
||||
|
||||
return (float)error;
|
||||
}
|
||||
|
||||
void vorbis_lpc_predict(float *coeff,float *prime,int 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 */
|
||||
|
||||
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];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#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 */
|
||||
|
||||
|
||||
/* This extra sample padding is really only needed by the FIR resampler, but it helps the other resamplers as well. */
|
||||
|
||||
void 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;
|
||||
|
||||
int 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 ) {
|
||||
/* 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;
|
||||
offset = sample->length - lpc_samples;
|
||||
|
||||
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 ];
|
||||
}
|
||||
}
|
||||
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 ];
|
||||
}
|
||||
}
|
||||
|
||||
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 );
|
||||
|
||||
if ( sample->flags & IT_SAMPLE_16BIT )
|
||||
{
|
||||
s16 = ( signed short * ) realloc( sample->data, ( sample->length + lpc_extra ) * 2 * sizeof(short) );
|
||||
sample->data = s16;
|
||||
|
||||
s16 += sample->length * 2;
|
||||
sample->length += lpc_extra;
|
||||
|
||||
for ( o = 0; o < lpc_extra; o++ )
|
||||
{
|
||||
s16[ o * 2 + 0 ] = (signed short)lpc_output[ o ];
|
||||
s16[ o * 2 + 1 ] = (signed short)lpc_output[ o + lpc_extra ];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s8 = ( signed char * ) realloc( sample->data, ( sample->length + lpc_extra ) * 2 );
|
||||
sample->data = s8;
|
||||
|
||||
s8 += sample->length * 2;
|
||||
sample->length += lpc_extra;
|
||||
|
||||
for ( o = 0; o < lpc_extra; o++ )
|
||||
{
|
||||
s8[ o * 2 + 0 ] = (signed char)lpc_output[ o ];
|
||||
s8[ o * 2 + 1 ] = (signed char)lpc_output[ o + lpc_extra ];
|
||||
}
|
||||
}
|
||||
}
|
||||
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 ];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s8 = ( signed char * ) sample->data;
|
||||
s8 += offset;
|
||||
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_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) );
|
||||
sample->data = s16;
|
||||
|
||||
s16 += sample->length;
|
||||
sample->length += lpc_extra;
|
||||
|
||||
for ( o = 0; o < lpc_extra; o++ )
|
||||
{
|
||||
s16[ o ] = (signed short)lpc_output[ o ];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s8 = ( signed char * ) realloc( sample->data, sample->length + lpc_extra );
|
||||
sample->data = s8;
|
||||
|
||||
s8 += sample->length;
|
||||
sample->length += lpc_extra;
|
||||
|
||||
for ( o = 0; o < lpc_extra; o++ )
|
||||
{
|
||||
s8[ o ] = (signed char)lpc_output[ o ];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
/* Otherwise, pad with silence. */
|
||||
{
|
||||
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;
|
||||
|
||||
offset *= n;
|
||||
lpc_samples *= n;
|
||||
|
||||
sample->data = realloc( sample->data, offset + lpc_samples );
|
||||
memset( (char*)sample->data + offset, 0, lpc_samples );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* memfile.c - Module for reading data from / / \ \
|
||||
* memory using a DUMBFILE. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
typedef struct MEMFILE MEMFILE;
|
||||
|
||||
struct MEMFILE
|
||||
{
|
||||
const char *ptr, *ptr_begin;
|
||||
long left, size;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int DUMBCALLBACK 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 DUMBCALLBACK dumb_memfile_getc(void *f)
|
||||
{
|
||||
MEMFILE *m = f;
|
||||
if (m->left <= 0) return -1;
|
||||
m->left--;
|
||||
return *(const unsigned char *)m->ptr++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int32 DUMBCALLBACK dumb_memfile_getnc(char *ptr, int32 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 DUMBCALLBACK dumb_memfile_close(void *f)
|
||||
{
|
||||
free(f);
|
||||
}
|
||||
|
||||
|
||||
static int DUMBCALLBACK dumb_memfile_seek(void *f, long n)
|
||||
{
|
||||
MEMFILE *m = f;
|
||||
|
||||
m->ptr = m->ptr_begin + n;
|
||||
m->left = m->size - n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long DUMBCALLBACK 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 *DUMBEXPORT dumbfile_open_memory(const char *data, int32 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);
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* resamp2.inc - Resampling helper template. / / \ \
|
||||
* | < / \_
|
||||
* By Bob and entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* In order to find a good trade-off between | \ / /
|
||||
* speed and accuracy in this code, some tests | ' /
|
||||
* were carried out regarding the behaviour of \__/
|
||||
* long long ints with gcc. The following code
|
||||
* was tested:
|
||||
*
|
||||
* int a, b, c;
|
||||
* c = ((long long)a * b) >> 16;
|
||||
*
|
||||
* DJGPP GCC Version 3.0.3 generated the following assembly language code for
|
||||
* the multiplication and scaling, leaving the 32-bit result in EAX.
|
||||
*
|
||||
* movl -8(%ebp), %eax ; read one int into EAX
|
||||
* imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX
|
||||
* shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX
|
||||
*
|
||||
* Note that a 32*32->64 multiplication is performed, allowing for high
|
||||
* accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally),
|
||||
* so it is a minor concern when four multiplications are being performed
|
||||
* (the cubic resampler). On the Pentium MMX and earlier, it takes four or
|
||||
* more cycles, so this method is unsuitable for use in the low-quality
|
||||
* resamplers.
|
||||
*
|
||||
* Since "long long" is a gcc-specific extension, we use LONG_LONG instead,
|
||||
* defined in dumb.h. We may investigate later what code MSVC generates, but
|
||||
* if it seems too slow then we suggest you use a good compiler.
|
||||
*
|
||||
* FIXME: these comments are somewhat out of date now.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define SUFFIX3 _2
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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->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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Create mono destination resampler. */
|
||||
/* SUFFIX3 was set above. */
|
||||
#if 0
|
||||
#define VOLUME_PARAMETERS MONO_DEST_VOLUME_PARAMETERS
|
||||
#define VOLUME_VARIABLES MONO_DEST_VOLUME_VARIABLES
|
||||
#define SET_VOLUME_VARIABLES SET_MONO_DEST_VOLUME_VARIABLES
|
||||
#define RETURN_VOLUME_VARIABLES RETURN_MONO_DEST_VOLUME_VARIABLES
|
||||
#define VOLUMES_ARE_ZERO MONO_DEST_VOLUMES_ARE_ZERO
|
||||
#define PEEK_FIR MONO_DEST_PEEK_FIR
|
||||
#define MIX_FIR MONO_DEST_MIX_FIR
|
||||
#define MIX_ZEROS(op) *dst++ op 0
|
||||
#include "resamp3.inc"
|
||||
#else
|
||||
#undef SUFFIX3
|
||||
#endif
|
||||
|
||||
/* 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 = xs_FloorToInt(volume_left->volume * 16777216.f); \
|
||||
lvold = xs_FloorToInt(volume_left->delta * 16777216.f); \
|
||||
lvolt = xs_FloorToInt(volume_left->target * 16777216.f); \
|
||||
lvolm = xs_FloorToInt(volume_left->mix * 16777216.f); \
|
||||
lvol = MULSCV( lvolr, lvolm ); \
|
||||
if ( lvolr == lvolt ) volume_left = NULL; \
|
||||
} else { \
|
||||
lvol = 0; \
|
||||
lvold = 0; \
|
||||
lvolt = 0; \
|
||||
lvolm = 0; \
|
||||
} \
|
||||
if ( volume_right ) { \
|
||||
rvolr = xs_FloorToInt(volume_right->volume * 16777216.f); \
|
||||
rvold = xs_FloorToInt(volume_right->delta * 16777216.f); \
|
||||
rvolt = xs_FloorToInt(volume_right->target * 16777216.f); \
|
||||
rvolm = xs_FloorToInt(volume_right->mix * 16777216.f); \
|
||||
rvol = MULSCV( 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 = (float)lvolr / 16777216.0f; \
|
||||
if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \
|
||||
}
|
||||
#define VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
|
||||
#define MIX_ALIAS(op, upd, offset) STEREO_DEST_MIX_ALIAS(op, upd, offset)
|
||||
#define MIX_LINEAR(op, upd, o0, o1) STEREO_DEST_MIX_LINEAR(op, upd, o0, o1)
|
||||
#define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3)
|
||||
#define PEEK_FIR STEREO_DEST_PEEK_FIR
|
||||
#define MIX_FIR STEREO_DEST_MIX_FIR
|
||||
#define MIX_ZEROS(op) { *dst++ op 0; *dst++ op 0; }
|
||||
#include "resamp3.inc"
|
||||
|
||||
|
||||
|
||||
#undef STEREO_DEST_MIX_CUBIC
|
||||
#undef STEREO_DEST_MIX_LINEAR
|
||||
#undef STEREO_DEST_MIX_ALIAS
|
||||
#undef MONO_DEST_VOLUMES_ARE_ZERO
|
||||
#undef SET_MONO_DEST_VOLUME_VARIABLES
|
||||
#undef RETURN_MONO_DEST_VOLUME_VARIABLES
|
||||
#undef MONO_DEST_VOLUME_ZEROS
|
||||
#undef MONO_DEST_VOLUME_VARIABLES
|
||||
#undef MONO_DEST_VOLUME_PARAMETERS
|
||||
#undef STEREO_DEST_PEEK_ALIAS
|
||||
#undef POKE_ALIAS
|
||||
#undef MONO_DEST_PEEK_FIR
|
||||
#undef STEREO_DEST_PEEK_FIR
|
||||
#undef MONO_DEST_MIX_FIR
|
||||
#undef STEREO_DEST_MIX_FIR
|
||||
#undef ADVANCE_FIR
|
||||
#undef POKE_FIR
|
||||
#undef COPYSRC2
|
||||
#undef COPYSRC
|
||||
#undef DIVIDE_BY_SRC_CHANNELS
|
||||
#undef SRC_CHANNELS
|
||||
#undef SUFFIX2
|
|
@ -1,436 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* resamp3.inc - Resampling helper template. / / \ \
|
||||
* | < / \_
|
||||
* By Bob and entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* In order to find a good trade-off between | \ / /
|
||||
* speed and accuracy in this code, some tests | ' /
|
||||
* were carried out regarding the behaviour of \__/
|
||||
* long long ints with gcc. The following code
|
||||
* was tested:
|
||||
*
|
||||
* int a, b, c;
|
||||
* c = ((long long)a * b) >> 16;
|
||||
*
|
||||
* DJGPP GCC Version 3.0.3 generated the following assembly language code for
|
||||
* the multiplication and scaling, leaving the 32-bit result in EAX.
|
||||
*
|
||||
* movl -8(%ebp), %eax ; read one int into EAX
|
||||
* imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX
|
||||
* shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX
|
||||
*
|
||||
* Note that a 32*32->64 multiplication is performed, allowing for high
|
||||
* accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally),
|
||||
* so it is a minor concern when four multiplications are being performed
|
||||
* (the cubic resampler). On the Pentium MMX and earlier, it takes four or
|
||||
* more cycles, so this method is unsuitable for use in the low-quality
|
||||
* resamplers.
|
||||
*
|
||||
* Since "long long" is a gcc-specific extension, we use LONG_LONG instead,
|
||||
* defined in dumb.h. We may investigate later what code MSVC generates, but
|
||||
* if it seems too slow then we suggest you use a good compiler.
|
||||
*
|
||||
* FIXME: these comments are somewhat out of date now.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VOLUME_PARAMETERS, double delta)
|
||||
{
|
||||
int dt, inv_dt;
|
||||
int VOLUME_VARIABLES;
|
||||
long done;
|
||||
long todo;
|
||||
double tododbl;
|
||||
int quality;
|
||||
|
||||
if (!resampler || resampler->dir == 0) return 0;
|
||||
ASSERT(resampler->dir == -1 || resampler->dir == 1);
|
||||
|
||||
done = 0;
|
||||
dt = xs_CRoundToInt(delta * 65536.0);
|
||||
if (dt == 0 || dt == 0x80000000) return 0;
|
||||
inv_dt = xs_CRoundToInt(1.0 / delta * 65536.0);
|
||||
SET_VOLUME_VARIABLES;
|
||||
|
||||
if (VOLUMES_ARE_ZERO) dst = NULL;
|
||||
|
||||
_dumb_init_cubic();
|
||||
|
||||
quality = resampler->quality;
|
||||
|
||||
while (done < dst_size) {
|
||||
if (process_pickup(resampler)) {
|
||||
RETURN_VOLUME_VARIABLES;
|
||||
return done;
|
||||
}
|
||||
|
||||
if ((resampler->dir ^ dt) < 0)
|
||||
dt = -dt;
|
||||
|
||||
if (resampler->dir < 0)
|
||||
tododbl = ((resampler->pos - resampler->start) * 65536.f + (resampler->subpos - dt)) / -dt;
|
||||
else
|
||||
tododbl = ((resampler->end - resampler->pos) * 65536.f - (resampler->subpos + 1 - dt)) / dt;
|
||||
|
||||
if (tododbl <= 0)
|
||||
todo = 0;
|
||||
else if (tododbl >= dst_size - done)
|
||||
todo = dst_size - done;
|
||||
else
|
||||
todo = xs_FloorToInt(tododbl);
|
||||
|
||||
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 if (quality <= DUMB_RQ_ALIASING) {
|
||||
/* Aliasing, backwards */
|
||||
SRCTYPE xbuf[2*SRC_CHANNELS];
|
||||
SRCTYPE *x = &xbuf[0];
|
||||
SRCTYPE *xstart;
|
||||
COPYSRC(xbuf, 0, resampler->X, 1);
|
||||
COPYSRC(xbuf, 1, resampler->X, 2);
|
||||
while (todo && x < &xbuf[2*SRC_CHANNELS]) {
|
||||
// TODO: check what happens when multiple tempo slides occur per row
|
||||
HEAVYASSERT(pos >= resampler->start);
|
||||
MIX_ALIAS(+=, 1, 0);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x -= (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
todo--;
|
||||
}
|
||||
x = xstart = &src[pos*SRC_CHANNELS];
|
||||
LOOP4(todo,
|
||||
MIX_ALIAS(+=, 1, 2);
|
||||
subpos += dt;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
);
|
||||
pos += DIVIDE_BY_SRC_CHANNELS(x - xstart);
|
||||
} else if (quality <= DUMB_LQ_LINEAR) {
|
||||
/* Linear interpolation, backwards */
|
||||
SRCTYPE xbuf[3*SRC_CHANNELS];
|
||||
SRCTYPE *x = &xbuf[1*SRC_CHANNELS];
|
||||
COPYSRC(xbuf, 0, resampler->X, 1);
|
||||
COPYSRC(xbuf, 1, resampler->X, 2);
|
||||
COPYSRC(xbuf, 2, src, pos);
|
||||
while (todo && x < &xbuf[3*SRC_CHANNELS]) {
|
||||
HEAVYASSERT(pos >= resampler->start);
|
||||
MIX_LINEAR(+=, 1, 0, -1);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x -= (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
todo--;
|
||||
}
|
||||
// TODO: use xstart for others too
|
||||
x = &src[pos*SRC_CHANNELS];
|
||||
LOOP4(todo,
|
||||
HEAVYASSERT(pos >= resampler->start);
|
||||
MIX_LINEAR(+=, 1, 1, 2);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
);
|
||||
} else if (quality <= DUMB_LQ_CUBIC) {
|
||||
/* Cubic interpolation, backwards */
|
||||
SRCTYPE xbuf[6*SRC_CHANNELS];
|
||||
SRCTYPE *x = &xbuf[3*SRC_CHANNELS];
|
||||
COPYSRC(xbuf, 0, resampler->X, 0);
|
||||
COPYSRC(xbuf, 1, resampler->X, 1);
|
||||
COPYSRC(xbuf, 2, resampler->X, 2);
|
||||
COPYSRC(xbuf, 3, src, pos);
|
||||
if (pos-1 >= resampler->start) COPYSRC(xbuf, 4, src, pos-1);
|
||||
if (pos-2 >= resampler->start) COPYSRC(xbuf, 5, src, pos-2);
|
||||
while (todo && x < &xbuf[6*SRC_CHANNELS]) {
|
||||
HEAVYASSERT(pos >= resampler->start);
|
||||
MIX_CUBIC(+=, 1, x, x, 0, -1, -2, -3);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x -= (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
todo--;
|
||||
}
|
||||
x = &src[pos*SRC_CHANNELS];
|
||||
LOOP4(todo,
|
||||
HEAVYASSERT(pos >= resampler->start);
|
||||
MIX_CUBIC(+=, 1, x, x, 0, 1, 2, 3);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
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] )
|
||||
#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 if (quality <= DUMB_RQ_ALIASING) {
|
||||
/* Aliasing, forwards */
|
||||
SRCTYPE xbuf[2*SRC_CHANNELS];
|
||||
SRCTYPE *x = &xbuf[0];
|
||||
SRCTYPE *xstart;
|
||||
COPYSRC(xbuf, 0, resampler->X, 1);
|
||||
COPYSRC(xbuf, 1, resampler->X, 2);
|
||||
while (todo && x < &xbuf[2*SRC_CHANNELS]) {
|
||||
HEAVYASSERT(pos < resampler->end);
|
||||
MIX_ALIAS(+=, 1, 0);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
todo--;
|
||||
}
|
||||
x = xstart = &src[pos*SRC_CHANNELS];
|
||||
LOOP4(todo,
|
||||
MIX_ALIAS(+=, 1, -2);
|
||||
subpos += dt;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
);
|
||||
pos += DIVIDE_BY_SRC_CHANNELS(x - xstart);
|
||||
} else if (quality <= DUMB_LQ_LINEAR) {
|
||||
/* Linear interpolation, forwards */
|
||||
SRCTYPE xbuf[3*SRC_CHANNELS];
|
||||
SRCTYPE *x = &xbuf[1*SRC_CHANNELS];
|
||||
COPYSRC(xbuf, 0, resampler->X, 1);
|
||||
COPYSRC(xbuf, 1, resampler->X, 2);
|
||||
COPYSRC(xbuf, 2, src, pos);
|
||||
while (todo && x < &xbuf[3*SRC_CHANNELS]) {
|
||||
HEAVYASSERT(pos < resampler->end);
|
||||
MIX_LINEAR(+=, 1, -1, 0);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
todo--;
|
||||
}
|
||||
x = &src[pos*SRC_CHANNELS];
|
||||
LOOP4(todo,
|
||||
HEAVYASSERT(pos < resampler->end);
|
||||
MIX_LINEAR(+=, 1, -2, -1);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
);
|
||||
} else if (quality <= DUMB_LQ_CUBIC) {
|
||||
/* Cubic interpolation, forwards */
|
||||
SRCTYPE xbuf[6*SRC_CHANNELS];
|
||||
SRCTYPE *x = &xbuf[3*SRC_CHANNELS];
|
||||
COPYSRC(xbuf, 0, resampler->X, 0);
|
||||
COPYSRC(xbuf, 1, resampler->X, 1);
|
||||
COPYSRC(xbuf, 2, resampler->X, 2);
|
||||
COPYSRC(xbuf, 3, src, pos);
|
||||
if (pos+1 < resampler->end) COPYSRC(xbuf, 4, src, pos+1);
|
||||
if (pos+2 < resampler->end) COPYSRC(xbuf, 5, src, pos+2);
|
||||
while (todo && x < &xbuf[6*SRC_CHANNELS]) {
|
||||
HEAVYASSERT(pos < resampler->end);
|
||||
MIX_CUBIC(+=, 1, x, x, -3, -2, -1, 0);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
todo--;
|
||||
}
|
||||
x = &src[pos*SRC_CHANNELS];
|
||||
LOOP4(todo,
|
||||
HEAVYASSERT(pos < resampler->end);
|
||||
MIX_CUBIC(+=, 1, x, x, -3, -2, -1, 0);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
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] )
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_VOLUME_VARIABLES;
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETERS, sample_t *dst)
|
||||
{
|
||||
int 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);
|
||||
|
||||
if (process_pickup(resampler)) { MIX_ZEROS(=); return; }
|
||||
|
||||
SET_VOLUME_VARIABLES;
|
||||
|
||||
if (VOLUMES_ARE_ZERO) { MIX_ZEROS(=); return; }
|
||||
|
||||
_dumb_init_cubic();
|
||||
|
||||
quality = resampler->quality;
|
||||
|
||||
src = resampler->src;
|
||||
pos = resampler->pos;
|
||||
subpos = resampler->subpos;
|
||||
x = resampler->X;
|
||||
|
||||
if (resampler->dir < 0) {
|
||||
HEAVYASSERT(pos >= resampler->start);
|
||||
if (quality <= DUMB_RQ_ALIASING) {
|
||||
/* Aliasing, backwards */
|
||||
MIX_ALIAS(=, 0, 1);
|
||||
} else if (quality <= DUMB_LQ_LINEAR) {
|
||||
/* Linear interpolation, backwards */
|
||||
MIX_LINEAR(=, 0, 2, 1);
|
||||
} else if (quality <= DUMB_LQ_CUBIC) {
|
||||
/* Cubic interpolation, backwards */
|
||||
MIX_CUBIC(=, 0, src, x, pos, 2, 1, 0);
|
||||
} else {
|
||||
/* FIR resampling, backwards */
|
||||
PEEK_FIR;
|
||||
}
|
||||
} else {
|
||||
HEAVYASSERT(pos < resampler->end);
|
||||
if (quality <= DUMB_RQ_ALIASING) {
|
||||
/* Aliasing */
|
||||
MIX_ALIAS(=, 0, 1);
|
||||
} else if (quality <= DUMB_LQ_LINEAR) {
|
||||
/* Linear interpolation, forwards */
|
||||
MIX_LINEAR(=, 0, 1, 2);
|
||||
} else if (quality <= DUMB_LQ_CUBIC) {
|
||||
/* Cubic interpolation, forwards */
|
||||
MIX_CUBIC(=, 0, x, src, 0, 1, 2, pos);
|
||||
} else {
|
||||
/* FIR resampling, forwards */
|
||||
PEEK_FIR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#undef MIX_ZEROS
|
||||
#undef MIX_FIR
|
||||
#undef PEEK_FIR
|
||||
#undef VOLUMES_ARE_ZERO
|
||||
#undef SET_VOLUME_VARIABLES
|
||||
#undef RETURN_VOLUME_VARIABLES
|
||||
#undef VOLUME_VARIABLES
|
||||
#undef VOLUME_PARAMETERS
|
||||
#undef SUFFIX3
|
|
@ -1,420 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* resample.c - Resampling helpers. / / \ \
|
||||
* | < / \_
|
||||
* By Bob and entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* In order to find a good trade-off between | \ / /
|
||||
* speed and accuracy in this code, some tests | ' /
|
||||
* were carried out regarding the behaviour of \__/
|
||||
* long long ints with gcc. The following code
|
||||
* was tested:
|
||||
*
|
||||
* int a, b, c;
|
||||
* c = ((long long)a * b) >> 16;
|
||||
*
|
||||
* DJGPP GCC Version 3.0.3 generated the following assembly language code for
|
||||
* the multiplication and scaling, leaving the 32-bit result in EAX.
|
||||
*
|
||||
* movl -8(%ebp), %eax ; read one int into EAX
|
||||
* imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX
|
||||
* shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX
|
||||
*
|
||||
* Note that a 32*32->64 multiplication is performed, allowing for high
|
||||
* accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally),
|
||||
* so it is a minor concern when four multiplications are being performed
|
||||
* (the cubic resampler). On the Pentium MMX and earlier, it takes four or
|
||||
* more cycles, so this method is unsuitable for use in the low-quality
|
||||
* resamplers.
|
||||
*
|
||||
* Since "long long" is a gcc-specific extension, we use LONG_LONG instead,
|
||||
* defined in dumb.h. We may investigate later what code MSVC generates, but
|
||||
* if it seems too slow then we suggest you use a good compiler.
|
||||
*
|
||||
* FIXME: these comments are somewhat out of date now.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include "dumb.h"
|
||||
|
||||
#include "internal/resampler.h"
|
||||
#include "internal/mulsc.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,
|
||||
* since at least one condition has to be tested for every sample generated.
|
||||
*/
|
||||
#ifdef HEAVYDEBUG
|
||||
#define HEAVYASSERT(cond) ASSERT(cond)
|
||||
#else
|
||||
#define HEAVYASSERT(cond)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Make MSVC shut the hell up about if ( upd ) UPDATE_VOLUME() conditions being constant */
|
||||
#ifdef _MSC_VER
|
||||
#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:
|
||||
*
|
||||
* 0 - DUMB_RQ_ALIASING - fastest
|
||||
* 1 - DUMB_RQ_BLEP - nicer than aliasing, but slower
|
||||
* 2 - DUMB_RQ_LINEAR
|
||||
* 3 - DUMB_RQ_BLAM - band-limited linear interpolation, nice but slower
|
||||
* 4 - DUMB_RQ_CUBIC
|
||||
* 5 - DUMB_RQ_FIR - nicest
|
||||
*
|
||||
* Values outside the range 0-4 will behave the same as the nearest
|
||||
* value within the range.
|
||||
*/
|
||||
int dumb_resampling_quality = DUMB_RQ_CUBIC;
|
||||
|
||||
|
||||
|
||||
/* From xs_Float.h ==============================================*/
|
||||
#if __BIG_ENDIAN__
|
||||
#define _xs_iman_ 1
|
||||
#else
|
||||
#define _xs_iman_ 0
|
||||
#endif //BigEndian_
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define finline inline
|
||||
#else
|
||||
#define finline __forceinline
|
||||
#endif
|
||||
|
||||
union _xs_doubleints
|
||||
{
|
||||
double val;
|
||||
unsigned int ival[2];
|
||||
};
|
||||
|
||||
static const double _xs_doublemagic = (6755399441055744.0); //2^52 * 1.5, uses limited precisicion to floor
|
||||
static const double _xs_doublemagicroundeps = (.5f-(1.5e-8)); //almost .5f = .5f - 1e^(number of exp bit)
|
||||
|
||||
static finline int xs_CRoundToInt(double val)
|
||||
{
|
||||
union _xs_doubleints uval;
|
||||
val += _xs_doublemagic;
|
||||
uval.val = val;
|
||||
return uval.ival[_xs_iman_];
|
||||
}
|
||||
static finline int xs_FloorToInt(double val)
|
||||
{
|
||||
union _xs_doubleints uval;
|
||||
val -= _xs_doublemagicroundeps;
|
||||
val += _xs_doublemagic;
|
||||
uval.val = val;
|
||||
return uval.ival[_xs_iman_];
|
||||
}
|
||||
/* Not from xs_Float.h ==========================================*/
|
||||
|
||||
|
||||
/* 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)--; \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#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 X PASTE(x.x, SRCBITS)
|
||||
|
||||
|
||||
|
||||
/* Cubic resampler: look-up tables
|
||||
*
|
||||
* a = 1.5*x1 - 1.5*x2 + 0.5*x3 - 0.5*x0
|
||||
* b = 2*x2 + x0 - 2.5*x1 - 0.5*x3
|
||||
* c = 0.5*x2 - 0.5*x0
|
||||
* d = x1
|
||||
*
|
||||
* x = a*t*t*t + b*t*t + c*t + d
|
||||
* = (-0.5*x0 + 1.5*x1 - 1.5*x2 + 0.5*x3) * t*t*t +
|
||||
* ( 1*x0 - 2.5*x1 + 2 *x2 - 0.5*x3) * t*t +
|
||||
* (-0.5*x0 + 0.5*x2 ) * t +
|
||||
* ( 1*x1 )
|
||||
* = (-0.5*t*t*t + 1 *t*t - 0.5*t ) * x0 +
|
||||
* ( 1.5*t*t*t - 2.5*t*t + 1) * x1 +
|
||||
* (-1.5*t*t*t + 2 *t*t + 0.5*t ) * x2 +
|
||||
* ( 0.5*t*t*t - 0.5*t*t ) * x3
|
||||
* = A0(t) * x0 + A1(t) * x1 + A2(t) * x2 + A3(t) * x3
|
||||
*
|
||||
* A0, A1, A2 and A3 stay within the range [-1,1].
|
||||
* In the tables, they are scaled with 14 fractional bits.
|
||||
*
|
||||
* Turns out we don't need to store A2 and A3; they are symmetrical to A1 and A0.
|
||||
*
|
||||
* TODO: A0 and A3 stay very small indeed. Consider different scale/resolution?
|
||||
*/
|
||||
|
||||
static short cubicA0[1025], cubicA1[1025];
|
||||
|
||||
void _dumb_init_cubic(void)
|
||||
{
|
||||
unsigned int t; /* 3*1024*1024*1024 is within range if it's unsigned */
|
||||
static int done = 0;
|
||||
if (done) return;
|
||||
for (t = 0; t < 1025; t++) {
|
||||
/* int casts to pacify warnings about negating unsigned values */
|
||||
cubicA0[t] = -(int)( t*t*t >> 17) + (int)( t*t >> 6) - (int)(t << 3);
|
||||
cubicA1[t] = (int)(3*t*t*t >> 17) - (int)(5*t*t >> 7) + (int)(1 << 14);
|
||||
}
|
||||
resampler_init();
|
||||
|
||||
done = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Create resamplers for 24-in-32-bit source samples. */
|
||||
|
||||
/* #define SUFFIX
|
||||
* MSVC warns if we try to paste a null SUFFIX, so instead we define
|
||||
* special macros for the function names that don't bother doing the
|
||||
* corresponding paste. The more generic definitions are further down.
|
||||
*/
|
||||
#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 SRCTYPE sample_t
|
||||
#define SRCBITS 24
|
||||
#define ALIAS(x, vol) MULSC(x, vol)
|
||||
#define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos))
|
||||
#define CUBIC(x0, x1, x2, x3) ( \
|
||||
MULSC(x0, cubicA0[subpos >> 6] << 2) + \
|
||||
MULSC(x1, cubicA1[subpos >> 6] << 2) + \
|
||||
MULSC(x2, cubicA1[1 + (subpos >> 6 ^ 1023)] << 2) + \
|
||||
MULSC(x3, cubicA0[1 + (subpos >> 6 ^ 1023)] << 2))
|
||||
#define CUBICVOL(x, vol) MULSC(x, vol)
|
||||
#define FIR(x) (x >> 8)
|
||||
#include "resample.inc"
|
||||
|
||||
/* Undefine the simplified macros. */
|
||||
#undef dumb_resample_get_current_sample
|
||||
#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_end_resampler PASTE(dumb_end_resampler, SUFFIX)
|
||||
|
||||
/* Create resamplers for 16-bit source samples. */
|
||||
#define SUFFIX _16
|
||||
#define SRCTYPE short
|
||||
#define SRCBITS 16
|
||||
#define ALIAS(x, vol) (x * vol >> 8)
|
||||
#define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos))
|
||||
#define CUBIC(x0, x1, x2, x3) ( \
|
||||
x0 * cubicA0[subpos >> 6] + \
|
||||
x1 * cubicA1[subpos >> 6] + \
|
||||
x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \
|
||||
x3 * cubicA0[1 + (subpos >> 6 ^ 1023)])
|
||||
#define CUBICVOL(x, vol) MULSCV((x), ((vol) << 10))
|
||||
#define FIR(x) (x)
|
||||
#include "resample.inc"
|
||||
|
||||
/* Create resamplers for 8-bit source samples. */
|
||||
#define SUFFIX _8
|
||||
#define SRCTYPE signed char
|
||||
#define SRCBITS 8
|
||||
#define ALIAS(x, vol) (x * vol)
|
||||
#define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos)
|
||||
#define CUBIC(x0, x1, x2, x3) (( \
|
||||
x0 * cubicA0[subpos >> 6] + \
|
||||
x1 * cubicA1[subpos >> 6] + \
|
||||
x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \
|
||||
x3 * cubicA0[1 + (subpos >> 6 ^ 1023)]) << 6)
|
||||
#define CUBICVOL(x, vol) MULSCV((x), ((vol) << 12))
|
||||
#define FIR(x) (x << 8)
|
||||
#include "resample.inc"
|
||||
|
||||
|
||||
#undef dumb_reset_resampler
|
||||
#undef dumb_start_resampler
|
||||
#undef process_pickup
|
||||
#undef dumb_resample
|
||||
#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, int32 pos, int32 start, int32 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, int32 pos, int32 start, int32 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);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int32 dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume, double 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);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int32 dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double 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);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int32 dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double 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);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int32 dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double 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);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
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);
|
||||
}
|
|
@ -1,299 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* resample.inc - Resampling helper template. / / \ \
|
||||
* | < / \_
|
||||
* By Bob and entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* In order to find a good trade-off between | \ / /
|
||||
* speed and accuracy in this code, some tests | ' /
|
||||
* were carried out regarding the behaviour of \__/
|
||||
* long long ints with gcc. The following code
|
||||
* was tested:
|
||||
*
|
||||
* int a, b, c;
|
||||
* c = ((long long)a * b) >> 16;
|
||||
*
|
||||
* DJGPP GCC Version 3.0.3 generated the following assembly language code for
|
||||
* the multiplication and scaling, leaving the 32-bit result in EAX.
|
||||
*
|
||||
* movl -8(%ebp), %eax ; read one int into EAX
|
||||
* imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX
|
||||
* shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX
|
||||
*
|
||||
* Note that a 32*32->64 multiplication is performed, allowing for high
|
||||
* accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally),
|
||||
* so it is a minor concern when four multiplications are being performed
|
||||
* (the cubic resampler). On the Pentium MMX and earlier, it takes four or
|
||||
* more cycles, so this method is unsuitable for use in the low-quality
|
||||
* resamplers.
|
||||
*
|
||||
* Since "long long" is a gcc-specific extension, we use LONG_LONG instead,
|
||||
* defined in dumb.h. We may investigate later what code MSVC generates, but
|
||||
* if it seems too slow then we suggest you use a good compiler.
|
||||
*
|
||||
* FIXME: these comments are somewhat out of date now.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, int src_channels, int32 pos, int32 start, int32 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 - DUMB_RESAMPLER_BASE);
|
||||
resampler_set_quality(resampler->fir_resampler[1], resampler->quality - DUMB_RESAMPLER_BASE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos, int32 start, int32 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 = MULSCV( vol##t, vol##m ); \
|
||||
} else { \
|
||||
vol = MULSCV( vol##r, vol##m ); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Create mono source resampler. */
|
||||
#define SUFFIX2 _1
|
||||
#define SRC_CHANNELS 1
|
||||
#define DIVIDE_BY_SRC_CHANNELS(x) (int)(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 MONO_DEST_VOLUME_VARIABLES vol, volr, vold, volt, volm
|
||||
#define MONO_DEST_VOLUME_ZEROS 0, 0
|
||||
#define SET_MONO_DEST_VOLUME_VARIABLES { \
|
||||
if ( volume ) { \
|
||||
volr = xs_FloorToInt(volume->volume * 16777216.f); \
|
||||
vold = xs_FloorToInt(volume->delta * 16777216.f); \
|
||||
volt = xs_FloorToInt(volume->target * 16777216.f); \
|
||||
volm = xs_FloorToInt(volume->mix * 16777216.f); \
|
||||
vol = MULSCV( 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 = (float)volr / 16777216.0f
|
||||
#define MONO_DEST_VOLUMES_ARE_ZERO (vol == 0 && volt == 0)
|
||||
#define STEREO_DEST_MIX_ALIAS(op, upd, offset) { \
|
||||
int xm = x[offset]; \
|
||||
*dst++ op ALIAS(xm, lvol); \
|
||||
*dst++ op ALIAS(xm, rvol); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
||||
}
|
||||
#define STEREO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
|
||||
int xm = LINEAR(x[o0], x[o1]); \
|
||||
*dst++ op MULSC(xm, lvol); \
|
||||
*dst++ op MULSC(xm, rvol); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
||||
}
|
||||
#define STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) { \
|
||||
int xm = CUBIC(x0[o0], x[o1], x[o2], x3[o3]); \
|
||||
*dst++ op CUBICVOL(xm, lvol); \
|
||||
*dst++ op CUBICVOL(xm, rvol); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
||||
}
|
||||
#define POKE_FIR(offset) { \
|
||||
resampler_write_sample( resampler->fir_resampler[0], FIR(x[offset]) ); \
|
||||
}
|
||||
#define MONO_DEST_PEEK_FIR *dst = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), vol )
|
||||
#define MONO_DEST_MIX_FIR { \
|
||||
*dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), vol ); \
|
||||
UPDATE_VOLUME( volume, vol ); \
|
||||
}
|
||||
#define ADVANCE_FIR resampler_remove_sample( resampler->fir_resampler[0], 1 )
|
||||
#define STEREO_DEST_PEEK_FIR { \
|
||||
int sample = resampler_get_sample( resampler->fir_resampler[0] ); \
|
||||
*dst++ = MULSC( sample, lvol ); \
|
||||
*dst++ = MULSC( sample, rvol ); \
|
||||
}
|
||||
#define STEREO_DEST_MIX_FIR { \
|
||||
int sample = resampler_get_sample( resampler->fir_resampler[0] ); \
|
||||
*dst++ += MULSC( sample, lvol ); \
|
||||
*dst++ += MULSC( sample, rvol ); \
|
||||
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) (int)((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 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 = xs_FloorToInt(volume_left->volume * 16777216.f); \
|
||||
lvold = xs_FloorToInt(volume_left->delta * 16777216.f); \
|
||||
lvolt = xs_FloorToInt(volume_left->target * 16777216.f); \
|
||||
lvolm = xs_FloorToInt(volume_left->mix * 16777216.f); \
|
||||
lvol = MULSCV( lvolr, lvolm ); \
|
||||
if ( lvolr == lvolt ) volume_left = NULL; \
|
||||
} else { \
|
||||
lvol = 0; \
|
||||
lvold = 0; \
|
||||
lvolt = 0; \
|
||||
lvolm = 0; \
|
||||
} \
|
||||
if ( volume_right ) { \
|
||||
rvolr = xs_FloorToInt(volume_right->volume * 16777216.f); \
|
||||
rvold = xs_FloorToInt(volume_right->delta * 16777216.f); \
|
||||
rvolt = xs_FloorToInt(volume_right->target * 16777216.f); \
|
||||
rvolm = xs_FloorToInt(volume_right->mix * 16777216.f); \
|
||||
rvol = MULSCV( 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 = (float)lvolr / 16777216.0f; \
|
||||
if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \
|
||||
}
|
||||
#define MONO_DEST_VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
|
||||
#define STEREO_DEST_MIX_ALIAS(op, upd, offset) { \
|
||||
*dst++ op ALIAS(x[(offset)*2], lvol); \
|
||||
*dst++ op ALIAS(x[(offset)*2+1], rvol); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
||||
}
|
||||
#define STEREO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
|
||||
*dst++ op MULSC(LINEAR(x[(o0)*2], x[(o1)*2]), lvol); \
|
||||
*dst++ op MULSC(LINEAR(x[(o0)*2+1], x[(o1)*2+1]), rvol); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
||||
}
|
||||
#define STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) { \
|
||||
*dst++ op CUBICVOL(CUBIC(x0[(o0)*2], x[(o1)*2], x[(o2)*2], x3[(o3)*2]), lvol); \
|
||||
*dst++ op CUBICVOL(CUBIC(x0[(o0)*2+1], x[(o1)*2+1], x[(o2)*2+1], x3[(o3)*2+1]), rvol); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
||||
}
|
||||
#define POKE_FIR(offset) { \
|
||||
resampler_write_sample( resampler->fir_resampler[0], FIR(x[(offset)*2+0]) ); \
|
||||
resampler_write_sample( resampler->fir_resampler[1], FIR(x[(offset)*2+1]) ); \
|
||||
}
|
||||
#define MONO_DEST_PEEK_FIR { \
|
||||
*dst = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \
|
||||
MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
|
||||
}
|
||||
#define MONO_DEST_MIX_FIR { \
|
||||
*dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \
|
||||
MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
|
||||
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++ = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \
|
||||
*dst++ = MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
|
||||
}
|
||||
#define STEREO_DEST_MIX_FIR { \
|
||||
*dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \
|
||||
*dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
|
||||
UPDATE_VOLUME( volume_left, lvol ); \
|
||||
UPDATE_VOLUME( volume_right, rvol ); \
|
||||
}
|
||||
#include "resamp2.inc"
|
||||
|
||||
|
||||
|
||||
void dumb_end_resampler(DUMB_RESAMPLER *resampler)
|
||||
{
|
||||
if (resampler)
|
||||
free(resampler);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#undef FIR
|
||||
#undef CUBICVOL
|
||||
#undef CUBIC
|
||||
#undef LINEAR
|
||||
#undef ALIAS
|
||||
#undef SRCBITS
|
||||
#undef SRCTYPE
|
||||
#undef SUFFIX
|
File diff suppressed because it is too large
Load diff
|
@ -1,87 +0,0 @@
|
|||
#include "dumb.h"
|
||||
#include "internal/riff.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct riff * riff_parse( DUMBFILE * f, int32 offset, int32 size, unsigned proper )
|
||||
{
|
||||
unsigned stream_size;
|
||||
struct riff * stream;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
stream_size = dumbfile_igetl(f);
|
||||
if ( stream_size + 8 > (unsigned)size ) return 0;
|
||||
if ( stream_size < 4 ) return 0;
|
||||
|
||||
stream = (struct riff *) malloc( sizeof( struct riff ) );
|
||||
if ( ! stream ) return 0;
|
||||
|
||||
stream->type = dumbfile_mgetl(f);
|
||||
stream->chunk_count = 0;
|
||||
stream->chunks = 0;
|
||||
|
||||
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 = dumbfile_mgetl(f);
|
||||
chunk->size = 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
|
||||
{
|
||||
chunk->nested = 0;
|
||||
}
|
||||
dumbfile_seek(f, chunk->offset + chunk->size, DFS_SEEK_SET);
|
||||
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;
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* sampbuf.c - Helper for allocating sample / / \ \
|
||||
* buffers. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
/* DEPRECATED */
|
||||
sample_t **create_sample_buffer(int n_channels, int32 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 **DUMBEXPORT allocate_sample_buffer(int n_channels, int32 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 DUMBEXPORT destroy_sample_buffer(sample_t **samples)
|
||||
{
|
||||
if (samples) {
|
||||
free(samples[0]);
|
||||
free(samples);
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* silence.c - Silencing helper. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_silence(sample_t *samples, int32 length)
|
||||
{
|
||||
memset(samples, 0, length * sizeof(*samples));
|
||||
}
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* stdfile.c - stdio file input module. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
typedef struct dumb_stdfile
|
||||
{
|
||||
FILE * file;
|
||||
long size;
|
||||
} dumb_stdfile;
|
||||
|
||||
|
||||
|
||||
static void *DUMBCALLBACK dumb_stdfile_open(const char *filename)
|
||||
{
|
||||
dumb_stdfile * file = ( dumb_stdfile * ) malloc( sizeof(dumb_stdfile) );
|
||||
if ( !file ) return 0;
|
||||
file->file = fopen(filename, "rb");
|
||||
fseek(file->file, 0, SEEK_END);
|
||||
file->size = ftell(file->file);
|
||||
fseek(file->file, 0, SEEK_SET);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int DUMBCALLBACK dumb_stdfile_skip(void *f, long n)
|
||||
{
|
||||
dumb_stdfile * file = ( dumb_stdfile * ) f;
|
||||
return fseek(file->file, n, SEEK_CUR);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int DUMBCALLBACK dumb_stdfile_getc(void *f)
|
||||
{
|
||||
dumb_stdfile * file = ( dumb_stdfile * ) f;
|
||||
return fgetc(file->file);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int32 DUMBCALLBACK dumb_stdfile_getnc(char *ptr, int32 n, void *f)
|
||||
{
|
||||
dumb_stdfile * file = ( dumb_stdfile * ) f;
|
||||
return (int32)fread(ptr, 1, n, file->file);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DUMBCALLBACK dumb_stdfile_close(void *f)
|
||||
{
|
||||
dumb_stdfile * file = ( dumb_stdfile * ) f;
|
||||
fclose(file->file);
|
||||
free(f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DUMBCALLBACK dumb_stdfile_noclose(void *f)
|
||||
{
|
||||
free(f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int DUMBCALLBACK dumb_stdfile_seek(void *f, long n)
|
||||
{
|
||||
dumb_stdfile * file = ( dumb_stdfile * ) f;
|
||||
return fseek(file->file, n, SEEK_SET);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static long DUMBCALLBACK 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
|
||||
};
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT 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 *DUMBEXPORT 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);
|
||||
fseek(p, 0, SEEK_SET);
|
||||
d = dumbfile_open_ex(file, &stdfile_dfs_leave_open);
|
||||
|
||||
return d;
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* itload.c - Code to read an Impulse Tracker / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By entheh. Don't worry Bob, you're credited | \ / /
|
||||
* in itread.c! | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_it_quick(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_it_quick(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* itload2.c - Function to read an Impulse Tracker / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you, and do an initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* Split off from itload.c by entheh. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_it(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_it_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,249 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* itmisc.c - Miscellaneous functions relating / / \ \
|
||||
* to module files. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
||||
|
||||
int dumb_it_default_panning_separation = 25;
|
||||
|
||||
|
||||
DUMB_IT_SIGDATA *DUMBEXPORT duh_get_it_sigdata(DUH *duh)
|
||||
{
|
||||
return duh_get_raw_sigdata(duh, -1, SIGTYPE_IT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const unsigned char *DUMBEXPORT dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd)
|
||||
{
|
||||
return sd ? sd->song_message : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd)
|
||||
{
|
||||
return sd ? sd->n_orders : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd)
|
||||
{
|
||||
return sd ? sd->n_samples : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd)
|
||||
{
|
||||
return sd ? sd->n_instruments : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const unsigned char *DUMBEXPORT 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 *DUMBEXPORT 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 *DUMBEXPORT 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 *DUMBEXPORT 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 DUMBEXPORT dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd)
|
||||
{
|
||||
return sd ? sd->global_volume : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv)
|
||||
{
|
||||
if (sd) sd->global_volume = gv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd)
|
||||
{
|
||||
return sd ? sd->mixing_volume : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv)
|
||||
{
|
||||
if (sd) sd->mixing_volume = mv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd)
|
||||
{
|
||||
return sd ? sd->speed : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed)
|
||||
{
|
||||
if (sd) sd->speed = speed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd)
|
||||
{
|
||||
return sd ? sd->tempo : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo)
|
||||
{
|
||||
if (sd) sd->tempo = tempo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT 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 DUMBEXPORT 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 DUMBEXPORT dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr)
|
||||
{
|
||||
return sr ? sr->order : -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr)
|
||||
{
|
||||
return sr ? sr->row : -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr)
|
||||
{
|
||||
return sr ? sr->globalvolume : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv)
|
||||
{
|
||||
if (sr) sr->globalvolume = gv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr)
|
||||
{
|
||||
return sr ? sr->tempo : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo)
|
||||
{
|
||||
if (sr) sr->tempo = tempo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr)
|
||||
{
|
||||
return sr ? sr->speed : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed)
|
||||
{
|
||||
if (sr) sr->speed = speed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DUMBEXPORT dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel)
|
||||
{
|
||||
return sr ? sr->channel[channel].channelvolume : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume)
|
||||
{
|
||||
if (sr) sr->channel[channel].channelvolume = volume;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT 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 DUMBEXPORT dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel)
|
||||
{
|
||||
return sr ? (sr->channel[channel].flags & IT_CHANNEL_MUTED) != 0 : 0;
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* itorder.c - Code to fix invalid patterns in / / \ \
|
||||
* the pattern table. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Julien Cugniere. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#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 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;
|
||||
}
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* itread2.c - Function to read an Impulse Tracker / / \ \
|
||||
* module from an open file and do an | < / \_
|
||||
* initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* Split off from itread.c by entheh. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT 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
|
@ -1,72 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* itunload.c - Code to free an Impulse Tracker / / \ \
|
||||
* module from memory. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
|
||||
if (sigdata->order)
|
||||
free(sigdata->order);
|
||||
|
||||
if (sigdata->instrument)
|
||||
free(sigdata->instrument);
|
||||
|
||||
if (sigdata->sample) {
|
||||
for (n = 0; n < sigdata->n_samples; n++)
|
||||
if (sigdata->sample[n].data)
|
||||
free(sigdata->sample[n].data);
|
||||
|
||||
free(sigdata->sample);
|
||||
}
|
||||
|
||||
if (sigdata->pattern) {
|
||||
for (n = 0; n < sigdata->n_patterns; n++)
|
||||
if (sigdata->pattern[n].entry)
|
||||
free(sigdata->pattern[n].entry);
|
||||
free(sigdata->pattern);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadmod.c - Code to read a 669 Composer module / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_669_quick(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_669_quick(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadmod2.c - Code to read a 669 Composer module / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you, and do an initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_669(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_669_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadamf.c - Code to read a DSMI AMF module file, / / \ \
|
||||
* opening and closing it for you. | < / \_
|
||||
* | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_amf_quick(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_amf_quick(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadamf2.c - Code to read a DSMI AMF module file, / / \ \
|
||||
* opening and closing it for you, and | < / \_
|
||||
* do an initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* By Chris Moeller. | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_amf(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_amf_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadany.c - Code to detect and read any of the / / \ \
|
||||
* module formats supported by DUMB, | < / \_
|
||||
* opening and closing the file for you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_any_quick(const char *filename, int restrict_, int subsong)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_any_quick(f, restrict_, subsong);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadany2.c - Code to detect and read any of the / / \ \
|
||||
* module formats supported by DUMB, | < / \_
|
||||
* opening and closing the file for | \/ /\ /
|
||||
* you, and do an initial run-through. \_ / > /
|
||||
* | \ / /
|
||||
* by Chris Moeller. | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT 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;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadasy.c - Code to read an ASYLUM Music Format / / \ \
|
||||
* module file, opening and closing it | < / \_
|
||||
* for you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_asy_quick(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_asy_quick(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadasy2.c - Code to read an ASYLUM Music Format / / \ \
|
||||
* module file, opening and closing it | < / \_
|
||||
* for you, and do an initial run- | \/ /\ /
|
||||
* through. \_ / > /
|
||||
* | \ / /
|
||||
* By Chris Moeller. | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_asy(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_asy_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadmod.c - Code to read a good old-fashioned / / \ \
|
||||
* Amiga module file, opening and | < / \_
|
||||
* closing it for you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By entheh. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_mod_quick(const char *filename, int restrict_)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_mod_quick(f, restrict_);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadmod2.c - Function to read a good old- / / \ \
|
||||
* fashioned Amiga module file, | < / \_
|
||||
* opening and closing it for you, | \/ /\ /
|
||||
* and do an initial run-through. \_ / > /
|
||||
* | \ / /
|
||||
* Split off from loadmod.c by entheh. | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_mod(const char *filename, int restrict_)
|
||||
{
|
||||
DUH *duh = dumb_load_mod_quick(filename, restrict_);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadmtm.c - Code to read a MultiTracker Module / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_mtm_quick(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_mtm_quick(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadmtm2.c - Code to read a MultiTracker Module / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you, and do an initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_mtm(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_mtm_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadokt.c - Code to read an Oktalyzer module / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_okt_quick(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_okt_quick(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadokt2.c - Function to read an Oktalyzer / / \ \
|
||||
* module file, opening and closing | < / \_
|
||||
* it for you, and do an initial run- | \/ /\ /
|
||||
* through. \_ / > /
|
||||
* | \ / /
|
||||
* By Chris Moeller. | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_okt(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_okt_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadoldpsm.c - Code to read a ProTracker Studio / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_old_psm_quick(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_old_psm_quick(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadoldpsm2.c - Code to read a ProTracker Studio / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you, and do an initial run- | \/ /\ /
|
||||
* through. \_ / > /
|
||||
* | \ / /
|
||||
* By Chris Moeller. | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_old_psm(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_old_psm_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadpsm.c - Code to read a ProTracker Studio / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_psm_quick(const char *filename, int subsong)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_psm_quick(f, subsong);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadpsm2.c - Code to read a ProTracker Studio / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you, and do an initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_psm(const char *filename, int subsong)
|
||||
{
|
||||
DUH *duh = dumb_load_psm_quick(filename, subsong);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadptm.c - Code to read a Poly Tracker v2.03 / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_ptm_quick(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_ptm_quick(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadptm2.c - Code to read a Poly Tracker v2.03 / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you, and do an initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_ptm(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_ptm_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadriff.c - Code to read a RIFF module file / / \ \
|
||||
* opening and closing it for you. | < / \_
|
||||
* | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_riff_quick( const char *filename )
|
||||
{
|
||||
DUH * duh;
|
||||
DUMBFILE * f = dumbfile_open( filename );
|
||||
|
||||
if ( ! f )
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_riff_quick( f );
|
||||
|
||||
dumbfile_close( f );
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadriff2.c - Code to read a RIFF module file / / \ \
|
||||
* opening and closing it for you, | < / \_
|
||||
* and do an initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_riff(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_riff_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loads3m.c - Code to read a ScreamTracker 3 / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By entheh. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_s3m_quick(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_s3m_quick(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loads3m2.c - Function to read a ScreamTracker 3 / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you, and do an initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* Split off from loads3m.c by entheh. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_s3m(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_s3m_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadstm.c - Code to read a ScreamTracker 2 / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_stm_quick(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_stm_quick(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadstm2.c - Function to read a ScreamTracker 2 / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you, and do an initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_stm(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_stm_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadxm.c - Code to read a Fast Tracker II / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By entheh. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#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 *DUMBEXPORT dumb_load_xm_quick(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_xm_quick(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadxm2.c - Function to read a Fast Tracker II / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you, and do an initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* Split off from loadxm.c by entheh. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_xm(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_xm_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* ptmeffect.c - Code for converting PTM / / \ \
|
||||
* effects to IT effects. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Chris Moeller. Based on xmeffect.c \_ / > /
|
||||
* by Julien Cugniere. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#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;
|
||||
|
||||
/* 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) {
|
||||
|
||||
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;
|
||||
|
||||
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_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_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_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_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;
|
||||
}
|
||||
|
||||
/* Inverse linearisation... */
|
||||
if (effect >= SBASE && effect < SBASE+16) {
|
||||
value = EFFECT_VALUE(effect-SBASE, value);
|
||||
effect = IT_S;
|
||||
}
|
||||
|
||||
entry->effect = effect;
|
||||
entry->effectvalue = value;
|
||||
}
|
|
@ -1,448 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* read669.c - Code to read a 669 Composer module / / \ \
|
||||
* from an open file. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Chris Moeller. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#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;
|
||||
|
||||
pattern->n_rows = 64;
|
||||
|
||||
if (dumbfile_getnc((char *)buffer, 64 * 3 * 8, f) < 64 * 3 * 8)
|
||||
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 */
|
||||
|
||||
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;
|
||||
|
||||
if (breakpoint == 63) breakpoint++;
|
||||
|
||||
entry = pattern->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++) {
|
||||
|
||||
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;
|
||||
|
||||
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:
|
||||
if (entry->effectvalue == 0) {
|
||||
entry->effect = IT_PANNING_SLIDE;
|
||||
entry->effectvalue = 0xFE;
|
||||
} else if (entry->effectvalue == 1) {
|
||||
entry->effect = IT_PANNING_SLIDE;
|
||||
entry->effectvalue = 0xEF;
|
||||
} else {
|
||||
entry->mask &= ~IT_ENTRY_EFFECT;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
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++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int it_669_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
|
||||
{
|
||||
dumbfile_getnc((char *)sample->name, 13, f);
|
||||
sample->name[13] = 0;
|
||||
|
||||
sample->filename[0] = 0;
|
||||
|
||||
sample->length = dumbfile_igetl(f);
|
||||
sample->loop_start = dumbfile_igetl(f);
|
||||
sample->loop_end = dumbfile_igetl(f);
|
||||
|
||||
if (dumbfile_error(f))
|
||||
return -1;
|
||||
|
||||
if (sample->length <= 0) {
|
||||
sample->flags = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sample->flags = IT_SAMPLE_EXISTS;
|
||||
|
||||
sample->global_volume = 64;
|
||||
sample->default_volume = 64;
|
||||
|
||||
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_end = sample->length;
|
||||
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int it_669_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f)
|
||||
{
|
||||
int32 i;
|
||||
int32 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;
|
||||
}
|
||||
|
||||
sample->data = malloc(sample->length);
|
||||
|
||||
if (!sample->data)
|
||||
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;
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
i = dumbfile_igetw(f);
|
||||
if (i != 0x6669 && i != 0x4E4A) return NULL;
|
||||
|
||||
*ext = (i == 0x4E4A);
|
||||
|
||||
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;
|
||||
|
||||
sigdata->order = NULL;
|
||||
sigdata->instrument = NULL;
|
||||
sigdata->pattern = NULL;
|
||||
sigdata->midi = NULL;
|
||||
sigdata->checkpoint = NULL;
|
||||
sigdata->sample = NULL;
|
||||
|
||||
sigdata->n_instruments = 0;
|
||||
|
||||
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;
|
||||
if (dumbfile_getnc((char *)sigdata->song_message + 38, 36, f) < 36) {
|
||||
_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);
|
||||
|
||||
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;
|
||||
}
|
||||
if (dumbfile_getnc((char *)sigdata->order, 128, f) < 128) {
|
||||
_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;
|
||||
|
||||
if (dumbfile_getnc((char *)tempolist, 128, f) < 128) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dumbfile_getnc((char *)breaklist, 128, f) < 128) {
|
||||
_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++) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
return sigdata;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_669_quick(DUMBFILE *f)
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
int ext;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_669_load_sigdata(f, &ext);
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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 *DUMBEXPORT dumb_read_669(DUMBFILE *f)
|
||||
{
|
||||
DUH *duh = dumb_read_669_quick(f);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,788 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readam.c - Code to read a RIFF AM module / / \ \
|
||||
* from a parsed RIFF structure. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Chris Moeller. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
#include "internal/riff.h"
|
||||
|
||||
static int it_riff_am_process_sample( IT_SAMPLE * sample, DUMBFILE * f, int len, int ver )
|
||||
{
|
||||
int header_length;
|
||||
int default_pan;
|
||||
int default_volume;
|
||||
int flags;
|
||||
int length;
|
||||
int length_bytes;
|
||||
int loop_start;
|
||||
int loop_end;
|
||||
int sample_rate;
|
||||
|
||||
int32 start = dumbfile_pos( f );
|
||||
|
||||
if ( ver == 0 )
|
||||
{
|
||||
if ( len < 0x38 )
|
||||
return -1;
|
||||
|
||||
header_length = 0x38;
|
||||
|
||||
dumbfile_getnc( (char *) sample->name, 28, f );
|
||||
sample->name[ 28 ] = 0;
|
||||
|
||||
default_pan = dumbfile_getc( f );
|
||||
default_volume = dumbfile_getc( f );
|
||||
flags = dumbfile_igetw( f );
|
||||
length = dumbfile_igetl( f );
|
||||
loop_start = dumbfile_igetl( f );
|
||||
loop_end = dumbfile_igetl( f );
|
||||
sample_rate = dumbfile_igetl( f );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len < 4) return -1;
|
||||
|
||||
header_length = dumbfile_igetl( f );
|
||||
if ( header_length < 0x40 )
|
||||
return -1;
|
||||
if ( header_length + 4 > len )
|
||||
return -1;
|
||||
|
||||
start += 4;
|
||||
len -= 4;
|
||||
|
||||
dumbfile_getnc( (char *) sample->name, 32, f );
|
||||
|
||||
default_pan = dumbfile_igetw( f );
|
||||
default_volume = dumbfile_igetw( f );
|
||||
flags = dumbfile_igetw( f );
|
||||
dumbfile_skip( f, 2 );
|
||||
length = dumbfile_igetl( f );
|
||||
loop_start = dumbfile_igetl( f );
|
||||
loop_end = dumbfile_igetl( f );
|
||||
sample_rate = dumbfile_igetl( f );
|
||||
|
||||
if ( default_pan > 0x7FFF || default_volume > 0x7FFF )
|
||||
return -1;
|
||||
|
||||
default_pan = default_pan * 64 / 32767;
|
||||
default_volume = default_volume * 64 / 32767;
|
||||
}
|
||||
|
||||
if ( ! length ) {
|
||||
sample->flags &= ~IT_SAMPLE_EXISTS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( flags & ~( 0x8000 | 0x80 | 0x20 | 0x10 | 0x08 | 0x04 ) )
|
||||
return -1;
|
||||
|
||||
length_bytes = length << ( ( flags & 0x04 ) >> 2 );
|
||||
|
||||
if ( length_bytes + header_length > len )
|
||||
return -1;
|
||||
|
||||
sample->flags = 0;
|
||||
|
||||
if ( flags & 0x80 ) sample->flags |= IT_SAMPLE_EXISTS;
|
||||
if ( flags & 0x04 ) sample->flags |= IT_SAMPLE_16BIT;
|
||||
|
||||
sample->length = length;
|
||||
sample->loop_start = loop_start;
|
||||
sample->loop_end = loop_end;
|
||||
sample->C5_speed = sample_rate;
|
||||
sample->default_volume = default_volume;
|
||||
sample->default_pan = default_pan | ( ( flags & 0x20 ) << 2 );
|
||||
sample->filename[0] = 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;
|
||||
|
||||
if ( flags & 0x08 )
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
length_bytes = sample->length << ( ( flags & 0x04 ) >> 2 );
|
||||
|
||||
sample->data = malloc( length_bytes );
|
||||
if ( ! sample->data )
|
||||
return -1;
|
||||
|
||||
if ( dumbfile_seek( f, start + header_length, DFS_SEEK_SET ) )
|
||||
return -1;
|
||||
|
||||
dumbfile_getnc( sample->data, length_bytes, f );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int it_riff_am_process_pattern( IT_PATTERN * pattern, DUMBFILE * f, int len, int ver )
|
||||
{
|
||||
int nrows, row;
|
||||
long start, end;
|
||||
unsigned flags;
|
||||
int p, q, r;
|
||||
IT_ENTRY * entry;
|
||||
|
||||
nrows = dumbfile_getc( f ) + 1;
|
||||
|
||||
pattern->n_rows = nrows;
|
||||
|
||||
len -= 1;
|
||||
|
||||
pattern->n_entries = 0;
|
||||
|
||||
row = 0;
|
||||
|
||||
start = dumbfile_pos( f );
|
||||
end = start + len;
|
||||
|
||||
while ( (row < nrows) && !dumbfile_error( f ) && (dumbfile_pos( f ) < end) ) {
|
||||
p = dumbfile_getc( f );
|
||||
if ( ! p ) {
|
||||
++ row;
|
||||
continue;
|
||||
}
|
||||
|
||||
flags = p & 0xE0;
|
||||
|
||||
if (flags) {
|
||||
++ pattern->n_entries;
|
||||
if (flags & 0x80) dumbfile_skip( f, 2 );
|
||||
if (flags & 0x40) dumbfile_skip( f, 2 );
|
||||
if (flags & 0x20) dumbfile_skip( f, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! pattern->n_entries ) return 0;
|
||||
|
||||
pattern->n_entries += nrows;
|
||||
|
||||
pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) );
|
||||
if ( ! pattern->entry ) return -1;
|
||||
|
||||
entry = pattern->entry;
|
||||
|
||||
row = 0;
|
||||
|
||||
dumbfile_seek( f, start, DFS_SEEK_SET );
|
||||
|
||||
while ( ( row < nrows ) && !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 & 0x1F;
|
||||
entry->mask = 0;
|
||||
|
||||
if (flags & 0xE0)
|
||||
{
|
||||
if ( flags & 0x80 )
|
||||
{
|
||||
q = dumbfile_getc( f );
|
||||
r = dumbfile_getc( f );
|
||||
_dumb_it_xm_convert_effect( r, q, entry, 0 );
|
||||
}
|
||||
|
||||
if ( flags & 0x40 )
|
||||
{
|
||||
q = dumbfile_getc( f );
|
||||
r = dumbfile_getc( f );
|
||||
if ( q )
|
||||
{
|
||||
entry->mask |= IT_ENTRY_INSTRUMENT;
|
||||
entry->instrument = q;
|
||||
}
|
||||
if ( r )
|
||||
{
|
||||
entry->mask |= IT_ENTRY_NOTE;
|
||||
entry->note = r - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( flags & 0x20 )
|
||||
{
|
||||
q = dumbfile_getc( f );
|
||||
entry->mask |= IT_ENTRY_VOLPAN;
|
||||
if ( ver == 0 ) entry->volpan = q;
|
||||
else entry->volpan = q * 64 / 127;
|
||||
}
|
||||
|
||||
if (entry->mask) entry++;
|
||||
}
|
||||
}
|
||||
|
||||
while ( row < nrows )
|
||||
{
|
||||
IT_SET_END_ROW( entry );
|
||||
++ entry;
|
||||
++ row;
|
||||
}
|
||||
|
||||
pattern->n_entries = (int)(entry - pattern->entry);
|
||||
if ( ! pattern->n_entries ) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( DUMBFILE * f, struct riff * stream )
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
|
||||
int n, o, p, found;
|
||||
|
||||
if ( ! stream ) goto error;
|
||||
|
||||
if ( stream->type != DUMB_ID( 'A', 'M', 'F', 'F' ) ) goto error;
|
||||
|
||||
sigdata = malloc( sizeof( *sigdata ) );
|
||||
if ( ! sigdata ) goto error;
|
||||
|
||||
sigdata->n_patterns = 0;
|
||||
sigdata->n_samples = 0;
|
||||
sigdata->name[0] = 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( 'M', 'A', 'I', 'N' ):
|
||||
/* initialization data */
|
||||
if ( ( found & 1 ) || ( c->size < 0x48 ) ) goto error_sd;
|
||||
found |= 1;
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'O', 'R', 'D', 'R' ):
|
||||
if ( ( found & 2 ) || ( c->size < 1 ) ) goto error_sd;
|
||||
found |= 2;
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'P', 'A', 'T', 'T' ):
|
||||
if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_sd;
|
||||
o = dumbfile_getc( f );
|
||||
if ( o >= sigdata->n_patterns ) sigdata->n_patterns = o + 1;
|
||||
o = dumbfile_igetl( f );
|
||||
if ( (unsigned)o + 5 > c->size ) goto error_sd;
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'I', 'N', 'S', 'T' ):
|
||||
{
|
||||
if ( c->size < 0xE1 ) goto error_sd;
|
||||
if ( dumbfile_seek( f, c->offset + 1, DFS_SEEK_SET ) ) goto error_sd;
|
||||
o = dumbfile_getc( f );
|
||||
if ( o >= sigdata->n_samples ) sigdata->n_samples = o + 1;
|
||||
if ( c->size >= 0x121 )
|
||||
{
|
||||
if ( dumbfile_seek( f, c->offset + 0xE1, DFS_SEEK_SET ) ) goto error_sd;
|
||||
if ( dumbfile_mgetl( f ) == DUMB_ID('S','A','M','P') )
|
||||
{
|
||||
unsigned size = dumbfile_igetl( f );
|
||||
if ( size + 0xE1 + 8 > c->size ) goto error_sd;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( found != 3 || !sigdata->n_samples || !sigdata->n_patterns ) 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->mixing_volume = 48;
|
||||
sigdata->pan_separation = 128;
|
||||
|
||||
sigdata->n_instruments = 0;
|
||||
sigdata->n_orders = 0;
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
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; (unsigned)n < stream->chunk_count; ++n )
|
||||
{
|
||||
struct riff_chunk * c = stream->chunks + n;
|
||||
switch ( c->type )
|
||||
{
|
||||
case DUMB_ID( 'M', 'A', 'I', 'N' ):
|
||||
if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd;
|
||||
dumbfile_getnc( (char *) sigdata->name, 64, f );
|
||||
sigdata->name[ 64 ] = 0;
|
||||
sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
|
||||
o = dumbfile_getc( f );
|
||||
if ( ! ( o & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES;
|
||||
if ( ( o & ~3 ) || ! ( o & 2 ) ) goto error_usd; // unknown flags
|
||||
sigdata->n_pchannels = dumbfile_getc( f );
|
||||
sigdata->speed = dumbfile_getc( f );
|
||||
sigdata->tempo = dumbfile_getc( f );
|
||||
|
||||
dumbfile_skip( f, 4 );
|
||||
|
||||
sigdata->global_volume = dumbfile_getc( f );
|
||||
|
||||
if ( c->size < 0x48 + (unsigned)sigdata->n_pchannels ) goto error_usd;
|
||||
|
||||
for ( o = 0; o < sigdata->n_pchannels; ++o )
|
||||
{
|
||||
p = dumbfile_getc( f );
|
||||
sigdata->channel_pan[ o ] = p;
|
||||
if ( p >= 128 )
|
||||
{
|
||||
sigdata->channel_volume[ o ] = 0;
|
||||
}
|
||||
}
|
||||
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->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;
|
||||
sample->flags = 0;
|
||||
sample->name[ 0 ] = 0;
|
||||
}
|
||||
|
||||
for ( n = 0; (unsigned)n < stream->chunk_count; ++n )
|
||||
{
|
||||
struct riff_chunk * c = stream->chunks + n;
|
||||
switch ( c->type )
|
||||
{
|
||||
case DUMB_ID( 'O', 'R', 'D', 'R' ):
|
||||
if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd;
|
||||
sigdata->n_orders = dumbfile_getc( f ) + 1;
|
||||
if ( (unsigned)sigdata->n_orders + 1 > c->size ) goto error_usd;
|
||||
sigdata->order = malloc( sigdata->n_orders );
|
||||
if ( ! sigdata->order ) goto error_usd;
|
||||
dumbfile_getnc( (char *) sigdata->order, sigdata->n_orders, f );
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'P', 'A', 'T', 'T' ):
|
||||
if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd;
|
||||
o = dumbfile_getc( f );
|
||||
p = dumbfile_igetl( f );
|
||||
if ( it_riff_am_process_pattern( sigdata->pattern + o, f, p, 0 ) ) goto error_usd;
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'I', 'N', 'S', 'T' ):
|
||||
{
|
||||
IT_SAMPLE * sample;
|
||||
if ( dumbfile_seek( f, c->offset + 1, DFS_SEEK_SET ) ) goto error_usd;
|
||||
sample = sigdata->sample + dumbfile_getc( f );
|
||||
if ( c->size >= 0x121 )
|
||||
{
|
||||
if ( dumbfile_seek( f, c->offset + 0xE1, DFS_SEEK_SET ) ) goto error_usd;
|
||||
if ( dumbfile_mgetl( f ) == DUMB_ID('S','A','M','P') )
|
||||
{
|
||||
unsigned size = dumbfile_igetl( f );
|
||||
if ( it_riff_am_process_sample( sample, f, size, 0 ) ) goto error_usd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dumbfile_seek( f, c->offset + 2, DFS_SEEK_SET );
|
||||
dumbfile_getnc( (char *) sample->name, 28, f );
|
||||
sample->name[ 28 ] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_dumb_it_fix_invalid_orders( sigdata );
|
||||
|
||||
return sigdata;
|
||||
|
||||
error_usd:
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
goto error;
|
||||
error_sd:
|
||||
free( sigdata );
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( DUMBFILE * f, struct riff * stream )
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
|
||||
int n, o, p, found;
|
||||
|
||||
if ( ! f || ! stream ) goto error;
|
||||
|
||||
if ( stream->type != DUMB_ID( 'A', 'M', ' ', ' ' ) ) goto error;
|
||||
|
||||
sigdata = malloc(sizeof(*sigdata));
|
||||
if ( ! sigdata ) goto error;
|
||||
|
||||
sigdata->n_patterns = 0;
|
||||
sigdata->n_samples = 0;
|
||||
sigdata->name[0] = 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( 'I' ,'N' ,'I' ,'T' ):
|
||||
/* initialization data */
|
||||
if ( ( found & 1 ) || ( c->size < 0x48 ) ) goto error_sd;
|
||||
found |= 1;
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'O', 'R', 'D', 'R' ):
|
||||
if ( ( found & 2 ) || ( c->size < 1 ) ) goto error_sd;
|
||||
found |= 2;
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'P', 'A', 'T', 'T' ):
|
||||
if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_sd;
|
||||
o = dumbfile_getc( f );
|
||||
if ( o >= sigdata->n_patterns ) sigdata->n_patterns = o + 1;
|
||||
o = dumbfile_igetl( f );
|
||||
if ( (unsigned)o + 5 > c->size ) goto error_sd;
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'R', 'I', 'F', 'F' ):
|
||||
{
|
||||
struct riff * str = c->nested;
|
||||
switch ( str->type )
|
||||
{
|
||||
case DUMB_ID( 'A', 'I', ' ', ' ' ):
|
||||
for ( o = 0; (unsigned)o < str->chunk_count; ++o )
|
||||
{
|
||||
struct riff_chunk * chk = str->chunks + o;
|
||||
switch( chk->type )
|
||||
{
|
||||
case DUMB_ID( 'I', 'N', 'S', 'T' ):
|
||||
{
|
||||
struct riff * temp;
|
||||
unsigned size;
|
||||
unsigned sample_found;
|
||||
if ( dumbfile_seek( f, chk->offset, DFS_SEEK_SET ) ) goto error_sd;
|
||||
size = dumbfile_igetl( f );
|
||||
if ( size < 0x142 ) goto error_sd;
|
||||
sample_found = 0;
|
||||
dumbfile_skip( f, 1 );
|
||||
p = dumbfile_getc( f );
|
||||
if ( p >= sigdata->n_samples ) sigdata->n_samples = p + 1;
|
||||
temp = riff_parse( f, chk->offset + 4 + size, chk->size - size - 4, 1 );
|
||||
if ( temp )
|
||||
{
|
||||
if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) )
|
||||
{
|
||||
for ( p = 0; (unsigned)p < temp->chunk_count; ++p )
|
||||
{
|
||||
if ( temp->chunks[ p ].type == DUMB_ID( 'S', 'A', 'M', 'P' ) )
|
||||
{
|
||||
if ( sample_found )
|
||||
{
|
||||
riff_free( temp );
|
||||
goto error_sd;
|
||||
}
|
||||
sample_found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
riff_free( temp );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( found != 3 || !sigdata->n_samples || !sigdata->n_patterns ) 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->mixing_volume = 48;
|
||||
sigdata->pan_separation = 128;
|
||||
|
||||
sigdata->n_instruments = 0;
|
||||
sigdata->n_orders = 0;
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
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; (unsigned)n < stream->chunk_count; ++n )
|
||||
{
|
||||
struct riff_chunk * c = stream->chunks + n;
|
||||
switch ( c->type )
|
||||
{
|
||||
case DUMB_ID( 'I', 'N', 'I', 'T' ):
|
||||
if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd;
|
||||
dumbfile_getnc( (char *) sigdata->name, 64, f );
|
||||
sigdata->name[ 64 ] = 0;
|
||||
sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
|
||||
o = dumbfile_getc( f );
|
||||
if ( ! ( o & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES;
|
||||
if ( ( o & ~3 ) || ! ( o & 2 ) ) goto error_usd; // unknown flags
|
||||
sigdata->n_pchannels = dumbfile_getc( f );
|
||||
sigdata->speed = dumbfile_getc( f );
|
||||
sigdata->tempo = dumbfile_getc( f );
|
||||
|
||||
dumbfile_skip( f, 4 );
|
||||
|
||||
sigdata->global_volume = dumbfile_getc( f );
|
||||
|
||||
if ( c->size < 0x48 + (unsigned)sigdata->n_pchannels ) goto error_usd;
|
||||
|
||||
for ( o = 0; o < sigdata->n_pchannels; ++o )
|
||||
{
|
||||
p = dumbfile_getc( f );
|
||||
if ( p <= 128 )
|
||||
{
|
||||
sigdata->channel_pan[ o ] = p / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
sigdata->channel_volume[ o ] = 0;
|
||||
}
|
||||
}
|
||||
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->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;
|
||||
sample->flags = 0;
|
||||
sample->name[ 0 ] = 0;
|
||||
}
|
||||
|
||||
for ( n = 0; (unsigned)n < stream->chunk_count; ++n )
|
||||
{
|
||||
struct riff_chunk * c = stream->chunks + n;
|
||||
switch ( c->type )
|
||||
{
|
||||
case DUMB_ID( 'O', 'R', 'D', 'R' ):
|
||||
if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd;
|
||||
sigdata->n_orders = dumbfile_getc( f ) + 1;
|
||||
if ( (unsigned)sigdata->n_orders + 1 > c->size ) goto error_usd;
|
||||
sigdata->order = malloc( sigdata->n_orders );
|
||||
if ( ! sigdata->order ) goto error_usd;
|
||||
dumbfile_getnc( (char *) sigdata->order, sigdata->n_orders, f );
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'P', 'A', 'T', 'T' ):
|
||||
if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd;
|
||||
o = dumbfile_getc( f );
|
||||
p = dumbfile_igetl( f );
|
||||
if ( it_riff_am_process_pattern( sigdata->pattern + o, f, p, 1 ) ) goto error_usd;
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'R', 'I', 'F', 'F' ):
|
||||
{
|
||||
struct riff * str = c->nested;
|
||||
switch ( str->type )
|
||||
{
|
||||
case DUMB_ID('A', 'I', ' ', ' '):
|
||||
for ( o = 0; (unsigned)o < str->chunk_count; ++o )
|
||||
{
|
||||
struct riff_chunk * chk = str->chunks + o;
|
||||
switch( chk->type )
|
||||
{
|
||||
case DUMB_ID( 'I', 'N', 'S', 'T' ):
|
||||
{
|
||||
struct riff * temp;
|
||||
unsigned size;
|
||||
unsigned sample_found;
|
||||
IT_SAMPLE * sample;
|
||||
if ( dumbfile_seek( f, chk->offset, DFS_SEEK_SET ) ) goto error_usd;
|
||||
size = dumbfile_igetl( f );
|
||||
dumbfile_skip( f, 1 );
|
||||
p = dumbfile_getc( f );
|
||||
temp = riff_parse( f, chk->offset + 4 + size, chk->size - size - 4, 1 );
|
||||
sample_found = 0;
|
||||
sample = sigdata->sample + p;
|
||||
if ( temp )
|
||||
{
|
||||
if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) )
|
||||
{
|
||||
for ( p = 0; (unsigned)p < temp->chunk_count; ++p )
|
||||
{
|
||||
struct riff_chunk * c = temp->chunks + p;
|
||||
if ( c->type == DUMB_ID( 'S', 'A', 'M', 'P' ) )
|
||||
{
|
||||
if ( sample_found )
|
||||
{
|
||||
riff_free( temp );
|
||||
goto error_usd;
|
||||
}
|
||||
{
|
||||
riff_free( temp );
|
||||
goto error_usd;
|
||||
}
|
||||
if ( it_riff_am_process_sample( sample, f, c->size, 1 ) )
|
||||
{
|
||||
riff_free( temp );
|
||||
goto error_usd;
|
||||
}
|
||||
sample_found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
riff_free( temp );
|
||||
}
|
||||
if ( ! sample_found )
|
||||
{
|
||||
dumbfile_seek( f, chk->offset + 6, DFS_SEEK_SET );
|
||||
dumbfile_getnc( (char *) sample->name, 32, f );
|
||||
sample->name[ 32 ] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_dumb_it_fix_invalid_orders( sigdata );
|
||||
|
||||
return sigdata;
|
||||
|
||||
error_usd:
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
goto error;
|
||||
error_sd:
|
||||
free( sigdata );
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DUH *dumb_read_riff_amff( DUMBFILE * f, struct riff * stream )
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
long length;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_riff_amff_load_sigdata( f, stream );
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
|
||||
|
||||
{
|
||||
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 AMFF";
|
||||
return make_duh( length, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
|
||||
}
|
||||
}
|
||||
|
||||
DUH *dumb_read_riff_am( DUMBFILE * f, struct riff * stream )
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_riff_am_load_sigdata( f, stream );
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
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 AM";
|
||||
return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
|
||||
}
|
||||
}
|
|
@ -1,559 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readamf.c - Code to read a DSMI AMF module from / / \ \
|
||||
* an open file. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Chris Moeller. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
||||
|
||||
|
||||
static void it_amf_process_track( IT_ENTRY *entry_table, unsigned char *track, int rows, int channels )
|
||||
{
|
||||
int last_instrument = 0;
|
||||
int tracksize = track[ 0 ] + ( track[ 1 ] << 8 ) + ( track[ 2 ] << 16 );
|
||||
track += 3;
|
||||
while ( tracksize-- ) {
|
||||
unsigned int row = track[ 0 ];
|
||||
unsigned int command = track[ 1 ];
|
||||
unsigned int argument = track[ 2 ];
|
||||
IT_ENTRY * entry = entry_table + row * channels;
|
||||
if ( row >= ( unsigned int ) rows ) break;
|
||||
if ( command < 0x7F ) {
|
||||
entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT | IT_ENTRY_VOLPAN;
|
||||
entry->note = command;
|
||||
if ( ! entry->instrument ) entry->instrument = last_instrument;
|
||||
entry->volpan = argument;
|
||||
}
|
||||
else if ( command == 0x7F ) {
|
||||
signed char row_delta = ( signed char ) argument;
|
||||
int row_source = ( int ) row + ( int ) row_delta;
|
||||
if ( row_source >= 0 && row_source < ( int ) rows ) {
|
||||
*entry = entry_table[ row_source * channels ];
|
||||
}
|
||||
}
|
||||
else if ( command == 0x80 ) {
|
||||
entry->mask |= IT_ENTRY_INSTRUMENT;
|
||||
last_instrument = argument + 1;
|
||||
entry->instrument = last_instrument;
|
||||
}
|
||||
else if ( command == 0x83 ) {
|
||||
entry->mask |= IT_ENTRY_VOLPAN;
|
||||
entry->volpan = argument;
|
||||
}
|
||||
else {
|
||||
unsigned int effect = command & 0x7F;
|
||||
unsigned int effectvalue = argument;
|
||||
switch (effect) {
|
||||
case 0x01: effect = IT_SET_SPEED; break;
|
||||
|
||||
case 0x02: effect = IT_VOLUME_SLIDE;
|
||||
case 0x0A: if ( effect == 0x0A ) effect = IT_VOLSLIDE_TONEPORTA;
|
||||
case 0x0B: if ( effect == 0x0B ) effect = IT_VOLSLIDE_VIBRATO;
|
||||
if ( effectvalue & 0x80 ) effectvalue = ( -( signed char ) effectvalue ) & 0x0F;
|
||||
else effectvalue = ( effectvalue & 0x0F ) << 4;
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
if ( effectvalue & 0x80 ) {
|
||||
effect = IT_PORTAMENTO_UP;
|
||||
effectvalue = ( -( signed char ) effectvalue ) & 0x7F;
|
||||
}
|
||||
else {
|
||||
effect = IT_PORTAMENTO_DOWN;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x06: effect = IT_TONE_PORTAMENTO; break;
|
||||
|
||||
case 0x07: effect = IT_TREMOR; break;
|
||||
|
||||
case 0x08: effect = IT_ARPEGGIO; break;
|
||||
|
||||
case 0x09: effect = IT_VIBRATO; break;
|
||||
|
||||
case 0x0C: effect = IT_BREAK_TO_ROW; break;
|
||||
|
||||
case 0x0D: effect = IT_JUMP_TO_ORDER; break;
|
||||
|
||||
case 0x0F: effect = IT_RETRIGGER_NOTE; break;
|
||||
|
||||
case 0x10: effect = IT_SET_SAMPLE_OFFSET; break;
|
||||
|
||||
case 0x11:
|
||||
if ( effectvalue ) {
|
||||
effect = IT_VOLUME_SLIDE;
|
||||
if ( effectvalue & 0x80 )
|
||||
effectvalue = 0xF0 | ( ( -( signed char ) effectvalue ) & 0x0F );
|
||||
else
|
||||
effectvalue = 0x0F | ( ( effectvalue & 0x0F ) << 4 );
|
||||
}
|
||||
else
|
||||
effect = 0;
|
||||
break;
|
||||
|
||||
case 0x12:
|
||||
case 0x16:
|
||||
if ( effectvalue ) {
|
||||
int mask = ( effect == 0x16 ) ? 0xE0 : 0xF0;
|
||||
effect = ( effectvalue & 0x80 ) ? IT_PORTAMENTO_UP : IT_PORTAMENTO_DOWN;
|
||||
if ( effectvalue & 0x80 )
|
||||
effectvalue = mask | ( ( -( signed char ) effectvalue ) & 0x0F );
|
||||
else
|
||||
effectvalue = mask | ( effectvalue & 0x0F );
|
||||
}
|
||||
else
|
||||
effect = 0;
|
||||
break;
|
||||
|
||||
case 0x13:
|
||||
effect = IT_S;
|
||||
effectvalue = EFFECT_VALUE( IT_S_NOTE_DELAY, effectvalue & 0x0F );
|
||||
break;
|
||||
|
||||
case 0x14:
|
||||
effect = IT_S;
|
||||
effectvalue = EFFECT_VALUE( IT_S_DELAYED_NOTE_CUT, effectvalue & 0x0F );
|
||||
break;
|
||||
|
||||
case 0x15: effect = IT_SET_SONG_TEMPO; break;
|
||||
|
||||
case 0x17:
|
||||
effectvalue = ( effectvalue + 64 ) & 0x7F;
|
||||
if ( entry->mask & IT_ENTRY_EFFECT ) {
|
||||
if ( !( entry->mask & IT_ENTRY_VOLPAN ) ) {
|
||||
entry->mask |= IT_ENTRY_VOLPAN;
|
||||
entry->volpan = ( effectvalue / 2 ) + 128;
|
||||
}
|
||||
effect = 0;
|
||||
}
|
||||
else {
|
||||
effect = IT_SET_PANNING;
|
||||
}
|
||||
break;
|
||||
|
||||
default: effect = effectvalue = 0;
|
||||
}
|
||||
if ( effect ) {
|
||||
entry->mask |= IT_ENTRY_EFFECT;
|
||||
entry->effect = effect;
|
||||
entry->effectvalue = effectvalue;
|
||||
}
|
||||
}
|
||||
track += 3;
|
||||
}
|
||||
}
|
||||
|
||||
static int it_amf_process_pattern( IT_PATTERN *pattern, IT_ENTRY *entry_table, int rows, int channels )
|
||||
{
|
||||
int i, j;
|
||||
int n_entries = rows;
|
||||
IT_ENTRY * entry;
|
||||
|
||||
pattern->n_rows = rows;
|
||||
|
||||
for ( i = 0, j = channels * rows; i < j; i++ ) {
|
||||
if ( entry_table[ i ].mask ) {
|
||||
n_entries++;
|
||||
}
|
||||
}
|
||||
|
||||
pattern->n_entries = n_entries;
|
||||
|
||||
pattern->entry = entry = malloc( n_entries * sizeof( IT_ENTRY ) );
|
||||
if ( !entry ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for ( i = 0; i < rows; i++ ) {
|
||||
for ( j = 0; j < channels; j++ ) {
|
||||
if ( entry_table[ i * channels + j ].mask ) {
|
||||
*entry = entry_table[ i * channels + j ];
|
||||
entry->channel = j;
|
||||
entry++;
|
||||
}
|
||||
}
|
||||
IT_SET_END_ROW( entry );
|
||||
entry++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int it_amf_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f, int * offset, int ver )
|
||||
{
|
||||
int exists;
|
||||
|
||||
exists = dumbfile_getc( f );
|
||||
|
||||
dumbfile_getnc( (char *) sample->name, 32, f );
|
||||
sample->name[32] = 0;
|
||||
|
||||
dumbfile_getnc( (char *) sample->filename, 13, f );
|
||||
sample->filename[13] = 0;
|
||||
|
||||
*offset = dumbfile_igetl( f );
|
||||
sample->length = dumbfile_igetl( f );
|
||||
sample->C5_speed = dumbfile_igetw( f );
|
||||
sample->default_volume = dumbfile_getc( f );
|
||||
sample->global_volume = 64;
|
||||
if ( sample->default_volume > 64 ) sample->default_volume = 64;
|
||||
|
||||
if ( ver >= 11 ) {
|
||||
sample->loop_start = dumbfile_igetl( f );
|
||||
sample->loop_end = dumbfile_igetl( f );
|
||||
} else {
|
||||
sample->loop_start = dumbfile_igetw( f );
|
||||
sample->loop_end = sample->length;
|
||||
}
|
||||
|
||||
if ( sample->length <= 0 ) {
|
||||
sample->flags = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sample->flags = exists == 1 ? IT_SAMPLE_EXISTS : 0;
|
||||
|
||||
sample->default_pan = 0;
|
||||
sample->finetune = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int it_amf_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f )
|
||||
{
|
||||
int i, read_length = 0;
|
||||
|
||||
sample->data = malloc( sample->length );
|
||||
|
||||
if ( !sample->data )
|
||||
return -1;
|
||||
|
||||
if ( sample->length )
|
||||
read_length = dumbfile_getnc( sample->data, sample->length, f );
|
||||
|
||||
for ( i = 0; i < read_length; i++ ) {
|
||||
( ( char * ) sample->data )[ i ] ^= 0x80;
|
||||
}
|
||||
|
||||
for ( i = read_length; i < sample->length; i++ ) {
|
||||
( ( char * ) sample->data )[ i ] = 0;
|
||||
}
|
||||
|
||||
return 0; /* Sometimes the last sample is truncated :( */
|
||||
}
|
||||
|
||||
static DUMB_IT_SIGDATA *it_amf_load_sigdata(DUMBFILE *f, int * version)
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
int i, j, ver, ntracks, realntracks, nchannels;
|
||||
|
||||
int maxsampleseekpos = 0;
|
||||
int sampleseekpos[256];
|
||||
|
||||
unsigned short *orderstotracks;
|
||||
unsigned short *trackmap;
|
||||
unsigned int tracksize[256];
|
||||
|
||||
unsigned char **track;
|
||||
|
||||
static const char sig[] = "AMF";
|
||||
|
||||
char signature [3];
|
||||
|
||||
if ( dumbfile_getnc( signature, 3, f ) != 3 ||
|
||||
memcmp( signature, sig, 3 ) ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*version = ver = dumbfile_getc( f );
|
||||
if ( ver < 10 || ver > 14) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata = malloc(sizeof(*sigdata));
|
||||
if (!sigdata) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dumbfile_getnc( (char *) sigdata->name, 32, f );
|
||||
sigdata->name[ 32 ] = 0;
|
||||
sigdata->n_samples = dumbfile_getc( f );
|
||||
sigdata->n_orders = dumbfile_getc( f );
|
||||
ntracks = dumbfile_igetw( f );
|
||||
nchannels = dumbfile_getc( f );
|
||||
|
||||
if ( dumbfile_error( f ) ||
|
||||
sigdata->n_samples < 1 || sigdata->n_samples > 255 ||
|
||||
sigdata->n_orders < 1 || sigdata->n_orders > 255 ||
|
||||
! ntracks ||
|
||||
nchannels < 1 || nchannels > 32 ) {
|
||||
free( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->n_pchannels = nchannels;
|
||||
|
||||
memset( sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS );
|
||||
|
||||
if ( ver >= 11 ) {
|
||||
int nchannels = ( ver >= 13 ) ? 32 : 16;
|
||||
for ( i = 0; i < nchannels; i++ ) {
|
||||
signed char panpos = dumbfile_getc( f );
|
||||
int pan = ( panpos + 64 ) / 2;
|
||||
if ( pan < 0 ) pan = 0;
|
||||
else if ( pan > 64 ) pan = IT_SURROUND;
|
||||
sigdata->channel_pan[ i ] = pan;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int sep = 32 * dumb_it_default_panning_separation / 100;
|
||||
for ( i = 0; i < 16; i++ ) {
|
||||
sigdata->channel_pan[ i ] = ( dumbfile_getc( f ) & 1 ) ? 32 - sep : 32 + sep;
|
||||
}
|
||||
}
|
||||
|
||||
sigdata->tempo = 125;
|
||||
sigdata->speed = 6;
|
||||
if ( ver >= 13 ) {
|
||||
i = dumbfile_getc( f );
|
||||
if ( i >= 32 ) sigdata->tempo = i;
|
||||
i = dumbfile_getc( f );
|
||||
if ( i <= 32 ) sigdata->speed = i;
|
||||
}
|
||||
|
||||
sigdata->order = malloc( sigdata->n_orders );
|
||||
if ( !sigdata->order ) {
|
||||
free( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
orderstotracks = malloc( sigdata->n_orders * nchannels * sizeof( unsigned short ) );
|
||||
if ( !orderstotracks ) {
|
||||
free( sigdata->order );
|
||||
free( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( i = 0; i < sigdata->n_orders; i++ ) {
|
||||
sigdata->order[ i ] = i;
|
||||
tracksize[ i ] = 64;
|
||||
if ( ver >= 14 ) {
|
||||
tracksize[ i ] = dumbfile_igetw( f );
|
||||
}
|
||||
for ( j = 0; j < nchannels; j++ ) {
|
||||
orderstotracks[ i * nchannels + j ] = dumbfile_igetw( f );
|
||||
}
|
||||
}
|
||||
|
||||
if ( dumbfile_error( f ) ) {
|
||||
free( orderstotracks );
|
||||
free( sigdata->order );
|
||||
free( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
|
||||
if ( !sigdata->sample ) {
|
||||
free( orderstotracks );
|
||||
free( sigdata->order );
|
||||
free( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
sigdata->song_message = NULL;
|
||||
sigdata->instrument = NULL;
|
||||
sigdata->pattern = NULL;
|
||||
sigdata->midi = NULL;
|
||||
sigdata->checkpoint = NULL;
|
||||
|
||||
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 ) {
|
||||
int offset;
|
||||
if ( it_amf_read_sample_header( &sigdata->sample[i], f, &offset, ver ) ) {
|
||||
goto error_ott;
|
||||
}
|
||||
sampleseekpos[ i ] = offset;
|
||||
if ( offset > maxsampleseekpos ) maxsampleseekpos = offset;
|
||||
}
|
||||
|
||||
sigdata->n_patterns = sigdata->n_orders;
|
||||
|
||||
sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
|
||||
if ( !sigdata->pattern ) {
|
||||
goto error_ott;
|
||||
}
|
||||
for (i = 0; i < sigdata->n_patterns; ++i)
|
||||
sigdata->pattern[i].entry = NULL;
|
||||
|
||||
trackmap = malloc( ntracks * sizeof( unsigned short ) );
|
||||
if ( !trackmap ) {
|
||||
goto error_ott;
|
||||
}
|
||||
|
||||
if ( dumbfile_getnc( ( char * ) trackmap, ntracks * sizeof( unsigned short ), f ) != (long)(ntracks * sizeof( unsigned short )) ) {
|
||||
goto error_tm;
|
||||
}
|
||||
|
||||
realntracks = 0;
|
||||
|
||||
for ( i = 0; i < ntracks; i++ ) {
|
||||
if ( trackmap[ i ] > realntracks ) realntracks = trackmap[ i ];
|
||||
}
|
||||
|
||||
track = calloc( realntracks, sizeof( unsigned char * ) );
|
||||
if ( !track ) {
|
||||
goto error_tm;
|
||||
}
|
||||
|
||||
for ( i = 0; i < realntracks; i++ ) {
|
||||
int tracksize = dumbfile_igetw( f );
|
||||
tracksize += dumbfile_getc( f ) << 16;
|
||||
track[ i ] = malloc( tracksize * 3 + 3 );
|
||||
if ( !track[ i ] ) {
|
||||
goto error_all;
|
||||
}
|
||||
track[ i ][ 0 ] = tracksize & 255;
|
||||
track[ i ][ 1 ] = ( tracksize >> 8 ) & 255;
|
||||
track[ i ][ 2 ] = ( tracksize >> 16 ) & 255;
|
||||
if ( dumbfile_getnc( (char *) track[ i ] + 3, tracksize * 3, f ) != tracksize * 3 ) {
|
||||
goto error_all;
|
||||
}
|
||||
}
|
||||
|
||||
for ( i = 1; i <= maxsampleseekpos; i++ ) {
|
||||
for ( j = 0; j < sigdata->n_samples; j++ ) {
|
||||
if ( sampleseekpos[ j ] == i ) {
|
||||
if ( it_amf_read_sample_data( &sigdata->sample[ j ], f ) ) {
|
||||
goto error_all;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Process tracks into patterns */
|
||||
for ( i = 0; i < sigdata->n_patterns; i++ ) {
|
||||
IT_ENTRY * entry_table = calloc( tracksize[ i ] * nchannels, sizeof( IT_ENTRY ) );
|
||||
if ( !entry_table ) {
|
||||
goto error_all;
|
||||
}
|
||||
for ( j = 0; j < nchannels; j++ ) {
|
||||
int ntrack = orderstotracks[ i * nchannels + j ];
|
||||
if ( ntrack && ntrack <= ntracks ) {
|
||||
int realtrack = trackmap[ ntrack - 1 ];
|
||||
if ( realtrack ) {
|
||||
realtrack--;
|
||||
if ( realtrack < realntracks && track[ realtrack ] ) {
|
||||
it_amf_process_track( entry_table + j, track[ realtrack ], tracksize[ i ], nchannels );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( it_amf_process_pattern( &sigdata->pattern[ i ], entry_table, tracksize[ i ], nchannels ) ) {
|
||||
free( entry_table );
|
||||
goto error_all;
|
||||
}
|
||||
free( entry_table );
|
||||
}
|
||||
|
||||
/* Now let's initialise the remaining variables, and we're done! */
|
||||
sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO | IT_WAS_AN_S3M;
|
||||
|
||||
sigdata->global_volume = 128;
|
||||
sigdata->mixing_volume = 48;
|
||||
sigdata->pan_separation = 128;
|
||||
|
||||
_dumb_it_fix_invalid_orders(sigdata);
|
||||
|
||||
for ( i = 0; i < realntracks; i++ ) {
|
||||
if ( track[ i ] ) {
|
||||
free( track[ i ] );
|
||||
}
|
||||
}
|
||||
free( track );
|
||||
free( trackmap );
|
||||
free( orderstotracks );
|
||||
|
||||
return sigdata;
|
||||
|
||||
error_all:
|
||||
for ( i = 0; i < realntracks; i++ ) {
|
||||
if ( track[ i ] ) {
|
||||
free( track[ i ] );
|
||||
}
|
||||
}
|
||||
free( track );
|
||||
error_tm:
|
||||
free( trackmap );
|
||||
error_ott:
|
||||
free( orderstotracks );
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_amf_quick(DUMBFILE *f)
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
int version;
|
||||
|
||||
sigdata = it_amf_load_sigdata(f, &version);
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
const char *tag[2][2];
|
||||
char ver_string[14];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
|
||||
tag[1][0] = "FORMAT";
|
||||
memcpy( ver_string, "DSMI AMF v", 10 );
|
||||
ver_string[10] = '0' + version / 10;
|
||||
ver_string[11] = '.';
|
||||
ver_string[12] = '0' + version % 10;
|
||||
ver_string[13] = 0;
|
||||
tag[1][1] = ver_string;
|
||||
return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readamf2.c - Function to read a DSMI AMF module / / \ \
|
||||
* from an open file and do an initial | < / \_
|
||||
* run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_amf(DUMBFILE *f)
|
||||
{
|
||||
DUH *duh = dumb_read_amf_quick(f);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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 *DUMBEXPORT 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;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readany2.c - Code to detect and read any of the / / \ \
|
||||
* module formats supported by DUMB | < / \_
|
||||
* from an open file and do an initial | \/ /\ /
|
||||
* run-through. \_ / > /
|
||||
* | \ / /
|
||||
* by Chris Moeller. | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT 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;
|
||||
}
|
|
@ -1,339 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readasy.c - Code to read an ASYLUM Music Format / / \ \
|
||||
* module from an open file. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Chris Moeller. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#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;
|
||||
|
||||
if ( dumbfile_getnc( (char *) buffer, 64 * 8 * 4, f ) != 64 * 8 * 4 )
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 ( 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.
|
||||
|
||||
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;
|
||||
|
||||
sample->filename[0] = 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 );
|
||||
|
||||
if ( sample->length <= 0 ) {
|
||||
sample->flags = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sample->flags = IT_SAMPLE_EXISTS;
|
||||
|
||||
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
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int it_asy_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f )
|
||||
{
|
||||
int32 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;
|
||||
}
|
||||
|
||||
sample->data = malloc( sample->length );
|
||||
|
||||
if ( !sample->data )
|
||||
return -1;
|
||||
|
||||
if ( sample->length )
|
||||
dumbfile_getnc( sample->data, sample->length, f );
|
||||
|
||||
dumbfile_skip( f, truncated_size );
|
||||
|
||||
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 */
|
||||
|
||||
char signature [32];
|
||||
|
||||
if ( dumbfile_getnc( signature, 32, f ) != 32 ||
|
||||
memcmp( signature, sig_part, 19 ) ||
|
||||
memcmp( signature + 19, sig_rest, 5 ) ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata = malloc(sizeof(*sigdata));
|
||||
if (!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 ( dumbfile_error( f ) || !sigdata->n_samples || sigdata->n_samples > 64 || !sigdata->n_patterns ||
|
||||
!sigdata->n_orders ) {
|
||||
free( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( sigdata->restart_position > sigdata->n_orders ) /* XXX */
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
sigdata->order = malloc( sigdata->n_orders );
|
||||
if ( !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->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
|
||||
if ( !sigdata->sample ) {
|
||||
free( sigdata->order );
|
||||
free( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->song_message = NULL;
|
||||
sigdata->instrument = NULL;
|
||||
sigdata->pattern = NULL;
|
||||
sigdata->midi = NULL;
|
||||
sigdata->checkpoint = NULL;
|
||||
|
||||
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 ) {
|
||||
if ( it_asy_read_sample_header( &sigdata->sample[i], f ) ) {
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ( dumbfile_skip( f, 37 * ( 64 - sigdata->n_samples ) ) ) {
|
||||
_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;
|
||||
|
||||
/* 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 );
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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->global_volume = 128;
|
||||
sigdata->mixing_volume = 48;
|
||||
sigdata->pan_separation = 128;
|
||||
|
||||
sigdata->n_pchannels = 8;
|
||||
|
||||
sigdata->name[0] = 0;
|
||||
|
||||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_asy_quick(DUMBFILE *f)
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_asy_load_sigdata(f);
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,383 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readam.c - Code to read a RIFF DSMF module / / \ \
|
||||
* from a parsed RIFF structure. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Chris Moeller. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
#include "internal/riff.h"
|
||||
|
||||
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;
|
||||
|
||||
/*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] )
|
||||
return -1;*/
|
||||
|
||||
if ( ! sample->length ) {
|
||||
sample->flags &= ~IT_SAMPLE_EXISTS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*if ( flags & ~( 2 | 1 ) )
|
||||
return -1;*/
|
||||
|
||||
if ( sample->length + 64 > len )
|
||||
return -1;
|
||||
|
||||
sample->flags = IT_SAMPLE_EXISTS;
|
||||
|
||||
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;
|
||||
|
||||
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->data = malloc( sample->length );
|
||||
if ( ! sample->data )
|
||||
return -1;
|
||||
|
||||
dumbfile_getnc( sample->data, sample->length, f );
|
||||
|
||||
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 )
|
||||
{
|
||||
int length, row;
|
||||
unsigned flags;
|
||||
long start, end;
|
||||
int p, q, r;
|
||||
IT_ENTRY * entry;
|
||||
|
||||
length = dumbfile_igetw( f );
|
||||
if ( length > len ) return -1;
|
||||
|
||||
len = length - 2;
|
||||
|
||||
pattern->n_rows = 64;
|
||||
pattern->n_entries = 64;
|
||||
|
||||
row = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 ( pattern->n_entries == 64 ) return 0;
|
||||
|
||||
pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) );
|
||||
if ( ! pattern->entry ) return -1;
|
||||
|
||||
entry = pattern->entry;
|
||||
|
||||
row = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
flags = p;
|
||||
entry->channel = flags & 0x0F;
|
||||
entry->mask = 0;
|
||||
|
||||
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;
|
||||
entry->instrument = q;
|
||||
}
|
||||
}
|
||||
|
||||
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 (entry->mask) entry++;
|
||||
}
|
||||
}
|
||||
|
||||
while ( row < 64 )
|
||||
{
|
||||
IT_SET_END_ROW( entry );
|
||||
++ entry;
|
||||
++ row;
|
||||
}
|
||||
|
||||
pattern->n_entries = (int)(entry - pattern->entry);
|
||||
if ( ! pattern->n_entries ) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( DUMBFILE * f, struct riff * stream )
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
|
||||
int n, o, found;
|
||||
|
||||
if ( ! stream ) goto error;
|
||||
|
||||
if ( stream->type != DUMB_ID( 'D', 'S', 'M', 'F' ) ) goto error;
|
||||
|
||||
sigdata = malloc(sizeof(*sigdata));
|
||||
if ( ! sigdata ) goto error;
|
||||
|
||||
sigdata->n_patterns = 0;
|
||||
sigdata->n_samples = 0;
|
||||
sigdata->name[0] = 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;
|
||||
|
||||
case DUMB_ID( 'P', 'A', 'T', 'T' ):
|
||||
++ sigdata->n_patterns;
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'I', 'N', 'S', 'T' ):
|
||||
++ sigdata->n_samples;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !found || !sigdata->n_samples || !sigdata->n_patterns ) 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->mixing_volume = 48;
|
||||
sigdata->pan_separation = 128;
|
||||
|
||||
sigdata->n_instruments = 0;
|
||||
sigdata->n_orders = 0;
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
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; (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;
|
||||
}
|
||||
|
||||
sigdata->order = malloc( 128 );
|
||||
if ( ! sigdata->order ) goto error_usd;
|
||||
dumbfile_getnc( (char *) sigdata->order, 128, f );
|
||||
|
||||
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->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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
_dumb_it_fix_invalid_orders( sigdata );
|
||||
|
||||
return sigdata;
|
||||
|
||||
error_usd:
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
goto error;
|
||||
error_sd:
|
||||
free( sigdata );
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DUH *dumb_read_riff_dsmf( DUMBFILE * f, struct riff * stream )
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_riff_dsmf_load_sigdata( f, stream );
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
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 );
|
||||
}
|
||||
}
|
|
@ -1,633 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readmod.c - Code to read a good old-fashioned / / \ \
|
||||
* Amiga module from an open file. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
||||
|
||||
|
||||
static int it_mod_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer)
|
||||
{
|
||||
int pos;
|
||||
int channel;
|
||||
int row;
|
||||
IT_ENTRY *entry;
|
||||
|
||||
pattern->n_rows = 64;
|
||||
|
||||
if (n_channels == 0) {
|
||||
/* Read the first four channels, leaving gaps for the rest. */
|
||||
for (pos = 0; pos < 64*8*4; pos += 8*4)
|
||||
dumbfile_getnc((char *)buffer + pos, 4*4, f);
|
||||
/* Read the other channels into the gaps we left. */
|
||||
for (pos = 4*4; pos < 64*8*4; pos += 8*4)
|
||||
dumbfile_getnc((char *)buffer + pos, 4*4, f);
|
||||
|
||||
n_channels = 8;
|
||||
} else
|
||||
dumbfile_getnc((char *)buffer, 64 * n_channels * 4, f);
|
||||
|
||||
if (dumbfile_error(f))
|
||||
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 < n_channels; channel++) {
|
||||
if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3])
|
||||
pattern->n_entries++;
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
|
||||
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 < n_channels; channel++) {
|
||||
if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3]) {
|
||||
unsigned char sample = (buffer[pos+0] & 0xF0) | (buffer[pos+2] >> 4);
|
||||
int period = ((int)(buffer[pos+0] & 0x0F) << 8) | buffer[pos+1];
|
||||
|
||||
entry->channel = channel;
|
||||
entry->mask = 0;
|
||||
|
||||
if (period) {
|
||||
int note;
|
||||
entry->mask |= IT_ENTRY_NOTE;
|
||||
|
||||
/* frequency = (AMIGA_DIVISOR / 8) / (period * 2)
|
||||
* C-1: period = 214 -> frequency = 16726
|
||||
* so, set C5_speed to 16726
|
||||
* and period = 214 should translate to C5 aka 60
|
||||
* halve the period, go up an octive
|
||||
*
|
||||
* period = 214 / pow(DUMB_SEMITONE_BASE, note - 60)
|
||||
* pow(DUMB_SEMITONE_BASE, note - 60) = 214 / period
|
||||
* note - 60 = log(214/period) / log(DUMB_SEMITONE_BASE)
|
||||
*/
|
||||
note = (int)floor(log(214.0/period) / log(DUMB_SEMITONE_BASE) + 60.5);
|
||||
entry->note = MID(0, note, 119);
|
||||
// or should we preserve the period?
|
||||
//entry->note = buffer[pos+0] & 0x0F; /* High nibble */
|
||||
//entry->volpan = buffer[pos+1]; /* Low byte */
|
||||
// and what about finetune?
|
||||
}
|
||||
|
||||
if (sample) {
|
||||
entry->mask |= IT_ENTRY_INSTRUMENT;
|
||||
entry->instrument = sample;
|
||||
}
|
||||
|
||||
_dumb_it_xm_convert_effect(buffer[pos+2] & 0x0F, buffer[pos+3], entry, 1);
|
||||
|
||||
entry++;
|
||||
}
|
||||
pos += 4;
|
||||
}
|
||||
IT_SET_END_ROW(entry);
|
||||
entry++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int it_mod_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f, int stk)
|
||||
{
|
||||
int finetune, loop_start, loop_length;
|
||||
|
||||
/**
|
||||
21 22 Chars Sample 1 name. If the name is not a full
|
||||
22 chars in length, it will be null
|
||||
terminated.
|
||||
|
||||
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;
|
||||
|
||||
sample->filename[0] = 0;
|
||||
|
||||
sample->length = dumbfile_mgetw(f) << 1;
|
||||
finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
|
||||
/** Each finetune step changes the note 1/8th of a semitone. */
|
||||
sample->global_volume = 64;
|
||||
sample->default_volume = dumbfile_getc(f); // Should we be setting global_volume to this instead?
|
||||
loop_start = dumbfile_mgetw(f);
|
||||
if ( !stk ) loop_start <<= 1;
|
||||
loop_length = dumbfile_mgetw(f) << 1;
|
||||
if ( loop_length > 2 && loop_start + loop_length > sample->length && loop_start / 2 + loop_length <= sample->length )
|
||||
loop_start /= 2;
|
||||
sample->loop_start = loop_start;
|
||||
sample->loop_end = loop_start + loop_length;
|
||||
/**
|
||||
Once this sample has been played completely from beginning
|
||||
to end, if the repeat length (next field) is greater than two bytes it
|
||||
will loop back to this position in the sample and continue playing. Once
|
||||
it has played for the repeat length, it continues to loop back to the
|
||||
repeat start offset. This means the sample continues playing until it is
|
||||
told to stop.
|
||||
*/
|
||||
|
||||
if (sample->length <= 0) {
|
||||
sample->flags = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sample->flags = IT_SAMPLE_EXISTS;
|
||||
|
||||
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->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;
|
||||
|
||||
return dumbfile_error(f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int it_mod_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f, uint32 fft)
|
||||
{
|
||||
int32 i;
|
||||
int32 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;
|
||||
}
|
||||
|
||||
if (sample->length) {
|
||||
sample->data = malloc(sample->length);
|
||||
|
||||
if (!sample->data)
|
||||
return -1;
|
||||
|
||||
/* Sample data are stored in "8-bit two's compliment format" (sic). */
|
||||
/*
|
||||
for (i = 0; i < sample->length; i++)
|
||||
((signed char *)sample->left)[i] = dumbfile_getc(f);
|
||||
*/
|
||||
/* F U Olivier Lapicque */
|
||||
if (sample->length >= 5)
|
||||
{
|
||||
i = dumbfile_getnc(sample->data, 5, f);
|
||||
if (i == 5)
|
||||
{
|
||||
if (!memcmp(sample->data, "ADPCM", 5))
|
||||
{
|
||||
if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
i += dumbfile_getnc(((char *)sample->data) + 5, sample->length - 5, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = dumbfile_getnc(sample->data, sample->length, f);
|
||||
}
|
||||
if (i < sample->length)
|
||||
{
|
||||
if (i <= 0)
|
||||
{
|
||||
sample->flags = 0;
|
||||
return 0;
|
||||
}
|
||||
sample->length = i;
|
||||
if (sample->loop_end > i) sample->loop_end = i;
|
||||
// holy crap!
|
||||
if (sample->loop_start > i) sample->flags &= ~IT_SAMPLE_LOOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* skip truncated data */
|
||||
int feh = dumbfile_error(f);
|
||||
|
||||
if (truncated_size) dumbfile_skip(f, truncated_size);
|
||||
// Should we be truncating it?
|
||||
|
||||
if (feh)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) {
|
||||
int delta = 0;
|
||||
for (i = 0; i < sample->length; i++) {
|
||||
delta += ((signed char *)sample->data)[i];
|
||||
((signed char *)sample->data)[i] = delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define MOD_FFT_OFFSET (20 + 31*(22+2+1+1+2+2) + 1 + 1 + 128)
|
||||
|
||||
static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict_)
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
int n_channels;
|
||||
int i;
|
||||
uint32 fft;
|
||||
|
||||
if ( dumbfile_seek(f, MOD_FFT_OFFSET, DFS_SEEK_SET) )
|
||||
return NULL;
|
||||
|
||||
fft = dumbfile_mgetl(f);
|
||||
if (dumbfile_error(f))
|
||||
return NULL;
|
||||
|
||||
if ( dumbfile_seek(f, 0, DFS_SEEK_SET) )
|
||||
return NULL;
|
||||
|
||||
sigdata = malloc(sizeof(*sigdata));
|
||||
if (!sigdata) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
1 20 Chars Title of the song. If the title is not a
|
||||
full 20 chars in length, it will be null-
|
||||
terminated.
|
||||
*/
|
||||
if (dumbfile_getnc((char *)sigdata->name, 20, f) < 20) {
|
||||
free(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
sigdata->name[20] = 0;
|
||||
|
||||
sigdata->n_samples = 31;
|
||||
|
||||
switch (fft) {
|
||||
case DUMB_ID('M','.','K','.'):
|
||||
case DUMB_ID('M','!','K','!'):
|
||||
case DUMB_ID('M','&','K','!'):
|
||||
case DUMB_ID('N','.','T','.'):
|
||||
case DUMB_ID('N','S','M','S'):
|
||||
case DUMB_ID('F','L','T','4'):
|
||||
case DUMB_ID('M',0,0,0):
|
||||
case DUMB_ID('8',0,0,0):
|
||||
n_channels = 4;
|
||||
break;
|
||||
case DUMB_ID('F','L','T','8'):
|
||||
n_channels = 0;
|
||||
/* 0 indicates a special case; two four-channel patterns must be
|
||||
* combined into one eight-channel pattern. Pattern indexes must
|
||||
* be halved. Why oh why do they obfuscate so?
|
||||
*/
|
||||
/*for (i = 0; i < 128; i++)
|
||||
sigdata->order[i] >>= 1;*/
|
||||
break;
|
||||
case DUMB_ID('C','D','8','1'):
|
||||
case DUMB_ID('O','C','T','A'):
|
||||
case DUMB_ID('O','K','T','A'):
|
||||
n_channels = 8;
|
||||
break;
|
||||
case DUMB_ID('1','6','C','N'):
|
||||
n_channels = 16;
|
||||
break;
|
||||
case DUMB_ID('3','2','C','N'):
|
||||
n_channels = 32;
|
||||
break;
|
||||
default:
|
||||
/* If we get an illegal tag, assume 4 channels 15 samples. */
|
||||
if ((fft & 0x0000FFFFL) == DUMB_ID(0,0,'C','H')) {
|
||||
if (fft >= '1' << 24 && fft < '4' << 24) {
|
||||
n_channels = ((fft & 0x00FF0000L) >> 16) - '0';
|
||||
if ((unsigned int)n_channels >= 10) {
|
||||
/* Rightmost character wasn't a digit. */
|
||||
n_channels = 4;
|
||||
sigdata->n_samples = 15;
|
||||
} else {
|
||||
n_channels += (((fft & 0xFF000000L) >> 24) - '0') * 10;
|
||||
/* MODs should really only go up to 32 channels, but we're lenient. */
|
||||
if ((unsigned int)(n_channels - 1) >= DUMB_IT_N_CHANNELS - 1) {
|
||||
/* No channels or too many? Can't be right... */
|
||||
n_channels = 4;
|
||||
sigdata->n_samples = 15;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
n_channels = 4;
|
||||
sigdata->n_samples = 15;
|
||||
}
|
||||
} else if ((fft & 0x00FFFFFFL) == DUMB_ID(0,'C','H','N')) {
|
||||
n_channels = (fft >> 24) - '0';
|
||||
if ((unsigned int)(n_channels - 1) >= 9) {
|
||||
/* Character was '0' or it wasn't a digit */
|
||||
n_channels = 4;
|
||||
sigdata->n_samples = 15;
|
||||
}
|
||||
} else if ((fft & 0xFFFFFF00L) == DUMB_ID('T','D','Z',0)) {
|
||||
n_channels = (fft & 0x000000FFL) - '0';
|
||||
if ((unsigned int)(n_channels - 1) >= 9) {
|
||||
/* We've been very lenient, given that it should have
|
||||
* been 1, 2 or 3, but this MOD has been very naughty and
|
||||
* must be punished.
|
||||
*/
|
||||
n_channels = 4;
|
||||
sigdata->n_samples = 15;
|
||||
}
|
||||
} else {
|
||||
n_channels = 4;
|
||||
sigdata->n_samples = 15;
|
||||
}
|
||||
}
|
||||
|
||||
// moo
|
||||
if ( ( restrict_ & 1 ) && sigdata->n_samples == 15 )
|
||||
{
|
||||
free(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->n_pchannels = n_channels ? n_channels : 8; /* special case for 0, see above */
|
||||
|
||||
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
|
||||
if (!sigdata->sample) {
|
||||
free(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->song_message = NULL;
|
||||
sigdata->order = NULL;
|
||||
sigdata->instrument = NULL;
|
||||
sigdata->pattern = NULL;
|
||||
sigdata->midi = NULL;
|
||||
sigdata->checkpoint = NULL;
|
||||
|
||||
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++) {
|
||||
if (it_mod_read_sample_header(&sigdata->sample[i], f, sigdata->n_samples == 15)) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
sigdata->n_orders = dumbfile_getc(f);
|
||||
sigdata->restart_position = dumbfile_getc(f);
|
||||
// what if this is >= 127? what about with Fast Tracker II?
|
||||
|
||||
/* if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}*/
|
||||
|
||||
//if (sigdata->restart_position >= sigdata->n_orders)
|
||||
//sigdata->restart_position = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
|
||||
sigdata->n_orders = 128;
|
||||
//while (sigdata->n_orders > 1 && !sigdata->order[sigdata->n_orders - 1]) sigdata->n_orders--;
|
||||
}
|
||||
|
||||
if ( ! n_channels )
|
||||
for (i = 0; i < 128; i++)
|
||||
sigdata->order[i] >>= 1;
|
||||
|
||||
/* "The old NST format contains only 15 samples (instead of 31). Further
|
||||
* it doesn't contain a file format tag (id). So Pattern data offset is
|
||||
* at 20+15*30+1+1+128."
|
||||
* - Then I shall assume the File Format Tag never exists if there are
|
||||
* only 15 samples. I hope this isn't a faulty assumption...
|
||||
*/
|
||||
if (sigdata->n_samples == 31)
|
||||
dumbfile_skip(f, 4);
|
||||
|
||||
sigdata->n_patterns = -1;
|
||||
|
||||
if ( ( restrict_ & 2 ) )
|
||||
{
|
||||
unsigned char buffer[5];
|
||||
long sample_number;
|
||||
long total_sample_size;
|
||||
long offset = dumbfile_pos(f);
|
||||
long remain = dumbfile_get_size(f) - offset;
|
||||
if ( dumbfile_error( f ) ||
|
||||
dumbfile_seek( f, 0, SEEK_END ) ) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
sample_number = sigdata->n_samples - 1;
|
||||
total_sample_size = 0;
|
||||
while (dumbfile_pos(f) > offset && sample_number >= 0) {
|
||||
if (sigdata->sample[sample_number].flags & IT_SAMPLE_EXISTS) {
|
||||
if ( dumbfile_seek(f, -((sigdata->sample[sample_number].length + 1) / 2 + 5 + 16), DFS_SEEK_CUR) ||
|
||||
dumbfile_getnc((char *)buffer, 5, f) < 5 ) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
if ( !memcmp( buffer, "ADPCM", 5 ) ) { /* BAH */
|
||||
total_sample_size += (sigdata->sample[sample_number].length + 1) / 2 + 5 + 16;
|
||||
if ( dumbfile_seek(f, -5, DFS_SEEK_CUR) ) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
total_sample_size += sigdata->sample[sample_number].length;
|
||||
if ( dumbfile_seek(f, -(sigdata->sample[sample_number].length - ((sigdata->sample[sample_number].length + 1) / 2 + 5 + 16) + 5), DFS_SEEK_CUR) ) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
--sample_number;
|
||||
}
|
||||
|
||||
if (remain > total_sample_size) {
|
||||
sigdata->n_patterns = ( remain - total_sample_size + 4 ) / ( 256 * sigdata->n_pchannels );
|
||||
if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) {
|
||||
remain -= sigdata->n_patterns * 256 * sigdata->n_pchannels;
|
||||
if (dumbfile_skip(f, remain - total_sample_size)) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
if (sigdata->order[i] > sigdata->n_patterns)
|
||||
sigdata->n_patterns = sigdata->order[i];
|
||||
}
|
||||
sigdata->n_patterns++;
|
||||
}
|
||||
|
||||
if ( sigdata->n_patterns <= 0 ) {
|
||||
_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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* Read in the patterns */
|
||||
{
|
||||
unsigned char *buffer = malloc(256 * sigdata->n_pchannels); /* 64 rows * 4 bytes */
|
||||
if (!buffer) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < sigdata->n_patterns; i++) {
|
||||
if (it_mod_read_pattern(&sigdata->pattern[i], f, n_channels, buffer) != 0) {
|
||||
free(buffer);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
/* And finally, the sample data */
|
||||
for (i = 0; i < sigdata->n_samples; i++) {
|
||||
if (it_mod_read_sample_data(&sigdata->sample[i], f, fft)) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* w00t! */
|
||||
/*if ( n_channels == 4 &&
|
||||
( sigdata->n_samples == 15 ||
|
||||
( ( fft & 240 ) != DUMB_ID( 0, 0, 'C', 0 ) &&
|
||||
( fft & 240 ) != DUMB_ID( 0, 0, 'H', 0 ) &&
|
||||
( fft & 240 ) != 0 ) ) ) {
|
||||
for ( i = 0; i < sigdata->n_samples; ++i ) {
|
||||
IT_SAMPLE * sample = &sigdata->sample [i];
|
||||
if ( sample && ( sample->flags & IT_SAMPLE_EXISTS ) ) {
|
||||
int n, o;
|
||||
o = sample->length;
|
||||
if ( o > 4 ) o = 4;
|
||||
for ( n = 0; n < o; ++n )
|
||||
( ( char * ) sample->data ) [n] = 0;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/* 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->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->speed = 6;
|
||||
sigdata->tempo = 125;
|
||||
sigdata->pan_separation = 128;
|
||||
|
||||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_mod_quick(DUMBFILE *f, int restrict_)
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_mod_load_sigdata(f, restrict_);
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
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] = "MOD";
|
||||
return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readmod2.c - Function to read a good old- / / \ \
|
||||
* fashioned Amiga module from an | < / \_
|
||||
* open file and do an initial | \/ /\ /
|
||||
* run-through. \_ / > /
|
||||
* | \ / /
|
||||
* Split off from readmod.c by entheh. | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_mod(DUMBFILE *f, int restrict_)
|
||||
{
|
||||
DUH *duh = dumb_read_mod_quick(f, restrict_);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,413 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readmtm.c - Code to read a MultiTracker Module / / \ \
|
||||
* from an open file. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Chris Moeller. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
||||
static 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 && ptr < end) 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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (note) {
|
||||
entry->mask |= IT_ENTRY_NOTE;
|
||||
entry->note = note + 24;
|
||||
}
|
||||
|
||||
if (sample) {
|
||||
entry->mask |= IT_ENTRY_INSTRUMENT;
|
||||
entry->instrument = sample;
|
||||
}
|
||||
|
||||
_dumb_it_xm_convert_effect(t[1] & 0xF, t[2], entry, 1);
|
||||
|
||||
if (entry->mask) entry++;
|
||||
}
|
||||
}
|
||||
}
|
||||
IT_SET_END_ROW(entry);
|
||||
entry++;
|
||||
}
|
||||
|
||||
pattern->n_entries = (int)(entry - pattern->entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int it_mtm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
|
||||
{
|
||||
int finetune, flags;
|
||||
|
||||
dumbfile_getnc((char *)sample->name, 22, f);
|
||||
sample->name[22] = 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);
|
||||
|
||||
flags = dumbfile_getc(f);
|
||||
|
||||
if (sample->length <= 0) {
|
||||
sample->flags = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sample->flags = IT_SAMPLE_EXISTS;
|
||||
|
||||
if (flags & 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
|
||||
|
||||
if (sample->loop_end > sample->length)
|
||||
sample->loop_end = sample->length;
|
||||
|
||||
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;
|
||||
|
||||
return dumbfile_error(f);
|
||||
}
|
||||
|
||||
static int it_mtm_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f)
|
||||
{
|
||||
int32 i;
|
||||
int32 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;
|
||||
}
|
||||
|
||||
sample->data = malloc(sample->length);
|
||||
|
||||
if (!sample->data)
|
||||
return -1;
|
||||
|
||||
dumbfile_getnc((char *)sample->data, sample->length, f);
|
||||
dumbfile_skip(f, truncated_size);
|
||||
|
||||
if (dumbfile_error(f))
|
||||
return -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;
|
||||
|
||||
int n, o, n_tracks, l_comment, n_rows, n_channels;
|
||||
|
||||
unsigned char * track;
|
||||
|
||||
unsigned short * sequence;
|
||||
|
||||
char * comment;
|
||||
|
||||
if (dumbfile_getc(f) != 'M' ||
|
||||
dumbfile_getc(f) != 'T' ||
|
||||
dumbfile_getc(f) != 'M') 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;
|
||||
|
||||
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;
|
||||
|
||||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
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 = 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->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->song_message = NULL;
|
||||
sigdata->order = NULL;
|
||||
sigdata->instrument = NULL;
|
||||
sigdata->pattern = NULL;
|
||||
sigdata->midi = NULL;
|
||||
sigdata->checkpoint = NULL;
|
||||
|
||||
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;
|
||||
|
||||
for (n = 0; n < sigdata->n_samples; n++) {
|
||||
if (it_mtm_read_sample_header(&sigdata->sample[n], f)) goto error_usd;
|
||||
}
|
||||
|
||||
sigdata->order = malloc(sigdata->n_orders);
|
||||
if (!sigdata->order) goto error_usd;
|
||||
|
||||
if (dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_usd;
|
||||
if (sigdata->n_orders < 128)
|
||||
if (dumbfile_skip(f, 128 - sigdata->n_orders)) goto error_usd;
|
||||
|
||||
track = malloc(192 * n_tracks);
|
||||
if (!track) goto error_usd;
|
||||
|
||||
if (dumbfile_getnc((char *)track, 192 * n_tracks, f) < 192 * n_tracks) goto error_ft;
|
||||
|
||||
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;
|
||||
|
||||
sequence = malloc(sigdata->n_patterns * 32 * sizeof(*sequence));
|
||||
if (!sequence) 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (l_comment) {
|
||||
comment = malloc(l_comment);
|
||||
if (!comment) goto error_fs;
|
||||
if (dumbfile_getnc(comment, l_comment, f) < l_comment) goto error_fc;
|
||||
|
||||
/* Time for annoying "logic", yes. We want each line which has text,
|
||||
* and each blank line in between all the valid lines.
|
||||
*/
|
||||
|
||||
/* Find last actual line. */
|
||||
for (o = -1, n = 0; n < l_comment; n += 40) {
|
||||
if (comment[n]) o = n;
|
||||
}
|
||||
|
||||
if (o >= 0) {
|
||||
|
||||
size_t l;
|
||||
int m;
|
||||
for (l = 0, n = 0; n <= o; n += 40) {
|
||||
l += strlen_max(&comment[n], 40) + 2;
|
||||
}
|
||||
|
||||
l -= 1;
|
||||
|
||||
sigdata->song_message = malloc(l);
|
||||
if (!sigdata->song_message) goto error_fc;
|
||||
|
||||
for (m = 0, n = 0; n <= o; n += 40) {
|
||||
int p = (int)strlen_max(&comment[n], 40);
|
||||
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;
|
||||
}
|
||||
|
||||
free(comment);
|
||||
}
|
||||
|
||||
for (n = 0; n < sigdata->n_samples; n++) {
|
||||
if (it_mtm_read_sample_data(&sigdata->sample[n], f)) goto error_fs;
|
||||
}
|
||||
|
||||
_dumb_it_fix_invalid_orders(sigdata);
|
||||
|
||||
free(sequence);
|
||||
free(track);
|
||||
|
||||
return sigdata;
|
||||
|
||||
error_fc:
|
||||
free(comment);
|
||||
error_fs:
|
||||
free(sequence);
|
||||
error_ft:
|
||||
free(track);
|
||||
error_usd:
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
|
||||
error_sd:
|
||||
free(sigdata);
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char hexdigit(int in)
|
||||
{
|
||||
if (in < 10) return in + '0';
|
||||
else return in + 'A' - 10;
|
||||
}
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_mtm_quick(DUMBFILE *f)
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
int ver;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_mtm_load_sigdata(f, &ver);
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,558 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readokt.c - Code to read an Oktalyzer module / / \ \
|
||||
* from an open file. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Chris Moeller. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#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;
|
||||
|
||||
n_rows = (data[0] << 8) | data[1];
|
||||
if (!n_rows) n_rows = 64;
|
||||
|
||||
if (length < 2 + (n_rows * n_channels * 4)) return -1;
|
||||
|
||||
pattern->n_rows = n_rows;
|
||||
|
||||
/* 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->entry = (IT_ENTRY *) malloc(pattern->n_entries * sizeof(*pattern->entry));
|
||||
if (!pattern->entry)
|
||||
return -1;
|
||||
|
||||
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;
|
||||
|
||||
if (data[pos+0] > 0 && data[pos+0] <= 36) {
|
||||
entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT;
|
||||
|
||||
entry->note = data[pos+0] + 35;
|
||||
entry->instrument = data[pos+1] + 1;
|
||||
}
|
||||
|
||||
entry->effect = 0;
|
||||
entry->effectvalue = data[pos+3];
|
||||
|
||||
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 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 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 15: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_SET_FILTER, data[pos+3] & 0x0F); break;
|
||||
|
||||
case 25: entry->effect = IT_JUMP_TO_ORDER; break;
|
||||
|
||||
case 27: entry->note = IT_NOTE_OFF; entry->mask |= IT_ENTRY_NOTE; break;
|
||||
|
||||
case 28: entry->effect = IT_SET_SPEED; 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;
|
||||
}
|
||||
|
||||
if ( entry->effect ) entry->mask |= IT_ENTRY_EFFECT;
|
||||
|
||||
entry++;
|
||||
}
|
||||
pos += 4;
|
||||
}
|
||||
IT_SET_END_ROW(entry);
|
||||
entry++;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
sample->filename[0] = 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;
|
||||
|
||||
if (sample->length <= 0) {
|
||||
sample->flags = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
sample->flags = IT_SAMPLE_EXISTS;
|
||||
|
||||
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 (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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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);
|
||||
|
||||
if (!sample->data)
|
||||
return -1;
|
||||
|
||||
memcpy(sample->data, data, length);
|
||||
}
|
||||
|
||||
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_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;
|
||||
|
||||
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;
|
||||
|
||||
bytes_read = dumbfile_mgetl( f );
|
||||
if ( bytes_read < 0 ) break;
|
||||
|
||||
chunk->type = bytes_read;
|
||||
chunk->size = dumbfile_mgetl( f );
|
||||
|
||||
if ( dumbfile_error( f ) ) break;
|
||||
|
||||
chunk->data = (unsigned char *) malloc( chunk->size );
|
||||
if ( !chunk->data )
|
||||
{
|
||||
free( mod->chunks );
|
||||
free( mod );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bytes_read = dumbfile_getnc( ( char * ) chunk->data, chunk->size, f );
|
||||
if ( bytes_read < (long)chunk->size )
|
||||
{
|
||||
if ( bytes_read <= 0 ) {
|
||||
free( chunk->data );
|
||||
break;
|
||||
} else {
|
||||
chunk->size = bytes_read;
|
||||
mod->chunk_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mod->chunk_count++;
|
||||
}
|
||||
|
||||
if ( !mod->chunk_count ) {
|
||||
if ( mod->chunks ) free(mod->chunks);
|
||||
free(mod);
|
||||
mod = NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
char signature[8];
|
||||
|
||||
if (dumbfile_getnc(signature, 8, f) < 8 ||
|
||||
memcmp(signature, "OKTASONG", 8)) {
|
||||
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->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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!n_channels) {
|
||||
free(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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->song_message = NULL;
|
||||
sigdata->order = NULL;
|
||||
sigdata->instrument = NULL;
|
||||
sigdata->pattern = NULL;
|
||||
sigdata->midi = NULL;
|
||||
sigdata->checkpoint = NULL;
|
||||
|
||||
sigdata->n_instruments = 0;
|
||||
|
||||
for (i = 0; (unsigned)i < (unsigned)sigdata->n_samples; i++)
|
||||
sigdata->sample[i].data = NULL;
|
||||
|
||||
chunk = get_chunk_by_type(mod, DUMB_ID('S','A','M','P'), 0);
|
||||
|
||||
for (i = 0; (unsigned)i < (unsigned)sigdata->n_samples; i++) {
|
||||
it_okt_read_sample_header(&sigdata->sample[i], chunk->data + 32 * i);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* 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];
|
||||
|
||||
j = get_chunk_count(mod, DUMB_ID('P','B','O','D'));
|
||||
if (sigdata->n_patterns > (int)j) sigdata->n_patterns = (int)j;
|
||||
|
||||
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; (unsigned)i < (unsigned)sigdata->n_patterns; i++)
|
||||
sigdata->pattern[i].entry = NULL;
|
||||
|
||||
/* Read in the patterns */
|
||||
for (i = 0; (unsigned)i < (unsigned)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; (unsigned)i < (unsigned)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 (; (unsigned)i < (unsigned)sigdata->n_samples; i++) {
|
||||
sigdata->sample[i].flags = 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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
_dumb_it_fix_invalid_orders(sigdata);
|
||||
|
||||
return sigdata;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_okt_quick(DUMBFILE *f)
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_okt_load_sigdata(f);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readokt2.c - Function to read an Oktalyzer / / \ \
|
||||
* module from an open file and do | < / \_
|
||||
* an initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* By Chris Moeller. | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_okt(DUMBFILE *f)
|
||||
{
|
||||
DUH *duh = dumb_read_okt_quick(f);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -1,689 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readpsm.c - Code to read an old Protracker / / \ \
|
||||
* Studio module from an open file. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Chris Moeller. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
||||
static int CDECL psm_sample_compare(const void *e1, const void *e2)
|
||||
{
|
||||
const unsigned char * pa = e1;
|
||||
const unsigned char * pb = e2;
|
||||
int a = pa[37] | (pa[38] << 8) | (pa[39] << 16) | (pa[40] << 24);
|
||||
int b = pb[37] | (pb[38] << 8) | (pb[39] << 16) | (pb[40] << 24);
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static int it_old_psm_read_samples(IT_SAMPLE ** sample, DUMBFILE * f, int * num)
|
||||
{
|
||||
int n, o, count = *num, true_num, snum, offset, flags, finetune, delta;
|
||||
|
||||
unsigned char * buffer;
|
||||
const unsigned char * sdata;
|
||||
int32 sample_bytes;
|
||||
|
||||
buffer = malloc(count * 64);
|
||||
if (!buffer) goto error;
|
||||
|
||||
if (dumbfile_getnc((char *)buffer, count * 64, f) < count * 64) goto error_fb;
|
||||
|
||||
true_num = 0;
|
||||
|
||||
for (n = 0; n < count; n++) {
|
||||
snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8);
|
||||
if ((snum < 1) || (snum > 255)) goto error_fb;
|
||||
if (true_num < snum) true_num = snum;
|
||||
}
|
||||
|
||||
if (true_num > count) {
|
||||
IT_SAMPLE * meh = realloc(*sample, true_num * sizeof(*meh));
|
||||
if (!meh) goto error_fb;
|
||||
for (n = count; n < true_num; n++) {
|
||||
meh[n].data = NULL;
|
||||
}
|
||||
*sample = meh;
|
||||
*num = true_num;
|
||||
}
|
||||
|
||||
qsort(buffer, count, 64, &psm_sample_compare);
|
||||
|
||||
for (n = 0; n < true_num; n++) {
|
||||
(*sample)[n].flags = 0;
|
||||
}
|
||||
|
||||
for (n = 0; n < count; n++) {
|
||||
IT_SAMPLE * s;
|
||||
snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8);
|
||||
s = &((*sample)[snum - 1]);
|
||||
memcpy(s->filename, buffer + (n * 64), 13);
|
||||
s->filename[13] = 0;
|
||||
memcpy(s->name, buffer + (n * 64) + 13, 24);
|
||||
s->name[24] = 0;
|
||||
offset = buffer[(n * 64) + 37] | (buffer[(n * 64) + 38] << 8) |
|
||||
(buffer[(n * 64) + 39] << 16) | (buffer[(n * 64) + 40] << 24);
|
||||
flags = buffer[(n * 64) + 47];
|
||||
s->length = buffer[(n * 64) + 48] | (buffer[(n * 64) + 49] << 8) |
|
||||
(buffer[(n * 64) + 50] << 16) | (buffer[(n * 64) + 51] << 24);
|
||||
s->loop_start = buffer[(n * 64) + 52] | (buffer[(n * 64) + 53] << 8) |
|
||||
(buffer[(n * 64) + 54] << 16) | (buffer[(n * 64) + 55] << 24);
|
||||
s->loop_end = buffer[(n * 64) + 56] | (buffer[(n * 64) + 57] << 8) |
|
||||
(buffer[(n * 64) + 58] << 16) | (buffer[(n * 64) + 59] << 24);
|
||||
|
||||
if (s->length <= 0) continue;
|
||||
|
||||
finetune = buffer[(n * 64) + 60];
|
||||
s->default_volume = buffer[(n * 64) + 61];
|
||||
s->C5_speed = buffer[(n * 64) + 62] | (buffer[(n * 64) + 63] << 8);
|
||||
if (finetune & 15) {
|
||||
finetune &= 15;
|
||||
if (finetune >= 8) finetune -= 16;
|
||||
//s->C5_speed = (long)((double)s->C5_speed * pow(DUMB_PITCH_BASE, finetune*32));
|
||||
s->finetune = finetune * 32;
|
||||
}
|
||||
else s->finetune = 0;
|
||||
|
||||
s->flags |= IT_SAMPLE_EXISTS;
|
||||
if (flags & 0x41) {
|
||||
s->flags &= ~IT_SAMPLE_EXISTS;
|
||||
continue;
|
||||
}
|
||||
if (flags & 0x20) s->flags |= IT_SAMPLE_PINGPONG_LOOP;
|
||||
if (flags & 4) s->flags |= IT_SAMPLE_16BIT;
|
||||
|
||||
if (flags & 0x80) {
|
||||
s->flags |= IT_SAMPLE_LOOP;
|
||||
if ((unsigned int)s->loop_end > (unsigned int)s->length)
|
||||
s->loop_end = s->length;
|
||||
else if ((unsigned int)s->loop_start >= (unsigned int)s->loop_end)
|
||||
s->flags &= ~IT_SAMPLE_LOOP;
|
||||
else
|
||||
s->length = s->loop_end;
|
||||
}
|
||||
|
||||
s->global_volume = 64;
|
||||
|
||||
s->vibrato_speed = 0;
|
||||
s->vibrato_depth = 0;
|
||||
s->vibrato_rate = 0;
|
||||
s->vibrato_waveform = IT_VIBRATO_SINE;
|
||||
s->max_resampling_quality = -1;
|
||||
|
||||
sample_bytes = s->length * ((flags & 4) ? 2 : 1);
|
||||
s->data = malloc(sample_bytes);
|
||||
if (!s->data) goto error_fb;
|
||||
|
||||
if (dumbfile_seek(f, offset, DFS_SEEK_SET) || dumbfile_getnc(s->data, sample_bytes, f) < sample_bytes) goto error_fb;
|
||||
sdata = ( const unsigned char * ) s->data;
|
||||
|
||||
if (flags & 0x10) {
|
||||
if (flags & 8) {
|
||||
if (flags & 4) {
|
||||
for (o = 0; o < s->length; o++)
|
||||
((short *)s->data)[o] = (sdata[o * 2] | (sdata[(o * 2) + 1] << 8)) ^ 0x8000;
|
||||
} else {
|
||||
for (o = 0; o < s->length; o++)
|
||||
((signed char *)s->data)[o] = sdata[o] ^ 0x80;
|
||||
}
|
||||
} else {
|
||||
if (flags & 4) {
|
||||
for (o = 0; o < s->length; o++)
|
||||
((short *)s->data)[o] = sdata[o * 2] | (sdata[(o * 2) + 1] << 8);
|
||||
} else {
|
||||
memcpy(s->data, sdata, s->length);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
delta = 0;
|
||||
if (flags & 8) {
|
||||
/* unsigned delta? mehhh, does anything even use this? */
|
||||
if (flags & 4) {
|
||||
for (o = 0; o < s->length; o++) {
|
||||
delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8));
|
||||
((short *)s->data)[o] = delta ^ 0x8000;
|
||||
}
|
||||
} else {
|
||||
for (o = 0; o < s->length; o++) {
|
||||
delta += (signed char)sdata[o];
|
||||
((signed char *)s->data)[o] = delta ^ 0x80;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (flags & 4) {
|
||||
for (o = 0; o < s->length; o++) {
|
||||
delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8));
|
||||
((short *)s->data)[o] = delta;
|
||||
}
|
||||
} else {
|
||||
for (o = 0; o < s->length; o++) {
|
||||
delta += (signed char)sdata[o];
|
||||
((signed char *)s->data)[o] = delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
return 0;
|
||||
|
||||
error_fb:
|
||||
free(buffer);
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int it_old_psm_read_patterns(IT_PATTERN * pattern, DUMBFILE * f, int num, int size, int pchans)
|
||||
{
|
||||
int n, offset, psize, rows, chans, row, flags, channel;
|
||||
|
||||
unsigned char * buffer, * ptr, * end;
|
||||
|
||||
IT_ENTRY * entry;
|
||||
|
||||
buffer = malloc(size);
|
||||
if (!buffer) goto error;
|
||||
|
||||
if (dumbfile_getnc((char *)buffer, size, f) < size) goto error_fb;
|
||||
|
||||
offset = 0;
|
||||
|
||||
for (n = 0; n < num; n++) {
|
||||
IT_PATTERN * p = &pattern[n];
|
||||
|
||||
if (offset >= size) goto error_fb;
|
||||
|
||||
ptr = buffer + offset;
|
||||
psize = ptr[0] | (ptr[1] << 8);
|
||||
rows = ptr[2];
|
||||
chans = ptr[3];
|
||||
|
||||
if (!rows || !chans) {
|
||||
p->n_rows = 1;
|
||||
p->n_entries = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
psize = (psize + 15) & ~15;
|
||||
|
||||
end = ptr + psize;
|
||||
ptr += 4;
|
||||
|
||||
p->n_rows = rows;
|
||||
p->n_entries = rows;
|
||||
row = 0;
|
||||
|
||||
while ((row < rows) && (ptr < end)) {
|
||||
flags = *ptr++;
|
||||
if (!flags) {
|
||||
row++;
|
||||
continue;
|
||||
}
|
||||
if (flags & 0xE0) {
|
||||
p->n_entries++;
|
||||
if (flags & 0x80) ptr += 2;
|
||||
if (flags & 0x40) ptr++;
|
||||
if (flags & 0x20) {
|
||||
ptr++;
|
||||
if (*ptr == 40) ptr += 3;
|
||||
else ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entry = malloc(p->n_entries * sizeof(*p->entry));
|
||||
if (!entry) goto error_fb;
|
||||
|
||||
p->entry = entry;
|
||||
|
||||
ptr = buffer + offset + 4;
|
||||
row = 0;
|
||||
|
||||
while ((row < rows) && (ptr < end)) {
|
||||
flags = *ptr++;
|
||||
if (!flags) {
|
||||
IT_SET_END_ROW(entry);
|
||||
entry++;
|
||||
row++;
|
||||
continue;
|
||||
}
|
||||
if (flags & 0xE0) {
|
||||
entry->mask = 0;
|
||||
entry->channel = channel = flags & 0x1F;
|
||||
if (channel >= chans)
|
||||
{
|
||||
//channel = 0;
|
||||
//goto error_fb;
|
||||
}
|
||||
if (flags & 0x80) {
|
||||
if ((*ptr < 60) && (channel < pchans)) {
|
||||
entry->mask |= IT_ENTRY_NOTE;
|
||||
entry->note = *ptr + 35;
|
||||
}
|
||||
ptr++;
|
||||
if (*ptr) {
|
||||
entry->mask |= IT_ENTRY_INSTRUMENT;
|
||||
entry->instrument = *ptr;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
if (flags & 0x40) {
|
||||
if (*ptr <= 64) {
|
||||
entry->mask |= IT_ENTRY_VOLPAN;
|
||||
entry->volpan = *ptr;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
if (flags & 0x20) {
|
||||
entry->mask |= IT_ENTRY_EFFECT;
|
||||
|
||||
switch (*ptr) {
|
||||
case 1:
|
||||
entry->effect = IT_XM_FINE_VOLSLIDE_UP;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
entry->effect = IT_VOLUME_SLIDE;
|
||||
entry->effectvalue = (ptr[1] << 4) & 0xF0;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
entry->effect = IT_XM_FINE_VOLSLIDE_DOWN;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 4:
|
||||
entry->effect = IT_VOLUME_SLIDE;
|
||||
entry->effectvalue = ptr[1] & 0xF;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
entry->effect = IT_PORTAMENTO_UP;
|
||||
entry->effectvalue = EFFECT_VALUE(0xF, ptr[1]);
|
||||
break;
|
||||
|
||||
case 11:
|
||||
entry->effect = IT_PORTAMENTO_UP;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 12:
|
||||
entry->effect = IT_PORTAMENTO_DOWN;
|
||||
entry->effectvalue = EFFECT_VALUE(ptr[1], 0xF);
|
||||
break;
|
||||
|
||||
case 13:
|
||||
entry->effect = IT_PORTAMENTO_DOWN;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 14:
|
||||
entry->effect = IT_TONE_PORTAMENTO;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 15:
|
||||
entry->effect = IT_S;
|
||||
entry->effectvalue = EFFECT_VALUE(IT_S_SET_GLISSANDO_CONTROL, ptr[1] & 15);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
entry->effect = IT_VOLSLIDE_TONEPORTA;
|
||||
entry->effectvalue = ptr[1] << 4;
|
||||
break;
|
||||
|
||||
case 17:
|
||||
entry->effect = IT_VOLSLIDE_TONEPORTA;
|
||||
entry->effectvalue = ptr[1] & 0xF;
|
||||
break;
|
||||
|
||||
case 20:
|
||||
entry->effect = IT_VIBRATO;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 21:
|
||||
entry->effect = IT_S;
|
||||
entry->effectvalue = EFFECT_VALUE(IT_S_SET_VIBRATO_WAVEFORM, ptr[1] & 11);
|
||||
break;
|
||||
|
||||
case 22:
|
||||
entry->effect = IT_VOLSLIDE_VIBRATO;
|
||||
entry->effectvalue = ptr[1] << 4;
|
||||
break;
|
||||
|
||||
case 23:
|
||||
entry->effect = IT_VOLSLIDE_VIBRATO;
|
||||
entry->effectvalue = ptr[1] & 0xF;
|
||||
break;
|
||||
|
||||
case 30:
|
||||
entry->effect = IT_TREMOLO;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 31:
|
||||
entry->effect = IT_S;
|
||||
entry->effectvalue = EFFECT_VALUE(IT_S_SET_TREMOLO_WAVEFORM, ptr[1] & 11);
|
||||
break;
|
||||
|
||||
case 40:
|
||||
entry->effect = IT_SET_SAMPLE_OFFSET;
|
||||
entry->effectvalue = ptr[2];
|
||||
ptr += 2;
|
||||
break;
|
||||
|
||||
case 41:
|
||||
entry->effect = IT_XM_RETRIGGER_NOTE;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 42:
|
||||
entry->effect = IT_S;
|
||||
entry->effectvalue = EFFECT_VALUE(IT_S_DELAYED_NOTE_CUT, ptr[1] & 0xF);
|
||||
break;
|
||||
|
||||
case 43:
|
||||
entry->effect = IT_S;
|
||||
entry->effectvalue = EFFECT_VALUE(IT_S_NOTE_DELAY, ptr[1] & 0xF);
|
||||
break;
|
||||
|
||||
case 50:
|
||||
entry->effect = IT_JUMP_TO_ORDER;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 51:
|
||||
entry->effect = IT_BREAK_TO_ROW;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 52:
|
||||
entry->effect = IT_S;
|
||||
entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_LOOP, ptr[1] & 0xF);
|
||||
break;
|
||||
|
||||
case 53:
|
||||
entry->effect = IT_S;
|
||||
entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_DELAY, ptr[1] & 0xF);
|
||||
break;
|
||||
|
||||
case 60:
|
||||
entry->effect = IT_SET_SPEED;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 61:
|
||||
entry->effect = IT_SET_SONG_TEMPO;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 70:
|
||||
entry->effect = IT_ARPEGGIO;
|
||||
entry->effectvalue = ptr[1];
|
||||
break;
|
||||
|
||||
case 71:
|
||||
entry->effect = IT_S;
|
||||
entry->effectvalue = EFFECT_VALUE(IT_S_FINETUNE, ptr[1] & 0xF);
|
||||
break;
|
||||
|
||||
case 72:
|
||||
/* "balance" ... panning? */
|
||||
entry->effect = IT_SET_PANNING;
|
||||
entry->effectvalue = ((ptr[1] - ((ptr[1] & 8) >> 3)) << 5) / 7;
|
||||
break;
|
||||
|
||||
default:
|
||||
entry->mask &= ~IT_ENTRY_EFFECT;
|
||||
}
|
||||
|
||||
ptr += 2;
|
||||
}
|
||||
if (entry->mask) entry++;
|
||||
}
|
||||
}
|
||||
|
||||
p->n_entries = (int)(entry - p->entry);
|
||||
offset += psize;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
return 0;
|
||||
|
||||
error_fb:
|
||||
free(buffer);
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define PSM_COMPONENT_ORDERS 0
|
||||
#define PSM_COMPONENT_PANPOS 1
|
||||
#define PSM_COMPONENT_PATTERNS 2
|
||||
#define PSM_COMPONENT_SAMPLE_HEADERS 3
|
||||
#define PSM_COMPONENT_COMMENTS 4
|
||||
|
||||
typedef struct PSM_COMPONENT
|
||||
{
|
||||
unsigned char type;
|
||||
int32 offset;
|
||||
}
|
||||
PSM_COMPONENT;
|
||||
|
||||
static int CDECL psm_component_compare(const void *e1, const void *e2)
|
||||
{
|
||||
return ((const PSM_COMPONENT *)e1)->offset -
|
||||
((const PSM_COMPONENT *)e2)->offset;
|
||||
}
|
||||
|
||||
static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f)
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
|
||||
PSM_COMPONENT *component;
|
||||
int n_components = 0;
|
||||
|
||||
int n, flags, version, pver, n_orders, n_channels, total_pattern_size;
|
||||
|
||||
if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',254)) goto error;
|
||||
|
||||
sigdata = malloc(sizeof(*sigdata));
|
||||
if (!sigdata) goto error;
|
||||
|
||||
if (dumbfile_getnc((char *)sigdata->name, 60, f) < 60 ||
|
||||
sigdata->name[59] != 0x1A) goto error_sd;
|
||||
sigdata->name[59] = 0;
|
||||
|
||||
flags = dumbfile_getc(f);
|
||||
version = dumbfile_getc(f);
|
||||
pver = dumbfile_getc(f);
|
||||
sigdata->speed = dumbfile_getc(f);
|
||||
sigdata->tempo = dumbfile_getc(f);
|
||||
sigdata->mixing_volume = dumbfile_getc(f);
|
||||
sigdata->n_orders = dumbfile_igetw(f);
|
||||
n_orders = dumbfile_igetw(f);
|
||||
sigdata->n_patterns = dumbfile_igetw(f);
|
||||
sigdata->n_samples = dumbfile_igetw(f);
|
||||
sigdata->n_pchannels = dumbfile_igetw(f);
|
||||
n_channels = dumbfile_igetw(f);
|
||||
|
||||
if (dumbfile_error(f) ||
|
||||
(flags & 1) ||
|
||||
(version != 1 && version != 0x10) ||
|
||||
(pver) ||
|
||||
(sigdata->n_orders <= 0) ||
|
||||
(sigdata->n_orders > 255) ||
|
||||
(n_orders > 255) ||
|
||||
(n_orders < sigdata->n_orders) ||
|
||||
(sigdata->n_patterns > 255) ||
|
||||
(sigdata->n_samples > 255) ||
|
||||
(sigdata->n_pchannels > DUMB_IT_N_CHANNELS) ||
|
||||
(sigdata->n_pchannels > n_channels) ||
|
||||
(n_channels > DUMB_IT_N_CHANNELS))
|
||||
goto error_sd;
|
||||
|
||||
sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
|
||||
|
||||
sigdata->global_volume = 128;
|
||||
sigdata->pan_separation = 128;
|
||||
|
||||
sigdata->song_message = NULL;
|
||||
sigdata->order = NULL;
|
||||
sigdata->instrument = NULL;
|
||||
sigdata->sample = NULL;
|
||||
sigdata->pattern = NULL;
|
||||
sigdata->midi = NULL;
|
||||
sigdata->checkpoint = NULL;
|
||||
|
||||
sigdata->n_instruments = 0;
|
||||
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
sigdata->order = malloc(sigdata->n_orders);
|
||||
if (!sigdata->order) goto error_usd;
|
||||
|
||||
if (sigdata->n_samples) {
|
||||
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
|
||||
if (!sigdata->sample) goto error_usd;
|
||||
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) goto error_usd;
|
||||
for (n = 0; n < sigdata->n_patterns; n++)
|
||||
sigdata->pattern[n].entry = NULL;
|
||||
}
|
||||
|
||||
component = malloc(5 * sizeof(*component));
|
||||
if (!component) goto error_usd;
|
||||
|
||||
for (n = 0; n < 5; n++) {
|
||||
component[n_components].offset = dumbfile_igetl(f);
|
||||
if (component[n_components].offset) {
|
||||
component[n_components].type = n;
|
||||
n_components++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!n_components) goto error_fc;
|
||||
|
||||
total_pattern_size = dumbfile_igetl(f);
|
||||
if (!total_pattern_size) goto error_fc;
|
||||
|
||||
qsort(component, n_components, sizeof(PSM_COMPONENT), &psm_component_compare);
|
||||
|
||||
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 < n_components; n++)
|
||||
{
|
||||
int o;
|
||||
|
||||
if ( dumbfile_seek(f, component[n].offset, DFS_SEEK_SET) ) goto error_fc;
|
||||
|
||||
switch (component[n].type) {
|
||||
|
||||
case PSM_COMPONENT_ORDERS:
|
||||
if (dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_fc;
|
||||
if (n_orders > sigdata->n_orders)
|
||||
if (dumbfile_skip(f, n_orders - sigdata->n_orders))
|
||||
goto error_fc;
|
||||
if (dumbfile_igetw(f)) goto error_fc;
|
||||
break;
|
||||
|
||||
case PSM_COMPONENT_PANPOS:
|
||||
if (dumbfile_getnc((char *)sigdata->channel_pan, sigdata->n_pchannels, f) < sigdata->n_pchannels) goto error_fc;
|
||||
for (o = 0; o < sigdata->n_pchannels; o++) {
|
||||
sigdata->channel_pan[o] -= (sigdata->channel_pan[o] & 8) >> 3;
|
||||
sigdata->channel_pan[o] = ((int)sigdata->channel_pan[o] << 5) / 7;
|
||||
}
|
||||
break;
|
||||
|
||||
case PSM_COMPONENT_PATTERNS:
|
||||
if (it_old_psm_read_patterns(sigdata->pattern, f, sigdata->n_patterns, total_pattern_size, sigdata->n_pchannels)) goto error_fc;
|
||||
break;
|
||||
|
||||
case PSM_COMPONENT_SAMPLE_HEADERS:
|
||||
if (it_old_psm_read_samples(&sigdata->sample, f, &sigdata->n_samples)) goto error_fc;
|
||||
break;
|
||||
|
||||
case PSM_COMPONENT_COMMENTS:
|
||||
if (dumbfile_mgetl(f) == DUMB_ID('T','E','X','T')) {
|
||||
o = dumbfile_igetw(f);
|
||||
if (o > 0) {
|
||||
sigdata->song_message = malloc(o + 1);
|
||||
if (dumbfile_getnc((char *)sigdata->song_message, o, f) < o) goto error_fc;
|
||||
sigdata->song_message[o] = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_dumb_it_fix_invalid_orders(sigdata);
|
||||
|
||||
free(component);
|
||||
|
||||
return sigdata;
|
||||
|
||||
error_fc:
|
||||
free(component);
|
||||
error_usd:
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
error_sd:
|
||||
free(sigdata);
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_old_psm_quick(DUMBFILE *f)
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_old_psm_load_sigdata(f);
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
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] = "PSM (old)";
|
||||
return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,554 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readptm.c - Code to read a Poly Tracker v2.03 / / \ \
|
||||
* module from an open file. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Chris Moeller. Based on reads3m.c \_ / > /
|
||||
* by entheh. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
// IT_STEREO... :o
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
||||
|
||||
|
||||
static int it_ptm_read_sample_header(IT_SAMPLE *sample, int32 *offset, DUMBFILE *f)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = dumbfile_getc(f);
|
||||
|
||||
dumbfile_getnc((char *)sample->filename, 12, f);
|
||||
sample->filename[12] = 0;
|
||||
|
||||
sample->default_volume = dumbfile_getc(f);
|
||||
|
||||
sample->C5_speed = dumbfile_igetw(f) << 1;
|
||||
|
||||
dumbfile_skip(f, 2); /* segment */
|
||||
|
||||
*offset = 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);
|
||||
|
||||
dumbfile_getnc((char *)sample->name, 28, f);
|
||||
sample->name[28] = 0;
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
if ((flags & 3) == 0) {
|
||||
/* Looks like no sample */
|
||||
sample->flags &= ~IT_SAMPLE_EXISTS;
|
||||
return dumbfile_error(f);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (flags & 16) {
|
||||
sample->flags |= IT_SAMPLE_16BIT;
|
||||
|
||||
sample->length >>= 1;
|
||||
sample->loop_start >>= 1;
|
||||
sample->loop_end >>= 1;
|
||||
}
|
||||
|
||||
if (sample->loop_end) sample->loop_end--;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
int32 n;
|
||||
int s;
|
||||
|
||||
sample->data = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
|
||||
if (!sample->data)
|
||||
return -1;
|
||||
|
||||
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 (dumbfile_error(f) && !last)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
|
||||
IT_ENTRY *entry;
|
||||
|
||||
unsigned char channel;
|
||||
|
||||
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);
|
||||
|
||||
#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;
|
||||
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;
|
||||
}
|
||||
#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];
|
||||
}
|
||||
}
|
||||
#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.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
|
||||
|
||||
if (!pattern->entry)
|
||||
return -1;
|
||||
|
||||
entry = pattern->entry;
|
||||
|
||||
while (bufpos < buflen) {
|
||||
unsigned char b = buffer[bufpos++];
|
||||
|
||||
if (b == 0)
|
||||
{
|
||||
/* End of row */
|
||||
IT_SET_END_ROW(entry);
|
||||
entry++;
|
||||
continue;
|
||||
}
|
||||
|
||||
channel = b & 31;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 & 128) {
|
||||
entry->volpan = buffer[bufpos++];
|
||||
if (entry->volpan <= 64)
|
||||
entry->mask |= IT_ENTRY_VOLPAN;
|
||||
}
|
||||
|
||||
entry++;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(entry == pattern->entry + pattern->n_entries);
|
||||
|
||||
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 */
|
||||
/* 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
|
||||
|
||||
typedef struct PTM_COMPONENT
|
||||
{
|
||||
unsigned char type;
|
||||
unsigned char n;
|
||||
int32 offset;
|
||||
}
|
||||
PTM_COMPONENT;
|
||||
|
||||
|
||||
|
||||
static int CDECL ptm_component_compare(const void *e1, const void *e2)
|
||||
{
|
||||
return ((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;
|
||||
|
||||
int n;
|
||||
|
||||
unsigned char *buffer;
|
||||
|
||||
sigdata = malloc(sizeof(*sigdata));
|
||||
if (!sigdata) return NULL;
|
||||
|
||||
/* Skip song name. */
|
||||
dumbfile_getnc((char *)sigdata->name, 28, f);
|
||||
sigdata->name[28] = 0;
|
||||
|
||||
if (dumbfile_getc(f) != 0x1A || dumbfile_igetw(f) != 0x203) {
|
||||
free(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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->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;
|
||||
}
|
||||
|
||||
sigdata->n_pchannels = dumbfile_igetw(f);
|
||||
|
||||
if (dumbfile_igetw(f) != 0) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dumbfile_skip(f, 2);
|
||||
|
||||
if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','F')) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dumbfile_skip(f, 16);
|
||||
|
||||
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_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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Orders, byte each, length = sigdata->n_orders (should be even) */
|
||||
dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f);
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_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);
|
||||
|
||||
_dumb_it_fix_invalid_orders(sigdata);
|
||||
|
||||
return sigdata;
|
||||
}
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_ptm_quick(DUMBFILE *f)
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_ptm_load_sigdata(f);
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readriff.c - Code to read a RIFF module file / / \ \
|
||||
* from memory. | < / \_
|
||||
* | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
#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 );
|
||||
|
||||
/* 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 *DUMBEXPORT 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 );
|
||||
|
||||
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;
|
||||
|
||||
riff_free( stream );
|
||||
|
||||
return duh;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue