mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2025-01-18 14:41:40 +00:00
Merge branch 'master' into openal
This commit is contained in:
commit
c249157876
235 changed files with 13078 additions and 18982 deletions
|
@ -1,6 +1,11 @@
|
|||
cmake_minimum_required( VERSION 2.4 )
|
||||
project(ZDoom)
|
||||
|
||||
if( COMMAND cmake_policy )
|
||||
cmake_policy( SET CMP0011 NEW )
|
||||
cmake_policy( SET CMP0054 NEW )
|
||||
endif( COMMAND cmake_policy )
|
||||
|
||||
list( APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} )
|
||||
include( CreateLaunchers )
|
||||
include( FindPackageHandleStandardArgs )
|
||||
|
@ -26,8 +31,6 @@ endif(CMAKE_CROSSCOMPILING)
|
|||
|
||||
# Simplify pk3 building, add_pk3(filename srcdirectory)
|
||||
function( add_pk3 PK3_NAME PK3_DIR )
|
||||
get_target_property(ZIPDIR_EXE zipdir LOCATION)
|
||||
|
||||
# Generate target name. Just use "pk3" for main pk3 target.
|
||||
string( REPLACE "." "_" PK3_TARGET ${PK3_NAME} )
|
||||
if( ${PK3_TARGET} STREQUAL "zdoom_pk3" )
|
||||
|
@ -36,20 +39,22 @@ function( add_pk3 PK3_NAME PK3_DIR )
|
|||
|
||||
if( NOT NO_GENERATOR_EXPRESSIONS AND NOT ZDOOM_OUTPUT_OLDSTYLE )
|
||||
add_custom_command( OUTPUT ${ZDOOM_OUTPUT_DIR}/${PK3_NAME}
|
||||
COMMAND ${ZIPDIR_EXE} -udf ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ${PK3_DIR}
|
||||
COMMAND zipdir -udf ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ${PK3_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} $<TARGET_FILE_DIR:zdoom>/${PK3_NAME}
|
||||
DEPENDS zipdir )
|
||||
else( NOT NO_GENERATOR_EXPRESSIONS AND NOT ZDOOM_OUTPUT_OLDSTYLE )
|
||||
add_custom_command( OUTPUT ${ZDOOM_OUTPUT_DIR}/${PK3_NAME}
|
||||
COMMAND ${ZIPDIR_EXE} -udf ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ${PK3_DIR}
|
||||
COMMAND zipdir -udf ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ${PK3_DIR}
|
||||
DEPENDS zipdir )
|
||||
endif( NOT NO_GENERATOR_EXPRESSIONS AND NOT ZDOOM_OUTPUT_OLDSTYLE )
|
||||
|
||||
# Touch the zipdir executable here so that the pk3s are forced to rebuild
|
||||
# each time since their dependecy has "changed."
|
||||
add_custom_target( ${PK3_TARGET} ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${ZIPDIR_EXE}
|
||||
DEPENDS ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} )
|
||||
if( NOT NO_GENERATOR_EXPRESSIONS )
|
||||
# Touch the zipdir executable here so that the pk3s are forced to
|
||||
# rebuild each time since their dependecy has "changed."
|
||||
add_custom_target( ${PK3_TARGET} ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E touch $<TARGET_FILE:zipdir>
|
||||
DEPENDS ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} )
|
||||
endif( NOT NO_GENERATOR_EXPRESSIONS )
|
||||
endfunction( add_pk3 )
|
||||
|
||||
# Macro for building libraries without debugging information
|
||||
|
|
|
@ -44,6 +44,8 @@ if(__create_launchers)
|
|||
endif()
|
||||
set(__create_launchers YES)
|
||||
|
||||
cmake_policy( SET CMP0026 OLD )
|
||||
|
||||
include(CleanDirectoryList)
|
||||
|
||||
# We must run the following at "include" time, not at function call time,
|
||||
|
@ -184,7 +186,7 @@ macro(_launcher_process_args)
|
|||
set(USERFILE_ENV_COMMANDS)
|
||||
foreach(_arg "${RUNTIME_LIBRARIES_ENVIRONMENT}" ${ENVIRONMENT})
|
||||
string(CONFIGURE
|
||||
"@USERFILE_ENVIRONMENT@@LAUNCHER_LINESEP@@_arg@"
|
||||
"${USERFILE_ENVIRONMENT}${LAUNCHER_LINESEP}${_arg}"
|
||||
USERFILE_ENVIRONMENT
|
||||
@ONLY)
|
||||
string(CONFIGURE
|
||||
|
|
|
@ -5,13 +5,6 @@ make_release_only()
|
|||
include( CheckFunctionExists )
|
||||
include( CheckCXXCompilerFlag )
|
||||
|
||||
# DUMB is much slower in a Debug build than a Release build, so we force a Release
|
||||
# build here, since we're not maintaining DUMB, only using it.
|
||||
# Comment out the below line to allow Debug builds.
|
||||
if( NOT CMAKE_BUILD_TYPE MATCHES "Release" )
|
||||
set( CMAKE_BUILD_TYPE "RelWithDebInfo" )
|
||||
endif( NOT CMAKE_BUILD_TYPE MATCHES "Release" )
|
||||
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -DDEBUGMODE=1" )
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
|
||||
|
@ -26,82 +19,92 @@ endif( NOT ITOA_EXISTS )
|
|||
include_directories( include )
|
||||
|
||||
add_library( dumb
|
||||
src/core/atexit.c
|
||||
src/core/duhlen.c
|
||||
src/core/duhtag.c
|
||||
src/core/dumbfile.c
|
||||
src/core/loadduh.c
|
||||
src/core/makeduh.c
|
||||
src/core/rawsig.c
|
||||
src/core/readduh.c
|
||||
src/core/register.c
|
||||
src/core/rendduh.c
|
||||
src/core/rendsig.c
|
||||
src/core/unload.c
|
||||
src/helpers/barray.c
|
||||
src/helpers/blip_buf.c
|
||||
src/helpers/clickrem.c
|
||||
src/helpers/memfile.c
|
||||
src/helpers/resample.c
|
||||
src/helpers/riff.c
|
||||
src/helpers/sampbuf.c
|
||||
src/helpers/silence.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/it/filter.cpp
|
||||
src/it/itload.c
|
||||
src/it/itload2.c
|
||||
src/it/itmisc.c
|
||||
src/it/itorder.c
|
||||
src/it/itread.c
|
||||
src/it/itread2.c
|
||||
src/it/itrender.c
|
||||
src/it/itunload.c
|
||||
src/it/load669.c
|
||||
src/it/load6692.c
|
||||
src/it/loadasy.c
|
||||
src/it/loadasy2.c
|
||||
src/it/loadmod.c
|
||||
src/it/loadmod2.c
|
||||
src/it/loadmtm.c
|
||||
src/it/loadmtm2.c
|
||||
src/it/loadokt.c
|
||||
src/it/loadokt2.c
|
||||
src/it/loadoldpsm.c
|
||||
src/it/loadoldpsm2.c
|
||||
src/it/loadpsm.c
|
||||
src/it/loadpsm2.c
|
||||
src/it/loadptm.c
|
||||
src/it/loadptm2.c
|
||||
src/it/loadriff.c
|
||||
src/it/loadriff2.c
|
||||
src/it/loads3m.c
|
||||
src/it/loads3m2.c
|
||||
src/it/loadstm.c
|
||||
src/it/loadstm2.c
|
||||
src/it/loadxm.c
|
||||
src/it/loadxm2.c
|
||||
src/it/ptmeffect.c
|
||||
src/it/read669.c
|
||||
src/it/read6692.c
|
||||
src/it/readam.c
|
||||
src/it/readasy.c
|
||||
src/it/readdsmf.c
|
||||
src/it/readmod.c
|
||||
src/it/readmod2.c
|
||||
src/it/readmtm.c
|
||||
src/it/readokt.c
|
||||
src/it/readokt2.c
|
||||
src/it/readoldpsm.c
|
||||
src/it/readpsm.c
|
||||
src/it/readptm.c
|
||||
src/it/readriff.c
|
||||
src/it/reads3m.c
|
||||
src/it/reads3m2.c
|
||||
src/it/readstm.c
|
||||
src/it/readstm2.c
|
||||
src/it/readxm.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/xmeffect.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( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
|
|
2555
dumb/ChangeLog
2555
dumb/ChangeLog
File diff suppressed because it is too large
Load diff
118
dumb/cmake/CMakeLists.txt
Normal file
118
dumb/cmake/CMakeLists.txt
Normal file
|
@ -0,0 +1,118 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
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(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
|
||||
INSTALL(FILES ${INSTALL_HEADERS} DESTINATION include/)
|
||||
INSTALL(TARGETS dumb
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
30
dumb/cmake/readme.txt
Normal file
30
dumb/cmake/readme.txt
Normal file
|
@ -0,0 +1,30 @@
|
|||
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,281 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* deprec.txt - Deprecated functions, why they / / \ \
|
||||
* were deprecated, and what to do | < / \_
|
||||
* instead. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
|
||||
**********************************************
|
||||
*** How the functions have been deprecated ***
|
||||
**********************************************
|
||||
|
||||
|
||||
GCC 3.1 and later provide a very useful attribute. The following:
|
||||
|
||||
__attribute__((__deprecated__))
|
||||
|
||||
when written alongside a function prototype, variable declaration or type
|
||||
definition, will result in a warning from GCC if any such part of the API
|
||||
is used. The warning will even tell you where the declaration is, and I
|
||||
have inserted comments by all the deprecated declarations, telling you
|
||||
what to do.
|
||||
|
||||
Unfortunately, GCC 2.x and 3.0.x and MSVC do not have any means to
|
||||
deprecate things. The approach I have taken with these compilers is to
|
||||
avoid prototyping the deprecated parts of the API. This means you will get
|
||||
warnings and errors, and they won't be very helpful. If your program
|
||||
compiles, you may get strange crashes when you run it, since the compiler
|
||||
needs the declarations in order to make sure function calls are carried
|
||||
out correctly.
|
||||
|
||||
If you would like the deprecated parts of the API to be declared, you can
|
||||
compile with the -DDUMB_DECLARE_DEPRECATED switch for GCC, or the
|
||||
-D"DUMB_DECLARE_DEPRECATED" switch for MSVC. This will be accepted by
|
||||
GCC 3.x but is unnecessary. Use this switch with other people's projects
|
||||
if necessary, but please make the effort to update your own projects to
|
||||
use the new API, as the deprecated parts may be removed in the future.
|
||||
|
||||
The rest of this file explains why some parts of the API were deprecated,
|
||||
and how to adapt your code.
|
||||
|
||||
|
||||
**************************************
|
||||
*** What happened to DUH_RENDERER? ***
|
||||
**************************************
|
||||
|
||||
|
||||
The DUH_RENDERER struct was designed for rendering audio to an end-user
|
||||
format - 8-bit or 16-bit, signed or unsigned, with stereo samples
|
||||
interleaved. In order for it to do this, it was built on top of the
|
||||
hitherto undocumented DUH_SIGRENDERER struct, which rendered audio in
|
||||
DUMB's internal 32-bit signed format with channels (left/right) stored
|
||||
separately. The DUH_RENDERER struct contained a pointer to a
|
||||
DUH_SIGRENDERER struct, along with some other data like the position and
|
||||
number of channels.
|
||||
|
||||
There were then some developments in the API. The DUH_SIGRENDERER struct
|
||||
also stored the position and the number of channels, so I decided to write
|
||||
functions for returning these. Suddenly there was no need to store them in
|
||||
the DUH_RENDERER struct. Before long, the DUH_RENDERER struct contained
|
||||
nothing but a pointer to a DUH_SIGRENDERER.
|
||||
|
||||
I decided it would be a good idea to unify the structs. After all, there
|
||||
really is no difference between the data stored in each, and it would be
|
||||
easy to make duh_render(DUH_RENDERER *dr, ...) and
|
||||
duh_render_signal(DUH_SIGRENDERER *sr, ...) work on the same type of
|
||||
struct. (Note that duh_render_signal() is now deprecated too; see the next
|
||||
section.) It took some deliberation, but I decided I didn't want functions
|
||||
to be #defined (it prevents you from using these names for member
|
||||
functions in C++ classes), and that meant they had to be defined
|
||||
somewhere. Defining redundant functions is a source of bloat, inefficiency
|
||||
and general inelegance. After weighing things up, I decided it was better
|
||||
to deprecate the redundant functions and have people begin to use the more
|
||||
efficient versions, and eventually the redundant functions will be able to
|
||||
be removed.
|
||||
|
||||
So why did I choose to keep the more complicated name, DUH_SIGRENDERER?
|
||||
The reason has to do with what DUMB will become in the future. Signals are
|
||||
an inherent part of the DUH struct and how .duh files will be constructed.
|
||||
It will be possible to have multiple signals in a single DUH struct, and
|
||||
you will be able to choose which one you want to play (this is the 'sig'
|
||||
parameter passed to duh_start_sigrenderer()). But don't hold your breath;
|
||||
we still have a long way to go before .duh files will start to appear...
|
||||
|
||||
|
||||
typedef DUH_SIGRENDERER DUH_RENDERER;
|
||||
|
||||
Wherever you are using DUH_RENDERER in your program, simply replace it
|
||||
with DUH_SIGRENDERER. An automated (case-sensitive!) search and replace
|
||||
operation should get this done.
|
||||
|
||||
|
||||
DUH_RENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos);
|
||||
|
||||
Use duh_start_sigrenderer() instead. It takes an extra parameter, 'sig',
|
||||
which comes after 'duh' and before 'n_channels'; pass 0 for this. So an
|
||||
example would be, replace:
|
||||
|
||||
sr = duh_start_renderer(duh, 2, 0);
|
||||
|
||||
with:
|
||||
|
||||
sr = duh_start_sigrenderer(duh, 0, 2, 0);
|
||||
|
||||
|
||||
int duh_renderer_get_n_channels(DUH_RENDERER *dr);
|
||||
long duh_renderer_get_position(DUH_RENDERER *dr);
|
||||
void duh_end_renderer(DUH_RENDERER *dr);
|
||||
|
||||
These are easy enough to fix; all you have to do is replace 'renderer'
|
||||
with 'sigrenderer'. So the new functions are:
|
||||
|
||||
int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);
|
||||
long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer);
|
||||
void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer);
|
||||
|
||||
|
||||
Note that duh_render() has NOT been deprecated. It now uses DUH_SIGRENDERER
|
||||
instead of DUH_RENDERER, but its functionality is unchanged. You do not have
|
||||
to change calls to this function in any way.
|
||||
|
||||
|
||||
DUH_RENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sr);
|
||||
DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_RENDERER *dr);
|
||||
DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_RENDERER *dr);
|
||||
|
||||
These functions did not exist in the last release of DUMB, so you are
|
||||
probably not using them, but they are included here for completeness. All
|
||||
you have to do here is unwrap the function, since the structs have been
|
||||
unified. So, for instance, replace:
|
||||
|
||||
duh_renderer_encapsulate_sigrenderer(my_sigrenderer)
|
||||
|
||||
with:
|
||||
|
||||
my_sigrenderer
|
||||
|
||||
Simple!
|
||||
|
||||
|
||||
AL_DUH_PLAYER *al_duh_encapsulate_renderer(DUH_RENDERER *dr,
|
||||
float volume, long bufsize, int freq);
|
||||
DUH_RENDERER *al_duh_get_renderer(AL_DUH_PLAYER *dp);
|
||||
DUH_RENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp);
|
||||
|
||||
Again, these functions were not in the last release, so you probably
|
||||
aren't using them. Nevertheless, the fix is simple as always: simply
|
||||
replace 'renderer' with 'sigrenderer'. So the new functions are:
|
||||
|
||||
AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer(DUH_SIGRENDERER *sr,
|
||||
float volume, long bufsize, int freq);
|
||||
DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp);
|
||||
DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp);
|
||||
|
||||
|
||||
*********************
|
||||
*** Miscellaneous ***
|
||||
*********************
|
||||
|
||||
|
||||
long duh_render_signal(DUH_SIGRENDERER *sigrenderer,
|
||||
float volume, float delta,
|
||||
long size, sample_t **samples);
|
||||
|
||||
This function used to return samples in DUMB's internal format. This
|
||||
format consisted of 32-bit integers whose 'normal range' was -0x8000 to
|
||||
0x7FFF (any samples outside this range would have to be clipped when sent
|
||||
to the sound card).
|
||||
|
||||
DUMB's internal format has changed. DUMB still uses 32-bit integers, but
|
||||
now the normal range is -0x800000 to 0x7FFFFF. The lowest eight bits are
|
||||
discarded at the final stage by duh_render() when you ask for 16-bit
|
||||
output. A new function, duh_sigrenderer_get_samples(), will return samples
|
||||
in DUMB's new internal format. It takes exactly the same parameters, so
|
||||
all you have to do to the call itself is change the name; however, you
|
||||
will most likely have to change your code to account for the new
|
||||
normalised range.
|
||||
|
||||
duh_render_signal() will still be able to give you the samples in DUMB's
|
||||
old internal format, but it is inefficient. You should change your code as
|
||||
soon as possible.
|
||||
|
||||
|
||||
typedef void (*DUH_SIGRENDERER_CALLBACK)(void *data, sample_t **samples,
|
||||
int n_channels, long length);
|
||||
|
||||
void duh_sigrenderer_set_callback(DUH_SIGRENDERER *sigrenderer,
|
||||
DUH_SIGRENDERER_CALLBACK callback, void *data);
|
||||
|
||||
This callback was intended to allow you to analyse the output. It was by
|
||||
no means intended to let you modify the output. For this reason, the names
|
||||
have been changed to DUH_SIGRENDERER_ANALYSER_CALLBACK and
|
||||
duh_sigrenderer_set_analyser_callback, and the 'samples' parameter to your
|
||||
callback should now be specified as follows:
|
||||
|
||||
const sample_t *const *samples
|
||||
|
||||
The first 'const' indicates that you must not modify the samples. The
|
||||
second indicates that you must not modify the pointers to each channel.
|
||||
|
||||
There is a second reason why this change was necessary, and it is the one
|
||||
described further up for duh_render_signal()'s entry: the format in which
|
||||
the samples themselves are stored has changed. They are 256 times as
|
||||
large, with a normal range from -0x800000 to 0x7FFFFF. You will most
|
||||
likely need to change your code to account for this.
|
||||
|
||||
If you try to call the old function, it will print a message to stderr
|
||||
directing you to this file, and it will not install the callback. You
|
||||
shouldn't be able to get this far without a compiler warning (or, if you
|
||||
don't have GCC 3.1 or later, some compiler errors).
|
||||
|
||||
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 at the bottom of this file.
|
||||
|
||||
For reference, here are the new definitions:
|
||||
|
||||
typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data,
|
||||
const sample_t *const *samples, int n_channels, long length);
|
||||
|
||||
void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer,
|
||||
DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data);
|
||||
|
||||
|
||||
int dumb_resampling_quality;
|
||||
|
||||
This variable has changed meaning. It used to hold a value from 0 to 4,
|
||||
whose meaning was as follows:
|
||||
|
||||
0 - aliasing
|
||||
1,2 - linear interpolation
|
||||
3 - quadratic interpolation
|
||||
4 - cubic interpolation
|
||||
|
||||
0,1 - always use a straightforward interpolation algorithm
|
||||
2,3,4 - when decimating (increasing the pitch), use a linear average
|
||||
algorithm designed to reduce frequencies that would otherwise
|
||||
reflect off the Nyquist
|
||||
|
||||
Now the variable only holds values from 0 to 2, and these values have
|
||||
preprocessor constants associated with them. The somewhat inappropriate
|
||||
quadratic interpolation has been removed. The linear average algorithm has
|
||||
also been removed, and may or may not come back; there are probably more
|
||||
efficient ways of achieving the same effect, which I shall be
|
||||
investigating in the future.
|
||||
|
||||
This change will have hardly any noticeable effect on existing programs.
|
||||
Levels 2, 3 and 4 used considerably more processor time because of the
|
||||
linear average algorithm. Likewise, Level 2 in the new scheme (cubic) uses
|
||||
considerably more processor time than Levels 1 and 0, and Levels 3 and 4
|
||||
will behave identically to Level 2.
|
||||
|
||||
|
||||
******************
|
||||
*** Conclusion ***
|
||||
******************
|
||||
|
||||
|
||||
"I conclude that... DUMB is the bestest music player in the world because...
|
||||
Complete this sentence in fifteen words or fewer... D'OH!"
|
||||
|
||||
The preceding conclusion formerly appeared in dumb.txt, and is deprecated
|
||||
because it's lame.
|
||||
|
||||
|
||||
Ben Davis
|
||||
entheh@users.sf.net
|
||||
IRC EFnet #dumb
|
||||
See readme.txt for details on using IRC.
|
|
@ -1,296 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* duhspecs.txt - DUH File Specifications. / / \ \
|
||||
* | < / \_
|
||||
* Written by entheh, one of the few programmers | \/ /\ /
|
||||
* in existance who can spell correctly. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
Technical Details
|
||||
=================
|
||||
|
||||
WARNING: until this warning disappears, the DUH file format could change at
|
||||
any moment. This should not be of great concern, since DUH files are not
|
||||
designed to be edited directly, but will always be generated from some other
|
||||
format. However, it is our intention that this warning be removed before the
|
||||
first release.
|
||||
|
||||
This document is written chiefly in the context of writing a DUH file, since
|
||||
the library already contains the necessary functionality to read and play a
|
||||
DUH file.
|
||||
|
||||
DUH files are currently saved using Allegro's file compression routines. See
|
||||
Allegro's documentation and source code for details on this system. If you
|
||||
wish to port DUMB away from Allegro and wish to preserve the file compression
|
||||
capabilities, you will have to borrow the packfile source code from Allegro.
|
||||
|
||||
If you are happy to do away with file compression, please store the following
|
||||
four-byte signature before the rest of the file: "slh." Alternatively, write
|
||||
your DUH file writer with Allegro, and open the file with F_WRITE_NOPACK.
|
||||
This will enable versions of the library using Allegro's file compression
|
||||
routines to load the file. If you are reading a DUH file and you detect the
|
||||
signature "slh!", then the file is compressed (and is not necessarily a DUH
|
||||
file).
|
||||
|
||||
All numbers are little-endian unless specified otherwise. Allegro's
|
||||
pack_iget*() and pack_iput*() functions can be used to read and write data in
|
||||
this format. However, the four-byte signatures can be encoded into long ints
|
||||
with AL_ID() and read and written with pack_m*().
|
||||
|
||||
|
||||
Overall Structure
|
||||
=================
|
||||
|
||||
Size Type Value Example C code to save to PACKFILE *f
|
||||
|
||||
4 ID "DUH!" pack_mputl(AL_ID('D','U','H','!'), f);
|
||||
4 Int Number of signals pack_iputl(n_signals, f);
|
||||
|
||||
For each signal { for (i = 0; i < n_signals; i++) {
|
||||
4 ID Signal type pack_mputl(AL_ID('S','E','Q','U'), f);
|
||||
* - Signal data write_sequence(f);
|
||||
} }
|
||||
|
||||
* The size of the data for any signal must either be constant or somehow
|
||||
encoded in the data themselves. The library contains functions to read
|
||||
various standard signal types, including "SAMP" and "SEQU" (sample and
|
||||
sequence respectively), and the formats for these types are laid out
|
||||
further down. If you wish to create your own signals, you must provide your
|
||||
own loading function for the signal. This will be described in more detail
|
||||
in a separate file.
|
||||
|
||||
In order to play a DUH file, we simply play the first signal. Signals can
|
||||
construct their sound from the samples of other signals, and they in turn can
|
||||
use other signals. Thus a recursive structure is built up. Recursive cycles
|
||||
are not permitted.
|
||||
|
||||
|
||||
Signal: SAMP (Sample)
|
||||
=====================
|
||||
|
||||
Size Type Value Example C code to save to PACKFILE *f
|
||||
|
||||
4 Int Size pack_iputl(size, f);
|
||||
1 Bits Flags pack_putc(flags, f);
|
||||
1 ID Compression type pack_putc(compress, f); /* NOT IMPLEMENTED YET */
|
||||
|
||||
The flags are stored in a bit-field. Bit 0 indicates whether 16-bit samples
|
||||
(set) or 8-bit samples (clear) are stored in the file. In both cases, the
|
||||
samples are signed. NOTE: this bit might be replaced with a system allowing
|
||||
for various sample compression algorithms, or altered so there are different
|
||||
signal types for the purpose.
|
||||
|
||||
If Bit 1 is set, the sample is a looping sample, and loops indefinitely. In
|
||||
this case the loop start point will be saved. The loop end point is not
|
||||
saved, and is assumed to be the end of the sample. (When creating DUH files
|
||||
from other formats which allow for the loop end to be earlier, you should
|
||||
truncate the sample.)
|
||||
|
||||
If Bit 1 is not set, then Bit 2 may be set to indicate that the sample is
|
||||
looping but only loops a finite number of times before continuing to play
|
||||
normally. In this mode, both loop points (start and end) are saved in the
|
||||
file. The number of times to loop will be specified on an instance-by-
|
||||
instance basis using signal parameter #0, which should be set immediately
|
||||
(before any samples are rendered) if it is to be set at all. It defaults to 0
|
||||
(so the sample just plays through normally). In fact this parameter's value
|
||||
is added to the loop count, but this is immaterial since there is no reason
|
||||
to specify it more than once.
|
||||
|
||||
If Bit 1 is set, you should make sure Bit 2 is clear to allow for the
|
||||
possibility of future expansion.
|
||||
|
||||
If Bit 3 is set, a ping-pong loop is used. When the sample reaches the loop
|
||||
end point, it starts to play backwards until it reaches the loop start point,
|
||||
at which time it will resume forward playback. When using a finite loop,
|
||||
every change of direction counts as one iteration. That means an odd loop
|
||||
count will cause the sample to proceed backwards when the looping ends.
|
||||
|
||||
If neither Bit 1 nor Bit 2 is set, then neither loop point will be saved. In
|
||||
this case, you should also make sure Bit 3 is clear for the same reason as
|
||||
above.
|
||||
|
||||
You may find the following definitions useful:
|
||||
|
||||
#define SAMPFLAG_16BIT 1
|
||||
#define SAMPFLAG_LOOP 2
|
||||
#define SAMPFLAG_XLOOP 4
|
||||
#define SAMPFLAG_PINGPONG 8
|
||||
|
||||
#define SAMPPARAM_N_LOOPS 0
|
||||
|
||||
Size Type Value Example C code to save to PACKFILE *f
|
||||
|
||||
4 Int Loop start pack_iputl(loop_start, f);
|
||||
4 Int Loop end pack_iputl(loop_end, f);
|
||||
|
||||
For a 16-bit sample: if (flags & SAMPFLAG_16BIT)
|
||||
for (n = 0; n < size; n++)
|
||||
x*2 Int Sample data pack_iputw(sample[n], f);
|
||||
For an 8-bit sample: else
|
||||
for (n = 0; n < size; n++)
|
||||
x*1 Int Sample data pack_putc(sample[n], f);
|
||||
|
||||
/*
|
||||
Compression type is 0 for uncompressed PCM.
|
||||
*/
|
||||
|
||||
|
||||
Signal: SEQU (Sequence)
|
||||
=======================
|
||||
|
||||
Size Type Value Example C code to save to PACKFILE *f
|
||||
|
||||
4 Int Size size = pack_igetl(f);
|
||||
x - Sequencing data pack_fwrite(data, size, f);
|
||||
|
||||
The sequence signal provides a medium in which other signals can be played at
|
||||
specific times for specific lengths. You can control the pitch, volume and
|
||||
other parameters for a signal, and these can change during the signal.
|
||||
|
||||
A sequence consists of a series of commands. Each command is preceded by a
|
||||
time, which measures how long to wait before executing this command. A time
|
||||
of zero indicates that this command is simultaneous with the previous. A time
|
||||
of -1 indicates the end of the sequence. Note that signals do not stop
|
||||
playing when the end is reached.
|
||||
|
||||
All times are measured in units such that 65536 corresponds to one second.
|
||||
The timing in DUMB is accurate to the nearest sample, and cannot be offset in
|
||||
the way it can with much mixing software, so you can rely on timing to
|
||||
achieve certain effects. Resampling should be accurate enough to satisfy the
|
||||
most acute musician's ear, but juggling pitches at this level of accuracy
|
||||
requires knowledge of temperaments such as many musicians do not have. The
|
||||
vast majority of people are satisfied with the even temperament. More on this
|
||||
later.
|
||||
|
||||
Size Type Value Example C code to save to PACKFILE *f
|
||||
|
||||
4 Int Time pack_iputl(time, f);
|
||||
1 ID Command pack_putc(SEQUENCE_START_SIGNAL, f);
|
||||
|
||||
/********************************
|
||||
Proposed change:
|
||||
Time is a short, encoded in 2 bytes.
|
||||
The value of 'time' is actually an unsigned offset from the time of the
|
||||
previous command. 0 means at the same time as the last command.
|
||||
If the time in between this signal and the previous one is larger than
|
||||
65534 ticks, then the value 65535 is written, followed by 4 more bytes (uint)
|
||||
indicating the time offset.
|
||||
**********************************/
|
||||
|
||||
Here are definitions for the various commands:
|
||||
|
||||
#define SEQUENCE_START_SIGNAL 0
|
||||
#define SEQUENCE_SET_VOLUME 1
|
||||
#define SEQUENCE_SET_PITCH 2
|
||||
#define SEQUENCE_SET_PARAMETER 3
|
||||
#define SEQUENCE_STOP_SIGNAL 4
|
||||
|
||||
Below are the details of what to write after each command code. The various
|
||||
fields are explained afterwards.
|
||||
|
||||
Size Type Value Example C code to save to PACKFILE *f
|
||||
|
||||
SEQUENCE_START_SIGNAL:
|
||||
1 ID Reference pack_putc(ref, f);
|
||||
4 Int Signal pack_iputl(signal, f); /* --> Can we drop this to 2 bytes? (65536 signals) */
|
||||
4 Int Starting position pack_iputl(pos, f);
|
||||
2 Int Volume pack_iputw(volume, f);
|
||||
2 Int Pitch pack_iputw(pitch, f);
|
||||
|
||||
SEQUENCE_SET_VOLUME:
|
||||
1 ID Reference pack_putc(ref, f);
|
||||
2 Int Volume pack_iputw(volume, f);
|
||||
|
||||
SEQUENCE_SET_PITCH:
|
||||
1 ID Reference pack_putc(ref, f);
|
||||
2 Int Pitch pack_iputw(pitch, f);
|
||||
|
||||
SEQUENCE_SET_PARAMETER:
|
||||
1 ID Reference pack_putc(ref, f);
|
||||
1 ID Parameter ID pack_putc(id, f);
|
||||
4 Int Value pack_iputl(value, f);
|
||||
|
||||
SEQUENCE_STOP_SIGNAL:
|
||||
1 ID Reference pack_putc(ref, f);
|
||||
|
||||
When you initiate a signal, you must choose a reference number. If you want
|
||||
to modify the signal's volume, pitch or parameters, or stop the signal later,
|
||||
you must use this reference number to do so. Need more than 256 reference
|
||||
numbers? Use two sequences, and get your brain seen to.
|
||||
|
||||
If you initiate a new signal with the same reference number, the reference
|
||||
will belong to the new signal. The old signal becomes anonymous, and will
|
||||
either continue to play indefinitely or stop of its own accord. Even if the
|
||||
new signal stops, the old one remains anonymous. DUMB will safely ignore
|
||||
operations on reference numbers not used by any signal, or which were used by
|
||||
a signal which has now stopped.
|
||||
|
||||
Of course all signals will stop if the sequence itself is stopped.
|
||||
|
||||
To initiate a signal, you must index the signal. The index is 0-based, so to
|
||||
initiate the fifth signal in the file you must specify 4. Out-of-range values
|
||||
will be handled safely, as will the case where a signal tries to generate
|
||||
itself directly or indirectly from its own samples (a recursive cycle).
|
||||
|
||||
When you initiate a signal, you can specify a starting position. This will be
|
||||
passed directly to the appropriate signal's start_samples function, so for a
|
||||
SAMP (sample) signal it represents the sample on which to start, after any
|
||||
loops have been expanded (so you can start on the backwards-playing part of
|
||||
a ping-pong loop for example by careful choice of the starting position).
|
||||
|
||||
Volume is probably the simplest parameter. It is on a linear scale ranging
|
||||
from 0 to 65535. Note that most music sounds more dramatic if the volume
|
||||
rises and falls exponentially or on a greater curve. Linear fades are more
|
||||
suitable for fading in and out, and do not sound dramatic in the least.
|
||||
|
||||
Pitch is specified on what is perceived as a linear scale. It is in fact
|
||||
logarithmic, but you will not need to worry about this for most purposes.
|
||||
Pitch 0 represents that the sample will be played at 65536 Hz. (This is not
|
||||
strictly true, and will be explained further later.) In the likely case that
|
||||
your sample is not recorded at 65536 Hz, you will first need to calculate the
|
||||
central pitch. Use the following formula:
|
||||
|
||||
pitch_centre = 12 * 256 * log(sampling_frequency / 65536.0) / log(2);
|
||||
|
||||
If your programming language does not have a log function, look for ln, or
|
||||
any function that calculates the logarithm (to any base) of the number you
|
||||
give it. If you are lucky enough to find a logarithm to base 2, you can omit
|
||||
the final division since the divisor evaluates to 1.
|
||||
|
||||
Once you have calculated pitch_centre, you can use it to play the sample at
|
||||
the frequency at which it was recorded. Each time you add or subtract 256,
|
||||
the sample will increase or decrease respectively in pitch by one semitone in
|
||||
the even temperament. (The even temperament was noted further up as being
|
||||
suitable for most musical applications.) One octave is represented by an
|
||||
interval of 12 * 256.
|
||||
|
||||
If you wish to use another temperament, you can calculate the appropriate
|
||||
intervals in pitch as follows:
|
||||
|
||||
pitch_interval = 12 * 256 * log(ratio) / log(2);
|
||||
|
||||
where, for example, ratio = 1.5 for a perfect fifth. An octave is, of course,
|
||||
still represented by 12 * 256.
|
||||
|
||||
The SEQUENCE_SET_PARAMETER command needs little explanation. Quite simply,
|
||||
the parameter ID and value you specify are passed on to the set_parameter
|
||||
function of the signal to which this reference belongs. Exactly what this
|
||||
does depends on the signal in question.
|
||||
|
||||
Remember, a sequence is a signal in itself. Like all signals, it is subject
|
||||
to changes in pitch. Increasing the pitch of a sequence will also speed it
|
||||
up. This capability is used to allow DUH files to be rendered at different
|
||||
sampling frequencies, and it is also available for use by the musician. This
|
||||
means that samples are only played at 65536 Hz if the pitch of the sequence
|
||||
itself has not been adjusted.
|
1699
dumb/docs/dumb.txt
1699
dumb/docs/dumb.txt
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,264 +0,0 @@
|
|||
TO DO: add question regarding set_close_button_callback vs set_window_close_hook
|
||||
TO DO: add question regarding mixing of DJGPP and MinGW object files
|
||||
|
||||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* faq.txt - Frequently Asked Questions. / / \ \
|
||||
* | < / \_
|
||||
* This file covers some of the common problems | \/ /\ /
|
||||
* and misconceptions people have with DUMB. If \_ / > /
|
||||
* your problem is not covered here, please | \ / /
|
||||
* contact me. I'll do my best to help - but | ' /
|
||||
* don't be offended if I just direct you to the \__/
|
||||
* manual!
|
||||
*/
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* I get a lot of strange warnings and errors when I compile my projects *
|
||||
* with this release of DUMB. They work with older versions! What happened? *
|
||||
*****************************************************************************
|
||||
|
||||
Some parts of DUMB's API have been deprecated. See docs/deprec.txt for
|
||||
full details, including an explanation as to why your compiler warnings
|
||||
and errors are so unfriendly, and information on how to fix each warning
|
||||
or error.
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* When I try to compile DUMB with Allegro, it complains that it cannot find *
|
||||
* 'internal/alconfig.h'! What's wrong? *
|
||||
*****************************************************************************
|
||||
|
||||
In Allegro 4.0.1, and quite likely some other versions of Allegro, the
|
||||
msvcmake batch file does not install Allegro properly. I believe this was
|
||||
fixed in Allegro 4.0.2, but don't take my word for it. Some include files
|
||||
are neglected, including alconfig.h. The fix is quite easy; you need to
|
||||
copy all of Allegro's include files to your compiler's directory. The
|
||||
following should do this for you (alter it accordingly depending on where
|
||||
MSVC and Allegro are installed):
|
||||
|
||||
cd\progra~1\msvc\include
|
||||
xcopy/s \allegro\include\*.*
|
||||
|
||||
You can safely tell it to overwrite all files.
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* When I build a project that uses DUMB, I get an error that it doesn't *
|
||||
* find -laldmbd! What's wrong? *
|
||||
*****************************************************************************
|
||||
|
||||
See the notes for DUMB v0.8 in release.txt; the existence of libaldmbd.a
|
||||
in DUMB v0.7 was due to a mistake in the makefiles. It should be
|
||||
libaldmd.a, in order to maintain DOS compatibility. All subsequent
|
||||
releases get it right, but you will have to change your project files to
|
||||
allow for the change. If this is someone else's project, please let them
|
||||
know that it needs changing.
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* When I build a project that uses DUMB, I get some linker errors about *
|
||||
* _free, _malloc, etc. already being defined in LIBC.lib! What's wrong? *
|
||||
*****************************************************************************
|
||||
|
||||
MSVC offers three different implementations of the standard libraries.
|
||||
When you link statically with a library, you have to use the same
|
||||
implementation that the library uses. You need the multithreaded DLL
|
||||
implementation, which you can select by passing /MD when you compile (not
|
||||
when you link). See howto.txt for details.
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* I created an IT file with Impulse Tracker, but DUMB won't play it! Why? *
|
||||
*****************************************************************************
|
||||
|
||||
You probably created some patterns but didn't give any information on the
|
||||
order in which they should be played. Impulse Tracker will also fail to
|
||||
play your music if you press F5. Press F11 and you will have an
|
||||
opportunity to create an order list, required for playback.
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* I created an IT file with ModPlug Tracker and I have it fading out at the *
|
||||
* end. Why won't it loop when I play it with DUMB? *
|
||||
*****************************************************************************
|
||||
|
||||
It loops at zero volume. This is what Impulse Tracker itself does. Fix the
|
||||
IT file by setting the global volume explicitly (Vxx in the effects
|
||||
column), either at the start, or right at the end before looping. Also see
|
||||
the next two questions.
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* My module plays too loud and distorts badly with DUMB! What can I do? *
|
||||
*****************************************************************************
|
||||
|
||||
This problem is most often caused by ModPlug Tracker, which has a complete
|
||||
lack of regard for the playback volume of the original tracker. See the
|
||||
next question for DUMB's official position with regard to ModPlug Tracker.
|
||||
If you wrote your module with ModPlug Tracker, please try loading it with
|
||||
the original tracker and see if it distorts there too. If it does, reduce
|
||||
the volume. If not, then it's a problem with DUMB; please let me know.
|
||||
|
||||
If for whatever reason you cannot modify the module file itself, you can
|
||||
make it sound better by reducing the volume passed to al_start_duh().
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* I created a music module with ModPlug Tracker, and DUMB doesn't play it *
|
||||
* right! *
|
||||
*****************************************************************************
|
||||
|
||||
DUMB cannot and will not support ModPlug Tracker. Please see
|
||||
docs/modplug.txt for details. The original trackers, which DUMB is
|
||||
designed to mimic as closely as possible, are listed in readme.txt.
|
||||
If you find DUMB plays your module differently from the original tracker,
|
||||
then please contact me.
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* My program crashes as soon as I try to load anything with DUMB! *
|
||||
*****************************************************************************
|
||||
|
||||
Please take my advice and use the debugging build of DUMB, not the
|
||||
optimised build. Then you'll probably find it aborts instead of crashing.
|
||||
In this case you probably forgot to register a DUMBFILE system; this is
|
||||
necessary for loading stand-alone files, though not for loading Allegro
|
||||
datafiles with embedded music. Follow the instructions in docs/howto.txt
|
||||
carefully and you shouldn't have this problem.
|
||||
|
||||
If DUMB crashes with a specific music module, please let me know.
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* I want to use the stdio file access functions to load stand-alone music *
|
||||
* files, but I also want to load datafiles containing music files. The docs *
|
||||
* say I shouldn't call both dumb_register_stdfiles() and *
|
||||
* dumb_register_packfiles(). What shall I do? *
|
||||
*****************************************************************************
|
||||
|
||||
When you register a DUMBFILE system, it only applies to files opened with
|
||||
dumbfile_open(), i.e. separate files. When a file is embedded in a
|
||||
datafile, dumbfile_open_ex() is used to read it, enabling it to use
|
||||
PACKFILEs regardless of which DUMBFILE system is registered. In short, you
|
||||
do not need to call dumb_register_packfiles() in order to load datafiles
|
||||
with embedded music. See the section on "Sequential File Input" in
|
||||
docs/dumb.txt if you're interested in how all this works.
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* I want to read a specific object in a datafile using Allegro's *
|
||||
* "demo.dat#MY_MUSIC" syntax. Why won't it work? *
|
||||
*****************************************************************************
|
||||
|
||||
Did you call dumb_register_packfiles(), or did you call
|
||||
dumb_register_stdfiles()? It will only work if you use the former.
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* My program runs, but no music plays! What am I doing wrong? *
|
||||
*****************************************************************************
|
||||
|
||||
There are a number of possible causes for this. The most likely reason is
|
||||
that you aren't calling al_poll_duh(); see docs/howto.txt for further
|
||||
information.
|
||||
|
||||
Other possible causes are as follows:
|
||||
|
||||
- The speakers are turned down (duh)
|
||||
- The volume of some system mixer is turned down
|
||||
- Another program is using the sound card (not a problem for most modern
|
||||
systems)
|
||||
- You didn't initialise Allegro's sound system; see install_sound() in
|
||||
Allegro's docs
|
||||
- Allegro's drivers don't work on your system and chosen platform
|
||||
|
||||
In order to narrow down the cause, consider the following:
|
||||
|
||||
- Do you get any other sound from your program?
|
||||
- Do other Allegro+DUMB programs generate sound?
|
||||
- Do other Allegro programs generate sound?
|
||||
- Do other non-Allegro programs generate sound?
|
||||
- Does your program fail only on a specific platform (e.g. DOS but not
|
||||
Windows)?
|
||||
|
||||
This problem is highly system-specific; please try hard to solve it by
|
||||
yourself before contacting me. However, if you think this problem could
|
||||
affect other people, please let me know what the problem is and how you
|
||||
fixed it, if you did. Be as specific as possible.
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* The music stutters! What can I do? *
|
||||
*****************************************************************************
|
||||
|
||||
If you have an older computer, it may not be able to cope with the load.
|
||||
Try reducing quality options; look up dumb_resampling_quality and
|
||||
dumb_it_max_to_mix in docs/dumb.txt, and consider changing the frequency
|
||||
you pass to al_start_duh().
|
||||
|
||||
Stuttering may not be caused by excessive load. To find out, try
|
||||
increasing the buffer size passed to al_start_duh(). Beware of making it
|
||||
too big though; older systems will freeze periodically if it's too big,
|
||||
because they render larger chunks less frequently. The timing of callbacks
|
||||
will also be less accurate, if you are using those.
|
||||
|
||||
If you're using the 'dumbplay' example, you can control these parameters
|
||||
by editing dumb.ini.
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* Why does DUMB use so much processor time compared with other players? *
|
||||
*****************************************************************************
|
||||
|
||||
This should be less so in this release than in previous releases; the
|
||||
resampling and filtering algorithms have been optimised.
|
||||
|
||||
By default, DUMB uses the most expensive resampling quality option. I've
|
||||
found on an AthlonXP 1800+ and on a Pentium 233 that it typically uses
|
||||
about twice as much processor time as the least expensive option.
|
||||
|
||||
Try setting dumb_resampling_quality to DUMB_RQ_ALIASING or DUMB_RQ_LINEAR.
|
||||
See dumb.txt for more information. If you're using the example programs,
|
||||
you can control this variable by editing dumb.ini.
|
||||
|
||||
DUMB uses 32-bit ints for mixing. Some players use 16-bit ints, and are
|
||||
therefore marginally faster (not much!) and lower quality. So you can't
|
||||
expect DUMB to beat these players. Furthermore, DUMB is currently written
|
||||
entirely in C. GCC does an impressive job on the C code, but that's not to
|
||||
say some custom-written assembly language couldn't beat it ...
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* Why does DUMB generate so much background noise? *
|
||||
*****************************************************************************
|
||||
|
||||
You're probably using the DOS build on a system with bad Sound Blaster
|
||||
compatibility (most Windows XP systems fall in this category). This would
|
||||
mean DUMB could only access an 8-bit driver. The Windows build will almost
|
||||
certainly give better results. Your DOS binary will still give good
|
||||
results on systems with better compatibility (like my Windows 98 system).
|
||||
|
||||
|
||||
*****************************************************************************
|
||||
* I e-mailed you and you replied with "RTFM"! What does that mean? *
|
||||
*****************************************************************************
|
||||
|
||||
Read The Manual. If it's a specific problem, I'll probably be kind and
|
||||
tell you where to look in the manual. However, if I get the impression you
|
||||
haven't even looked for a solution in the manual, expect no mercy ...
|
||||
|
||||
|
||||
Ben Davis
|
||||
entheh@users.sf.net
|
||||
IRC EFnet #dumb
|
||||
See readme.txt for details on using IRC.
|
|
@ -1,113 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* fnptr.txt - Function pointer explanation. / / \ \
|
||||
* | < / \_
|
||||
* | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
|
||||
C allows you to create and use function pointers. A function pointer is a
|
||||
variable that points to a function, and you can use it to call that function.
|
||||
Why is this useful?
|
||||
|
||||
Function pointers can be passed as parameters. As an example, here's a
|
||||
function from Allegro:
|
||||
|
||||
void create_light_table(COLOR_MAP *table, const PALETTE pal, int r, g, b,
|
||||
void (*callback)(int pos));
|
||||
|
||||
Don't worry about the syntax just yet, but the last parameter, 'callback', is
|
||||
a pointer to a function that takes an int parameter. create_light_table() can
|
||||
take some time to complete its work, and you may want to display a progress
|
||||
indicator. So you write a function to draw the progress indicator, and then,
|
||||
for 'callback', you specify a pointer to your function. This will enable
|
||||
create_light_table() to call your function at intervals during its
|
||||
processing. (If you don't want to use the callback, you can pass NULL, but
|
||||
this only works because create_light_table() checks actively for NULL. You
|
||||
can't always specify NULL when you want nothing to happen.)
|
||||
|
||||
There are many other uses. In addition to using function pointers as
|
||||
parameters, Allegro has some global function pointers you can set to point to
|
||||
your functions. Function pointers can also be used in structs, and this is
|
||||
where DUMB makes the most use of them.
|
||||
|
||||
So how are they used?
|
||||
|
||||
void bar(void) { ... } /* Here's a function */
|
||||
void (*foo)(void) = &bar; /* Take a pointer */
|
||||
(*foo)(); /* Call the function */
|
||||
|
||||
char *baz(float a) { ... } /* Here's another function */
|
||||
char *(*foobarbaz)(float a) = &baz; /* Take a pointer */
|
||||
char *rv = (*foobarbaz)(0.1); /* Call the function */
|
||||
|
||||
In both these cases, note how the statement for calling the pointed-to
|
||||
function (third line) resembles the definition of the function pointer
|
||||
(second line). This is true of any variable in C, and can lead to some truly
|
||||
obfuscated definitions if you are that way inclined. Such definitions can be
|
||||
clarified with typedefs, but before you use those, it is important you
|
||||
understand how the above statements work. I speak from experience: function
|
||||
pointer notation looks random and scary, until you understand why it's the
|
||||
way it is; then it makes perfect sense.
|
||||
|
||||
(It is actually permissible to omit the & when taking a pointer and to write
|
||||
e.g. foobarbaz(0.1) instead of (*foobarbaz)(0.1). However, I recommend not
|
||||
doing this, since the syntax for using the pointer no longer resembles the
|
||||
definition. Writing e.g. (*foobarbaz)(0.1) also makes a clear distinction
|
||||
between function pointer calls and ordinary function calls, which makes code
|
||||
more readable.)
|
||||
|
||||
Note that function pointers have the return value and parameter list
|
||||
specified. A function pointer can only point to a function with a matching
|
||||
return value and matching parameters. (You can break this rule by casting the
|
||||
pointer explicitly, but there is no situation where doing so is portable to
|
||||
all computers, and I strongly advise against it unless you're writing system
|
||||
code. If you're not sure whether you're writing system code or not, then
|
||||
you're not.)
|
||||
|
||||
The parameter names need not match (although the types must). If you wish to
|
||||
rename a parameter in your function, you do not have to change the function
|
||||
pointer accordingly. In fact, when you define a function pointer, you don't
|
||||
even have to specify the names of parameters if you don't want to. I normally
|
||||
do so for clarity.
|
||||
|
||||
It is possible to typedef a function pointer. In order to typedef a function
|
||||
pointer, you start by declaring the pointer as a variable:
|
||||
|
||||
void (*myfunc)(void);
|
||||
|
||||
Then you write 'typedef' before it and replace the variable name, which is
|
||||
myfunc, with the type name (this rule can be applied to any variable when you
|
||||
want to use typedef):
|
||||
|
||||
typedef void (*MYTYPE)(void);
|
||||
|
||||
Now 'MYTYPE' represents a pointer to a function with no parameters and no
|
||||
return value. The following two lines are completely equivalent:
|
||||
|
||||
MYTYPE myfunc;
|
||||
void (*myfunc)(void);
|
||||
|
||||
Note that we use MYTYPE without an asterisk (*), since it is already a
|
||||
pointer.
|
||||
|
||||
That's it. If you feel anything should be explained better here, or if you
|
||||
feel something should be added, please don't hesitate to let me know!
|
||||
|
||||
|
||||
Ben Davis
|
||||
entheh@users.sf.net
|
||||
IRC EFnet #dumb
|
||||
See readme.txt for details on using IRC.
|
|
@ -1,845 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* howto.txt - How To Use DUMB. / / \ \
|
||||
* | < / \_
|
||||
* See readme.txt for general information on | \/ /\ /
|
||||
* DUMB and how to set it up. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
|
||||
********************
|
||||
*** Introduction ***
|
||||
********************
|
||||
|
||||
|
||||
Welcome to the DUMB How-To! It is assumed here that you have already set DUMB
|
||||
up on your system, with or without Allegro. If not, please see readme.txt.
|
||||
|
||||
|
||||
*********************************
|
||||
*** Adding music to your game ***
|
||||
*********************************
|
||||
|
||||
|
||||
These instructions will help you add a piece of music to your game, assuming
|
||||
your music is stored in a stand-alone IT, XM, S3M or MOD file. If you wish to
|
||||
use a different method (such as putting the music file in an Allegro
|
||||
datafile), please follow these instructions first, test your program, and
|
||||
then follow the instructions further down for adapting your code.
|
||||
|
||||
|
||||
1. You need to include DUMB's header file. If you have Allegro, add the
|
||||
following line to the top of your source file (or at the top of each file
|
||||
where you wish to use DUMB):
|
||||
|
||||
#include <aldumb.h>
|
||||
|
||||
If you do not have Allegro or do not wish to use it, use dumb.h instead.
|
||||
|
||||
|
||||
2. You need to link with DUMB's library file or files. If you are compiling
|
||||
with GCC from a command line on any platform, you need to add the
|
||||
following to the command line:
|
||||
|
||||
If you are using Allegro: -laldmd -ldumbd
|
||||
If you are not using Allegro: -ldumbd
|
||||
|
||||
If you are using MSVC from the command line:
|
||||
|
||||
If you are using Allegro: /link aldmd.lib dumbd.lib
|
||||
If you are not using Allegro: /link dumbd.lib
|
||||
|
||||
With MSVC, you must also add /MD to the command line when compiling (not
|
||||
when linking).
|
||||
|
||||
Note that -laldmd or aldmd.lib must PRECEDE alleg.lib, -lalleg_s,
|
||||
`allegro-config --libs`, or whatever you are already using to link with
|
||||
Allegro. For MSVC users, the /MD flag selects the multithreaded DLL
|
||||
implementation of the standard libraries; since DUMB is statically linked,
|
||||
you have to use the same library DUMB uses. You would also need this flag
|
||||
to link statically with Allegro; if you already have it, there's no need
|
||||
to put it twice.
|
||||
|
||||
(If anyone would like to contribute instructions for doing the above using
|
||||
MSVC's IDE, please contact me. Contact details are at the end of this
|
||||
file.)
|
||||
|
||||
If you are using RHIDE, go to Options -> Libraries. You will need to type
|
||||
'aldmd' and 'dumbd' in two boxes, making sure 'aldmd' comes above whatever
|
||||
you are using to link with Allegro (or just put 'dumbd' if you are not
|
||||
using Allegro). Make sure the box next to each of these libraries is
|
||||
checked.
|
||||
|
||||
The above are the debugging libraries. It is VERY HIGHLY RECOMMENDED that
|
||||
you use the debugging libraries at first. The reason is as follows.
|
||||
Although DUMB is supposedly robust against corrupt music files and things
|
||||
like lack of memory, it will NOT tolerate programmer error. If you write
|
||||
faulty code, DUMB will probably crash rather than returning an error code
|
||||
for you. However, the debugging libraries will abort in many cases,
|
||||
enabling you to find out what the cause is.
|
||||
|
||||
Once your program is up and running reliably, you can replace 'aldmd' with
|
||||
'aldmb' and 'dumbd' with 'dumb'. Don't forget to do this, or DUMB will be
|
||||
a lot slower than it should be!
|
||||
|
||||
|
||||
3. As you use DUMB, it may claim system resources (memory in particular). You
|
||||
will need to arrange for these resources to be freed at the end. Doing so
|
||||
is very easy. Simply write the following line at the top of your main
|
||||
function, but below allegro_init() if you are using Allegro:
|
||||
|
||||
atexit(&dumb_exit);
|
||||
|
||||
This arranges for the function dumb_exit() to be called when your program
|
||||
exits; you do not need to call dumb_exit() yourself. This method is
|
||||
preferable to calling dumb_exit() manually, as it will free resources even
|
||||
if your program aborts unexpectedly.
|
||||
|
||||
If you are happy with this, please skip ahead to Step 4. If you are
|
||||
interested in alternative methods, read on, but read on carefully.
|
||||
|
||||
In fact it mostly doesn't matter where you put the above atexit() line,
|
||||
provided it gets called only once, and before you do anything with DUMB.
|
||||
If you are using DUMB with Allegro, it is recommended that you write the
|
||||
functions in this order:
|
||||
|
||||
allegro_init();
|
||||
atexit(&dumb_exit);
|
||||
|
||||
And then you must NOT call allegro_exit() yourself (because it has to be
|
||||
called after dumb_exit()). Alternatively, if you prefer not to use
|
||||
atexit() (or you cannot), you will have to do the following before
|
||||
exiting:
|
||||
|
||||
dumb_exit();
|
||||
allegro_exit();
|
||||
|
||||
|
||||
4. DUMB does not automatically do any of its own file input. You have to tell
|
||||
it how to read files. Don't worry, it's easy. Simply call the following
|
||||
function near the beginning of your program, after your atexit() call:
|
||||
|
||||
dumb_register_stdfiles();
|
||||
|
||||
This tells DUMB to use ordinary stdio FILE structs for reading and writing
|
||||
files. If you are using Allegro and would rather DUMB used PACKFILEs, call
|
||||
the following function INSTEAD:
|
||||
|
||||
dumb_register_packfiles();
|
||||
|
||||
In the latter case, DUMB will be affected by any password you set with
|
||||
packfile_password() in the same way that other PACKFILEs are.
|
||||
|
||||
Note that the procedure for loading datafiles with embedded music is
|
||||
independent of these two functions; even if you will be loading datafiles,
|
||||
you can use either of these functions. If you are loading datafiles, your
|
||||
executable might be slightly smaller if you use dumb_register_packfiles().
|
||||
On the other hand, dumb_register_stdfiles() will probably be faster. If
|
||||
you are only ever going to load datafiles and never stand-alone files, you
|
||||
can actually leave this step out; but I would recommend you put this in,
|
||||
test your code with a stand-alone file, then follow the instructions in
|
||||
the next section in order to adapt your code to use the datafile (you will
|
||||
be reminded that you can remove the function call).
|
||||
|
||||
|
||||
5. If you are using Allegro, you'll have to initialise Allegro's sound
|
||||
system. In most cases the following line will do the job:
|
||||
|
||||
install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL);
|
||||
|
||||
You may like to initialise a MIDI driver though; see Allegro's docs for
|
||||
details. Put this line after allegro_init().
|
||||
|
||||
|
||||
6. All pieces of music are stored in memory in DUH structs. To handle these,
|
||||
you must define pointers to them. Such pointers look like this:
|
||||
|
||||
DUH *myduh;
|
||||
|
||||
You can of course replace 'myduh' with anything you like. If you are
|
||||
unfamiliar with pointers, please see ptr.txt. It is very important that
|
||||
you understand these if you wish to use DUMB correctly.
|
||||
|
||||
You do not have direct access to the contents of a DUH struct, so do not
|
||||
try. DUMB's functions provide everything you need; if you disagree, please
|
||||
let me know and I shall see what I can do. Contact details are at the end
|
||||
of this file.
|
||||
|
||||
Given the above definition, you can load a piece of music using one of the
|
||||
following lines, depending on what file format you want to load:
|
||||
|
||||
myduh = dumb_load_it("a_one.it");
|
||||
myduh = dumb_load_xm("a_two.xm");
|
||||
myduh = dumb_load_s3m("a_one_two.s3m");
|
||||
myduh = dumb_load_mod("three_four.mod");
|
||||
|
||||
Obviously you can use relative or absolute paths as normal. You should
|
||||
always use forward slash (/), not backslash (\), when coding in C and
|
||||
similar languages.
|
||||
|
||||
Every piece of music you load must be unloaded when you've finished with
|
||||
it. When you type the above line in, it is good practice to type the
|
||||
following line in at the same time, but put it at the end of the program:
|
||||
|
||||
unload_duh(myduh);
|
||||
|
||||
You will now be able to use the DUH struct anywhere in between the two
|
||||
lines you just added. There is no need to check the return value; if the
|
||||
DUH failed to load for one reason or another (this could be due to lack of
|
||||
memory as well as the file not being there), then DUMB will do nothing -
|
||||
safely.
|
||||
|
||||
|
||||
7. From this step onwards, it will be assumed you're using Allegro. If not,
|
||||
please read these steps anyway, and then see the section entitled
|
||||
"Rendering music into a buffer". You will have to write your own playback
|
||||
code using whatever sound output system is available. Alternatively you
|
||||
may like to write data to a file (especially if you have a file that
|
||||
consumes a lot of processor time), but beware that any streaming audio
|
||||
format is likely to be substantially larger than the module file you
|
||||
generate it from, and formats like MP3 will be lower quality. You might
|
||||
not be able to hear the difference between the MP3 and the original, but
|
||||
many people can and don't like it, so please consider them. I'm one of
|
||||
them. If you really want to use a lossy compression format, I highly
|
||||
recommend Ogg Vorbis:
|
||||
|
||||
http://www.vorbis.com/
|
||||
|
||||
But I digress.
|
||||
|
||||
In order to play the DUH you loaded, you need to define a pointer to an
|
||||
AL_DUH_PLAYER struct:
|
||||
|
||||
AL_DUH_PLAYER *dp;
|
||||
|
||||
Two of the functions you will need are prototyped as follows:
|
||||
|
||||
AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos,
|
||||
float volume, long bufsize, int freq);
|
||||
|
||||
void al_stop_duh(AL_DUH_PLAYER *dp);
|
||||
|
||||
As you can see, al_start_duh() returns a pointer to an AL_DUH_PLAYER
|
||||
struct when you call it. You then pass this pointer to all the other
|
||||
functions. Again, if it is a NULL pointer for whatever reason (usually
|
||||
lack of memory), DUMB will safely do nothing. When you call al_stop_duh(),
|
||||
the pointer becomes invalid and you should not use it again; if there's
|
||||
any risk of the pointer being used again, it is wise to set it to NULL at
|
||||
this point. You can reassign the variable with a new call to
|
||||
al_start_duh() of course.
|
||||
|
||||
Set 'n_channels' to 1 or 2 for mono or stereo respectively. Note that this
|
||||
parameter has nothing to do with the number of samples that can play at
|
||||
once in a music module. Set 'pos' to 0 to play from the beginning; each
|
||||
time you add 65536, you will have advanced one second into the piece. As a
|
||||
general rule, set the volume to 1.0f and adjust it later if the music is
|
||||
too loud or too quiet - but see Allegro's set_volume_per_voice() function
|
||||
first.
|
||||
|
||||
'bufsize' can generally be set to 4096. If your music stutters, try
|
||||
increasing it; if your game freezes periodically, try reducing it. Find a
|
||||
happy medium. Set 'freq' to 48000 for the best quality, though 44100 will
|
||||
do in most cases. 22050 will be fine for a lot of music, though 11025 may
|
||||
sound muffled. You can choose any other value, higher, lower or in
|
||||
between. If your music stutters, and increasing 'bufsize' doesn't fix it,
|
||||
try reducing this value.
|
||||
|
||||
Once you have put in a call to al_start_duh(), it is good practice to
|
||||
insert the call to al_stop_duh() at the same time. You must call
|
||||
al_stop_duh() before the DUH is unloaded (unload_duh(), Step 6 above).
|
||||
|
||||
Don't get impetuous, your program is not ready yet! Proceed to Step 8.
|
||||
|
||||
|
||||
8. DUMB does not play music in the background for you; if you were expecting
|
||||
it to do so, please see the explanation at the end of this step. For your
|
||||
music to be played, you have to call another function at regular
|
||||
intervals. Here is its prototype:
|
||||
|
||||
int al_poll_duh(AL_DUH_PLAYER *dp);
|
||||
|
||||
Do NOT call this function from inside a timer function unless you really
|
||||
know what you are doing. The reasons why this is bad are explained
|
||||
further down. You should call it from your main program.
|
||||
|
||||
Simply writing the following line will be sufficient in general, if you
|
||||
have a variable 'dp' that points to your AL_DUH_PLAYER struct.
|
||||
|
||||
al_poll_duh(dp);
|
||||
|
||||
As a general rule, calling this once for each logic update will do the
|
||||
trick. If, however, you are executing time-consuming algorithms such as
|
||||
software 3D rendering, you may wish to insert calls to this function in
|
||||
the middle of those algorithms. You cannot call this function too often
|
||||
(within reason); if it has nothing to do it will return immediately.
|
||||
|
||||
Exactly how often you need to call the function depends on the values for
|
||||
'bufsize' and 'freq' that you passed to al_start_duh():
|
||||
|
||||
n = freq / bufsize;
|
||||
|
||||
You have to call al_poll_duh() at least n times a second. Do not hesitate
|
||||
to call it more often for safety; if the sound stutters, you may need to
|
||||
do just that. (Or you may need to increase the buffer size or reduce the
|
||||
quality settings; the only way to find out is to try.)
|
||||
|
||||
For now, don't worry about al_poll_duh()'s return value. As soon as you
|
||||
need it, it will be explained.
|
||||
|
||||
If you are happy, please skip to Step 9. If you were expecting DUMB to
|
||||
play your music in the background, please read on.
|
||||
|
||||
The natural way to play music in the background on most operating systems
|
||||
nowadays is to use threads. DOS was not built with multithreading in mind,
|
||||
and its system operations (notably disk access) assume they will only be
|
||||
used from a single thread.
|
||||
|
||||
Interrupts are the next best thing to threads. A DOS hardware interrupt
|
||||
could be triggered at any moment, and a handler function will be called.
|
||||
This is how Allegro's timer functions work. Unfortunately, what you can do
|
||||
inside an interrupt handler is very limited. For one thing, all code and
|
||||
data used by the handler must be locked in memory; if not, it could get
|
||||
written to disk (virtual memory). If the main program was accessing the
|
||||
disk when it got interrupted, the system would then die a horrible death.
|
||||
This precludes the possibility of allocating extra memory inside the
|
||||
handler, and DUMB does a lot of that in al_poll_duh().
|
||||
|
||||
Given DUMB's architecture, which cannot change for reasons which will
|
||||
become apparent in future versions, this renders it impossible to come up
|
||||
with a portable solution for making DUMB play music in the background.
|
||||
Having said that, if you wish to write your own wrapper for al_poll_duh()
|
||||
and use it in a thread, there is nothing stopping you. If you do do this,
|
||||
you will have to be very careful when stopping the music; see the
|
||||
description of al_poll_duh() in dumb.txt for more information.
|
||||
|
||||
So why not kill DOS? It is all too common a practice among programmers to
|
||||
quote the phrase, "DOS is as dead as the dodo." Despite being a decidedly
|
||||
derisible demonstation of the dreary device of alliteration, it shows a
|
||||
distinct lack of experience. Many embedded systems still use DOS because
|
||||
it provides hardware access capabilities and real-time possibilities
|
||||
unparalleled by any current multitasking operating system. For an argument
|
||||
closer to home, I used to use RHIDE for DOS before I switched to Linux,
|
||||
and I have not found a single Freeware Windows IDE that measures up to
|
||||
RHIDE. I'm sure many people are in the same boat, and really appreciate
|
||||
DUMB's DOS port.
|
||||
|
||||
We will not be removing DOS support from DUMB. Any blind suggestions to do
|
||||
so will be met with fiery flames. You have been warned.
|
||||
|
||||
|
||||
9. Test your program!
|
||||
|
||||
If you have trouble, check through the above steps to make sure you didn't
|
||||
miss one out. Refer to faq.txt to see if your problem is addressed there.
|
||||
If you still have trouble, contact me; details are at the end of this
|
||||
file.
|
||||
|
||||
|
||||
**********************************
|
||||
*** Controlling music playback ***
|
||||
**********************************
|
||||
|
||||
|
||||
Here I describe some common operations you may wish to perform. The method
|
||||
for doing so will seem a bit strange sometimes, as will the names of the
|
||||
structs. However, there is a reason behind everything. If you would like to
|
||||
do more exotic things, or better understand some of the methods used here,
|
||||
then see dumb.txt, which covers everything from the ground up.
|
||||
|
||||
|
||||
To control playback quality:
|
||||
|
||||
#define DUMB_RQ_ALIASING
|
||||
#define DUMB_RQ_LINEAR
|
||||
#define DUMB_RQ_CUBIC
|
||||
#define DUMB_RQ_N_LEVELS
|
||||
extern int dumb_resampling_quality;
|
||||
extern int dumb_it_max_to_mix;
|
||||
|
||||
Please note that dumb_resampling_quality has changed in DUMB v0.9.2. See
|
||||
deprec.txt for more details on the change.
|
||||
|
||||
dumb_resampling_quality can be set to any of the DUMB_RQ_* constants
|
||||
(except DUMB_RQ_N_LEVELS; see below). Resampling is the term given to the
|
||||
process of adjusting a sample's pitch (in this context).
|
||||
dumb_resampling_quality defaults to DUMB_RQ_CUBIC, which sounds nice but
|
||||
takes a lot of processor power. Try reducing it if you have an older
|
||||
computer or if you are trying to mix an insane number of samples (or
|
||||
both!). See dumb.txt for details on what the different values actually do.
|
||||
|
||||
If you wish to give this option to your user, you can use
|
||||
DUMB_RQ_N_LEVELS. All the values from 0 to DUMB_RQ_N_LEVELS - 1 will be
|
||||
valid resampling levels. If a value outside this range is chosen, it is
|
||||
not the end of the world; DUMB will behave as if you had chosen the value
|
||||
at whichever extreme you went beyond.
|
||||
|
||||
dumb_it_max_to_mix, defaulting to 64, is the maximum number of samples
|
||||
DUMB will ever mix together when playing an IT, XM, S3M or MOD file.
|
||||
Unlike many other music systems, DUMB will still keep track of all samples
|
||||
(up to a fixed maximum of 256 of them, roughly speaking), and then will
|
||||
just render as many of them as this variable permits, starting with the
|
||||
loudest ones. When samples are cut or come back in, the exact timings will
|
||||
not generally be predictable - but nor will they be important.
|
||||
|
||||
dumb_it_max_to_mix applies to each currently playing module file
|
||||
independently. So if you set it to 64, but render two modules
|
||||
simultaneously, DUMB could end up mixing up to 128 samples.
|
||||
|
||||
|
||||
To pause and resume playback, set the volume, get the current playback
|
||||
position, or get the length of time a DUH will play for before either looping
|
||||
or freezing (effect F00 in XM and MOD files, which means no new notes will be
|
||||
played but any existing notes will continue):
|
||||
|
||||
void al_pause_duh(AL_DUH_PLAYER *dp);
|
||||
void al_resume_duh(AL_DUH_PLAYER *dp);
|
||||
void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume);
|
||||
long al_duh_get_position(AL_DUH_PLAYER *dp);
|
||||
|
||||
long duh_get_length(DUH *duh);
|
||||
|
||||
These functions are pretty self-explanatory. The volume passed to
|
||||
al_duh_set_volume() and the position returned by al_duh_get_position() are
|
||||
in the same units as those you passed to al_start_duh(). The length
|
||||
returned by duh_get_length() is in the same units as the aforementioned
|
||||
position; see dumb.txt for more information on this function. Be careful
|
||||
with al_duh_get_position(); it will return a position slightly ahead of
|
||||
what you can hear, because the system has to keep ahead slightly to avoid
|
||||
stuttering.
|
||||
|
||||
|
||||
To prevent the music from looping and/or freezing:
|
||||
|
||||
DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp);
|
||||
DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer);
|
||||
|
||||
void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer,
|
||||
int (*callback)(void *data), void *data);
|
||||
void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer,
|
||||
int (*callback)(void *data), void *data);
|
||||
|
||||
int dumb_it_callback_terminate(void *data);
|
||||
|
||||
If you are unfamiliar with function pointers, please see fnptr.txt.
|
||||
|
||||
Note that these functions apply to IT, XM, S3M and MOD files - not just to
|
||||
IT files. This holds true throughout DUMB, for all functions with "it" in
|
||||
the name. The xm_speed_zero event can only occur with XM and MOD files.
|
||||
|
||||
The first two functions will return a pointer to a struct contained by the
|
||||
struct you pass. This system is necessary to ensure that these operations
|
||||
are possible when not using Allegro. Typically you would write the
|
||||
following code:
|
||||
|
||||
{
|
||||
DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp);
|
||||
DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sigrenderer);
|
||||
dumb_it_set_loop_callback(itsr, &dumb_it_callback_terminate, NULL);
|
||||
dumb_it_set_xm_speed_zero_callback
|
||||
(itsr, &dumb_it_callback_terminate, NULL);
|
||||
}
|
||||
|
||||
Once you have done this, the return value of al_poll_duh() becomes
|
||||
significant. It will be 0 as long as the music is playing. When the music
|
||||
stops, al_poll_duh() will return nonzero. You can call al_stop_duh() and
|
||||
do something else as soon as you wish, but calling al_poll_duh() some more
|
||||
will not do any harm.
|
||||
|
||||
al_poll_duh() will also return 1 if the music could not be loaded, or if
|
||||
memory was short when trying to play it, or if it was a quirky music file
|
||||
with no music in it (technically one with an empty order list). This
|
||||
happens regardless of whether or not you execute the above code to disable
|
||||
looping. Normally you shouldn't need to worry about this.
|
||||
|
||||
To undo the above and make DUMB loop or freeze again, pass NULL instead of
|
||||
&dumb_it_callback_terminate. If you would like to fade on looping, or loop
|
||||
a finite number of times, or display a message when looping, or whatever,
|
||||
you will have to write your own callback function. In this case, please
|
||||
see dumb.txt.
|
||||
|
||||
Note that the above code can safely be applied for a DUH that doesn't
|
||||
contain a music module but contains some other kind of music.
|
||||
duh_get_it_sigrenderer() will return NULL, and the code will do nothing.
|
||||
|
||||
|
||||
To analyse the audio as it's generated:
|
||||
|
||||
typedef int sample_t;
|
||||
|
||||
typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data,
|
||||
const sample_t *const *samples, int n_channels, long length);
|
||||
|
||||
void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer,
|
||||
DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data);
|
||||
|
||||
If the above confuses you, see fnptr.txt. These functions, along with
|
||||
al_duh_get_sigrenderer() from the last section, enable you to register a
|
||||
callback function. Every time some samples are generated, they will be
|
||||
passed to this function. This enables you to display an oscilloscope or
|
||||
spectrum analyser, for example.
|
||||
|
||||
Beware: your callback function may occasionally be called with
|
||||
samples == NULL. This means the main program has decided to skip through
|
||||
the music without generating any data. You should handle this case
|
||||
elegantly, typically by returning immediately, but you may wish to make a
|
||||
note of the fact that the music is being skipped, for whatever reason.
|
||||
|
||||
Beware again: if the main program ever calls duh_sigrenderer_get_samples()
|
||||
on a buffer that isn't all silence, this callback function will be passed
|
||||
the existing buffer after mixing, and thus it will include the original
|
||||
data. This will not be an issue if you stick to duh_render(), which always
|
||||
starts with a buffer filled with silence.
|
||||
|
||||
The samples array is two-dimensional. Refer to it as follows:
|
||||
|
||||
samples[channel_number][sample_position]
|
||||
|
||||
where 0 <= channel_number < n_channels,
|
||||
and 0 <= sample_position < length.
|
||||
|
||||
In addition you can pass any 'data' pointer you like to
|
||||
duh_sigrenderer_set_analyser_callback(), and this pointer will be relayed
|
||||
to your callback function each time.
|
||||
|
||||
To remove the callback function, pass NULL to
|
||||
duh_sigrenderer_set_analyser_callback().
|
||||
|
||||
|
||||
Everything below this point assumes some knowledge of how a music module is
|
||||
constructed. If you do not have this knowledge, talk to whoever is writing
|
||||
music for you, or download a tracking program and play with it (see
|
||||
readme.txt).
|
||||
|
||||
|
||||
To start playing an IT, XM, S3M or MOD from an arbitrary order number (the
|
||||
default being 0, the beginning of the song), use the following:
|
||||
|
||||
DUH_SIGRENDERER *dumb_it_start_at_order
|
||||
(DUH *duh, int n_channels, int startorder);
|
||||
AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer
|
||||
(DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq);
|
||||
|
||||
The usage of these functions is as follows:
|
||||
|
||||
{
|
||||
DUH_SIGRENDERER *sr = dumb_it_start_at_order
|
||||
(duh, n_channels, startorder);
|
||||
dp = al_duh_encapsulate_sigrenderer(sr, volume, bufsize, freq);
|
||||
}
|
||||
|
||||
Replace 'dp' with whatever your AL_DUH_PLAYER pointer is. You also need
|
||||
to insert suitable values for n_channels, startorder, volume, bufsize and
|
||||
freq. These have the same meaning as those passed to al_start_duh().
|
||||
|
||||
WARNING: after passing a pointer to an "encapsulate" function, do not use
|
||||
that pointer again. (More specifically, do not use it again if
|
||||
the function returns NULL, because the function will have
|
||||
destroyed the pointer if this happens, to help prevent memory
|
||||
leaks.) There will be a "get" function with which you can obtain
|
||||
the original pointer if it is still valid, or NULL otherwise.
|
||||
|
||||
The above functions will fail (safely) if you try to use them with a DUH
|
||||
that contains a different type of music.
|
||||
|
||||
Notice that there is no 'pos' parameter. If you would like to skip through
|
||||
the music, you can use this function:
|
||||
|
||||
long duh_sigrenderer_get_samples(
|
||||
DUH_SIGRENDERER *sigrenderer,
|
||||
float volume, float delta,
|
||||
long size, sample_t **samples
|
||||
);
|
||||
|
||||
Pass 0 for volume and NULL for samples, and this function will skip
|
||||
through the music nice and quickly. So insert the following between the
|
||||
two above statements:
|
||||
|
||||
duh_sigrenderer_get_samples(sr, 0, 65536.0f / freq, pos, NULL);
|
||||
|
||||
Substitute for 'freq' and 'pos'. An explanation of the 'delta' parameter
|
||||
can be found further down in this file.
|
||||
|
||||
Finally, note that duh_get_length() is only meaningful when you start
|
||||
playing music from order 0.
|
||||
|
||||
|
||||
If an IT file contains Zxx effects, DUMB will generate MIDI messages, which
|
||||
will control the low-pass resonant filters unless the IT file actively
|
||||
specifies something else. In rare cases this may not be what the Zxx effects
|
||||
were intended to do; if this is the case, you can block the MIDI messages as
|
||||
follows. Note that this does NOT mean filters are disabled; if an instrument
|
||||
specifies initial cut-off and resonance values, or has a filter envelope,
|
||||
then filters will be applied. It only makes sense to use this procedure at
|
||||
the beginning of playback.
|
||||
|
||||
void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer,
|
||||
int (*callback)(void *data, int channel, unsigned char byte),
|
||||
void *data);
|
||||
|
||||
int dumb_it_callback_midi_block(void *data, int channel,
|
||||
unsigned char byte);
|
||||
|
||||
Using some functions described in the previous section, we arrive at the
|
||||
following code:
|
||||
|
||||
{
|
||||
DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp);
|
||||
DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sigrenderer);
|
||||
dumb_it_set_midi_callback(itsr, &dumb_it_callback_midi_block, NULL);
|
||||
}
|
||||
|
||||
DUMB offers no way of disabling filters completely. Disabling filters is not
|
||||
recommended as a means to reduce processor usage, as it will completely
|
||||
damage any piece of music that uses the filters. If you want lower processor
|
||||
consumption, use a piece of music that does not use filters.
|
||||
|
||||
|
||||
Finally, DUMB offers a myriad of functions for querying and adjusting
|
||||
module playback. Those beginning with "dumb_it_sd" operate on the
|
||||
DUMB_IT_SIGDATA struct, which represents the piece of music before it starts
|
||||
to play. Those beginning with "dumb_it_sr" operate on the DUMB_IT_SIGRENDERER
|
||||
struct, which represents a currently playing instance of the music. Note that
|
||||
duh_get_length(), described above, becomes meaningless after some of these
|
||||
functions are used.
|
||||
|
||||
The method for getting a DUMB_IT_SIGRENDERER struct has already been given,
|
||||
but the function prototypes are repeated here for convenience:
|
||||
|
||||
DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp);
|
||||
DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer);
|
||||
|
||||
Getting a DUMB_IT_SIGDATA struct is simpler:
|
||||
|
||||
DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh);
|
||||
|
||||
For a list of dumb_it_sd_*() and dumb_it_sr_*() functions, please see
|
||||
dumb.txt. These functions are new, and may not provide exactly what you need;
|
||||
if not, please let me know.
|
||||
|
||||
|
||||
**************************************************
|
||||
*** Embedding music files in Allegro datafiles ***
|
||||
**************************************************
|
||||
|
||||
|
||||
In this section it is assumed you are already reasonably familiar with how
|
||||
Allegro datafiles are used. If not, please refer to Allegro's documentation.
|
||||
At the time of writing, the documentation you need is off the beaten track,
|
||||
so to speak, in allegro/tools/grabber.txt.
|
||||
|
||||
To add a piece of music to a datafile, you need to create an object of type
|
||||
"IT ", "XM ", "S3M " or "MOD " (note the spaces used as padding, although
|
||||
you do not need to type these into the grabber). Then grab the piece of music
|
||||
in. The grabber will treat it as a binary object. Save the datafile as usual.
|
||||
|
||||
|
||||
To use a piece of music you added to the datafile, follow these steps:
|
||||
|
||||
|
||||
1. Before loading the datafile, call one or more of these functions,
|
||||
depending on which music format or formats you'd like to support:
|
||||
|
||||
dumb_register_dat_it(DUMB_DAT_IT);
|
||||
dumb_register_dat_xm(DUMB_DAT_XM);
|
||||
dumb_register_dat_s3m(DUMB_DAT_S3M);
|
||||
dumb_register_dat_mod(DUMB_DAT_MOD);
|
||||
|
||||
Remember, do not call multiple functions unless you want to support
|
||||
multiple formats. Calling more functions will add unused code to your
|
||||
executable.
|
||||
|
||||
It is important that you make call these before loading the datafile,
|
||||
since they tell Allegro how to load the respective files straight from
|
||||
datafiles in the future. They will not help Allegro interpret any module
|
||||
files that have already been loaded as binary objects (but if you really
|
||||
need to interpret a module that has been loaded in this fashion, have a
|
||||
look at dumbfile_open_memory() in dumb.txt).
|
||||
|
||||
If for whatever reason your music objects are identified by a different
|
||||
type in the datafile, you can tell DUMB what that type is by changing the
|
||||
parameter to the registration function above. Use Allegro's DAT_ID()
|
||||
macro, e.g. DAT_ID('B','L','A','H'). This is not really recommended
|
||||
though, since it would prevent a hypothetical grabber plug-in from being
|
||||
able to play your music files. Use the above types if possible.
|
||||
|
||||
|
||||
2. Whenever you need a pointer to a DUH struct, simply use the 'dat' field.
|
||||
Do this in the same way you would for a pointer to a BITMAP struct or
|
||||
anything else. If it makes you feel more comfortable, you can extract the
|
||||
pointer in advance:
|
||||
|
||||
DATAFILE *dat = load_datafile("smurf.dat");
|
||||
if (!dat) abort(); /* There are much nicer ways of handling failure! */
|
||||
DUH *myduh = (DUH *)dat[GAME_MUSIC].dat;
|
||||
|
||||
Note that the explicit (DUH *) cast is only necessary for C++, not for C.
|
||||
However, it does no harm.
|
||||
|
||||
Be sure that you do NOT call unload_duh() for anything stored in the
|
||||
datafile. These DUHs will be freed when you call unload_datafile(), and
|
||||
freeing them twice is practically guaranteed to crash your program.
|
||||
|
||||
|
||||
3. If you only ever load music as part of a datafile, and you never load any
|
||||
stand-alone music files, you do not need to register a file input system
|
||||
for DUMB to use. If you followed the instructions for the first section
|
||||
you will have one of these two lines in your program:
|
||||
|
||||
dumb_register_stdfiles();
|
||||
dumb_register_packfiles();
|
||||
|
||||
You can safely delete this line - but only if you never load any
|
||||
stand-alone music files. The debugging library will bale you out if you
|
||||
delete it when you shouldn't; the optimised library won't.
|
||||
|
||||
|
||||
*************************************
|
||||
*** Rendering music into a buffer ***
|
||||
*************************************
|
||||
|
||||
|
||||
NOTE: much of the API formerly described in this section has been deprecated,
|
||||
and you will need to alter your code. See deprec.txt for details. If
|
||||
you are reading this section for the first time, you can ignore this
|
||||
note.
|
||||
|
||||
Rendering to a buffer is similar to playing using an AL_DUH_PLAYER. However,
|
||||
you must use a DUH_SIGRENDERER struct instead. Here are the functions:
|
||||
|
||||
DUH_SIGRENDERER *duh_start_sigrenderer
|
||||
(DUH *duh, int sig, int n_channels, long pos);
|
||||
|
||||
int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);
|
||||
long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer);
|
||||
|
||||
long duh_sigrenderer_get_samples(DUH_SIGRENDERER *sigrenderer,
|
||||
float volume, float delta, long size, sample_t **samples);
|
||||
|
||||
long duh_render(DUH_SIGRENDERER *sigrenderer,
|
||||
int bits, int unsign, float volume, float delta, long size, void *sptr);
|
||||
|
||||
void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer);
|
||||
|
||||
The parameters to duh_start_sigrenderer() have the same meanings as those to
|
||||
al_start_duh(). However, note that the volume is not set at this stage. You
|
||||
pass the desired volume each time you want to render a block. The 'sig'
|
||||
parameter should be set to 0 for now.
|
||||
|
||||
Notice that there are two rendering functions. duh_sigrenderer_get_samples()
|
||||
will generate samples in the internal 32-bit format, with a normal range from
|
||||
-0x800000 to 0x7FFFFF and with each channel in a separate array; duh_render()
|
||||
will convert to 8 or 16 bits, signed or unsigned, with stereo samples
|
||||
interleaved, left first.
|
||||
|
||||
When you call duh_render(), pass 8 or 16 for 'bits'. If you pass 8, 'sptr' is
|
||||
expected to be an array of chars. If you pass 16, 'sptr' is expected to be an
|
||||
array of shorts. Endianness therefore depends on the platform, and you should
|
||||
not try to interpret 16-bit wave data as an array of chars (unless you're
|
||||
writing highly system-specific code anyway). Because DUMB renders internally
|
||||
with 32 bits, there is no significant speed increase in rendering an 8-bit
|
||||
stream.
|
||||
|
||||
If you are rendering in stereo, make sure your 'sptr' array is twice as big!
|
||||
|
||||
If you set 'unsign' to a nonzero value, then the samples generated will be
|
||||
centred on 0x80 or 0x8000, suitably stored in an array of unsigned chars or
|
||||
unsigned shorts. If 'unsign' is zero, the samples will be centred on 0,
|
||||
suitably stored in an array of signed chars or signed shorts. Note that 8-bit
|
||||
WAV files are unsigned while 16-bit WAV files are signed. This convention was
|
||||
used by the SoundBlaster 16 when receiving samples to be sent to the
|
||||
speakers. If you wish to write 16-bit sample data to a WAV file, don't use
|
||||
fwrite(); instead, take the shorts one at a time, split them up into chars as
|
||||
follows, and write the chars to the file.
|
||||
|
||||
short sptr[n];
|
||||
char lsb = (char)sptr[n];
|
||||
char msb = (char)(sptr[n] >> 8);
|
||||
|
||||
For a 16-bit WAV file, write the LSB (less significant byte) first.
|
||||
|
||||
The following applies equally to duh_render() and
|
||||
duh_sigrenderer_get_samples(), except where otherwise stated.
|
||||
|
||||
If you set 'delta' to 1.0f, the sound generated will be suitable for playback
|
||||
at 65536 Hz. Increasing 'delta' causes the wave to speed up, given a constant
|
||||
sampling rate for playback. Supposing you want to vary the playback sampling
|
||||
rate but keep the pitch constant, here's the equation for 'delta':
|
||||
|
||||
delta = 65536.0f / sampling_rate;
|
||||
|
||||
'size' is the number of samples you want rendered. For duh_render(), they
|
||||
will be rendered into an array which you pass as 'sptr'. Note that stereo
|
||||
samples count as one; so if you set n_channels to 2, your array must contain
|
||||
(2 * size) elements.
|
||||
|
||||
For duh_sigrenderer_get_samples() you will have to use the following
|
||||
functions:
|
||||
|
||||
sample_t **create_sample_buffer(int n_channels, long length);
|
||||
void destroy_sample_buffer(sample_t **samples);
|
||||
|
||||
void dumb_silence(sample_t *samples, long length);
|
||||
|
||||
create_sample_buffer() allocates the channels sequentially in memory, so the
|
||||
following technique is valid:
|
||||
|
||||
sample_t **samples = create_sample_buffer(n_channels, length);
|
||||
dumb_silence(samples[0], n_channels * length);
|
||||
|
||||
It is necessary to fill the buffer with silence like this because
|
||||
duh_sigrenderer_get_samples() mixes what it renders with the existing
|
||||
contents of the buffer.
|
||||
|
||||
The return values from duh_render() and duh_sigrenderer_get_samples() tell
|
||||
you how many samples were actually generated. In most cases, this will be the
|
||||
same as the 'size' parameter. However, if you reach the end of the DUH (which
|
||||
will happen if you disable looping or freezing as described further up), this
|
||||
function will return less. When that happens, you can assume the stream has
|
||||
finished. In the case of duh_render(), the remainder of the array will not
|
||||
have been initialised, so you either have to initialise it yourself or avoid
|
||||
using it.
|
||||
|
||||
If for whatever reason duh_start_sigrenderer() returns NULL, then
|
||||
duh_render() and duh_sigrenderer_get_samples() will generate exactly 0
|
||||
samples, duh_sigrenderer_get_n_channels() will return 0,
|
||||
duh_sigrenderer_get_position() will return -1, and duh_end_sigrenderer() will
|
||||
safely do nothing.
|
||||
|
||||
|
||||
*********************
|
||||
*** Miscellaneous ***
|
||||
*********************
|
||||
|
||||
|
||||
Please see dumb.txt for an API reference and for information on thread safety
|
||||
with DUMB. The API reference has been stripped down, since some functions and
|
||||
variables are subject to change. If something does not appear in dumb.txt,
|
||||
please do not use it.
|
||||
|
||||
|
||||
******************
|
||||
*** Conclusion ***
|
||||
******************
|
||||
|
||||
|
||||
If you have any difficulties, or if you use DUMB successfully, please don't
|
||||
hesitate to contact me (see below).
|
||||
|
||||
Enjoy!
|
||||
|
||||
|
||||
Ben Davis
|
||||
entheh@users.sf.net
|
||||
IRC EFnet #dumb
|
||||
See readme.txt for details on using IRC.
|
|
@ -1,137 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* modplug.txt - Our official position regarding / / \ \
|
||||
* compatibility with ModPlug | < / \_
|
||||
* Tracker. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
|
||||
********************
|
||||
*** Introduction ***
|
||||
********************
|
||||
|
||||
ModPlug Tracker is a very popular tracker for Windows. Its popularity is due
|
||||
to the intuitive interface and its many advanced features. The author has
|
||||
done a good job with this piece of software, but sadly in doing so he has
|
||||
desecrated the IT file format.
|
||||
|
||||
I am not against ModPlug Tracker being used to write music modules. As
|
||||
already stated, it has some very advanced and convenient features; I use it
|
||||
myself. However, I believe its users should be aware of the entire situation
|
||||
before using it for any serious work.
|
||||
|
||||
ModPlug Tracker - http://www.modplug.com/
|
||||
|
||||
|
||||
*************************
|
||||
*** Incompatibilities ***
|
||||
*************************
|
||||
|
||||
There are a few situations in which ModPlug Tracker misinterprets the
|
||||
original module formats. I shall list the five I am most aware of, from least
|
||||
to most annoying:
|
||||
|
||||
5. Create a multisample instrument, for example a piano. Play a low note.
|
||||
Then go up the scale, but in the pattern data, make sure the instrument
|
||||
column is blank; put in only the notes. Play this with ModPlug Tracker,
|
||||
and play it with Impulse Tracker. Impulse Tracker changes sample as you go
|
||||
up the scale; ModPlug Tracker does not.
|
||||
|
||||
4. Arpeggio and Retrigger Note effects behave badly when combined with
|
||||
Portamento, which can appear in the volume column. While Retrigger Note
|
||||
isn't too bad, Arpeggio sounds completely wrong. Try it and see what
|
||||
happens. Then repeat the experiment in Impulse Tracker.
|
||||
|
||||
3. The filter algorithm is incorrect, in more ways than one. When Jeffrey Lim
|
||||
programmed the low-pass resonant filters into Impulse Tracker, he used a
|
||||
standard filter algorithm with a slight modification to achieve greater
|
||||
resonance. ModPlug Tracker does not incorporate this modification.
|
||||
Furthermore, ModPlug Tracker uses integer arithmetic with nowhere near
|
||||
enough precision; the wave output is really poor in some cases. I don't
|
||||
doubt it damages the acoustic properties of the filters in subtle ways.
|
||||
|
||||
2. When looping, ModPlug Tracker resets all variables. The original trackers
|
||||
do not do this.
|
||||
|
||||
1. Worst of all, ModPlug Tracker has no regard for playback volume, and
|
||||
generally has a much lower output level than the original trackers.
|
||||
|
||||
Cases 3, 2 and 1 lead people to write IT files that play badly in the
|
||||
original trackers. If some of these problems could be fixed, I'd be all for
|
||||
it - but these problems have been reported to the author and he had no
|
||||
motivation to fix them. ModPlug Tracker has been around long enough that
|
||||
fixing 3, 2 and 1 would be detrimental to too many people's music.
|
||||
|
||||
|
||||
******************
|
||||
*** Extensions ***
|
||||
******************
|
||||
|
||||
Worse than the incompatibilities are the extensions ModPlug Tracker makes,
|
||||
mostly to the IT format. DUMB currently supports one of these extensions,
|
||||
namely stereo samples, but supporting the others is not high on my list of
|
||||
priorities.
|
||||
|
||||
Other extensions ModPlug Tracker has provided mostly take the form of extra
|
||||
effects. For instance, S98 and S99 can be used to enable or disable reverb. I
|
||||
believe the latest versions of ModPlug Tracker offer alternative types of
|
||||
filter, such as high-pass and band-pass. As soon as an IT file uses any of
|
||||
these features, it will play incorrectly with Impulse Tracker.
|
||||
|
||||
By far the most evil extension provided by ModPlug Tracker is the effect
|
||||
plug-ins. These enable IT files to use VST effects. I recently downloaded an
|
||||
IT file that uses some effects from a collection named "DirectX Media Audio
|
||||
Effects". When can we expect these effects to be ported to Linux?
|
||||
|
||||
|
||||
******************
|
||||
*** Conclusion ***
|
||||
******************
|
||||
|
||||
ModPlug Tracker is trying to be two things at once. It wants to be an editor
|
||||
for the existing formats, but at the same time it wants to be proprietary,
|
||||
with all its own features and extensions. Unfortunately it is succeeding;
|
||||
there are many IT files out there that only play right in ModPlug Tracker. In
|
||||
my opinion, ModPlug Tracker should have come out with its own file format, in
|
||||
which all these extensions would have found a home.
|
||||
|
||||
If you are going to use ModPlug Tracker's extensions, I recommend you
|
||||
ultimately convert your music to a streamed format such as Ogg Vorbis. (If
|
||||
you were thinking of using MP3, then don't - consider using Ogg Vorbis
|
||||
instead.) If you release IT files that use ModPlug Tracker's extensions,
|
||||
please state prominently that the files are designed to be played with
|
||||
ModPlug Tracker. Finally, don't ask me to support ModPlug Tracker's
|
||||
extensions; ModPlug Tracker's playback code is available for use in your
|
||||
games, so use that instead.
|
||||
|
||||
Ogg Vorbis - http://www.vorbis.com/
|
||||
|
||||
Despite all the above problems, don't forget that ModPlug Tracker does have a
|
||||
lot of very useful features for editing files. These include a function for
|
||||
removing unused patterns, samples and instruments, drag-and-drop sample and
|
||||
instrument ripping, drop-down menus for selecting the effects by name without
|
||||
having to memorise the codes or refer to help, and lots of other nice things.
|
||||
I do recommend it as an editor, provided you make sure you are aware of the
|
||||
situation and do not use ModPlug Tracker's extensions or incompatibilities
|
||||
inadvertently.
|
||||
|
||||
Oh, and by the way, save your final version with Impulse Tracker. Then the
|
||||
samples will be compressed for you!
|
||||
|
||||
|
||||
Ben Davis
|
||||
entheh@users.sf.net
|
||||
IRC EFnet #dumb
|
||||
See readme.txt for details on using IRC.
|
|
@ -1,129 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* ptr.txt - Pointer explanation. / / \ \
|
||||
* | < / \_
|
||||
* | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
|
||||
A pointer is a small variable (often the same size as an int BUT NOT ALWAYS)
|
||||
that holds the address of something in memory. You create a pointer by adding
|
||||
a * to a variable, as follows:
|
||||
|
||||
int x, *y;
|
||||
|
||||
x = 5;
|
||||
y = &x;
|
||||
|
||||
The & means 'address of', so &x gives us a pointer to x. We are storing it in
|
||||
y.
|
||||
|
||||
(*y)++;
|
||||
|
||||
The * here means 'value at'. It's known as the 'dereferencing' operator. When
|
||||
written before a pointer, as it is here, it allows you to treat the value
|
||||
like a normal variable. In this case we are incrementing the value. If we
|
||||
look at x, we'll find that it now contains 6, not 5.
|
||||
|
||||
y++;
|
||||
|
||||
Here we are incrementing the pointer itself. This is useful for traversing
|
||||
through an array, but in this particular example it is not much use.
|
||||
|
||||
*y++;
|
||||
|
||||
Beware; this will increment the pointer, not the value stored there. It will
|
||||
return the value stored at the pointer (before incrementing the pointer), so
|
||||
you can use this in a bigger expression. This is why we needed brackets in
|
||||
the first example.
|
||||
|
||||
Note that you will not need these three examples when working with DUMB; they
|
||||
are simply to help illustrate the idea of pointers.
|
||||
|
||||
Also be aware that when defining pointers you attach the * to the variable,
|
||||
not to the type. The following example will create a pointer and an int, not
|
||||
two pointers:
|
||||
|
||||
int *a, b;
|
||||
|
||||
That is why I believe it's a good idea to put a space before the * and not
|
||||
after it, although programmers are divided on this.
|
||||
|
||||
y = 0;
|
||||
y = NULL;
|
||||
|
||||
These two statements are equivalent. 0, or NULL, is a special value that is
|
||||
guaranteed to have a different value from any valid pointer. This is most
|
||||
often used to indicate that something doesn't point anywhere. DUMB's
|
||||
functions may return it on occasion. However, in simple usage of DUMB, you
|
||||
will not actually need to check for it.
|
||||
|
||||
Some of DUMB's functions return pointers to structs. (A struct is an
|
||||
aggregration of other variables, such as ints, pointers, or other structs.
|
||||
You can generally treat a struct as a single unit.) Here's an example of such
|
||||
a function:
|
||||
|
||||
DUH *dumb_load_it(const char *filename);
|
||||
|
||||
You do not know what the DUH struct actually contains; dumb.h and aldumb.h
|
||||
only give the compiler enough information to deal with pointers to them. DUMB
|
||||
will take charge of everything that happens inside a DUH struct.
|
||||
|
||||
The above function will create a DUH struct for you. First it allocates
|
||||
the memory it needs, then it fills the struct with data, then it returns a
|
||||
pointer. This DUH struct will contain the data necessary to play an IT file.
|
||||
You can define a suitable variable and store the pointer in it as follows:
|
||||
|
||||
DUH *duh = dumb_load_it("music.it");
|
||||
|
||||
Or this can be split up:
|
||||
|
||||
DUH *duh;
|
||||
duh = dumb_load_it("music.it");
|
||||
|
||||
In order to use this DUH struct later, you must pass its pointer to other
|
||||
functions. To pass the pointer to a function, simply write 'duh' for the
|
||||
appropriate parameter.
|
||||
|
||||
When you've finished with a DUH struct (this applies equally to the other
|
||||
structs DUMB deals with), you must pass it to an appropriate function for
|
||||
freeing up the memory:
|
||||
|
||||
unload_duh(duh);
|
||||
|
||||
After you've done this, the memory will no longer be allocated, and the
|
||||
pointer will have no meaning. You may wish to set it to NULL at this point
|
||||
for safety. Alternatively just be sure not to use the present value of the
|
||||
pointer any more. You can of course assign a new value to the pointer, e.g.
|
||||
by calling dumb_load_it() again.
|
||||
|
||||
Note the following:
|
||||
|
||||
DUH *duh2 = duh;
|
||||
|
||||
This only duplicates the pointer, not the DUH itself. You still only have one
|
||||
copy of the DUH. There is no way of duplicating a DUH, short of loading it
|
||||
twice. This is not a problem, because DUMB can play it 'twice at the same
|
||||
time' anyway.
|
||||
|
||||
That should be all you need to know about pointers in order to use DUMB. If
|
||||
there's anything you feel should be explained better here, or anything else
|
||||
that should be added, please don't hesitate to let me know!
|
||||
|
||||
|
||||
Ben Davis
|
||||
entheh@users.sf.net
|
||||
IRC EFnet #dumb
|
||||
See readme.txt for details on using IRC.
|
|
@ -1,94 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* tutorial.txt - DUMB Programmers' Tutorial. / / \ \
|
||||
* | < / \_
|
||||
* See readme.txt for general information on | \/ /\ /
|
||||
* DUMB and how to set it up. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
|
||||
********************
|
||||
*** Introduction ***
|
||||
********************
|
||||
|
||||
|
||||
Welcome to the DUMB Programmers' Tutorial!
|
||||
|
||||
In order to follow this tutorial, you should already have set Allegro and
|
||||
DUMB up on your system, including DUMB's support for Allegro and the example
|
||||
programs. If you have not done so, see readme.txt for details.
|
||||
|
||||
You will also need some IT files. If you would like to compose your own, then
|
||||
first I must offer a word of warning: not everyone is capable of composing
|
||||
music. Do not assume you will be able to learn the art. By all means have a
|
||||
go; if you can learn to play tunes on the computer keyboard, you're well on
|
||||
the way to being a composer!
|
||||
|
||||
The best program for the job is Impulse Tracker itself, available from:
|
||||
|
||||
http://www.noisemusic.org/it/
|
||||
|
||||
This is a DOS program. Users of DOS-incapable operating systems may like to
|
||||
try ModPlug Tracker, but should be aware that it does not support all
|
||||
combinations of effects correctly, and some IT files will sound wrong. If you
|
||||
use a different operating system, or if you know of a better IT editor for
|
||||
Windows, please give me some links so I can put them here!
|
||||
|
||||
ModPlug Tracker is available from: http://www.modplug.com/
|
||||
|
||||
If you would like to download IT files composed by other people, check the
|
||||
following sites:
|
||||
|
||||
http://www.modplug.com/
|
||||
http://www.traxinspace.com/
|
||||
|
||||
Once again, if you know of more sites where IT files are available for
|
||||
download, please let me know.
|
||||
|
||||
Once you've got some IT files, we're ready to begin!
|
||||
|
||||
Note that support for S3M files has very recently been added to DUMB, but it
|
||||
is bound to be faulty. I recommend you use IT files in preference until later
|
||||
releases of DUMB.
|
||||
|
||||
|
||||
******************
|
||||
*** Try It Out ***
|
||||
******************
|
||||
|
||||
|
||||
We'll start simply by running one of the example programs.
|
||||
|
||||
Find playit.exe, in the dumb/examples folder. Choose an IT file, and pass it
|
||||
to playit.exe. In DOS, you can do this by typing 'playit' followed by the
|
||||
name of the IT file. In Windows, you can drag the IT file and drop it on
|
||||
playit.exe.
|
||||
|
||||
You should now hear the music play back. If not, make sure your speakers are
|
||||
on and volume is not turned down. Try one of Allegro's example programs. If
|
||||
you are using DJGPP under Windows, consider using a Windows compiler instead.
|
||||
If you cannot get it working, see readme.txt for details on seeking help with
|
||||
DUMB.
|
||||
|
||||
When you are satisfied, press any key to stop the music and return to the
|
||||
operating system.
|
||||
|
||||
|
||||
*************************
|
||||
*** How Does It Work? ***
|
||||
*************************
|
||||
|
||||
|
||||
Now load playit.c into your favourite editor. Here is an explanation of what
|
||||
it does:
|
|
@ -1,44 +0,0 @@
|
|||
# Please edit this file to control the playback quality for 'dumbplay'. Note
|
||||
# that this does not affect DUMB when you use it in your own programs; you
|
||||
# need to borrow some code from the example program in order to get that to
|
||||
# happen.
|
||||
|
||||
# dumb_resampling_quality can be 0 for aliasing, 1 for linear interpolation
|
||||
# or 2 for cubic interpolation. See docs/dumb.txt for details on what these
|
||||
# terms mean.
|
||||
|
||||
# dumb_it_max_to_mix is the maximum number of samples DUMB will render at a
|
||||
# time. See docs/dumb.txt for a more detailed description.
|
||||
|
||||
# Increase buffer_size to combat stuttering.
|
||||
|
||||
# The music module will be rendered at the sampling frequency specified by
|
||||
# sound_freq. This variable is also used by Allegro for initialising the
|
||||
# sound hardware.
|
||||
|
||||
# buffer_size and sound_freq are passed directly to al_start_duh(). See this
|
||||
# function's description in docs/dumb.txt for information about how to use
|
||||
# these variables.
|
||||
|
||||
# You can ignore the quality variable. Allegro uses it when relaying the
|
||||
# audio stream to the sound card. Only a masochist would set it lower than 2;
|
||||
# if your computer is powerful enough to run DUMB, it is powerful enough to
|
||||
# use this setting with Allegro.
|
||||
|
||||
# For best results, choose a value for sound_freq that your sound card can do
|
||||
# exactly. See Allegro's docs, "Standard config variables", for details. If
|
||||
# you do not choose an exact value, Allegro will round it to the nearest
|
||||
# value it can do; then when DUMB plays the stream at a sampling frequency of
|
||||
# sound_freq, Allegro will have to resample it. Allegro's 'quality = 2'
|
||||
# setting is only comparable with DUMB's 'dumb_resampling_quality = 1'
|
||||
# setting. Therefore, in order to appreciate DUMB's cubic resampler fully,
|
||||
# you will need to make sure Allegro doesn't do any resampling, by choosing
|
||||
# an exact value for sound_freq.
|
||||
|
||||
[sound]
|
||||
dumb_resampling_quality = 2
|
||||
dumb_it_max_to_mix = 256
|
||||
buffer_size = 4096
|
||||
sound_freq = 44100
|
||||
|
||||
quality = 2
|
|
@ -1,481 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* dumb2wav.c - Utility to convert DUH to WAV. / / \ \
|
||||
* | < / \_
|
||||
* By Chad Austin, based on dumbout.c by entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <dumb.h>
|
||||
|
||||
#include <internal/it.h>
|
||||
|
||||
union {
|
||||
float s32[4096];
|
||||
short s16[8192];
|
||||
char s8[16384];
|
||||
} buffer;
|
||||
|
||||
sample_t ** internal_buffer;
|
||||
|
||||
int loop_count = 1;
|
||||
|
||||
|
||||
static int write32_le(FILE* outf, unsigned int value) {
|
||||
int total = 0;
|
||||
total += fputc(value & 0xFF, outf);
|
||||
total += fputc((value >> 8) & 0xFF, outf);
|
||||
total += fputc((value >> 16) & 0xFF, outf);
|
||||
total += fputc((value >> 24) & 0xFF, outf);
|
||||
return total;
|
||||
}
|
||||
|
||||
static int write16_le(FILE* outf, unsigned int value) {
|
||||
int total = 0;
|
||||
total += fputc(value & 0xFF, outf);
|
||||
total += fputc((value >> 8) & 0xFF, outf);
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
static int loop_callback(void* data) {
|
||||
return (--loop_count <= 0 ? -1 : 0);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
DUH *duh;
|
||||
DUH_SIGRENDERER *sr;
|
||||
|
||||
const char *fn = NULL;
|
||||
const char *fn_out = NULL;
|
||||
FILE *outf;
|
||||
|
||||
int depth = 16;
|
||||
int unsign = 0;
|
||||
int freq = 44100;
|
||||
int n_channels = 2;
|
||||
int solo = -1;
|
||||
float volume = 1.0f;
|
||||
float delay = 0.0f;
|
||||
float delta;
|
||||
int bufsize;
|
||||
clock_t start, end;
|
||||
int data_written = 0; /* total bytes written to data chunk */
|
||||
|
||||
int i = 1;
|
||||
|
||||
LONG_LONG length;
|
||||
LONG_LONG done;
|
||||
int dots;
|
||||
|
||||
while (i < argc) {
|
||||
const char *arg = argv[i++];
|
||||
if (*arg != '-') {
|
||||
if (fn) {
|
||||
fprintf(stderr,
|
||||
"Cannot specify multiple filenames!\n"
|
||||
"Second filename found: \"%s\"\n", arg);
|
||||
return 1;
|
||||
}
|
||||
fn = arg;
|
||||
continue;
|
||||
}
|
||||
arg++;
|
||||
while (*arg) {
|
||||
char *endptr;
|
||||
switch (*arg++) {
|
||||
case 'o':
|
||||
case 'O':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments; output filename expected!\n");
|
||||
return 1;
|
||||
}
|
||||
fn_out = argv[i++];
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments; delay expected!\n");
|
||||
return 1;
|
||||
}
|
||||
delay = (float)strtod(argv[i++], &endptr);
|
||||
if (*endptr != 0 || delay < 0.0f || delay > 64.0f) {
|
||||
fprintf(stderr, "Invalid delay!\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
case 'V':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments; volume expected!\n");
|
||||
return 1;
|
||||
}
|
||||
volume = (float)strtod(argv[i++], &endptr);
|
||||
if (*endptr != 0 || volume < -8.0f || volume > 8.0f) {
|
||||
fprintf(stderr, "Invalid volume!\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
case 'S':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments; sampling rate expected!\n");
|
||||
return 1;
|
||||
}
|
||||
freq = strtol(argv[i++], &endptr, 10);
|
||||
if (*endptr != 0 || freq < 1 || freq > 960000) {
|
||||
fprintf(stderr, "Invalid sampling rate!\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
depth = 32;
|
||||
break;
|
||||
case '8':
|
||||
depth = 8;
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments: loop count expected!\n");
|
||||
return 1;
|
||||
}
|
||||
loop_count = strtol(argv[i++], &endptr, 10);
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
n_channels = 1;
|
||||
break;
|
||||
case 'u':
|
||||
case 'U':
|
||||
unsign = 1;
|
||||
break;
|
||||
case 'r':
|
||||
case 'R':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments; resampling quality expected!\n");
|
||||
return 1;
|
||||
}
|
||||
dumb_resampling_quality = strtol(argv[i++], &endptr, 10);
|
||||
if (*endptr != 0 || dumb_resampling_quality < 0 || dumb_resampling_quality > 2) {
|
||||
fprintf(stderr, "Invalid resampling quality!\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
case 'C':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments; channel number expected!\n");
|
||||
return 1;
|
||||
}
|
||||
solo = strtol(argv[i++], &endptr, 10);
|
||||
if (*endptr != 0 || solo < 0 || solo >= DUMB_IT_N_CHANNELS) {
|
||||
fprintf(stderr, "Invalid channel number!\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid switch - '%c'!\n", isprint(arg[-1]) ? arg[-1] : '?');
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fn) {
|
||||
fprintf(stderr,
|
||||
"Usage: dumb2wav [options] module [more-options]\n"
|
||||
"\n"
|
||||
"The module can be any IT, XM, S3M or MOD file. It will be rendered to a .wav\n"
|
||||
"file of the same name, unless you specify otherwise with the -o option.\n"
|
||||
"\n"
|
||||
"The valid options are:\n"
|
||||
"-o <file> specify the output filename (defaults to the input filename with\n"
|
||||
" the extension replaced with .wav); use - to write to standard\n"
|
||||
" output or . to write nowhere (useful for measuring DUMB's\n"
|
||||
" performance, and DOS and Windows don't have /dev/null!)\n"
|
||||
"-d <delay> set the initial delay, in seconds (default 0.0)\n"
|
||||
"-v <volume> adjust the volume (default 1.0)\n"
|
||||
"-s <freq> set the sampling rate in Hz (default 44100)\n"
|
||||
"-8 generate 8-bit instead of 16-bit\n"
|
||||
"-f generate floating point samples instead of 16-bit\n"
|
||||
"-m generate mono output instead of stereo left/right pairs\n"
|
||||
"-u generated unsigned output instead of signed\n"
|
||||
"-r <value> specify the resampling quality to use\n"
|
||||
"-l <value> specify the number of times to loop (default 1)\n"
|
||||
"-c <value> specify a channel number to solo\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
atexit(&dumb_exit);
|
||||
dumb_register_stdfiles();
|
||||
|
||||
dumb_it_max_to_mix = 256;
|
||||
|
||||
duh = load_duh(fn);
|
||||
if (!duh) {
|
||||
duh = dumb_load_it(fn);
|
||||
if (!duh) {
|
||||
duh = dumb_load_xm(fn);
|
||||
if (!duh) {
|
||||
duh = dumb_load_s3m(fn);
|
||||
if (!duh) {
|
||||
duh = dumb_load_mod(fn);
|
||||
if (!duh) {
|
||||
fprintf(stderr, "Unable to open %s!\n", fn);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sr = duh_start_sigrenderer(duh, 0, n_channels, 0);
|
||||
if (!sr) {
|
||||
unload_duh(duh);
|
||||
fprintf(stderr, "Unable to play file!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (solo >= 0) {
|
||||
DUMB_IT_SIGRENDERER * itsr = duh_get_it_sigrenderer(sr);
|
||||
if (itsr) {
|
||||
for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
|
||||
if (i != solo) {
|
||||
IT_CHANNEL * channel = &itsr->channel[i];
|
||||
IT_PLAYING * playing = channel->playing;
|
||||
channel->flags |= IT_CHANNEL_MUTED;
|
||||
/* start_sigrenderer leaves me all of the channels the first tick triggered */
|
||||
if (playing) {
|
||||
playing->ramp_volume[0] = 0;
|
||||
playing->ramp_volume[1] = 0;
|
||||
playing->ramp_delta[0] = 0;
|
||||
playing->ramp_delta[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fn_out) {
|
||||
if (fn_out[0] == '-' && fn_out[1] == 0)
|
||||
outf = stdout;
|
||||
else if (fn_out[0] == '.' && fn_out[1] == 0)
|
||||
outf = NULL;
|
||||
else {
|
||||
outf = fopen(fn_out, "wb");
|
||||
if (!outf) {
|
||||
fprintf(stderr, "Unable to open %s for writing!\n", fn_out);
|
||||
duh_end_sigrenderer(sr);
|
||||
unload_duh(duh);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
char *extptr = NULL, *p;
|
||||
char *fn_out = malloc(strlen(fn)+5);
|
||||
if (!fn_out) {
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
duh_end_sigrenderer(sr);
|
||||
unload_duh(duh);
|
||||
return 1;
|
||||
}
|
||||
strcpy(fn_out, fn);
|
||||
for (p = fn_out; *p; p++)
|
||||
if (*p == '.') extptr = p;
|
||||
if (!extptr) extptr = p;
|
||||
strcpy(extptr, ".wav");
|
||||
outf = fopen(fn_out, "wb");
|
||||
if (!outf) {
|
||||
fprintf(stderr, "Unable to open %s for writing!\n", fn_out);
|
||||
free(fn_out);
|
||||
duh_end_sigrenderer(sr);
|
||||
unload_duh(duh);
|
||||
return 1;
|
||||
}
|
||||
free(fn_out);
|
||||
}
|
||||
|
||||
{
|
||||
DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr);
|
||||
dumb_it_set_ramp_style(itsr, 2);
|
||||
dumb_it_set_loop_callback(itsr, loop_callback, NULL);
|
||||
dumb_it_set_xm_speed_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
|
||||
dumb_it_set_global_volume_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
|
||||
}
|
||||
|
||||
|
||||
if (outf) {
|
||||
/* write RIFF header: fill file length later */
|
||||
fwrite("RIFF", 1, 4, outf);
|
||||
fwrite(" ", 1, 4, outf);
|
||||
fwrite("WAVE", 1, 4, outf);
|
||||
|
||||
/* write format chunk */
|
||||
fwrite("fmt ", 1, 4, outf);
|
||||
|
||||
if (depth == 32)
|
||||
{
|
||||
write32_le(outf, 18);
|
||||
write16_le(outf, 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
write32_le(outf, 16); /* header length */
|
||||
write16_le(outf, 1); /* WAVE_FORMAT_PCM */
|
||||
}
|
||||
write16_le(outf, n_channels); /* channel count */
|
||||
write32_le(outf, freq); /* frequency */
|
||||
write32_le(outf, freq * n_channels * depth / 8); /*bytes/sec*/
|
||||
write16_le(outf, n_channels * depth / 8); /* block alignment */
|
||||
write16_le(outf, depth); /* bits per sample */
|
||||
|
||||
if (depth == 32)
|
||||
{
|
||||
write16_le(outf, 0);
|
||||
}
|
||||
|
||||
/* start data chunk */
|
||||
fwrite("data", 1, 4, outf);
|
||||
fwrite(" ", 1, 4, outf); /* fill in later */
|
||||
}
|
||||
|
||||
length = (LONG_LONG)_dumb_it_build_checkpoints(duh_get_it_sigdata(duh), 0) * freq >> 16;
|
||||
done = 0;
|
||||
dots = 0;
|
||||
delta = 65536.0f / freq;
|
||||
bufsize = sizeof(buffer);
|
||||
if (depth == 32) bufsize /= sizeof(*buffer.s32);
|
||||
else if (depth == 16) bufsize /= sizeof(*buffer.s16);
|
||||
bufsize /= n_channels;
|
||||
|
||||
if (depth == 32) {
|
||||
internal_buffer = create_sample_buffer(n_channels, bufsize);
|
||||
if (!internal_buffer) {
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
duh_end_sigrenderer(sr);
|
||||
unload_duh(duh);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
long l = (long)floor(delay * freq + 0.5f);
|
||||
l *= n_channels * (depth >> 3);
|
||||
if (l) {
|
||||
if (unsign && depth != 32) {
|
||||
if (depth == 16) {
|
||||
for (i = 0; i < 8192; i++) {
|
||||
buffer.s8[i*2] = 0x00;
|
||||
buffer.s8[i*2+1] = 0x80;
|
||||
}
|
||||
} else
|
||||
memset(buffer.s8, 0x80, 16384);
|
||||
} else
|
||||
memset(buffer.s8, 0, 16384);
|
||||
while (l >= 16384) {
|
||||
if (outf) fwrite(buffer.s8, 1, 16384, outf);
|
||||
l -= 16384;
|
||||
data_written += 16384;
|
||||
}
|
||||
if (l) {
|
||||
if (outf) fwrite(buffer.s8, 1, l, outf);
|
||||
data_written += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start = clock();
|
||||
|
||||
fprintf(stderr, "................................................................\n");
|
||||
for (;;) {
|
||||
int write_size;
|
||||
int l;
|
||||
|
||||
if (depth != 32) {
|
||||
l = duh_render(sr, depth, unsign, volume, delta, bufsize, &buffer);
|
||||
if (depth == 16) {
|
||||
for (i = 0; i < l * n_channels; i++) {
|
||||
short val = buffer.s16[i];
|
||||
buffer.s8[i*2] = val;
|
||||
buffer.s8[i*2+1] = val >> 8;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int j;
|
||||
dumb_silence(internal_buffer[0], bufsize * n_channels);
|
||||
l = duh_sigrenderer_get_samples(sr, volume, delta, bufsize, internal_buffer);
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
for (j = 0; j < l; j++) {
|
||||
buffer.s32[j * n_channels + i] = (float)((double)internal_buffer[i][j] * (1.0 / (double)(0x800000)));
|
||||
}
|
||||
}
|
||||
}
|
||||
write_size = l * n_channels * (depth >> 3);
|
||||
if (outf) fwrite(buffer.s8, 1, write_size, outf);
|
||||
data_written += write_size;
|
||||
if (l < bufsize) break;
|
||||
done += l;
|
||||
l = done * 64 / length;
|
||||
while (dots < 64 && l > dots) {
|
||||
fprintf(stderr, "|");
|
||||
dots++;
|
||||
}
|
||||
if (dots >= 64) {
|
||||
putchar('\n');
|
||||
dots = 0;
|
||||
done = 0;
|
||||
}
|
||||
}
|
||||
|
||||
while (64 > dots) {
|
||||
fprintf(stderr, "|");
|
||||
dots++;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
end = clock();
|
||||
|
||||
if (depth == 32) destroy_sample_buffer(internal_buffer);
|
||||
|
||||
/* fill in blanks we left in WAVE file */
|
||||
if (outf) {
|
||||
/* file size, not including RIFF header */
|
||||
const int fmt_size = 8 + ((depth == 32) ? 18 : 16);
|
||||
const int data_size = 8 + data_written;
|
||||
const int file_size = fmt_size + data_size;
|
||||
|
||||
/* can we seek stdout? */
|
||||
fseek(outf, 4, SEEK_SET);
|
||||
write32_le(outf, file_size);
|
||||
|
||||
fseek(outf, 12 + fmt_size + 4, SEEK_SET);
|
||||
write32_le(outf, data_written);
|
||||
}
|
||||
|
||||
|
||||
duh_end_sigrenderer(sr);
|
||||
unload_duh(duh);
|
||||
if (outf && outf != stdout) fclose(outf);
|
||||
|
||||
fprintf(stderr, "Elapsed time: %f seconds\n", (end - start) / (float)CLOCKS_PER_SEC);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,404 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* dumbout.c - Utility to stream music to a file. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <dumb.h>
|
||||
|
||||
#include <internal/it.h>
|
||||
|
||||
union {
|
||||
float s32[4096];
|
||||
short s16[8192];
|
||||
char s8[16384];
|
||||
} buffer;
|
||||
|
||||
sample_t ** internal_buffer;
|
||||
|
||||
int main(int argc, const char *const *argv) /* I'm const-crazy! */
|
||||
{
|
||||
DUH *duh;
|
||||
DUH_SIGRENDERER *sr;
|
||||
|
||||
const char *fn = NULL;
|
||||
const char *fn_out = NULL;
|
||||
FILE *outf;
|
||||
|
||||
int depth = 16;
|
||||
int bigendian = 0;
|
||||
int unsign = 0;
|
||||
int freq = 44100;
|
||||
int n_channels = 2;
|
||||
int solo = -1;
|
||||
float volume = 1.0f;
|
||||
float delay = 0.0f;
|
||||
float delta;
|
||||
int bufsize;
|
||||
clock_t start, end;
|
||||
|
||||
int i = 1;
|
||||
|
||||
LONG_LONG length;
|
||||
LONG_LONG done;
|
||||
int dots;
|
||||
|
||||
while (i < argc) {
|
||||
const char *arg = argv[i++];
|
||||
if (*arg != '-') {
|
||||
if (fn) {
|
||||
fprintf(stderr,
|
||||
"Cannot specify multiple filenames!\n"
|
||||
"Second filename found: \"%s\"\n", arg);
|
||||
return 1;
|
||||
}
|
||||
fn = arg;
|
||||
continue;
|
||||
}
|
||||
arg++;
|
||||
while (*arg) {
|
||||
char *endptr;
|
||||
switch (*arg++) {
|
||||
case 'o':
|
||||
case 'O':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments; output filename expected!\n");
|
||||
return 1;
|
||||
}
|
||||
fn_out = argv[i++];
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments; delay expected!\n");
|
||||
return 1;
|
||||
}
|
||||
delay = (float)strtod(argv[i++], &endptr);
|
||||
if (*endptr != 0 || delay < 0.0f || delay > 64.0f) {
|
||||
fprintf(stderr, "Invalid delay!\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
case 'V':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments; volume expected!\n");
|
||||
return 1;
|
||||
}
|
||||
volume = (float)strtod(argv[i++], &endptr);
|
||||
if (*endptr != 0 || volume < -8.0f || volume > 8.0f) {
|
||||
fprintf(stderr, "Invalid volume!\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
case 'S':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments; sampling rate expected!\n");
|
||||
return 1;
|
||||
}
|
||||
freq = strtol(argv[i++], &endptr, 10);
|
||||
if (*endptr != 0 || freq < 1 || freq > 960000) {
|
||||
fprintf(stderr, "Invalid sampling rate!\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
depth = 32;
|
||||
break;
|
||||
case '8':
|
||||
depth = 8;
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
bigendian = 1;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
n_channels = 1;
|
||||
break;
|
||||
case 'u':
|
||||
case 'U':
|
||||
unsign = 1;
|
||||
break;
|
||||
case 'r':
|
||||
case 'R':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments; resampling quality expected!\n");
|
||||
return 1;
|
||||
}
|
||||
dumb_resampling_quality = strtol(argv[i++], &endptr, 10);
|
||||
if (*endptr != 0 || dumb_resampling_quality < 0 || dumb_resampling_quality > 2) {
|
||||
fprintf(stderr, "Invalid resampling quality!\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
case 'C':
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Out of arguments; channel number expected!\n");
|
||||
return 1;
|
||||
}
|
||||
solo = strtol(argv[i++], &endptr, 10);
|
||||
if (*endptr != 0 || solo < 0 || solo >= DUMB_IT_N_CHANNELS) {
|
||||
fprintf(stderr, "Invalid channel number!\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid switch - '%c'!\n", isprint(arg[-1]) ? arg[-1] : '?');
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fn) {
|
||||
fprintf(stderr,
|
||||
"Usage: dumbout [options] module [more-options]\n"
|
||||
"\n"
|
||||
"The module can be any IT, XM, S3M or MOD file. It will be rendered to a .pcm\n"
|
||||
"file of the same name, unless you specify otherwise with the -o option.\n"
|
||||
"\n"
|
||||
"The valid options are:\n"
|
||||
"-o <file> specify the output filename (defaults to the input filename with\n"
|
||||
" the extension replaced with .pcm); use - to write to standard\n"
|
||||
" output or . to write nowhere (useful for measuring DUMB's\n"
|
||||
" performance, and DOS and Windows don't have /dev/null!)\n"
|
||||
"-d <delay> set the initial delay, in seconds (default 0.0)\n"
|
||||
"-v <volume> adjust the volume (default 1.0)\n"
|
||||
"-s <freq> set the sampling rate in Hz (default 44100)\n"
|
||||
"-8 generate 8-bit instead of 16-bit\n"
|
||||
"-f generate 32-bit floating point data instead of 16-bit\n"
|
||||
"-b generate big-endian data instead of little-endian (meaningless when\n"
|
||||
" using -8)\n"
|
||||
"-m generate mono output instead of stereo left/right pairs\n"
|
||||
"-u generated unsigned output instead of signed\n"
|
||||
"-r <value> specify the resampling quality to use\n"
|
||||
"-c <value> specify a channel number to solo\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
atexit(&dumb_exit);
|
||||
dumb_register_stdfiles();
|
||||
|
||||
dumb_it_max_to_mix = 256;
|
||||
|
||||
duh = load_duh(fn);
|
||||
if (!duh) {
|
||||
duh = dumb_load_it(fn);
|
||||
if (!duh) {
|
||||
duh = dumb_load_xm(fn);
|
||||
if (!duh) {
|
||||
duh = dumb_load_s3m(fn);
|
||||
if (!duh) {
|
||||
duh = dumb_load_mod(fn);
|
||||
if (!duh) {
|
||||
fprintf(stderr, "Unable to open %s!\n", fn);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sr = duh_start_sigrenderer(duh, 0, n_channels, 0);
|
||||
if (!sr) {
|
||||
unload_duh(duh);
|
||||
fprintf(stderr, "Unable to play file!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (solo >= 0) {
|
||||
DUMB_IT_SIGRENDERER * itsr = duh_get_it_sigrenderer(sr);
|
||||
if (itsr) {
|
||||
for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
|
||||
if (i != solo) {
|
||||
IT_CHANNEL * channel = &itsr->channel[i];
|
||||
IT_PLAYING * playing = channel->playing;
|
||||
channel->flags |= IT_CHANNEL_MUTED;
|
||||
/* start_sigrenderer leaves me all of the channels the first tick triggered */
|
||||
if (playing) {
|
||||
playing->ramp_volume[0] = 0;
|
||||
playing->ramp_volume[1] = 0;
|
||||
playing->ramp_delta[0] = 0;
|
||||
playing->ramp_delta[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fn_out) {
|
||||
if (fn_out[0] == '-' && fn_out[1] == 0)
|
||||
outf = stdout;
|
||||
else if (fn_out[0] == '.' && fn_out[1] == 0)
|
||||
outf = NULL;
|
||||
else {
|
||||
outf = fopen(fn_out, "wb");
|
||||
if (!outf) {
|
||||
fprintf(stderr, "Unable to open %s for writing!\n", fn_out);
|
||||
duh_end_sigrenderer(sr);
|
||||
unload_duh(duh);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
char *extptr = NULL, *p;
|
||||
char *fn_out = malloc(strlen(fn)+5);
|
||||
if (!fn_out) {
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
duh_end_sigrenderer(sr);
|
||||
unload_duh(duh);
|
||||
return 1;
|
||||
}
|
||||
strcpy(fn_out, fn);
|
||||
for (p = fn_out; *p; p++)
|
||||
if (*p == '.') extptr = p;
|
||||
if (!extptr) extptr = p;
|
||||
strcpy(extptr, ".pcm");
|
||||
outf = fopen(fn_out, "wb");
|
||||
if (!outf) {
|
||||
fprintf(stderr, "Unable to open %s for writing!\n", fn_out);
|
||||
free(fn_out);
|
||||
duh_end_sigrenderer(sr);
|
||||
unload_duh(duh);
|
||||
return 1;
|
||||
}
|
||||
free(fn_out);
|
||||
}
|
||||
|
||||
{
|
||||
DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr);
|
||||
dumb_it_set_ramp_style(itsr, 2);
|
||||
dumb_it_set_loop_callback(itsr, &dumb_it_callback_terminate, NULL);
|
||||
dumb_it_set_xm_speed_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
|
||||
dumb_it_set_global_volume_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
|
||||
}
|
||||
|
||||
length = (LONG_LONG)_dumb_it_build_checkpoints(duh_get_it_sigdata(duh), 0) * freq >> 16;
|
||||
done = 0;
|
||||
dots = 0;
|
||||
delta = 65536.0f / freq;
|
||||
bufsize = sizeof(buffer);
|
||||
if (depth == 32) bufsize /= sizeof(*buffer.s32);
|
||||
else if (depth == 16) bufsize /= sizeof(*buffer.s16);
|
||||
bufsize /= n_channels;
|
||||
|
||||
if (depth == 32) {
|
||||
internal_buffer = create_sample_buffer(n_channels, bufsize);
|
||||
if (!internal_buffer) {
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
duh_end_sigrenderer(sr);
|
||||
unload_duh(duh);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
long l = (long)floor(delay * freq + 0.5f);
|
||||
l *= n_channels * (depth >> 3);
|
||||
if (l) {
|
||||
if (unsign && depth != 32) {
|
||||
if (depth == 16) {
|
||||
if (bigendian) {
|
||||
for (i = 0; i < 8192; i++) {
|
||||
buffer.s8[i*2] = 0x80;
|
||||
buffer.s8[i*2+1] = 0x00;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 8192; i++) {
|
||||
buffer.s8[i*2] = 0x00;
|
||||
buffer.s8[i*2+1] = 0x80;
|
||||
}
|
||||
}
|
||||
} else
|
||||
memset(buffer.s8, 0x80, 16384);
|
||||
} else
|
||||
memset(buffer.s8, 0, 16384);
|
||||
while (l >= 16384) {
|
||||
if (outf) fwrite(buffer.s8, 1, 16384, outf);
|
||||
l -= 16384;
|
||||
}
|
||||
if (l && outf) fwrite(buffer.s8, 1, l, outf);
|
||||
}
|
||||
}
|
||||
|
||||
start = clock();
|
||||
|
||||
fprintf(stderr, "................................................................\n");
|
||||
for (;;) {
|
||||
int l;
|
||||
|
||||
if (depth != 32) {
|
||||
l = duh_render(sr, depth, unsign, volume, delta, bufsize, &buffer);
|
||||
if (depth == 16) {
|
||||
if (bigendian) {
|
||||
for (i = 0; i < l * n_channels; i++) {
|
||||
short val = buffer.s16[i];
|
||||
buffer.s8[i*2] = val >> 8;
|
||||
buffer.s8[i*2+1] = val;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < l * n_channels; i++) {
|
||||
short val = buffer.s16[i];
|
||||
buffer.s8[i*2] = val;
|
||||
buffer.s8[i*2+1] = val >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int j;
|
||||
dumb_silence(internal_buffer[0], bufsize * n_channels);
|
||||
l = duh_sigrenderer_get_samples(sr, volume, delta, bufsize, internal_buffer);
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
for (j = i; j < l; j++) {
|
||||
buffer.s32[j * n_channels] = (float)((double)internal_buffer[i][j] * (1.0 / (double)(0x800000)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outf) fwrite(buffer.s8, 1, l * n_channels * (depth >> 3), outf);
|
||||
if (l < bufsize) break;
|
||||
done += l;
|
||||
l = done * 64 / length;
|
||||
while (dots < 64 && l > dots) {
|
||||
fprintf(stderr, "|");
|
||||
dots++;
|
||||
}
|
||||
}
|
||||
|
||||
while (64 > dots) {
|
||||
fprintf(stderr, "|");
|
||||
dots++;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
end = clock();
|
||||
|
||||
if (depth == 32) destroy_sample_buffer(internal_buffer);
|
||||
|
||||
duh_end_sigrenderer(sr);
|
||||
unload_duh(duh);
|
||||
if (outf && outf != stdout) fclose(outf);
|
||||
|
||||
fprintf(stderr, "Elapsed time: %f seconds\n", (end - start) / (float)CLOCKS_PER_SEC);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,238 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* dumbplay.c - Not-so-simple program to play / / \ \
|
||||
* music. It used to be simpler! | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* IMPORTANT NOTE: This file is not very friendly. | ' /
|
||||
* I strongly recommend AGAINST using it as a \__/
|
||||
* reference for writing your own code. If you would
|
||||
* like to write a program that uses DUMB, or add DUMB to an existing
|
||||
* project, please use docs/howto.txt. It will help you a lot more than this
|
||||
* file can. (If you have difficulty reading documentation, you are lacking
|
||||
* an important coding skill, and now is as good a time as any to learn.)
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <allegro.h>
|
||||
|
||||
#ifndef ALLEGRO_DOS
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
/* Note that your own programs should use <aldumb.h> not "aldumb.h". <> tells
|
||||
* the compiler to look in the compiler's default header directory, which is
|
||||
* where DUMB should be installed before you use it (make install does this).
|
||||
* Use "" when it is your own header file. This example uses "" because DUMB
|
||||
* might not have been installed yet when the makefile builds it.
|
||||
*/
|
||||
#include "aldumb.h"
|
||||
|
||||
|
||||
|
||||
#ifndef ALLEGRO_DOS
|
||||
static volatile int closed = 0;
|
||||
static void closehook(void) { closed = 1; }
|
||||
#else
|
||||
#define closed 0
|
||||
#endif
|
||||
|
||||
#ifdef ALLEGRO_WINDOWS
|
||||
#define GFX_DUMB_MODE GFX_GDI
|
||||
#include <winalleg.h>
|
||||
#define YIELD() Sleep(1)
|
||||
#else
|
||||
#define GFX_DUMB_MODE GFX_AUTODETECT_WINDOWED
|
||||
#ifdef ALLEGRO_UNIX
|
||||
#include <sys/time.h>
|
||||
static void YIELD(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
}
|
||||
#else
|
||||
#define YIELD() yield_timeslice()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef ALLEGRO_DOS
|
||||
static int loop_callback(void *data)
|
||||
{
|
||||
(void)data;
|
||||
printf("Music has looped.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xm_speed_zero_callback(void *data)
|
||||
{
|
||||
(void)data;
|
||||
printf("Music has stopped.\n");
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int gfx_half_width;
|
||||
|
||||
static int loop_callback(void *data)
|
||||
{
|
||||
(void)data;
|
||||
if (gfx_half_width) {
|
||||
acquire_screen();
|
||||
textout_centre(screen, font, "Music has looped.", gfx_half_width, 36, 10);
|
||||
release_screen();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xm_speed_zero_callback(void *data)
|
||||
{
|
||||
(void)data;
|
||||
if (gfx_half_width) {
|
||||
text_mode(0); /* In case this is overwriting "Music has looped." */
|
||||
acquire_screen();
|
||||
textout_centre(screen, font, "Music has stopped.", gfx_half_width, 36, 10);
|
||||
release_screen();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static void usage(const char *exename)
|
||||
{
|
||||
allegro_message(
|
||||
#ifdef ALLEGRO_WINDOWS
|
||||
"Usage:\n"
|
||||
" At the command line: %s file\n"
|
||||
" In Windows Explorer: drag a file on to this program's icon.\n"
|
||||
#else
|
||||
"Usage: %s file\n"
|
||||
#endif
|
||||
"This will play the music file specified.\n"
|
||||
"File formats supported: IT XM S3M MOD.\n"
|
||||
"You can control playback quality by editing dumb.ini.\n", exename);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, const char *const *argv) /* I'm const-crazy! */
|
||||
{
|
||||
DUH *duh;
|
||||
AL_DUH_PLAYER *dp;
|
||||
|
||||
if (allegro_init())
|
||||
return 1;
|
||||
|
||||
if (argc != 2)
|
||||
usage(argv[0]);
|
||||
|
||||
set_config_file("dumb.ini");
|
||||
|
||||
if (install_keyboard()) {
|
||||
allegro_message("Failed to initialise keyboard driver!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
set_volume_per_voice(0);
|
||||
|
||||
if (install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL)) {
|
||||
allegro_message("Failed to initialise sound driver!\n%s\n", allegro_error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
atexit(&dumb_exit);
|
||||
|
||||
dumb_register_packfiles();
|
||||
|
||||
duh = dumb_load_it(argv[1]);
|
||||
if (!duh) {
|
||||
duh = dumb_load_xm(argv[1]);
|
||||
if (!duh) {
|
||||
duh = dumb_load_s3m(argv[1]);
|
||||
if (!duh) {
|
||||
duh = dumb_load_mod(argv[1]);
|
||||
if (!duh) {
|
||||
allegro_message("Failed to load %s!\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dumb_resampling_quality = get_config_int("sound", "dumb_resampling_quality", 4);
|
||||
dumb_it_max_to_mix = get_config_int("sound", "dumb_it_max_to_mix", 128);
|
||||
|
||||
#ifndef ALLEGRO_DOS
|
||||
{
|
||||
const char *fn = get_filename(argv[1]);
|
||||
gfx_half_width = strlen(fn);
|
||||
if (gfx_half_width < 22) gfx_half_width = 22;
|
||||
gfx_half_width = (gfx_half_width + 2) * 4;
|
||||
|
||||
/* set_window_title() is not const-correct (yet). */
|
||||
set_window_title((char *)"DUMB Music Player");
|
||||
|
||||
if (set_gfx_mode(GFX_DUMB_MODE, gfx_half_width*2, 80, 0, 0) == 0) {
|
||||
acquire_screen();
|
||||
textout_centre(screen, font, fn, gfx_half_width, 20, 14);
|
||||
textout_centre(screen, font, "Press any key to exit.", gfx_half_width, 52, 11);
|
||||
release_screen();
|
||||
} else
|
||||
gfx_half_width = 0;
|
||||
}
|
||||
|
||||
#if ALLEGRO_VERSION*10000 + ALLEGRO_SUB_VERSION*100 + ALLEGRO_WIP_VERSION >= 40105
|
||||
set_close_button_callback(&closehook);
|
||||
#else
|
||||
set_window_close_hook(&closehook);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
set_display_switch_mode(SWITCH_BACKGROUND);
|
||||
|
||||
dp = al_start_duh(duh, 2, 0, 1.0f,
|
||||
get_config_int("sound", "buffer_size", 4096),
|
||||
get_config_int("sound", "sound_freq", 44100));
|
||||
|
||||
{
|
||||
DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp);
|
||||
DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr);
|
||||
dumb_it_set_loop_callback(itsr, &loop_callback, NULL);
|
||||
dumb_it_set_xm_speed_zero_callback(itsr, &xm_speed_zero_callback, NULL);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (keypressed()) {
|
||||
readkey();
|
||||
break;
|
||||
}
|
||||
|
||||
if (al_poll_duh(dp) || closed)
|
||||
break;
|
||||
|
||||
YIELD();
|
||||
}
|
||||
|
||||
al_stop_duh(dp);
|
||||
|
||||
unload_duh(duh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
END_OF_MAIN();
|
|
@ -1,169 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* playduh.c - Simple program to play DUH files. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <allegro.h>
|
||||
|
||||
#ifndef ALLEGRO_DOS
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
/* Note that your own programs should use <aldumb.h> not "aldumb.h". <> tells
|
||||
* the compiler to look in the compiler's default header directory, which is
|
||||
* where DUMB should be installed before you use it (make install does this).
|
||||
* Use "" when it is your own header file. This example uses "" because DUMB
|
||||
* might not have been installed yet when the makefile builds it.
|
||||
*/
|
||||
#include "aldumb.h"
|
||||
|
||||
|
||||
|
||||
#ifndef ALLEGRO_DOS
|
||||
static int closed = 0;
|
||||
static void closehook(void) { closed = 1; }
|
||||
#else
|
||||
#define closed 0
|
||||
#endif
|
||||
|
||||
#ifdef ALLEGRO_WINDOWS
|
||||
#define GFX_DUMB_MODE GFX_GDI
|
||||
#include <winalleg.h>
|
||||
#define YIELD() Sleep(1)
|
||||
#else
|
||||
#define GFX_DUMB_MODE GFX_AUTODETECT_WINDOWED
|
||||
#ifdef ALLEGRO_UNIX
|
||||
#include <sys/time.h>
|
||||
static void YIELD(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
}
|
||||
#else
|
||||
#define YIELD() yield_timeslice()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
allegro_message(
|
||||
"Usage: playduh file.duh\n"
|
||||
"This will play the .duh file specified.\n"
|
||||
"You can control playback quality by editing dumb.ini.\n"
|
||||
);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
DUH *duh;
|
||||
AL_DUH_PLAYER *dp;
|
||||
|
||||
if (allegro_init())
|
||||
return 1;
|
||||
|
||||
if (argc != 2)
|
||||
usage();
|
||||
|
||||
set_config_file("dumb.ini");
|
||||
|
||||
if (install_keyboard()) {
|
||||
allegro_message("Failed to initialise keyboard driver!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
set_volume_per_voice(0);
|
||||
|
||||
if (install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL)) {
|
||||
allegro_message("Failed to initialise sound driver!\n%s\n", allegro_error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
atexit(&dumb_exit);
|
||||
|
||||
dumb_register_stdfiles();
|
||||
|
||||
/*
|
||||
dumb_register_sigtype_sample();
|
||||
dumb_register_sigtype_combining();
|
||||
dumb_register_sigtype_stereopan();
|
||||
dumb_register_sigtype_sequence();
|
||||
*/
|
||||
|
||||
duh = load_duh(argv[1]);
|
||||
if (!duh) {
|
||||
allegro_message("Failed to load %s!\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dumb_resampling_quality = get_config_int("sound", "dumb_resampling_quality", 4);
|
||||
// Are we sure dumb_it_max_to_mix will be unused? Can decide when editor matures...
|
||||
|
||||
#ifndef ALLEGRO_DOS
|
||||
{
|
||||
const char *fn = get_filename(argv[1]);
|
||||
int w = strlen(fn);
|
||||
if (w < 22) w = 22;
|
||||
w = (w + 2) * 4;
|
||||
|
||||
set_window_title("DUMB - IT player");
|
||||
|
||||
if (set_gfx_mode(GFX_DUMB_MODE, w*2, 80, 0, 0) == 0) {
|
||||
acquire_screen();
|
||||
textout_centre(screen, font, fn, w, 28, 14);
|
||||
textout_centre(screen, font, "Press any key to exit.", w, 44, 11);
|
||||
release_screen();
|
||||
}
|
||||
}
|
||||
|
||||
//set_window_close_hook(&closehook);
|
||||
#endif
|
||||
|
||||
set_display_switch_mode(SWITCH_BACKGROUND);
|
||||
|
||||
dp = al_start_duh(duh, 2, 0, 1.0,
|
||||
get_config_int("sound", "buffer_size", 4096),
|
||||
get_config_int("sound", "sound_freq", 44100));
|
||||
|
||||
for (;;) {
|
||||
if (keypressed()) {
|
||||
readkey();
|
||||
break;
|
||||
}
|
||||
|
||||
if (al_poll_duh(dp) || closed)
|
||||
break;
|
||||
|
||||
YIELD();
|
||||
}
|
||||
|
||||
al_stop_duh(dp);
|
||||
|
||||
unload_duh(duh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
END_OF_MAIN();
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#if defined(_DEBUG) && defined(_MSC_VER)
|
||||
#ifndef _CRTDBG_MAP_ALLOC
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
//#define _CRTDBG_MAP_ALLOC
|
||||
#endif
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
@ -171,11 +171,13 @@ void dumb_exit(void);
|
|||
|
||||
typedef struct DUMBFILE_SYSTEM
|
||||
{
|
||||
void *(*open)(const char *filename);
|
||||
int (*skip)(void *f, int32 n);
|
||||
int (*getc)(void *f);
|
||||
int32 (*getnc)(char *ptr, int32 n, void *f);
|
||||
void (*close)(void *f);
|
||||
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;
|
||||
|
||||
|
@ -187,7 +189,15 @@ 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, int32 n);
|
||||
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);
|
||||
|
||||
|
@ -383,10 +393,15 @@ int DUMBEXPORT dumb_it_scan_for_playable_orders(DUMB_IT_SIGDATA *sigdata, dumb_s
|
|||
|
||||
DUH_SIGRENDERER *DUMBEXPORT dumb_it_start_at_order(DUH *duh, int n_channels, int startorder);
|
||||
|
||||
void DUMBEXPORT dumb_it_set_resampling_quality(DUMB_IT_SIGRENDERER * sigrenderer, int quality);
|
||||
|
||||
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);
|
||||
|
@ -395,13 +410,13 @@ void DUMBEXPORT dumb_it_set_global_volume_zero_callback(DUMB_IT_SIGRENDERER *sig
|
|||
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 */
|
||||
/* 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 rstrict);
|
||||
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);
|
||||
|
@ -409,13 +424,14 @@ 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 rstrict);
|
||||
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);
|
||||
|
@ -423,13 +439,14 @@ 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 rstrict);
|
||||
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);
|
||||
|
@ -437,13 +454,14 @@ 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 rstrict);
|
||||
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);
|
||||
|
@ -451,8 +469,15 @@ 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);
|
||||
|
||||
|
@ -581,6 +606,10 @@ typedef void (*DUH_SIGRENDERER_GET_CURRENT_SAMPLE)(
|
|||
sample_t *samples
|
||||
);
|
||||
|
||||
typedef int32 (*DUH_SIGRENDERER_GET_POSITION)(
|
||||
sigrenderer_t *sigrenderer
|
||||
);
|
||||
|
||||
typedef void (*DUH_END_SIGRENDERER)(sigrenderer_t *sigrenderer);
|
||||
|
||||
typedef void (*DUH_UNLOAD_SIGDATA)(sigdata_t *sigdata);
|
||||
|
@ -596,6 +625,7 @@ typedef struct DUH_SIGTYPE_DESC
|
|||
DUH_SIGRENDERER_SET_SIGPARAM sigrenderer_set_sigparam;
|
||||
DUH_SIGRENDERER_GENERATE_SAMPLES sigrenderer_generate_samples;
|
||||
DUH_SIGRENDERER_GET_CURRENT_SAMPLE sigrenderer_get_current_sample;
|
||||
DUH_SIGRENDERER_GET_POSITION sigrenderer_get_position;
|
||||
DUH_END_SIGRENDERER end_sigrenderer;
|
||||
DUH_UNLOAD_SIGDATA unload_sigdata;
|
||||
}
|
||||
|
@ -658,10 +688,21 @@ void DUMBEXPORT dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr)
|
|||
/* Resampling Helpers */
|
||||
|
||||
#define DUMB_RQ_ALIASING 0
|
||||
#define DUMB_RQ_LINEAR 1
|
||||
#define DUMB_RQ_CUBIC 2
|
||||
#define DUMB_RQ_N_LEVELS 3
|
||||
extern int dumb_resampling_quality;
|
||||
#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;
|
||||
|
||||
|
@ -669,8 +710,6 @@ typedef struct DUMB_VOLUME_RAMP_INFO DUMB_VOLUME_RAMP_INFO;
|
|||
|
||||
typedef void (*DUMB_RESAMPLE_PICKUP)(DUMB_RESAMPLER *resampler, void *data);
|
||||
|
||||
#include "internal/blip_buf.h"
|
||||
|
||||
struct DUMB_RESAMPLER
|
||||
{
|
||||
void *src;
|
||||
|
@ -688,9 +727,8 @@ struct DUMB_RESAMPLER
|
|||
signed char x8[3*2];
|
||||
} x;
|
||||
int overshot;
|
||||
int last_clock;
|
||||
int last_amp[2];
|
||||
blip_t* blip_buffer[2];
|
||||
double fir_resampler_ratio;
|
||||
void* fir_resampler[2];
|
||||
};
|
||||
|
||||
struct DUMB_VOLUME_RAMP_INFO
|
||||
|
@ -699,6 +737,7 @@ struct DUMB_VOLUME_RAMP_INFO
|
|||
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);
|
||||
|
@ -749,6 +788,11 @@ void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DU
|
|||
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 */
|
||||
|
||||
|
|
27
dumb/include/internal/aldumb.h
Normal file
27
dumb/include/internal/aldumb.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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 */
|
|
@ -3,6 +3,23 @@
|
|||
|
||||
#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);
|
||||
|
@ -10,9 +27,13 @@ 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);
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
/** \file
|
||||
Sample buffer that resamples from input clock rate to output sample rate */
|
||||
|
||||
/* blip_buf 1.1.0 */
|
||||
#ifndef BLIP_BUF_H
|
||||
#define BLIP_BUF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** First parameter of most functions is blip_t*, or const blip_t* if nothing
|
||||
is changed. */
|
||||
typedef struct blip_t blip_t;
|
||||
|
||||
/** Creates new buffer that can hold at most sample_count samples. Sets rates
|
||||
so that there are blip_max_ratio clocks per sample. Returns pointer to new
|
||||
buffer, or NULL if insufficient memory. */
|
||||
blip_t* blip_new( int sample_count );
|
||||
|
||||
blip_t* blip_dup( blip_t* );
|
||||
|
||||
/** Sets approximate input clock rate and output sample rate. For every
|
||||
clock_rate input clocks, approximately sample_rate samples are generated. */
|
||||
void blip_set_rates( blip_t*, double clock_rate, double sample_rate );
|
||||
|
||||
enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
|
||||
clock_rate must not be greater than sample_rate*blip_max_ratio. */
|
||||
blip_max_ratio = 1 << 20 };
|
||||
|
||||
/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
|
||||
void blip_clear( blip_t* );
|
||||
|
||||
/** Adds positive/negative delta into buffer at specified clock time. */
|
||||
void blip_add_delta( blip_t*, unsigned int clock_time, int delta );
|
||||
|
||||
/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */
|
||||
void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta );
|
||||
|
||||
/** Length of time frame, in clocks, needed to make sample_count additional
|
||||
samples available. */
|
||||
int blip_clocks_needed( const blip_t*, int sample_count );
|
||||
|
||||
enum { /** Maximum number of samples that can be generated from one time frame. */
|
||||
blip_max_frame = 4000 };
|
||||
|
||||
/** Makes input clocks before clock_duration available for reading as output
|
||||
samples. Also begins new time frame at clock_duration, so that clock time 0 in
|
||||
the new time frame specifies the same clock as clock_duration in the old time
|
||||
frame specified. Deltas can have been added slightly past clock_duration (up to
|
||||
however many clocks there are in two output samples). */
|
||||
void blip_end_frame( blip_t*, unsigned int clock_duration );
|
||||
|
||||
/** Number of buffered samples available for reading. */
|
||||
int blip_samples_avail( const blip_t* );
|
||||
|
||||
/** Reads and removes at most 'count' samples and writes them to 'out'. If
|
||||
'stereo' is true, writes output to every other element of 'out', allowing easy
|
||||
interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed
|
||||
samples. Returns number of samples actually read. */
|
||||
int blip_read_samples( blip_t*, int out [], int count );
|
||||
|
||||
/** Reads the current integrator and returns it */
|
||||
int blip_peek_sample( blip_t* );
|
||||
|
||||
/** Frees buffer. No effect if NULL is passed. */
|
||||
void blip_delete( blip_t* );
|
||||
|
||||
|
||||
/* Deprecated */
|
||||
typedef blip_t blip_buffer_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
13
dumb/include/internal/dumbfile.h
Normal file
13
dumb/include/internal/dumbfile.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef DUMBFILE_H
|
||||
#define DUMBFILE_H
|
||||
|
||||
#include "../dumb.h"
|
||||
|
||||
struct DUMBFILE
|
||||
{
|
||||
const DUMBFILE_SYSTEM *dfs;
|
||||
void *file;
|
||||
long pos;
|
||||
};
|
||||
|
||||
#endif // DUMBFILE_H
|
|
@ -33,6 +33,7 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#include "barray.h"
|
||||
#include "tarray.h"
|
||||
|
||||
|
||||
/** TO DO: THINK ABOUT THE FOLLOWING:
|
||||
|
@ -56,7 +57,6 @@ sigdata->flags & IT_COMPATIBLE_GXX
|
|||
*/
|
||||
//#define STEREO_SAMPLES_COUNT_AS_TWO
|
||||
#define INVALID_ORDERS_END_SONG
|
||||
#define INVALID_NOTES_CAUSE_NOTE_CUT
|
||||
#define SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP
|
||||
#define VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
|
||||
|
||||
|
@ -73,10 +73,9 @@ sigdata->flags & IT_COMPATIBLE_GXX
|
|||
#define IT_INSM_SIGNATURE DUMB_ID('M', 'S', 'N', 'I')
|
||||
|
||||
|
||||
/* 1 minute per 4 rows, each row 6 ticks; this is divided by the tempo to get
|
||||
* the interval between ticks.
|
||||
/* This is divided by the tempo times 256 to get the interval between ticks.
|
||||
*/
|
||||
#define TICK_TIME_DIVIDEND ((65536 * 60) / (4 * 6))
|
||||
#define TICK_TIME_DIVIDEND (65536 * 5 * 128)
|
||||
|
||||
|
||||
|
||||
|
@ -209,7 +208,7 @@ struct IT_INSTRUMENT
|
|||
struct IT_SAMPLE
|
||||
{
|
||||
unsigned char name[35];
|
||||
unsigned char filename[14];
|
||||
unsigned char filename[15];
|
||||
unsigned char flags;
|
||||
unsigned char global_volume;
|
||||
unsigned char default_volume;
|
||||
|
@ -414,6 +413,8 @@ struct IT_PATTERN
|
|||
|
||||
#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
|
||||
|
||||
|
@ -484,7 +485,6 @@ struct IT_PLAYING
|
|||
unsigned char instnum;
|
||||
|
||||
unsigned char declick_stage;
|
||||
float declick_volume;
|
||||
|
||||
float float_volume[2];
|
||||
float ramp_volume[2];
|
||||
|
@ -602,7 +602,9 @@ struct IT_CHANNEL
|
|||
|
||||
unsigned char new_note_action;
|
||||
|
||||
unsigned int arpeggio;
|
||||
unsigned char const* arpeggio_table;
|
||||
signed char arpeggio_offsets[3];
|
||||
|
||||
int arpeggio_shift;
|
||||
unsigned char retrig;
|
||||
unsigned char xm_retrig;
|
||||
|
@ -687,8 +689,8 @@ struct DUMB_IT_SIGRENDERER
|
|||
unsigned char globalvolume;
|
||||
signed char globalvolslide;
|
||||
|
||||
int tempo;
|
||||
signed char temposlide;
|
||||
unsigned short tempo;
|
||||
|
||||
IT_CHANNEL channel[DUMB_IT_N_CHANNELS];
|
||||
|
||||
|
@ -722,13 +724,28 @@ struct DUMB_IT_SIGRENDERER
|
|||
#ifdef BIT_ARRAY_BULLSHIT
|
||||
/* bit array, which rows are played, only checked by pattern break or loop commands */
|
||||
void * played;
|
||||
|
||||
/*
|
||||
Loop indicator for internal processes, may also be useful for external processes
|
||||
0 - Not looped
|
||||
1 - Looped
|
||||
-1 - Continued past loop
|
||||
*/
|
||||
int looped;
|
||||
|
||||
/*
|
||||
Kept until looped
|
||||
*/
|
||||
LONG_LONG time_played;
|
||||
|
||||
void * row_timekeeper;
|
||||
#endif
|
||||
|
||||
int32 gvz_time;
|
||||
int gvz_sub_time;
|
||||
|
||||
int ramp_style;
|
||||
|
||||
int ramp_style;
|
||||
|
||||
//int max_output;
|
||||
|
||||
IT_PLAYING *free_playing;
|
||||
|
@ -904,4 +921,10 @@ 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 */
|
||||
|
|
30
dumb/include/internal/lpc.h
Normal file
30
dumb/include/internal/lpc.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* 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
|
36
dumb/include/internal/mulsc.h
Normal file
36
dumb/include/internal/mulsc.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#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 */
|
58
dumb/include/internal/resampler.h
Normal file
58
dumb/include/internal/resampler.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
#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,11 +1,14 @@
|
|||
#ifndef RIFF_H
|
||||
#define RIFF_H
|
||||
|
||||
struct riff;
|
||||
|
||||
struct riff_chunk
|
||||
{
|
||||
unsigned type;
|
||||
void * data;
|
||||
int32 offset;
|
||||
unsigned size;
|
||||
struct riff * nested;
|
||||
};
|
||||
|
||||
struct riff
|
||||
|
@ -15,7 +18,7 @@ struct riff
|
|||
struct riff_chunk * chunks;
|
||||
};
|
||||
|
||||
struct riff * riff_parse( unsigned char *, unsigned size, unsigned proper );
|
||||
struct riff * riff_parse( DUMBFILE * f, int32 offset, int32 size, unsigned proper );
|
||||
void riff_free( struct riff * );
|
||||
|
||||
#endif
|
||||
|
|
113
dumb/include/internal/stack_alloc.h
Normal file
113
dumb/include/internal/stack_alloc.h
Normal file
|
@ -0,0 +1,113 @@
|
|||
/* 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
|
31
dumb/include/internal/tarray.h
Normal file
31
dumb/include/internal/tarray.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef _T_ARRAY_H_
|
||||
#define _T_ARRAY_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef LONG_LONG
|
||||
#if defined __GNUC__ || defined __INTEL_COMPILER || defined __MWERKS__
|
||||
#define LONG_LONG long long
|
||||
#elif defined _MSC_VER || defined __WATCOMC__
|
||||
#define LONG_LONG __int64
|
||||
#elif defined __sgi
|
||||
#define LONG_LONG long long
|
||||
#else
|
||||
#error 64-bit integer type unknown
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void * timekeeping_array_create(size_t size);
|
||||
void timekeeping_array_destroy(void * array);
|
||||
void * timekeeping_array_dup(void * array);
|
||||
|
||||
void timekeeping_array_reset(void * array, size_t loop_start);
|
||||
|
||||
void timekeeping_array_push(void * array, size_t index, LONG_LONG time);
|
||||
void timekeeping_array_bump(void * array, size_t index);
|
||||
|
||||
unsigned int timekeeping_array_get_count(void * array, size_t index);
|
||||
|
||||
LONG_LONG timekeeping_array_get_item(void * array, size_t index);
|
||||
|
||||
#endif
|
141
dumb/licence.txt
141
dumb/licence.txt
|
@ -1,54 +1,87 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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
|
||||
|
||||
Copyright (C) 2001-2003 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 only reason why the link is not strictly required is that such a
|
||||
requirement prevents DUMB from being used in projects with certain other
|
||||
licences, notably the GPL. See http://www.gnu.org/philosophy/bsd.html .]
|
||||
|
||||
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 at any Monday
|
||||
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.]
|
||||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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
dumb/prj/.gitignore
vendored
Normal file
3
dumb/prj/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
dumb-build-Desktop-Release
|
||||
dumb-build-Desktop-Debug
|
||||
*.user
|
130
dumb/prj/dumb/dumb.pro
Normal file
130
dumb/prj/dumb/dumb.pro
Normal file
|
@ -0,0 +1,130 @@
|
|||
#-------------------------------------------------
|
||||
#
|
||||
# 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/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/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/tarray.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
|
962
dumb/readme.txt
962
dumb/readme.txt
|
@ -1,421 +1,541 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readme.txt - General information on DUMB. / / \ \
|
||||
* | < / \_
|
||||
* | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
|
||||
********************
|
||||
*** Introduction ***
|
||||
********************
|
||||
|
||||
|
||||
Thank you for downloading DUMB! 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
|
||||
|
||||
- Fast seeking 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
|
||||
|
||||
- Makefile provided for DJGPP, MinGW, Linux, BeOS and Mac OS X; project file
|
||||
provided for MSVC 6 (please contact me if you'd like to submit or request
|
||||
support for a new platform; the code itself should port anywhere that has a
|
||||
32-bit C compiler)
|
||||
|
||||
- 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)
|
||||
|
||||
|
||||
*********************
|
||||
*** 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/
|
||||
|
||||
Neil Walker has kindly uploaded some DUMB binaries at
|
||||
http://retrospec.sgn.net/allegro/ . They may not always be up to date, so you
|
||||
should try to compile it yourself first.
|
||||
|
||||
|
||||
**********************************************
|
||||
*** 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. 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.
|
||||
|
||||
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 the following to install the libraries:
|
||||
|
||||
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 the following:
|
||||
|
||||
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.
|
||||
|
||||
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 ***
|
||||
******************************************************
|
||||
|
||||
|
||||
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 now comes with a project file for Microsoft Visual C++ 6. To add DUMB to
|
||||
your project:
|
||||
|
||||
1. Open your project in VC++.
|
||||
2. Select Project|Insert Project into Workspace...
|
||||
3. Navigate to the dumb\vc6 directory, and select dumb.dsp.
|
||||
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.
|
||||
|
||||
Good thing you only have to do all that once ...
|
||||
|
||||
If you have the Intel compiler installed, it will - well, should - be used to
|
||||
compile DUMB. The only setting I 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 :)
|
||||
|
||||
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!). They are
|
||||
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.
|
||||
|
||||
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 possibly even 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 use dtou on some or all of the text files.
|
||||
If you have problems, just go and download the .tar.gz instead.
|
||||
|
||||
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. 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.
|
||||
|
||||
Information on the example programs is just below. 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!
|
||||
|
||||
|
||||
****************************
|
||||
*** The example programs ***
|
||||
****************************
|
||||
|
||||
|
||||
Two 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. No .wav
|
||||
support yet, sorry. 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.
|
||||
|
||||
|
||||
*********************************************
|
||||
*** Downloading music or writing your own ***
|
||||
*********************************************
|
||||
|
||||
|
||||
If you would like to compose your own music modules, then first I must offer
|
||||
a word of warning: not everyone is capable of composing music. Do not assume
|
||||
you will be able to learn the art. By all means have a go; if you can learn
|
||||
to play tunes on the computer keyboard, you're well on the way to being a
|
||||
composer!
|
||||
|
||||
The best programs for the job are the trackers that pioneered the file
|
||||
formats:
|
||||
|
||||
Impulse Tracker - IT files - http://www.noisemusic.org/it/
|
||||
Fast Tracker II - XM files - http://www.gwinternet.com/music/ft2/
|
||||
Scream Tracker 3 - S3M files -
|
||||
http://www.united-trackers.org/resources/software/screamtracker.htm
|
||||
|
||||
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.
|
||||
|
||||
Note that Fast Tracker II is Shareware. It arguably offers the best
|
||||
interface, but the IT file format is more powerful and better defined.
|
||||
Impulse Tracker and Scream Tracker 3 are Freeware. 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/
|
||||
|
||||
BEWARE OF WINAMP! Although it's excellent for MP3s, it is notorious for being
|
||||
one of the worst module players in existence; very few modules play correctly
|
||||
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
|
||||
|
||||
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 most
|
||||
cases the author will be thrilled, so don't hesitate!
|
||||
|
||||
A note about converting modules from one format to another: 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 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. However, I may be able to help more if you
|
||||
come on to IRC EFnet #dumb.
|
||||
|
||||
IRC stands for Internet Relay Chat, and is a type of chat network. Several
|
||||
such networks exist, and EFnet is a popular one. In order to connect to an
|
||||
IRC network, you first need an IRC client. Here are some:
|
||||
|
||||
http://www.xchat.org/
|
||||
http://www.visualirc.net/beta.php
|
||||
http://www.mirc.com/
|
||||
|
||||
Getting on to IRC can be a steep cliff, but it is not insurmountable, and
|
||||
it's well worth it. Once you have set up the client software, you need to
|
||||
connect to a server. Here is a list of EFnet servers I have had success with.
|
||||
Type "/server" (without quotes), then a space, then the name of a server.
|
||||
|
||||
irc.homelien.no
|
||||
irc.webgiro.se
|
||||
efnet.vuurwerk.nl
|
||||
efnet.demon.co.uk
|
||||
irc.isdnet.fr
|
||||
irc.prison.net
|
||||
|
||||
If these servers do not work, visit http://efnet.org/ircdb/servers.php for a
|
||||
huge list of other EFnet servers to try.
|
||||
|
||||
Once you're connected, type the following:
|
||||
|
||||
/join #dumb
|
||||
|
||||
A window will appear, and you can ask your question. It should be clear
|
||||
what's going on from this point onwards. I am 'entheh'. Note that unlike many
|
||||
other nerds I am not always at my computer, so if I don't answer your
|
||||
question, don't take it personally! I will usually be able to read your
|
||||
question when I come back.
|
||||
|
||||
|
||||
******************
|
||||
*** Conclusion ***
|
||||
******************
|
||||
|
||||
|
||||
This is the conclusion.
|
||||
|
||||
|
||||
Ben Davis
|
||||
entheh@users.sf.net
|
||||
IRC EFnet #dumb
|
||||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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
|
||||
|
|
1029
dumb/release.txt
1029
dumb/release.txt
File diff suppressed because it is too large
Load diff
|
@ -33,17 +33,14 @@ void DUMBEXPORT register_dumbfile_system(const DUMBFILE_SYSTEM *dfs)
|
|||
ASSERT(dfs->open);
|
||||
ASSERT(dfs->getc);
|
||||
ASSERT(dfs->close);
|
||||
ASSERT(dfs->seek);
|
||||
ASSERT(dfs->get_size);
|
||||
the_dfs = dfs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct DUMBFILE
|
||||
{
|
||||
const DUMBFILE_SYSTEM *dfs;
|
||||
void *file;
|
||||
int32 pos;
|
||||
};
|
||||
#include "internal/dumbfile.h"
|
||||
|
||||
|
||||
|
||||
|
@ -53,7 +50,7 @@ DUMBFILE *DUMBEXPORT dumbfile_open(const char *filename)
|
|||
|
||||
ASSERT(the_dfs);
|
||||
|
||||
f = malloc(sizeof(*f));
|
||||
f = (DUMBFILE *) malloc(sizeof(*f));
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
@ -82,7 +79,7 @@ DUMBFILE *DUMBEXPORT dumbfile_open_ex(void *file, const DUMBFILE_SYSTEM *dfs)
|
|||
ASSERT(dfs->getc);
|
||||
ASSERT(file);
|
||||
|
||||
f = malloc(sizeof(*f));
|
||||
f = (DUMBFILE *) malloc(sizeof(*f));
|
||||
|
||||
if (!f) {
|
||||
if (dfs->close)
|
||||
|
@ -109,7 +106,7 @@ int32 DUMBEXPORT dumbfile_pos(DUMBFILE *f)
|
|||
|
||||
|
||||
|
||||
int DUMBEXPORT dumbfile_skip(DUMBFILE *f, int32 n)
|
||||
int DUMBEXPORT dumbfile_skip(DUMBFILE *f, long n)
|
||||
{
|
||||
int rv;
|
||||
|
||||
|
@ -375,6 +372,26 @@ int32 DUMBEXPORT dumbfile_getnc(char *ptr, int32 n, DUMBFILE *f)
|
|||
|
||||
|
||||
|
||||
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);
|
||||
|
|
|
@ -147,7 +147,15 @@ int DUMBEXPORT duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer)
|
|||
|
||||
int32 DUMBEXPORT duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer)
|
||||
{
|
||||
return sigrenderer ? sigrenderer->pos : -1;
|
||||
DUH_SIGRENDERER_GET_POSITION proc;
|
||||
|
||||
if (!sigrenderer) return -1;
|
||||
|
||||
proc = sigrenderer->desc->sigrenderer_get_position;
|
||||
if (proc)
|
||||
return (*proc)(sigrenderer->sigrenderer);
|
||||
else
|
||||
return sigrenderer->pos;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,21 @@ void bit_array_set(void * array, size_t bit)
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -120,6 +135,21 @@ void bit_array_clear(void * array, size_t bit)
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -1,354 +0,0 @@
|
|||
/* blip_buf 1.1.0. http://www.slack.net/~ant/ */
|
||||
|
||||
#include "internal/blip_buf.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Library Copyright (C) 2003-2009 Shay Green. This library is free software;
|
||||
you can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#if defined (BLARGG_TEST) && BLARGG_TEST
|
||||
#include "blargg_test.h"
|
||||
#endif
|
||||
|
||||
/* Equivalent to ULONG_MAX >= 0xFFFFFFFF00000000.
|
||||
Avoids constants that don't fit in 32 bits. */
|
||||
#if ULONG_MAX/0xFFFFFFFF > 0xFFFFFFFF
|
||||
typedef unsigned long fixed_t;
|
||||
enum { pre_shift = 32 };
|
||||
|
||||
#elif defined(ULLONG_MAX)
|
||||
typedef unsigned long long fixed_t;
|
||||
enum { pre_shift = 32 };
|
||||
|
||||
#else
|
||||
typedef unsigned fixed_t;
|
||||
enum { pre_shift = 0 };
|
||||
|
||||
#endif
|
||||
|
||||
enum { time_bits = pre_shift + 20 };
|
||||
|
||||
static fixed_t const time_unit = (fixed_t) 1 << time_bits;
|
||||
|
||||
enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */
|
||||
enum { end_frame_extra = 2 }; /* allows deltas slightly after frame length */
|
||||
|
||||
enum { half_width = 8 };
|
||||
enum { buf_extra = half_width*2 + end_frame_extra };
|
||||
enum { phase_bits = 5 };
|
||||
enum { phase_count = 1 << phase_bits };
|
||||
enum { delta_bits = 15 };
|
||||
enum { delta_unit = 1 << delta_bits };
|
||||
enum { frac_bits = time_bits - pre_shift };
|
||||
|
||||
/* We could eliminate avail and encode whole samples in offset, but that would
|
||||
limit the total buffered samples to blip_max_frame. That could only be
|
||||
increased by decreasing time_bits, which would reduce resample ratio accuracy.
|
||||
*/
|
||||
|
||||
/** Sample buffer that resamples to output rate and accumulates samples
|
||||
until they're read out */
|
||||
struct blip_t
|
||||
{
|
||||
fixed_t factor;
|
||||
fixed_t offset;
|
||||
int avail;
|
||||
int size;
|
||||
int integrator;
|
||||
};
|
||||
|
||||
typedef int buf_t;
|
||||
|
||||
/* probably not totally portable */
|
||||
#define SAMPLES( buf ) ((buf_t*) ((buf) + 1))
|
||||
|
||||
/* Arithmetic (sign-preserving) right shift */
|
||||
#define ARITH_SHIFT( n, shift ) \
|
||||
((n) >> (shift))
|
||||
|
||||
enum { max_sample = +32767 };
|
||||
enum { min_sample = -32768 };
|
||||
|
||||
#define CLAMP( n ) \
|
||||
{\
|
||||
if ( (short) n != n )\
|
||||
n = ARITH_SHIFT( n, 16 ) ^ max_sample;\
|
||||
}
|
||||
|
||||
static void check_assumptions( void )
|
||||
{
|
||||
int n;
|
||||
|
||||
#if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF
|
||||
#error "int must be at least 32 bits"
|
||||
#endif
|
||||
|
||||
assert( (-3 >> 1) == -2 ); /* right shift must preserve sign */
|
||||
|
||||
n = max_sample * 2;
|
||||
CLAMP( n );
|
||||
assert( n == max_sample );
|
||||
|
||||
n = min_sample * 2;
|
||||
CLAMP( n );
|
||||
assert( n == min_sample );
|
||||
|
||||
assert( blip_max_ratio <= time_unit );
|
||||
assert( blip_max_frame <= (fixed_t) -1 >> time_bits );
|
||||
}
|
||||
|
||||
blip_t* blip_new( int size )
|
||||
{
|
||||
blip_t* m;
|
||||
assert( size >= 0 );
|
||||
|
||||
m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) );
|
||||
if ( m )
|
||||
{
|
||||
m->factor = time_unit / blip_max_ratio;
|
||||
m->size = size;
|
||||
blip_clear( m );
|
||||
check_assumptions();
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
blip_t* blip_dup( blip_t* m )
|
||||
{
|
||||
size_t size = sizeof *m + (m->size + buf_extra) * sizeof(buf_t);
|
||||
blip_t* r = (blip_t*) malloc( size );
|
||||
if ( r ) memcpy( r, m, size );
|
||||
return r;
|
||||
}
|
||||
|
||||
void blip_delete( blip_t* m )
|
||||
{
|
||||
if ( m != NULL )
|
||||
{
|
||||
/* Clear fields in case user tries to use after freeing */
|
||||
memset( m, 0, sizeof *m );
|
||||
free( m );
|
||||
}
|
||||
}
|
||||
|
||||
void blip_set_rates( blip_t* m, double clock_rate, double sample_rate )
|
||||
{
|
||||
double factor = time_unit * sample_rate / clock_rate;
|
||||
m->factor = (fixed_t) factor;
|
||||
|
||||
/* Fails if clock_rate exceeds maximum, relative to sample_rate */
|
||||
assert( 0 <= factor - m->factor && factor - m->factor < 1 );
|
||||
|
||||
/* Avoid requiring math.h. Equivalent to
|
||||
m->factor = (int) ceil( factor ) */
|
||||
if ( m->factor < factor )
|
||||
m->factor++;
|
||||
|
||||
/* At this point, factor is most likely rounded up, but could still
|
||||
have been rounded down in the floating-point calculation. */
|
||||
}
|
||||
|
||||
void blip_clear( blip_t* m )
|
||||
{
|
||||
/* We could set offset to 0, factor/2, or factor-1. 0 is suitable if
|
||||
factor is rounded up. factor-1 is suitable if factor is rounded down.
|
||||
Since we don't know rounding direction, factor/2 accommodates either,
|
||||
with the slight loss of showing an error in half the time. Since for
|
||||
a 64-bit factor this is years, the halving isn't a problem. */
|
||||
|
||||
m->offset = m->factor / 2;
|
||||
m->avail = 0;
|
||||
m->integrator = 0;
|
||||
memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) );
|
||||
}
|
||||
|
||||
int blip_clocks_needed( const blip_t* m, int samples )
|
||||
{
|
||||
fixed_t needed;
|
||||
|
||||
/* Fails if buffer can't hold that many more samples */
|
||||
assert( samples >= 0 && m->avail + samples <= m->size );
|
||||
|
||||
needed = (fixed_t) samples * time_unit;
|
||||
if ( needed < m->offset )
|
||||
return 0;
|
||||
|
||||
return (int)((needed - m->offset + m->factor - 1) / m->factor);
|
||||
}
|
||||
|
||||
void blip_end_frame( blip_t* m, unsigned t )
|
||||
{
|
||||
fixed_t off = t * m->factor + m->offset;
|
||||
m->avail += (int)(off >> time_bits);
|
||||
m->offset = off & (time_unit - 1);
|
||||
|
||||
/* Fails if buffer size was exceeded */
|
||||
assert( m->avail <= m->size );
|
||||
}
|
||||
|
||||
int blip_samples_avail( const blip_t* m )
|
||||
{
|
||||
return m->avail;
|
||||
}
|
||||
|
||||
static void remove_samples( blip_t* m, int count )
|
||||
{
|
||||
buf_t* buf = SAMPLES( m );
|
||||
int remain = m->avail + buf_extra - count;
|
||||
m->avail -= count;
|
||||
|
||||
memmove( &buf [0], &buf [count], remain * sizeof buf [0] );
|
||||
memset( &buf [remain], 0, count * sizeof buf [0] );
|
||||
}
|
||||
|
||||
int blip_read_samples( blip_t* m, int out [], int count )
|
||||
{
|
||||
assert( count >= 0 );
|
||||
|
||||
if ( count > m->avail )
|
||||
count = m->avail;
|
||||
|
||||
if ( count )
|
||||
{
|
||||
buf_t const* in = SAMPLES( m );
|
||||
buf_t const* end = in + count;
|
||||
int sum = m->integrator;
|
||||
do
|
||||
{
|
||||
/* Eliminate fraction */
|
||||
int s = ARITH_SHIFT( sum, delta_bits - 8 );
|
||||
|
||||
sum += *in++;
|
||||
|
||||
*out = s;
|
||||
out++;
|
||||
|
||||
/* High-pass filter */
|
||||
sum -= s >> (8 - (delta_bits - bass_shift)); //<< (delta_bits - bass_shift - 8);
|
||||
}
|
||||
while ( in != end );
|
||||
m->integrator = sum;
|
||||
|
||||
remove_samples( m, count );
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int blip_peek_sample( blip_t* m )
|
||||
{
|
||||
return ARITH_SHIFT( m->integrator, delta_bits - 8 );
|
||||
}
|
||||
|
||||
/* Things that didn't help performance on x86:
|
||||
__attribute__((aligned(128)))
|
||||
#define short int
|
||||
restrict
|
||||
*/
|
||||
|
||||
/* Sinc_Generator( 0.9, 0.55, 4.5 ) */
|
||||
static short const bl_step [phase_count + 1] [half_width] =
|
||||
{
|
||||
{ 43, -115, 350, -488, 1136, -914, 5861,21022},
|
||||
{ 44, -118, 348, -473, 1076, -799, 5274,21001},
|
||||
{ 45, -121, 344, -454, 1011, -677, 4706,20936},
|
||||
{ 46, -122, 336, -431, 942, -549, 4156,20829},
|
||||
{ 47, -123, 327, -404, 868, -418, 3629,20679},
|
||||
{ 47, -122, 316, -375, 792, -285, 3124,20488},
|
||||
{ 47, -120, 303, -344, 714, -151, 2644,20256},
|
||||
{ 46, -117, 289, -310, 634, -17, 2188,19985},
|
||||
{ 46, -114, 273, -275, 553, 117, 1758,19675},
|
||||
{ 44, -108, 255, -237, 471, 247, 1356,19327},
|
||||
{ 43, -103, 237, -199, 390, 373, 981,18944},
|
||||
{ 42, -98, 218, -160, 310, 495, 633,18527},
|
||||
{ 40, -91, 198, -121, 231, 611, 314,18078},
|
||||
{ 38, -84, 178, -81, 153, 722, 22,17599},
|
||||
{ 36, -76, 157, -43, 80, 824, -241,17092},
|
||||
{ 34, -68, 135, -3, 8, 919, -476,16558},
|
||||
{ 32, -61, 115, 34, -60, 1006, -683,16001},
|
||||
{ 29, -52, 94, 70, -123, 1083, -862,15422},
|
||||
{ 27, -44, 73, 106, -184, 1152,-1015,14824},
|
||||
{ 25, -36, 53, 139, -239, 1211,-1142,14210},
|
||||
{ 22, -27, 34, 170, -290, 1261,-1244,13582},
|
||||
{ 20, -20, 16, 199, -335, 1301,-1322,12942},
|
||||
{ 18, -12, -3, 226, -375, 1331,-1376,12293},
|
||||
{ 15, -4, -19, 250, -410, 1351,-1408,11638},
|
||||
{ 13, 3, -35, 272, -439, 1361,-1419,10979},
|
||||
{ 11, 9, -49, 292, -464, 1362,-1410,10319},
|
||||
{ 9, 16, -63, 309, -483, 1354,-1383, 9660},
|
||||
{ 7, 22, -75, 322, -496, 1337,-1339, 9005},
|
||||
{ 6, 26, -85, 333, -504, 1312,-1280, 8355},
|
||||
{ 4, 31, -94, 341, -507, 1278,-1205, 7713},
|
||||
{ 3, 35, -102, 347, -506, 1238,-1119, 7082},
|
||||
{ 1, 40, -110, 350, -499, 1190,-1021, 6464},
|
||||
{ 0, 43, -115, 350, -488, 1136, -914, 5861}
|
||||
};
|
||||
|
||||
/* Shifting by pre_shift allows calculation using unsigned int rather than
|
||||
possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient.
|
||||
And by having pre_shift 32, a 32-bit platform can easily do the shift by
|
||||
simply ignoring the low half. */
|
||||
|
||||
void blip_add_delta( blip_t* m, unsigned time, int delta )
|
||||
{
|
||||
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
|
||||
buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
|
||||
|
||||
int const phase_shift = frac_bits - phase_bits;
|
||||
int phase = fixed >> phase_shift & (phase_count - 1);
|
||||
short const* in = bl_step [phase];
|
||||
short const* rev = bl_step [phase_count - phase];
|
||||
|
||||
int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1);
|
||||
int delta2 = (delta * interp) >> delta_bits;
|
||||
delta -= delta2;
|
||||
|
||||
/* Fails if buffer size was exceeded */
|
||||
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
|
||||
|
||||
out [0] += in[0]*delta + in[half_width+0]*delta2;
|
||||
out [1] += in[1]*delta + in[half_width+1]*delta2;
|
||||
out [2] += in[2]*delta + in[half_width+2]*delta2;
|
||||
out [3] += in[3]*delta + in[half_width+3]*delta2;
|
||||
out [4] += in[4]*delta + in[half_width+4]*delta2;
|
||||
out [5] += in[5]*delta + in[half_width+5]*delta2;
|
||||
out [6] += in[6]*delta + in[half_width+6]*delta2;
|
||||
out [7] += in[7]*delta + in[half_width+7]*delta2;
|
||||
|
||||
in = rev;
|
||||
out [ 8] += in[7]*delta + in[7-half_width]*delta2;
|
||||
out [ 9] += in[6]*delta + in[6-half_width]*delta2;
|
||||
out [10] += in[5]*delta + in[5-half_width]*delta2;
|
||||
out [11] += in[4]*delta + in[4-half_width]*delta2;
|
||||
out [12] += in[3]*delta + in[3-half_width]*delta2;
|
||||
out [13] += in[2]*delta + in[2-half_width]*delta2;
|
||||
out [14] += in[1]*delta + in[1-half_width]*delta2;
|
||||
out [15] += in[0]*delta + in[0-half_width]*delta2;
|
||||
}
|
||||
|
||||
void blip_add_delta_fast( blip_t* m, unsigned time, int delta )
|
||||
{
|
||||
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
|
||||
buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
|
||||
|
||||
int interp = fixed >> (frac_bits - delta_bits) & (delta_unit - 1);
|
||||
int delta2 = delta * interp;
|
||||
|
||||
/* Fails if buffer size was exceeded */
|
||||
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
|
||||
|
||||
out [7] += delta * delta_unit - delta2;
|
||||
out [8] += delta2;
|
||||
}
|
320
dumb/src/helpers/lpc.c
Normal file
320
dumb/src/helpers/lpc.c
Normal file
|
@ -0,0 +1,320 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,13 +28,13 @@ typedef struct MEMFILE MEMFILE;
|
|||
|
||||
struct MEMFILE
|
||||
{
|
||||
const char *ptr;
|
||||
int32 left;
|
||||
const char *ptr, *ptr_begin;
|
||||
long left, size;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int dumb_memfile_skip(void *f, int32 n)
|
||||
static int DUMBCALLBACK dumb_memfile_skip(void *f, long n)
|
||||
{
|
||||
MEMFILE *m = f;
|
||||
if (n > m->left) return -1;
|
||||
|
@ -45,7 +45,7 @@ static int dumb_memfile_skip(void *f, int32 n)
|
|||
|
||||
|
||||
|
||||
static int dumb_memfile_getc(void *f)
|
||||
static int DUMBCALLBACK dumb_memfile_getc(void *f)
|
||||
{
|
||||
MEMFILE *m = f;
|
||||
if (m->left <= 0) return -1;
|
||||
|
@ -55,7 +55,7 @@ static int dumb_memfile_getc(void *f)
|
|||
|
||||
|
||||
|
||||
static int32 dumb_memfile_getnc(char *ptr, int32 n, void *f)
|
||||
static int32 DUMBCALLBACK dumb_memfile_getnc(char *ptr, int32 n, void *f)
|
||||
{
|
||||
MEMFILE *m = f;
|
||||
if (n > m->left) n = m->left;
|
||||
|
@ -67,19 +67,38 @@ static int32 dumb_memfile_getnc(char *ptr, int32 n, void *f)
|
|||
|
||||
|
||||
|
||||
static void dumb_memfile_close(void *f)
|
||||
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_close,
|
||||
&dumb_memfile_seek,
|
||||
&dumb_memfile_get_size
|
||||
};
|
||||
|
||||
|
||||
|
@ -89,8 +108,10 @@ 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);
|
||||
}
|
||||
|
|
|
@ -95,10 +95,8 @@ static int process_pickup(DUMB_RESAMPLER *resampler)
|
|||
#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 MIX_ALIAS(count) MONO_DEST_MIX_ALIAS(count)
|
||||
#define PEEK_ALIAS MONO_DEST_PEEK_ALIAS
|
||||
#define MIX_LINEAR(op, upd, o0, o1) MONO_DEST_MIX_LINEAR(op, upd, o0, o1)
|
||||
#define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) MONO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3)
|
||||
#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
|
||||
|
@ -111,26 +109,30 @@ static int process_pickup(DUMB_RESAMPLER *resampler)
|
|||
#define VOLUME_VARIABLES lvol, lvolr, lvold, lvolt, lvolm, rvol, rvolr, rvold, rvolt, rvolm
|
||||
#define SET_VOLUME_VARIABLES { \
|
||||
if ( volume_left ) { \
|
||||
lvolr = (int)(volume_left->volume * 16777216.0); \
|
||||
lvold = (int)(volume_left->delta * 16777216.0); \
|
||||
lvolt = (int)(volume_left->target * 16777216.0); \
|
||||
lvolm = (int)(volume_left->mix * 16777216.0); \
|
||||
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 = (int)(volume_right->volume * 16777216.0); \
|
||||
rvold = (int)(volume_right->delta * 16777216.0); \
|
||||
rvolt = (int)(volume_right->target * 16777216.0); \
|
||||
rvolm = (int)(volume_right->mix * 16777216.0); \
|
||||
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 { \
|
||||
|
@ -138,21 +140,19 @@ static int process_pickup(DUMB_RESAMPLER *resampler)
|
|||
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(count) STEREO_DEST_MIX_ALIAS(count)
|
||||
#define PEEK_ALIAS STEREO_DEST_PEEK_ALIAS
|
||||
#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 MONO_DEST_MIX_CUBIC
|
||||
#undef STEREO_DEST_MIX_LINEAR
|
||||
#undef MONO_DEST_MIX_LINEAR
|
||||
#undef STEREO_DEST_MIX_ALIAS
|
||||
#undef MONO_DEST_MIX_ALIAS
|
||||
#undef MONO_DEST_VOLUMES_ARE_ZERO
|
||||
#undef SET_MONO_DEST_VOLUME_VARIABLES
|
||||
#undef RETURN_MONO_DEST_VOLUME_VARIABLES
|
||||
|
@ -160,8 +160,13 @@ static int process_pickup(DUMB_RESAMPLER *resampler)
|
|||
#undef MONO_DEST_VOLUME_VARIABLES
|
||||
#undef MONO_DEST_VOLUME_PARAMETERS
|
||||
#undef STEREO_DEST_PEEK_ALIAS
|
||||
#undef MONO_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
|
||||
|
|
|
@ -50,22 +50,21 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
|||
int VOLUME_VARIABLES;
|
||||
long done;
|
||||
long todo;
|
||||
LONG_LONG todo64;
|
||||
double tododbl;
|
||||
int quality;
|
||||
int blip_samples[256*SRC_CHANNELS];
|
||||
|
||||
if (!resampler || resampler->dir == 0) return 0;
|
||||
ASSERT(resampler->dir == -1 || resampler->dir == 1);
|
||||
|
||||
done = 0;
|
||||
dt = (int)(delta * 65536.0 + 0.5);
|
||||
dt = xs_CRoundToInt(delta * 65536.0);
|
||||
if (dt == 0 || dt == 0x80000000) return 0;
|
||||
inv_dt = (int)(1.0 / delta * 65536.0 + 0.5);
|
||||
inv_dt = xs_CRoundToInt(1.0 / delta * 65536.0);
|
||||
SET_VOLUME_VARIABLES;
|
||||
|
||||
if (VOLUMES_ARE_ZERO) dst = NULL;
|
||||
|
||||
init_cubic();
|
||||
_dumb_init_cubic();
|
||||
|
||||
quality = resampler->quality;
|
||||
|
||||
|
@ -79,16 +78,16 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
|||
dt = -dt;
|
||||
|
||||
if (resampler->dir < 0)
|
||||
todo64 = ((((LONG_LONG)(resampler->pos - resampler->start) << 16) + resampler->subpos - dt) / -dt);
|
||||
tododbl = ((resampler->pos - resampler->start) * 65536.f + (resampler->subpos - dt)) / -dt;
|
||||
else
|
||||
todo64 = ((((LONG_LONG)(resampler->end - resampler->pos) << 16) - resampler->subpos - 1 + dt) / dt);
|
||||
tododbl = ((resampler->end - resampler->pos) * 65536.f - (resampler->subpos + 1 - dt)) / dt;
|
||||
|
||||
if (todo64 < 0)
|
||||
if (tododbl <= 0)
|
||||
todo = 0;
|
||||
else if (todo64 > dst_size - done)
|
||||
else if (tododbl >= dst_size - done)
|
||||
todo = dst_size - done;
|
||||
else
|
||||
todo = (long) todo64;
|
||||
todo = xs_FloorToInt(tododbl);
|
||||
|
||||
done += todo;
|
||||
|
||||
|
@ -106,34 +105,30 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
|||
subpos = (long)new_subpos & 65535;
|
||||
} else if (quality <= DUMB_RQ_ALIASING) {
|
||||
/* Aliasing, backwards */
|
||||
int todo_clocks = todo << 16, todo_clocks_set = todo_clocks;
|
||||
SRCTYPE xbuf[2*SRC_CHANNELS];
|
||||
SRCTYPE xbuf[2*SRC_CHANNELS];
|
||||
SRCTYPE *x = &xbuf[0];
|
||||
SRCTYPE *xstart;
|
||||
COPYSRC(xbuf, 0, resampler->X, 1);
|
||||
COPYSRC(xbuf, 1, resampler->X, 2);
|
||||
if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536;
|
||||
while (resampler->last_clock < todo_clocks_set && x < &xbuf[2*SRC_CHANNELS]) {
|
||||
while (todo && x < &xbuf[2*SRC_CHANNELS]) {
|
||||
// TODO: check what happens when multiple tempo slides occur per row
|
||||
HEAVYASSERT(pos >= resampler->start);
|
||||
POKE_ALIAS(0);
|
||||
pos--;
|
||||
x += SRC_CHANNELS;
|
||||
MIX_ALIAS(+=, 1, 0);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x -= (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
todo--;
|
||||
}
|
||||
x = &src[pos*SRC_CHANNELS];
|
||||
while ( todo_clocks ) {
|
||||
todo_clocks_set = todo_clocks;
|
||||
if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536;
|
||||
todo_clocks -= todo_clocks_set;
|
||||
while ( resampler->last_clock < todo_clocks_set )
|
||||
{
|
||||
POKE_ALIAS(2);
|
||||
pos--;
|
||||
x -= SRC_CHANNELS;
|
||||
}
|
||||
todo = todo_clocks_set >> 16;
|
||||
MIX_ALIAS( todo );
|
||||
}
|
||||
} else if (quality <= DUMB_RQ_LINEAR) {
|
||||
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];
|
||||
|
@ -159,7 +154,7 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
|||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
);
|
||||
} else {
|
||||
} else if (quality <= DUMB_LQ_CUBIC) {
|
||||
/* Cubic interpolation, backwards */
|
||||
SRCTYPE xbuf[6*SRC_CHANNELS];
|
||||
SRCTYPE *x = &xbuf[3*SRC_CHANNELS];
|
||||
|
@ -187,6 +182,33 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
|||
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;
|
||||
|
@ -211,33 +233,29 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
|||
subpos = (long)new_subpos & 65535;
|
||||
} else if (quality <= DUMB_RQ_ALIASING) {
|
||||
/* Aliasing, forwards */
|
||||
int todo_clocks = todo << 16, todo_clocks_set = todo_clocks;
|
||||
SRCTYPE xbuf[2*SRC_CHANNELS];
|
||||
SRCTYPE *x = &xbuf[0];
|
||||
SRCTYPE *xstart;
|
||||
COPYSRC(xbuf, 0, resampler->X, 1);
|
||||
COPYSRC(xbuf, 1, resampler->X, 2);
|
||||
if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536;
|
||||
while (resampler->last_clock < todo_clocks_set && x < &xbuf[2*SRC_CHANNELS]) {
|
||||
while (todo && x < &xbuf[2*SRC_CHANNELS]) {
|
||||
HEAVYASSERT(pos < resampler->end);
|
||||
POKE_ALIAS(0);
|
||||
pos++;
|
||||
x += SRC_CHANNELS;
|
||||
MIX_ALIAS(+=, 1, 0);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
todo--;
|
||||
}
|
||||
x = &src[pos*SRC_CHANNELS];
|
||||
while ( todo_clocks ) {
|
||||
todo_clocks_set = todo_clocks;
|
||||
if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536;
|
||||
todo_clocks -= todo_clocks_set;
|
||||
while ( resampler->last_clock < todo_clocks_set )
|
||||
{
|
||||
POKE_ALIAS(-2);
|
||||
pos++;
|
||||
x += SRC_CHANNELS;
|
||||
}
|
||||
todo = todo_clocks_set >> 16;
|
||||
MIX_ALIAS( todo );
|
||||
}
|
||||
} else if (quality <= DUMB_RQ_LINEAR) {
|
||||
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];
|
||||
|
@ -262,7 +280,7 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
|||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
);
|
||||
} else {
|
||||
} else if (quality <= DUMB_LQ_CUBIC) {
|
||||
/* Cubic interpolation, forwards */
|
||||
SRCTYPE xbuf[6*SRC_CHANNELS];
|
||||
SRCTYPE *x = &xbuf[3*SRC_CHANNELS];
|
||||
|
@ -290,6 +308,33 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
|||
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;
|
||||
|
@ -336,7 +381,7 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE
|
|||
|
||||
if (VOLUMES_ARE_ZERO) { MIX_ZEROS(=); return; }
|
||||
|
||||
init_cubic();
|
||||
_dumb_init_cubic();
|
||||
|
||||
quality = resampler->quality;
|
||||
|
||||
|
@ -347,27 +392,33 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE
|
|||
|
||||
if (resampler->dir < 0) {
|
||||
HEAVYASSERT(pos >= resampler->start);
|
||||
if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
|
||||
if (quality <= DUMB_RQ_ALIASING) {
|
||||
/* Aliasing, backwards */
|
||||
PEEK_ALIAS;
|
||||
} else if (quality <= DUMB_RQ_LINEAR) {
|
||||
MIX_ALIAS(=, 0, 1);
|
||||
} else if (quality <= DUMB_LQ_LINEAR) {
|
||||
/* Linear interpolation, backwards */
|
||||
MIX_LINEAR(=, 0, 2, 1);
|
||||
} else {
|
||||
} 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 (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
|
||||
if (quality <= DUMB_RQ_ALIASING) {
|
||||
/* Aliasing */
|
||||
PEEK_ALIAS;
|
||||
} else if (dumb_resampling_quality <= DUMB_RQ_LINEAR) {
|
||||
MIX_ALIAS(=, 0, 1);
|
||||
} else if (quality <= DUMB_LQ_LINEAR) {
|
||||
/* Linear interpolation, forwards */
|
||||
MIX_LINEAR(=, 0, 1, 2);
|
||||
} else {
|
||||
} else if (quality <= DUMB_LQ_CUBIC) {
|
||||
/* Cubic interpolation, forwards */
|
||||
MIX_CUBIC(=, 0, x, src, 0, 1, 2, pos);
|
||||
} else {
|
||||
/* FIR resampling, forwards */
|
||||
PEEK_FIR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,10 +426,8 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE
|
|||
|
||||
|
||||
#undef MIX_ZEROS
|
||||
#undef MIX_CUBIC
|
||||
#undef MIX_LINEAR
|
||||
#undef MIX_ALIAS
|
||||
#undef PEEK_ALIAS
|
||||
#undef MIX_FIR
|
||||
#undef PEEK_FIR
|
||||
#undef VOLUMES_ARE_ZERO
|
||||
#undef SET_VOLUME_VARIABLES
|
||||
#undef RETURN_VOLUME_VARIABLES
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
* In order to find a good trade-off between | \ / /
|
||||
* speed and accuracy in this code, some tests | ' /
|
||||
* were carried out regarding the behaviour of \__/
|
||||
* int32 int32 ints with gcc. The following code
|
||||
* long long ints with gcc. The following code
|
||||
* was tested:
|
||||
*
|
||||
* int a, b, c;
|
||||
* c = ((int32 int32)a * b) >> 16;
|
||||
* 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.
|
||||
|
@ -35,7 +35,7 @@
|
|||
* more cycles, so this method is unsuitable for use in the low-quality
|
||||
* resamplers.
|
||||
*
|
||||
* Since "int32 int32" is a gcc-specific extension, we use LONG_LONG instead,
|
||||
* 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.
|
||||
*
|
||||
|
@ -45,6 +45,9 @@
|
|||
#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
|
||||
|
@ -70,22 +73,57 @@
|
|||
* specification doesn't override it. The following values are valid:
|
||||
*
|
||||
* 0 - DUMB_RQ_ALIASING - fastest
|
||||
* 1 - DUMB_RQ_LINEAR
|
||||
* 2 - DUMB_RQ_CUBIC - nicest
|
||||
* 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-2 will behave the same as the nearest
|
||||
* Values outside the range 0-4 will behave the same as the nearest
|
||||
* value within the range.
|
||||
*/
|
||||
int dumb_resampling_quality = DUMB_RQ_CUBIC;
|
||||
|
||||
|
||||
|
||||
//#define MULSC(a, b) ((int)((LONG_LONG)(a) * (b) >> 16))
|
||||
//#define MULSC(a, b) ((a) * ((b) >> 2) >> 14)
|
||||
#define MULSCV(a, b) ((int)((LONG_LONG)(a) * (b) >> 32))
|
||||
#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32))
|
||||
#define MULSC16(a, b) ((int)((LONG_LONG)((a) << 12) * ((b) << 12) >> 32))
|
||||
/* 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.
|
||||
|
@ -112,9 +150,6 @@ int dumb_resampling_quality = DUMB_RQ_CUBIC;
|
|||
} \
|
||||
}
|
||||
#else
|
||||
/* [RH] Unrolling this makes the object code ~2.5x larger with
|
||||
* marginal, if any, improvement in performance.
|
||||
*/
|
||||
#define LOOP4(iterator, CONTENT) \
|
||||
{ \
|
||||
while ( (iterator)-- ) \
|
||||
|
@ -124,8 +159,6 @@ int dumb_resampling_quality = DUMB_RQ_CUBIC;
|
|||
}
|
||||
#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. */
|
||||
|
||||
|
@ -161,17 +194,19 @@ int dumb_resampling_quality = DUMB_RQ_CUBIC;
|
|||
|
||||
static short cubicA0[1025], cubicA1[1025];
|
||||
|
||||
static void init_cubic(void)
|
||||
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;
|
||||
done = 1;
|
||||
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);
|
||||
cubicA1[t] = (int)(3*t*t*t >> 17) - (int)(5*t*t >> 7) + (int)(1 << 14);
|
||||
}
|
||||
resampler_init();
|
||||
|
||||
done = 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -189,22 +224,15 @@ static void init_cubic(void)
|
|||
|
||||
#define SRCTYPE sample_t
|
||||
#define SRCBITS 24
|
||||
#define ALIAS(x) (x >> 8)
|
||||
#define ALIAS(x, vol) MULSC(x, vol)
|
||||
#define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos))
|
||||
/*
|
||||
#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
|
||||
a = (3 * (x1 - x2) + (x3 - x0)) >> 1; \
|
||||
b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) >> 1; \
|
||||
c = (x2 - x0) >> 1; \
|
||||
}
|
||||
#define CUBIC(d) MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + d, vol)
|
||||
*/
|
||||
#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. */
|
||||
|
@ -225,44 +253,30 @@ static void init_cubic(void)
|
|||
#define SUFFIX _16
|
||||
#define SRCTYPE short
|
||||
#define SRCBITS 16
|
||||
#define ALIAS(x) (x)
|
||||
#define ALIAS(x, vol) (x * vol >> 8)
|
||||
#define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos))
|
||||
/*
|
||||
#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
|
||||
a = (3 * (x1 - x2) + (x3 - x0)) << 7; \
|
||||
b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) << 7; \
|
||||
c = (x2 - x0) << 7; \
|
||||
}
|
||||
#define CUBIC(d) MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + (d << 8), vol)
|
||||
*/
|
||||
#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) (int)((LONG_LONG)(x) * (vol << 10) >> 32)
|
||||
#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) (x << 8)
|
||||
#define ALIAS(x, vol) (x * vol)
|
||||
#define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos)
|
||||
/*
|
||||
#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
|
||||
a = 3 * (x1 - x2) + (x3 - x0); \
|
||||
b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) << 15; \
|
||||
c = (x2 - x0) << 15; \
|
||||
}
|
||||
#define CUBIC(d) MULSC(MULSC(MULSC((a * subpos >> 1) + b, subpos) + c, subpos) + (d << 16), vol)
|
||||
*/
|
||||
#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) (int)((LONG_LONG)(x) * (vol << 12) >> 32)
|
||||
#define CUBICVOL(x, vol) MULSCV((x), ((vol) << 12))
|
||||
#define FIR(x) (x << 8)
|
||||
#include "resample.inc"
|
||||
|
||||
|
||||
|
|
|
@ -69,11 +69,11 @@ void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, int src_chann
|
|||
}
|
||||
for (i = 0; i < src_channels*3; i++) resampler->X[i] = 0;
|
||||
resampler->overshot = -1;
|
||||
resampler->last_clock = 0;
|
||||
resampler->last_amp[0] = 0;
|
||||
resampler->last_amp[1] = 0;
|
||||
blip_clear(resampler->blip_buffer[0]);
|
||||
blip_clear(resampler->blip_buffer[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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,21 +82,6 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
|||
{
|
||||
DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler));
|
||||
if (!resampler) return NULL;
|
||||
resampler->blip_buffer[0] = blip_new( 256 );
|
||||
if (!resampler->blip_buffer[0])
|
||||
{
|
||||
free(resampler);
|
||||
return NULL;
|
||||
}
|
||||
resampler->blip_buffer[1] = blip_new( 256 );
|
||||
if (!resampler->blip_buffer[1])
|
||||
{
|
||||
free(resampler->blip_buffer[0]);
|
||||
free(resampler);
|
||||
return NULL;
|
||||
}
|
||||
blip_set_rates(resampler->blip_buffer[0], 65536, 1);
|
||||
blip_set_rates(resampler->blip_buffer[1], 65536, 1);
|
||||
dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality);
|
||||
return resampler;
|
||||
}
|
||||
|
@ -109,6 +94,9 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
|||
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 { \
|
||||
|
@ -122,7 +110,7 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
|||
/* Create mono source resampler. */
|
||||
#define SUFFIX2 _1
|
||||
#define SRC_CHANNELS 1
|
||||
#define DIVIDE_BY_SRC_CHANNELS(x) (x)
|
||||
#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
|
||||
|
@ -130,58 +118,27 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
|||
#define MONO_DEST_VOLUME_ZEROS 0, 0
|
||||
#define SET_MONO_DEST_VOLUME_VARIABLES { \
|
||||
if ( volume ) { \
|
||||
volr = (int)(volume->volume * 16777216.0); \
|
||||
vold = (int)(volume->delta * 16777216.0); \
|
||||
volt = (int)(volume->target * 16777216.0); \
|
||||
volm = (int)(volume->mix * 16777216.0); \
|
||||
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 POKE_ALIAS(offset) { \
|
||||
int delta = ALIAS(x[offset]) - resampler->last_amp[0]; \
|
||||
resampler->last_amp[0] += delta; \
|
||||
if ( delta ) blip_add_delta( resampler->blip_buffer[0], resampler->last_clock, delta ); \
|
||||
resampler->last_clock += inv_dt; \
|
||||
}
|
||||
#define MONO_DEST_PEEK_ALIAS *dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), vol )
|
||||
#define MONO_DEST_MIX_ALIAS(count) { \
|
||||
int n = 0; \
|
||||
resampler->last_clock -= count * 65536; \
|
||||
blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \
|
||||
blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \
|
||||
LOOP4( count, \
|
||||
*dst++ += MULSC( blip_samples[n], vol ); \
|
||||
n++; \
|
||||
UPDATE_VOLUME( volume, vol ); \
|
||||
); \
|
||||
}
|
||||
#define STEREO_DEST_PEEK_ALIAS { \
|
||||
int sample = blip_peek_sample( resampler->blip_buffer[0] ); \
|
||||
*dst++ = MULSC( sample, lvol ); \
|
||||
*dst++ = MULSC( sample, rvol ); \
|
||||
}
|
||||
#define STEREO_DEST_MIX_ALIAS(count) { \
|
||||
int sample, n = 0; \
|
||||
resampler->last_clock -= count * 65536; \
|
||||
blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \
|
||||
blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \
|
||||
LOOP4( count, \
|
||||
sample = blip_samples[n++]; \
|
||||
*dst++ += MULSC( sample, lvol ); \
|
||||
*dst++ += MULSC( sample, rvol ); \
|
||||
UPDATE_VOLUME( volume_left, lvol ); \
|
||||
UPDATE_VOLUME( volume_right, rvol ); \
|
||||
); \
|
||||
}
|
||||
#define MONO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
|
||||
*dst++ op MULSC(LINEAR(x[o0], x[o1]), vol); \
|
||||
if ( upd ) UPDATE_VOLUME( volume, vol ); \
|
||||
#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]); \
|
||||
|
@ -190,10 +147,6 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
|||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
||||
}
|
||||
#define MONO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) { \
|
||||
*dst++ op CUBICVOL(CUBIC(x0[o0], x[o1], x[o2], x3[o3]), vol); \
|
||||
if ( upd ) UPDATE_VOLUME( volume, vol ); \
|
||||
}
|
||||
#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); \
|
||||
|
@ -201,12 +154,33 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
|||
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) ((x) >> 1)
|
||||
#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]; \
|
||||
|
@ -226,26 +200,30 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
|||
#define MONO_DEST_VOLUME_ZEROS 0, 0
|
||||
#define SET_MONO_DEST_VOLUME_VARIABLES { \
|
||||
if ( volume_left ) { \
|
||||
lvolr = (int)(volume_left->volume * 16777216.0); \
|
||||
lvold = (int)(volume_left->delta * 16777216.0); \
|
||||
lvolt = (int)(volume_left->target * 16777216.0); \
|
||||
lvolm = (int)(volume_left->mix * 16777216.0); \
|
||||
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 = (int)(volume_right->volume * 16777216.0); \
|
||||
rvold = (int)(volume_right->delta * 16777216.0); \
|
||||
rvolt = (int)(volume_right->target * 16777216.0); \
|
||||
rvolm = (int)(volume_right->mix * 16777216.0); \
|
||||
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 { \
|
||||
|
@ -253,54 +231,9 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
|||
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 POKE_ALIAS(offset) { \
|
||||
int deltal = ALIAS(x[(offset)*2+0]) - resampler->last_amp[0]; \
|
||||
int deltar = ALIAS(x[(offset)*2+1]) - resampler->last_amp[1]; \
|
||||
resampler->last_amp[0] += deltal; \
|
||||
resampler->last_amp[1] += deltar; \
|
||||
if ( deltal ) blip_add_delta( resampler->blip_buffer[0], resampler->last_clock, deltal ); \
|
||||
if ( deltar ) blip_add_delta( resampler->blip_buffer[1], resampler->last_clock, deltar ); \
|
||||
resampler->last_clock += inv_dt; \
|
||||
}
|
||||
#define MONO_DEST_PEEK_ALIAS { \
|
||||
*dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ) + \
|
||||
MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \
|
||||
}
|
||||
#define MONO_DEST_MIX_ALIAS(count) { \
|
||||
int n = 0; \
|
||||
resampler->last_clock -= count * 65536; \
|
||||
blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \
|
||||
blip_end_frame( resampler->blip_buffer[1], count * 65536 ); \
|
||||
blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \
|
||||
blip_read_samples( resampler->blip_buffer[1], blip_samples + 256, count ); \
|
||||
LOOP4( count, \
|
||||
*dst++ += MULSC( blip_samples[n], lvol ) + MULSC( blip_samples[256+n], rvol ); \
|
||||
n++; \
|
||||
UPDATE_VOLUME( volume_left, lvol ); \
|
||||
UPDATE_VOLUME( volume_right, rvol ); \
|
||||
); \
|
||||
}
|
||||
#define STEREO_DEST_PEEK_ALIAS { \
|
||||
*dst++ = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ); \
|
||||
*dst++ = MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \
|
||||
}
|
||||
#define STEREO_DEST_MIX_ALIAS(count) { \
|
||||
int n = 0; \
|
||||
resampler->last_clock -= count * 65536; \
|
||||
blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \
|
||||
blip_end_frame( resampler->blip_buffer[1], count * 65536 ); \
|
||||
blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \
|
||||
blip_read_samples( resampler->blip_buffer[1], blip_samples + 256, count ); \
|
||||
LOOP4( count, \
|
||||
*dst++ += MULSC( blip_samples[n], lvol); \
|
||||
*dst++ += MULSC( blip_samples[256+n], rvol); \
|
||||
n++; \
|
||||
UPDATE_VOLUME( volume_left, lvol ); \
|
||||
UPDATE_VOLUME( volume_right, rvol ); \
|
||||
); \
|
||||
}
|
||||
#define MONO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
|
||||
*dst++ op MULSC(LINEAR(x[(o0)*2], x[(o1)*2]), lvol) + MULSC(LINEAR(x[(o0)*2+1], x[(o1)*2+1]), rvol); \
|
||||
#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 ); \
|
||||
}
|
||||
|
@ -310,19 +243,40 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
|||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
||||
}
|
||||
#define MONO_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) + \
|
||||
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 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"
|
||||
|
||||
|
||||
|
@ -335,6 +289,7 @@ void dumb_end_resampler(DUMB_RESAMPLER *resampler)
|
|||
|
||||
|
||||
|
||||
#undef FIR
|
||||
#undef CUBICVOL
|
||||
#undef CUBIC
|
||||
#undef LINEAR
|
||||
|
|
1512
dumb/src/helpers/resampler.c
Normal file
1512
dumb/src/helpers/resampler.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,61 +1,59 @@
|
|||
#include "dumb.h"
|
||||
#include "internal/riff.h"
|
||||
#include "internal/dumb.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct riff * riff_parse( unsigned char * ptr, unsigned size, unsigned proper )
|
||||
struct riff * riff_parse( DUMBFILE * f, int32 offset, int32 size, unsigned proper )
|
||||
{
|
||||
unsigned stream_size;
|
||||
struct riff * stream;
|
||||
|
||||
if ( size < 8 ) return 0;
|
||||
|
||||
if ( ptr[0] != 'R' || ptr[1] != 'I' || ptr[2] != 'F' || ptr[3] != 'F' ) return 0;
|
||||
if ( size < 8 ) return 0;
|
||||
|
||||
stream_size = ptr[4] | ( ptr[5] << 8 ) | ( ptr[6] << 16 ) | ( ptr[7] << 24 );
|
||||
if ( stream_size + 8 > size ) 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 = malloc( sizeof( struct riff ) );
|
||||
stream = (struct riff *) malloc( sizeof( struct riff ) );
|
||||
if ( ! stream ) return 0;
|
||||
|
||||
stream->type = ( ptr[8] << 24 ) | ( ptr[9] << 16 ) | ( ptr[10] << 8 ) | ptr[11];
|
||||
stream->type = dumbfile_mgetl(f);
|
||||
stream->chunk_count = 0;
|
||||
stream->chunks = 0;
|
||||
|
||||
ptr += 12;
|
||||
stream_size -= 4;
|
||||
|
||||
while ( stream_size )
|
||||
while ( stream_size && !dumbfile_error(f) )
|
||||
{
|
||||
struct riff_chunk * chunk;
|
||||
if ( stream_size < 8 ) break;
|
||||
stream->chunks = realloc( stream->chunks, ( stream->chunk_count + 1 ) * sizeof( struct riff_chunk ) );
|
||||
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 = ( ptr[0] << 24 ) | ( ptr[1] << 16 ) | ( ptr[2] << 8 ) | ptr[3];
|
||||
chunk->size = ptr[4] | ( ptr[5] << 8 ) | ( ptr[6] << 16 ) | ( ptr[7] << 24 );
|
||||
ptr += 8;
|
||||
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') )
|
||||
if ( chunk->type == DUMB_ID('R','I','F','F') )
|
||||
{
|
||||
chunk->data = riff_parse( ptr - 8, chunk->size + 8, proper );
|
||||
if ( ! chunk->data ) break;
|
||||
chunk->nested = riff_parse( f, chunk->offset - 8, chunk->size + 8, proper );
|
||||
if ( ! chunk->nested ) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
chunk->data = malloc( chunk->size );
|
||||
if ( ! chunk->data ) break;
|
||||
memcpy( chunk->data, ptr, chunk->size );
|
||||
chunk->nested = 0;
|
||||
}
|
||||
ptr += chunk->size;
|
||||
dumbfile_seek(f, chunk->offset + chunk->size, DFS_SEEK_SET);
|
||||
stream_size -= chunk->size;
|
||||
if ( proper && ( chunk->size & 1 ) )
|
||||
{
|
||||
++ ptr;
|
||||
dumbfile_skip(f, 1);
|
||||
-- stream_size;
|
||||
}
|
||||
++stream->chunk_count;
|
||||
|
@ -80,8 +78,7 @@ void riff_free( struct riff * stream )
|
|||
for ( i = 0; i < stream->chunk_count; ++i )
|
||||
{
|
||||
struct riff_chunk * chunk = stream->chunks + i;
|
||||
if ( chunk->type == DUMB_ID('R','I','F','F') ) riff_free( ( struct riff * ) chunk->data );
|
||||
else free( chunk->data );
|
||||
if ( chunk->nested ) riff_free( chunk->nested );
|
||||
}
|
||||
free( stream->chunks );
|
||||
}
|
||||
|
|
|
@ -23,37 +23,79 @@
|
|||
|
||||
|
||||
|
||||
static void *dumb_stdfile_open(const char *filename)
|
||||
typedef struct dumb_stdfile
|
||||
{
|
||||
return fopen(filename, "rb");
|
||||
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 dumb_stdfile_skip(void *f, int32 n)
|
||||
static int DUMBCALLBACK dumb_stdfile_skip(void *f, long n)
|
||||
{
|
||||
return fseek(f, n, SEEK_CUR);
|
||||
dumb_stdfile * file = ( dumb_stdfile * ) f;
|
||||
return fseek(file->file, n, SEEK_CUR);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int dumb_stdfile_getc(void *f)
|
||||
static int DUMBCALLBACK dumb_stdfile_getc(void *f)
|
||||
{
|
||||
return fgetc(f);
|
||||
dumb_stdfile * file = ( dumb_stdfile * ) f;
|
||||
return fgetc(file->file);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int32 dumb_stdfile_getnc(char *ptr, int32 n, void *f)
|
||||
static int32 DUMBCALLBACK dumb_stdfile_getnc(char *ptr, int32 n, void *f)
|
||||
{
|
||||
return (int32)fread(ptr, 1, n, f);
|
||||
dumb_stdfile * file = ( dumb_stdfile * ) f;
|
||||
return (int32)fread(ptr, 1, n, file->file);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void dumb_stdfile_close(void *f)
|
||||
static void DUMBCALLBACK dumb_stdfile_close(void *f)
|
||||
{
|
||||
fclose(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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -63,7 +105,9 @@ static const DUMBFILE_SYSTEM stdfile_dfs = {
|
|||
&dumb_stdfile_skip,
|
||||
&dumb_stdfile_getc,
|
||||
&dumb_stdfile_getnc,
|
||||
&dumb_stdfile_close
|
||||
&dumb_stdfile_close,
|
||||
&dumb_stdfile_seek,
|
||||
&dumb_stdfile_get_size
|
||||
};
|
||||
|
||||
|
||||
|
@ -80,14 +124,23 @@ static const DUMBFILE_SYSTEM stdfile_dfs_leave_open = {
|
|||
&dumb_stdfile_skip,
|
||||
&dumb_stdfile_getc,
|
||||
&dumb_stdfile_getnc,
|
||||
NULL
|
||||
&dumb_stdfile_noclose,
|
||||
&dumb_stdfile_seek,
|
||||
&dumb_stdfile_get_size
|
||||
};
|
||||
|
||||
|
||||
|
||||
DUMBFILE *DUMBEXPORT dumbfile_open_stdfile(FILE *p)
|
||||
{
|
||||
DUMBFILE *d = dumbfile_open_ex(p, &stdfile_dfs_leave_open);
|
||||
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;
|
||||
}
|
||||
|
|
175
dumb/src/helpers/tarray.c
Normal file
175
dumb/src/helpers/tarray.c
Normal file
|
@ -0,0 +1,175 @@
|
|||
#include "internal/tarray.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
Structures which contain the play times of each pattern and row combination in the song,
|
||||
not guaranteed to be valid for the whole song until the loop status is no longer zero.
|
||||
The initial count and restart count will both be zero on song start, then both will be
|
||||
incremented until the song loops. Restart count will be reset to zero on loop for all
|
||||
rows which have a time equal to or greater than the loop start point, so time keeping
|
||||
functions will know which timestamp the song is currently located at.
|
||||
|
||||
Timestamp lists are guaranteed to be allocated in blocks of 16 timestamps at a time.
|
||||
*/
|
||||
|
||||
/*
|
||||
We don't need full timekeeping because the player loop only wants the first play time
|
||||
of the loop start order/row. We also don't really want full timekeeping because it
|
||||
involves a lot of memory allocations, which is also slow.
|
||||
*/
|
||||
|
||||
#undef FULL_TIMEKEEPING
|
||||
|
||||
typedef struct DUMB_IT_ROW_TIME
|
||||
{
|
||||
unsigned int count, restart_count;
|
||||
#ifndef FULL_TIMEKEEPING
|
||||
LONG_LONG first_time;
|
||||
#else
|
||||
LONG_LONG * times;
|
||||
#endif
|
||||
} DUMB_IT_ROW_TIME;
|
||||
|
||||
void * timekeeping_array_create(size_t size)
|
||||
{
|
||||
size_t * _size = (size_t *) calloc( 1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * size );
|
||||
if ( _size ) {
|
||||
*_size = size;
|
||||
}
|
||||
return _size;
|
||||
}
|
||||
|
||||
void timekeeping_array_destroy(void * array)
|
||||
{
|
||||
#ifdef FULL_TIMEKEEPING
|
||||
size_t i;
|
||||
size_t * size = (size_t *) array;
|
||||
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
|
||||
|
||||
for (i = 0; i < *size; i++) {
|
||||
if (s[i].times) free(s[i].times);
|
||||
}
|
||||
#endif
|
||||
|
||||
free(array);
|
||||
}
|
||||
|
||||
void * timekeeping_array_dup(void * array)
|
||||
{
|
||||
size_t i;
|
||||
size_t * size = (size_t *) array;
|
||||
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
|
||||
size_t * new_size = (size_t *) calloc( 1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * *size );
|
||||
if ( new_size ) {
|
||||
DUMB_IT_ROW_TIME * new_s = (DUMB_IT_ROW_TIME *)(new_size + 1);
|
||||
|
||||
*new_size = *size;
|
||||
|
||||
for (i = 0; i < *size; i++) {
|
||||
new_s[i].count = s[i].count;
|
||||
new_s[i].restart_count = s[i].restart_count;
|
||||
|
||||
#ifndef FULL_TIMEKEEPING
|
||||
new_s[i].first_time = s[i].first_time;
|
||||
#else
|
||||
if ( s[i].times ) {
|
||||
size_t time_count = ( s[i].count + 15 ) & ~15;
|
||||
new_s[i].times = (LONG_LONG *) malloc( sizeof(LONG_LONG) * time_count );
|
||||
if ( new_s[i].times == (void *)0 ) {
|
||||
timekeeping_array_destroy( new_size );
|
||||
return (void *) 0;
|
||||
}
|
||||
memcpy( new_s[i].times, s[i].times, sizeof(LONG_LONG) * s[i].count );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return new_size;
|
||||
}
|
||||
|
||||
void timekeeping_array_reset(void * array, size_t loop_start)
|
||||
{
|
||||
size_t i;
|
||||
size_t * size = (size_t *) array;
|
||||
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
|
||||
|
||||
DUMB_IT_ROW_TIME * s_loop_start = s + loop_start;
|
||||
LONG_LONG loop_start_time;
|
||||
|
||||
if ( loop_start >= *size || s_loop_start->count < 1 ) return;
|
||||
|
||||
#ifndef FULL_TIMEKEEPING
|
||||
loop_start_time = s_loop_start->first_time;
|
||||
#else
|
||||
loop_start_time = s_loop_start->times[0];
|
||||
#endif
|
||||
|
||||
for ( i = 0; i < *size; i++ ) {
|
||||
#ifndef FULL_TIMEKEEPING
|
||||
if ( s[i].count && s[i].first_time >= loop_start_time ) {
|
||||
#else
|
||||
if ( s[i].count && s[i].times[0] >= loop_start_time ) {
|
||||
#endif
|
||||
s[i].restart_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void timekeeping_array_push(void * array, size_t index, LONG_LONG time)
|
||||
{
|
||||
#ifdef FULL_TIMEKEEPING
|
||||
size_t i;
|
||||
size_t time_count;
|
||||
#endif
|
||||
size_t * size = (size_t *) array;
|
||||
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
|
||||
|
||||
if (index >= *size) return;
|
||||
|
||||
#ifndef FULL_TIMEKEEPING
|
||||
if ( !s[index].count++ )
|
||||
s[index].first_time = time;
|
||||
#else
|
||||
time_count = ( s[index].count + 16 ) & ~15;
|
||||
|
||||
s[index].times = (LONG_LONG *) realloc( s[index].times, sizeof(LONG_LONG) * time_count );
|
||||
|
||||
s[index].times[s[index].count++] = time;
|
||||
#endif
|
||||
}
|
||||
|
||||
void timekeeping_array_bump(void * array, size_t index)
|
||||
{
|
||||
size_t * size = (size_t *) array;
|
||||
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
|
||||
|
||||
if (index >= *size) return;
|
||||
|
||||
s[index].restart_count++;
|
||||
}
|
||||
|
||||
unsigned int timekeeping_array_get_count(void * array, size_t index)
|
||||
{
|
||||
size_t * size = (size_t *) array;
|
||||
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
|
||||
|
||||
if (index >= *size) return 0;
|
||||
|
||||
return s[index].count;
|
||||
}
|
||||
|
||||
LONG_LONG timekeeping_array_get_item(void * array, size_t index)
|
||||
{
|
||||
size_t * size = (size_t *) array;
|
||||
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
|
||||
|
||||
if (index >= *size || s[index].restart_count >= s[index].count) return 0;
|
||||
|
||||
#ifndef FULL_TIMEKEEPING
|
||||
return s[index].first_time;
|
||||
#else
|
||||
return s[index].times[s[index].restart_count];
|
||||
#endif
|
||||
}
|
|
@ -1,285 +0,0 @@
|
|||
#if defined(_DEBUG) && defined(_MSC_VER)
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__amd64__)
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#include <xmmintrin.h>
|
||||
#define HAVE_SSE_VERSION 1
|
||||
#endif
|
||||
#include <math.h>
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
extern "C" {
|
||||
#include "internal/it.h"
|
||||
}
|
||||
|
||||
#ifdef _M_IX86
|
||||
enum {
|
||||
CPU_HAVE_3DNOW = 1 << 0,
|
||||
CPU_HAVE_3DNOW_EX = 1 << 1,
|
||||
CPU_HAVE_SSE = 1 << 2,
|
||||
CPU_HAVE_SSE2 = 1 << 3,
|
||||
CPU_HAVE_SSE3 = 1 << 4,
|
||||
};
|
||||
|
||||
static bool query_cpu_feature_set(/*unsigned p_value*/) {
|
||||
__try {
|
||||
/*if (p_value & (CPU_HAVE_SSE | CPU_HAVE_SSE2 | CPU_HAVE_SSE2))*/ {
|
||||
int buffer[4];
|
||||
__cpuid(buffer,1);
|
||||
/*if (p_value & CPU_HAVE_SSE)*/ {
|
||||
if ((buffer[3]&(1<<25)) == 0) return false;
|
||||
}
|
||||
/*if (p_value & CPU_HAVE_SSE2) {
|
||||
if ((buffer[3]&(1<<26)) == 0) return false;
|
||||
}
|
||||
if (p_value & CPU_HAVE_SSE3) {
|
||||
if ((buffer[2]&(1<<0)) == 0) return false;
|
||||
}*/
|
||||
}
|
||||
|
||||
#ifdef _M_IX86
|
||||
/*if (p_value & (CPU_HAVE_3DNOW_EX | CPU_HAVE_3DNOW)) {
|
||||
int buffer_amd[4];
|
||||
__cpuid(buffer_amd,0x80000000);
|
||||
if ((unsigned)buffer_amd[0] < 0x80000001) return false;
|
||||
__cpuid(buffer_amd,0x80000001);
|
||||
|
||||
if (p_value & CPU_HAVE_3DNOW) {
|
||||
if ((buffer_amd[3]&(1<<22)) == 0) return false;
|
||||
}
|
||||
if (p_value & CPU_HAVE_3DNOW_EX) {
|
||||
if ((buffer_amd[3]&(1<<30)) == 0) return false;
|
||||
}
|
||||
}*/
|
||||
#endif
|
||||
return true;
|
||||
} __except(1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const bool g_have_sse = query_cpu_feature_set(/*CPU_HAVE_SSE*/);
|
||||
#elif defined(_M_X64) || defined(__amd64__)
|
||||
|
||||
enum {g_have_sse2 = true, g_have_sse = true, g_have_3dnow = false};
|
||||
|
||||
#else
|
||||
|
||||
enum {g_have_sse2 = false, g_have_sse = false, g_have_3dnow = false};
|
||||
|
||||
#endif
|
||||
|
||||
static void it_filter_int(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, int32 pos, sample_t *src, int32 size, int step, int sampfreq, int cutoff, int resonance);
|
||||
static void it_filter_sse(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, int32 pos, sample_t *src, int32 size, int step, int sampfreq, int cutoff, int resonance);
|
||||
|
||||
extern "C" void it_filter(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, int32 pos, sample_t *src, int32 size, int step, int sampfreq, int cutoff, int resonance)
|
||||
{
|
||||
if ( g_have_sse ) it_filter_sse(cr, state, dst, pos, src, size, step, sampfreq, cutoff, resonance);
|
||||
else it_filter_int(cr, state, dst, pos, src, size, step, sampfreq, cutoff, resonance);
|
||||
}
|
||||
|
||||
#define LOG10 2.30258509299
|
||||
#define MULSCA(a, b) ((int)((LONG_LONG)((a) << 4) * (b) >> 32))
|
||||
#define SCALEB 12
|
||||
|
||||
static void it_filter_int(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, int32 pos, sample_t *src, int32 size, int step, int sampfreq, int cutoff, int resonance)
|
||||
{
|
||||
//profiler( filter );
|
||||
|
||||
sample_t currsample = state->currsample;
|
||||
sample_t prevsample = state->prevsample;
|
||||
|
||||
float a, b, c;
|
||||
|
||||
int32 datasize;
|
||||
|
||||
{
|
||||
float inv_angle = (float)(sampfreq * pow(0.5, 0.25 + cutoff*(1.0/(24<<IT_ENVELOPE_SHIFT))) * (1.0/(2*3.14159265358979323846*110.0)));
|
||||
float loss = (float)exp(resonance*(-LOG10*1.2/128.0));
|
||||
float d, e;
|
||||
#if 0
|
||||
loss *= 2; // This is the mistake most players seem to make!
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
d = (1.0f - loss) / inv_angle;
|
||||
if (d > 2.0f) d = 2.0f;
|
||||
d = (loss - d) * inv_angle;
|
||||
e = inv_angle * inv_angle;
|
||||
a = 1.0f / (1.0f + d + e);
|
||||
c = -e * a;
|
||||
b = 1.0f - a - c;
|
||||
#else
|
||||
a = 1.0f / (inv_angle*inv_angle + inv_angle*loss + loss);
|
||||
c = -(inv_angle*inv_angle) * a;
|
||||
b = 1.0f - a - c;
|
||||
#endif
|
||||
}
|
||||
|
||||
dst += pos * step;
|
||||
datasize = size * step;
|
||||
|
||||
#define INT_FILTERS
|
||||
#ifdef INT_FILTERS
|
||||
{
|
||||
int ai = (int)(a * (1 << (16+SCALEB)));
|
||||
int bi = (int)(b * (1 << (16+SCALEB)));
|
||||
int ci = (int)(c * (1 << (16+SCALEB)));
|
||||
int i;
|
||||
|
||||
if (cr) {
|
||||
sample_t startstep = MULSCA(src[0], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci);
|
||||
dumb_record_click(cr, pos, startstep);
|
||||
}
|
||||
|
||||
for (i = 0; i < datasize; i += step) {
|
||||
{
|
||||
sample_t newsample = MULSCA(src[i], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci);
|
||||
prevsample = currsample;
|
||||
currsample = newsample;
|
||||
}
|
||||
dst[i] += currsample;
|
||||
}
|
||||
|
||||
if (cr) {
|
||||
sample_t endstep = MULSCA(src[datasize], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci);
|
||||
dumb_record_click(cr, pos + size, -endstep);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (cr) {
|
||||
float startstep = src[0]*a + currsample*b + prevsample*c;
|
||||
dumb_record_click(cr, pos, (sample_t)startstep);
|
||||
}
|
||||
|
||||
{
|
||||
int i = size % 3;
|
||||
while (i > 0) {
|
||||
{
|
||||
float newsample = *src*a + currsample*b + prevsample*c;
|
||||
src += step;
|
||||
prevsample = currsample;
|
||||
currsample = newsample;
|
||||
}
|
||||
*dst += (sample_t)currsample;
|
||||
dst += step;
|
||||
i--;
|
||||
}
|
||||
i = size / 3;
|
||||
while (i > 0) {
|
||||
float newsample;
|
||||
/* Gotta love unrolled loops! */
|
||||
*dst += (sample_t)(newsample = *src*a + currsample*b + prevsample*c);
|
||||
src += step; dst += step;
|
||||
*dst += (sample_t)(prevsample = *src*a + newsample*b + currsample*c);
|
||||
src += step; dst += step;
|
||||
*dst += (sample_t)(currsample = *src*a + prevsample*b + newsample*c);
|
||||
src += step; dst += step;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (cr) {
|
||||
float endstep = src[datasize]*a + currsample*b + prevsample*c;
|
||||
dumb_record_click(cr, pos + size, -(sample_t)endstep);
|
||||
}
|
||||
#endif
|
||||
|
||||
state->currsample = currsample;
|
||||
state->prevsample = prevsample;
|
||||
}
|
||||
|
||||
#if HAVE_SSE_VERSION
|
||||
static void it_filter_sse(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, int32 pos, sample_t *src, int32 size, int step, int sampfreq, int cutoff, int resonance)
|
||||
{
|
||||
__m128 data, impulse;
|
||||
__m128 temp1, temp2;
|
||||
|
||||
sample_t currsample = state->currsample;
|
||||
sample_t prevsample = state->prevsample;
|
||||
|
||||
float imp[4];
|
||||
|
||||
//profiler( filter_sse ); On ClawHammer Athlon64 3200+, ~12000 cycles, ~500 for that x87 setup code (as opposed to ~25500 for the original integer code)
|
||||
|
||||
int32 datasize;
|
||||
|
||||
{
|
||||
float inv_angle = (float)(sampfreq * pow(0.5, 0.25 + cutoff*(1.0/(24<<IT_ENVELOPE_SHIFT))) * (1.0/(2*3.14159265358979323846*110.0)));
|
||||
float loss = (float)exp(resonance*(-LOG10*1.2/128.0));
|
||||
float d, e;
|
||||
#if 0
|
||||
loss *= 2; // This is the mistake most players seem to make!
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
d = (1.0f - loss) / inv_angle;
|
||||
if (d > 2.0f) d = 2.0f;
|
||||
d = (loss - d) * inv_angle;
|
||||
e = inv_angle * inv_angle;
|
||||
imp[0] = 1.0f / (1.0f + d + e);
|
||||
imp[2] = -e * imp[0];
|
||||
imp[1] = 1.0f - imp[0] - imp[2];
|
||||
#else
|
||||
imp[0] = 1.0f / (inv_angle*inv_angle + inv_angle*loss + loss);
|
||||
imp[2] = -(inv_angle*inv_angle) * imp[0];
|
||||
imp[1] = 1.0f - imp[0] - imp[2];
|
||||
#endif
|
||||
imp[3] = 0;
|
||||
}
|
||||
|
||||
dst += pos * step;
|
||||
datasize = size * step;
|
||||
|
||||
{
|
||||
int ai, bi, ci, i;
|
||||
|
||||
if (cr) {
|
||||
sample_t startstep;
|
||||
ai = (int)(imp[0] * (1 << (16+SCALEB)));
|
||||
bi = (int)(imp[1] * (1 << (16+SCALEB)));
|
||||
ci = (int)(imp[2] * (1 << (16+SCALEB)));
|
||||
startstep = MULSCA(src[0], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci);
|
||||
dumb_record_click(cr, pos, startstep);
|
||||
}
|
||||
|
||||
data = _mm_cvtsi32_ss( data, prevsample );
|
||||
data = _mm_shuffle_ps( data, data, _MM_SHUFFLE(0, 0, 0, 0) );
|
||||
data = _mm_cvtsi32_ss( data, currsample );
|
||||
impulse = _mm_loadu_ps( (const float *) &imp );
|
||||
temp1 = _mm_shuffle_ps( data, data, _MM_SHUFFLE(0, 1, 0, 0) );
|
||||
|
||||
for (i = 0; i < datasize; i += step) {
|
||||
data = _mm_cvtsi32_ss( temp1, src [i] );
|
||||
temp1 = _mm_mul_ps( data, impulse );
|
||||
temp2 = _mm_shuffle_ps( temp1, temp1, _MM_SHUFFLE(0, 0, 3, 2) );
|
||||
temp1 = _mm_add_ps( temp1, temp2 );
|
||||
temp2 = _mm_shuffle_ps( temp1, temp1, _MM_SHUFFLE(0, 0, 0, 1) );
|
||||
temp1 = _mm_add_ps( temp1, temp2 );
|
||||
temp1 = _mm_shuffle_ps( temp1, data, _MM_SHUFFLE(0, 1, 0, 0) );
|
||||
dst [i] += _mm_cvtss_si32( temp1 );
|
||||
}
|
||||
|
||||
currsample = _mm_cvtss_si32( temp1 );
|
||||
temp1 = _mm_shuffle_ps( temp1, temp1, _MM_SHUFFLE(0, 0, 0, 2) );
|
||||
prevsample = _mm_cvtss_si32( temp1 );
|
||||
|
||||
#ifndef _M_X64
|
||||
_mm_empty();
|
||||
#endif
|
||||
|
||||
if (cr) {
|
||||
sample_t endstep = MULSCA(src[datasize], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci);
|
||||
dumb_record_click(cr, pos + size, -endstep);
|
||||
}
|
||||
}
|
||||
|
||||
state->currsample = currsample;
|
||||
state->prevsample = prevsample;
|
||||
}
|
||||
#endif
|
|
@ -21,6 +21,8 @@
|
|||
#include "internal/it.h"
|
||||
|
||||
|
||||
int dumb_it_default_panning_separation = 25;
|
||||
|
||||
|
||||
DUMB_IT_SIGDATA *DUMBEXPORT duh_get_it_sigdata(DUH *duh)
|
||||
{
|
||||
|
|
|
@ -24,80 +24,11 @@
|
|||
#include "internal/it.h"
|
||||
|
||||
#ifndef min
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
//#define INVESTIGATE_OLD_INSTRUMENTS
|
||||
|
||||
|
||||
typedef struct tdumbfile_mem_status
|
||||
{
|
||||
const unsigned char * ptr;
|
||||
unsigned offset, size;
|
||||
} dumbfile_mem_status;
|
||||
|
||||
static int dumbfile_mem_skip(void * f, int32 n)
|
||||
{
|
||||
dumbfile_mem_status * s = (dumbfile_mem_status *) f;
|
||||
s->offset += n;
|
||||
if (s->offset > s->size)
|
||||
{
|
||||
s->offset = s->size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int dumbfile_mem_getc(void * f)
|
||||
{
|
||||
dumbfile_mem_status * s = (dumbfile_mem_status *) f;
|
||||
if (s->offset < s->size)
|
||||
{
|
||||
return *(s->ptr + s->offset++);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int32 dumbfile_mem_getnc(char * ptr, int32 n, void * f)
|
||||
{
|
||||
dumbfile_mem_status * s = (dumbfile_mem_status *) f;
|
||||
int32 max = s->size - s->offset;
|
||||
if (max > n) max = n;
|
||||
if (max)
|
||||
{
|
||||
memcpy(ptr, s->ptr + s->offset, max);
|
||||
s->offset += max;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static DUMBFILE_SYSTEM mem_dfs = {
|
||||
NULL, // open
|
||||
&dumbfile_mem_skip,
|
||||
&dumbfile_mem_getc,
|
||||
&dumbfile_mem_getnc,
|
||||
NULL // close
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int it_seek(dumbfile_mem_status * s, int32 offset)
|
||||
{
|
||||
if ( (unsigned)offset > s->size )
|
||||
return -1;
|
||||
|
||||
s->offset = offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define INVESTIGATE_OLD_INSTRUMENTS
|
||||
|
||||
|
||||
|
||||
|
@ -178,7 +109,7 @@ static int readbits(int bitwidth, readblock_crap * crap)
|
|||
/** WARNING - do we even need to pass `right`? */
|
||||
/** WARNING - why bother memsetting at all? The whole array is written... */
|
||||
// if we do memset, dumb_silence() would be neater...
|
||||
static int decompress8(DUMBFILE *f, signed char *data, int len, int it215)
|
||||
static int decompress8(DUMBFILE *f, signed char *data, int len, int it215, int stereo)
|
||||
{
|
||||
int blocklen, blockpos;
|
||||
byte bitwidth;
|
||||
|
@ -188,7 +119,8 @@ static int decompress8(DUMBFILE *f, signed char *data, int len, int it215)
|
|||
|
||||
memset(&crap, 0, sizeof(crap));
|
||||
|
||||
memset(data, 0, len * sizeof(*data));
|
||||
for (blocklen = 0, blockpos = 0; blocklen < len; blocklen++, blockpos += 1 + stereo)
|
||||
data[ blockpos ] = 0;
|
||||
|
||||
while (len > 0) {
|
||||
//Read a block of compressed data:
|
||||
|
@ -254,6 +186,7 @@ static int decompress8(DUMBFILE *f, signed char *data, int len, int it215)
|
|||
* code. Yay, better compression :D
|
||||
*/
|
||||
*data++ = it215 ? d2 : d1;
|
||||
data += stereo;
|
||||
len--;
|
||||
blockpos++;
|
||||
}
|
||||
|
@ -264,7 +197,7 @@ static int decompress8(DUMBFILE *f, signed char *data, int len, int it215)
|
|||
|
||||
|
||||
|
||||
static int decompress16(DUMBFILE *f, short *data, int len, int it215)
|
||||
static int decompress16(DUMBFILE *f, short *data, int len, int it215, int stereo)
|
||||
{
|
||||
int blocklen, blockpos;
|
||||
byte bitwidth;
|
||||
|
@ -274,7 +207,8 @@ static int decompress16(DUMBFILE *f, short *data, int len, int it215)
|
|||
|
||||
memset(&crap, 0, sizeof(crap));
|
||||
|
||||
memset(data, 0, len * sizeof(*data));
|
||||
for ( blocklen = 0, blockpos = 0; blocklen < len; blocklen++, blockpos += 1 + stereo )
|
||||
data[ blockpos ] = 0;
|
||||
|
||||
while (len > 0) {
|
||||
//Read a block of compressed data:
|
||||
|
@ -339,6 +273,7 @@ static int decompress16(DUMBFILE *f, short *data, int len, int it215)
|
|||
* code. Yay, better compression :D
|
||||
*/
|
||||
*data++ = it215 ? d2 : d1;
|
||||
data += stereo;
|
||||
len--;
|
||||
blockpos++;
|
||||
}
|
||||
|
@ -388,7 +323,7 @@ static int it_read_old_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f)
|
|||
// XXX
|
||||
dumbfile_skip(f, 4);
|
||||
|
||||
dumbfile_getnc(instrument->filename, 13, f);
|
||||
dumbfile_getnc((char *)instrument->filename, 13, f);
|
||||
instrument->filename[13] = 0;
|
||||
|
||||
instrument->volume_envelope.flags = dumbfile_getc(f);
|
||||
|
@ -417,7 +352,7 @@ static int it_read_old_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f)
|
|||
*/
|
||||
dumbfile_skip(f, 4);
|
||||
|
||||
dumbfile_getnc(instrument->name, 26, f);
|
||||
dumbfile_getnc((char *)instrument->name, 26, f);
|
||||
instrument->name[26] = 0;
|
||||
|
||||
/* Skip unused bytes following the Instrument Name. */
|
||||
|
@ -503,7 +438,7 @@ static int it_read_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f, int maxlen
|
|||
|
||||
dumbfile_skip(f, 4);
|
||||
|
||||
dumbfile_getnc(instrument->filename, 13, f);
|
||||
dumbfile_getnc((char *)instrument->filename, 13, f);
|
||||
instrument->filename[13] = 0;
|
||||
|
||||
instrument->new_note_action = dumbfile_getc(f);
|
||||
|
@ -522,7 +457,7 @@ static int it_read_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f, int maxlen
|
|||
*/
|
||||
dumbfile_skip(f, 4);
|
||||
|
||||
dumbfile_getnc(instrument->name, 26, f);
|
||||
dumbfile_getnc((char *)instrument->name, 26, f);
|
||||
instrument->name[26] = 0;
|
||||
|
||||
instrument->filter_cutoff = dumbfile_getc(f);
|
||||
|
@ -606,14 +541,14 @@ static int it_read_sample_header(IT_SAMPLE *sample, unsigned char *convert, int3
|
|||
}
|
||||
}
|
||||
|
||||
dumbfile_getnc(sample->filename, 13, f);
|
||||
dumbfile_getnc((char *)sample->filename, 13, f);
|
||||
sample->filename[13] = 0;
|
||||
|
||||
sample->global_volume = dumbfile_getc(f);
|
||||
sample->flags = dumbfile_getc(f);
|
||||
sample->default_volume = dumbfile_getc(f);
|
||||
|
||||
dumbfile_getnc(sample->name, 26, f);
|
||||
dumbfile_getnc((char *)sample->name, 26, f);
|
||||
sample->name[26] = 0;
|
||||
|
||||
*convert = dumbfile_getc(f);
|
||||
|
@ -683,7 +618,7 @@ int32 _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f)
|
|||
int32 n, len, delta;
|
||||
signed char * ptr, * end;
|
||||
signed char compression_table[16];
|
||||
if (dumbfile_getnc(compression_table, 16, f) != 16)
|
||||
if (dumbfile_getnc((char *)compression_table, 16, f) != 16)
|
||||
return -1;
|
||||
ptr = (signed char *) sample->data;
|
||||
delta = 0;
|
||||
|
@ -704,7 +639,7 @@ int32 _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f)
|
|||
}
|
||||
|
||||
|
||||
static int32 it_read_sample_data(int cmwt, IT_SAMPLE *sample, unsigned char convert, DUMBFILE *f)
|
||||
static int32 it_read_sample_data(IT_SAMPLE *sample, unsigned char convert, DUMBFILE *f)
|
||||
{
|
||||
int32 n;
|
||||
|
||||
|
@ -721,21 +656,22 @@ static int32 it_read_sample_data(int cmwt, IT_SAMPLE *sample, unsigned char conv
|
|||
} else if (sample->flags & 8) {
|
||||
/* If the sample is packed, then we must unpack it. */
|
||||
|
||||
/** WARNING - unresolved business here... test with ModPlug? */
|
||||
/* Behavior as defined by greasemonkey's munch.py and observed by XMPlay and OpenMPT */
|
||||
|
||||
if (sample->flags & IT_SAMPLE_STEREO)
|
||||
//exit(37); // TODO: if this ever happens, maybe sample->length should be doubled below?
|
||||
return -1;
|
||||
|
||||
/*
|
||||
//#ifndef STEREO_SAMPLES_COUNT_AS_TWO
|
||||
ASSERT(!(sample->flags & IT_SAMPLE_STEREO));
|
||||
//#endif
|
||||
*/
|
||||
if (sample->flags & IT_SAMPLE_16BIT)
|
||||
decompress16(f, sample->data, datasize, ((cmwt >= 0x215) && (convert & 4)));
|
||||
else
|
||||
decompress8(f, sample->data, datasize, ((cmwt >= 0x215) && (convert & 4)));
|
||||
if (sample->flags & IT_SAMPLE_STEREO) {
|
||||
if (sample->flags & IT_SAMPLE_16BIT) {
|
||||
decompress16(f, (short *) sample->data, datasize >> 1, convert & 4, 1);
|
||||
decompress16(f, (short *) sample->data + 1, datasize >> 1, convert & 4, 1);
|
||||
} else {
|
||||
decompress8(f, (signed char *) sample->data, datasize >> 1, convert & 4, 1);
|
||||
decompress8(f, (signed char *) sample->data + 1, datasize >> 1, convert & 4, 1);
|
||||
}
|
||||
} else {
|
||||
if (sample->flags & IT_SAMPLE_16BIT)
|
||||
decompress16(f, (short *) sample->data, datasize, convert & 4, 0);
|
||||
else
|
||||
decompress8(f, (signed char *) sample->data, datasize, convert & 4, 0);
|
||||
}
|
||||
} else if (sample->flags & IT_SAMPLE_16BIT) {
|
||||
if (sample->flags & IT_SAMPLE_STEREO) {
|
||||
if (convert & 2) {
|
||||
|
@ -841,7 +777,7 @@ static int it_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buff
|
|||
return -1;
|
||||
|
||||
/* Read in the pattern data. */
|
||||
dumbfile_getnc(buffer, buflen, f);
|
||||
dumbfile_getnc((char *)buffer, buflen, f);
|
||||
|
||||
if (dumbfile_error(f))
|
||||
return -1;
|
||||
|
@ -1010,47 +946,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
|
||||
unsigned char *buffer;
|
||||
|
||||
unsigned char *file_buffer = NULL;
|
||||
unsigned int file_size = 0;
|
||||
int block_size;
|
||||
|
||||
dumbfile_mem_status memdata;
|
||||
|
||||
do
|
||||
{
|
||||
void * temp = realloc( file_buffer, file_size + 32768 );
|
||||
if ( !temp )
|
||||
{
|
||||
if ( file_buffer ) free( file_buffer );
|
||||
return NULL;
|
||||
}
|
||||
file_buffer = temp;
|
||||
block_size = dumbfile_getnc( file_buffer + file_size, 32768, f );
|
||||
if ( block_size < 0 )
|
||||
{
|
||||
free( file_buffer );
|
||||
return NULL;
|
||||
}
|
||||
file_size += block_size;
|
||||
}
|
||||
while ( block_size == 32768 );
|
||||
|
||||
memdata.ptr = file_buffer;
|
||||
memdata.offset = 0;
|
||||
memdata.size = file_size;
|
||||
|
||||
f = dumbfile_open_ex(&memdata, &mem_dfs);
|
||||
|
||||
if ( !f )
|
||||
{
|
||||
free( file_buffer );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dumbfile_mgetl(f) != IT_SIGNATURE)
|
||||
{
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1058,8 +955,6 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
|
||||
if (!sigdata)
|
||||
{
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1071,7 +966,7 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
sigdata->midi = NULL;
|
||||
sigdata->checkpoint = NULL;
|
||||
|
||||
dumbfile_getnc(sigdata->name, 26, f);
|
||||
dumbfile_getnc((char *)sigdata->name, 26, f);
|
||||
sigdata->name[26] = 0;
|
||||
|
||||
/* Skip pattern row highlight info. */
|
||||
|
@ -1104,22 +999,18 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
/* Skip Reserved. */
|
||||
dumbfile_skip(f, 4);
|
||||
|
||||
dumbfile_getnc(sigdata->channel_pan, DUMB_IT_N_CHANNELS, f);
|
||||
dumbfile_getnc(sigdata->channel_volume, DUMB_IT_N_CHANNELS, f);
|
||||
dumbfile_getnc((char *)sigdata->channel_pan, DUMB_IT_N_CHANNELS, f);
|
||||
dumbfile_getnc((char *)sigdata->channel_volume, DUMB_IT_N_CHANNELS, f);
|
||||
|
||||
// XXX sample count
|
||||
if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_instruments > 256 || sigdata->n_samples > 4000 || sigdata->n_patterns > 256) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->order = malloc(sigdata->n_orders);
|
||||
if (!sigdata->order) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1127,8 +1018,6 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
|
||||
if (!sigdata->instrument) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1137,8 +1026,6 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
|
||||
if (!sigdata->sample) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
for (n = 0; n < sigdata->n_samples; n++)
|
||||
|
@ -1149,22 +1036,18 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
|
||||
if (!sigdata->pattern) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
for (n = 0; n < sigdata->n_patterns; n++)
|
||||
sigdata->pattern[n].entry = NULL;
|
||||
}
|
||||
|
||||
dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
|
||||
dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f);
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
component = malloc(769 * sizeof(*component));
|
||||
if (!component) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1209,8 +1092,6 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
if (dumbfile_error(f)) {
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1231,8 +1112,6 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
if (!sigdata->midi) {
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
// Should we be happy with this outcome in some situations?
|
||||
}
|
||||
|
@ -1241,8 +1120,6 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
if (dumbfile_error(f) || dumbfile_skip(f, 8*i)) {
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
/* Read embedded MIDI configuration */
|
||||
|
@ -1250,18 +1127,14 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
if (dumbfile_skip(f, 32*9)) {
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
unsigned char len = 0;
|
||||
int j, leftdigit = -1;
|
||||
if (dumbfile_getnc(mididata, 32, f) < 32) {
|
||||
if (dumbfile_getnc((char *)mididata, 32, f) < 32) {
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
sigdata->midi->SFmacroz[i] = 0;
|
||||
|
@ -1291,7 +1164,7 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
for (i = 0; i < 128; i++) {
|
||||
unsigned char len = 0;
|
||||
int j, leftdigit = -1;
|
||||
dumbfile_getnc(mididata, 32, f);
|
||||
dumbfile_getnc((char *)mididata, 32, f);
|
||||
for (j = 0; j < 32; j++) {
|
||||
if (leftdigit >= 0) {
|
||||
if (mididata[j] == 0) {
|
||||
|
@ -1323,8 +1196,6 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
if (!buffer) {
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1353,12 +1224,10 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (it_seek(&memdata, component[n].offset)) {
|
||||
if (dumbfile_seek(f, component[n].offset, DFS_SEEK_SET)) {
|
||||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1370,12 +1239,10 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
}
|
||||
sigdata->song_message = malloc(message_length + 1);
|
||||
if (sigdata->song_message) {
|
||||
if (dumbfile_getnc(sigdata->song_message, message_length, f) < message_length) {
|
||||
if (dumbfile_getnc((char *)sigdata->song_message, message_length, f) < message_length) {
|
||||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
sigdata->song_message[message_length] = 0;
|
||||
|
@ -1392,8 +1259,6 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
|
@ -1403,8 +1268,6 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
|
@ -1414,8 +1277,6 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1442,21 +1303,17 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
m = component[n].sampfirst;
|
||||
|
||||
while (m >= 0) {
|
||||
if (it_seek(&memdata, component[m].offset)) {
|
||||
if (dumbfile_seek(f, component[m].offset, DFS_SEEK_SET)) {
|
||||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (it_read_sample_data(cmwt, &sigdata->sample[component[m].n], sample_convert[component[m].n], f)) {
|
||||
if (it_read_sample_data(&sigdata->sample[component[m].n], sample_convert[component[m].n], f)) {
|
||||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1500,7 +1357,7 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
}
|
||||
|
||||
mptx_id = dumbfile_igetl( f );
|
||||
while ( memdata.offset < file_size )
|
||||
while ( !dumbfile_error(f) && dumbfile_pos(f) < dumbfile_get_size(f) )
|
||||
{
|
||||
unsigned int size = dumbfile_igetw( f );
|
||||
switch (mptx_id)
|
||||
|
@ -1525,9 +1382,6 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
free(buffer);
|
||||
free(component);
|
||||
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
|
||||
_dumb_it_fix_invalid_orders(sigdata);
|
||||
|
||||
return sigdata;
|
||||
|
@ -1549,7 +1403,7 @@ DUH *DUMBEXPORT dumb_read_it_quick(DUMBFILE *f)
|
|||
{
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
|
||||
tag[1][0] = "FORMAT";
|
||||
tag[1][1] = "IT";
|
||||
return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
|
||||
|
|
File diff suppressed because it is too large
Load diff
42
dumb/src/it/loadamf.c
Normal file
42
dumb/src/it/loadamf.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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;
|
||||
}
|
34
dumb/src/it/loadamf2.c
Normal file
34
dumb/src/it/loadamf2.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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;
|
||||
}
|
38
dumb/src/it/loadany.c
Normal file
38
dumb/src/it/loadany.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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;
|
||||
}
|
29
dumb/src/it/loadany2.c
Normal file
29
dumb/src/it/loadany2.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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;
|
||||
}
|
|
@ -26,7 +26,7 @@
|
|||
* 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 rstrict)
|
||||
DUH *DUMBEXPORT dumb_load_mod_quick(const char *filename, int restrict_)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
@ -34,7 +34,7 @@ DUH *DUMBEXPORT dumb_load_mod_quick(const char *filename, int rstrict)
|
|||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_mod_quick(f, rstrict);
|
||||
duh = dumb_read_mod_quick(f, restrict_);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_mod(const char *filename, int rstrict)
|
||||
DUH *DUMBEXPORT dumb_load_mod(const char *filename, int restrict_)
|
||||
{
|
||||
DUH *duh = dumb_load_mod_quick(filename, rstrict);
|
||||
DUH *duh = dumb_load_mod_quick(filename, restrict_);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ static int it_669_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int tempo, int
|
|||
|
||||
pattern->n_rows = 64;
|
||||
|
||||
if (dumbfile_getnc(buffer, 64 * 3 * 8, f) < 64 * 3 * 8)
|
||||
if (dumbfile_getnc((char *)buffer, 64 * 3 * 8, f) < 64 * 3 * 8)
|
||||
return -1;
|
||||
|
||||
/* compute number of entries */
|
||||
|
@ -156,7 +156,7 @@ static int it_669_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int tempo, int
|
|||
|
||||
static int it_669_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
|
||||
{
|
||||
dumbfile_getnc(sample->name, 13, f);
|
||||
dumbfile_getnc((char *)sample->name, 13, f);
|
||||
sample->name[13] = 0;
|
||||
|
||||
sample->filename[0] = 0;
|
||||
|
@ -268,7 +268,7 @@ static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int * ext)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (dumbfile_getnc(sigdata->name, 36, f) < 36) {
|
||||
if (dumbfile_getnc((char *)sigdata->name, 36, f) < 36) {
|
||||
free(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -288,13 +288,13 @@ static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int * ext)
|
|||
free(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
if (dumbfile_getnc(sigdata->song_message, 36, f) < 36) {
|
||||
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(sigdata->song_message + 38, 36, f) < 36) {
|
||||
if (dumbfile_getnc((char *)sigdata->song_message + 38, 36, f) < 36) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int * ext)
|
|||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
if (dumbfile_getnc(sigdata->order, 128, f) < 128) {
|
||||
if (dumbfile_getnc((char *)sigdata->order, 128, f) < 128) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -332,12 +332,12 @@ static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int * ext)
|
|||
}
|
||||
sigdata->n_orders = i;
|
||||
|
||||
if (dumbfile_getnc(tempolist, 128, f) < 128) {
|
||||
if (dumbfile_getnc((char *)tempolist, 128, f) < 128) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dumbfile_getnc(breaklist, 128, f) < 128) {
|
||||
if (dumbfile_getnc((char *)breaklist, 128, f) < 128) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -413,8 +413,9 @@ static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int * ext)
|
|||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
for (i = 0; i < DUMB_IT_N_CHANNELS; i += 2) {
|
||||
sigdata->channel_pan[i+0] = 48;
|
||||
sigdata->channel_pan[i+1] = 16;
|
||||
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);
|
||||
|
@ -439,7 +440,7 @@ DUH *DUMBEXPORT dumb_read_669_quick(DUMBFILE *f)
|
|||
{
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
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);
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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;
|
||||
}
|
|
@ -24,7 +24,7 @@
|
|||
#include "internal/it.h"
|
||||
#include "internal/riff.h"
|
||||
|
||||
static int it_riff_am_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len, int ver )
|
||||
static int it_riff_am_process_sample( IT_SAMPLE * sample, DUMBFILE * f, int len, int ver )
|
||||
{
|
||||
int header_length;
|
||||
int default_pan;
|
||||
|
@ -34,49 +34,51 @@ static int it_riff_am_process_sample( IT_SAMPLE * sample, const unsigned char *
|
|||
int length_bytes;
|
||||
int loop_start;
|
||||
int loop_end;
|
||||
int sample_rate;
|
||||
int sample_rate;
|
||||
|
||||
int32 start = dumbfile_pos( f );
|
||||
|
||||
if ( ver == 0 )
|
||||
{
|
||||
{
|
||||
if ( len < 0x38 )
|
||||
return -1;
|
||||
|
||||
header_length = 0x38;
|
||||
|
||||
memcpy( sample->name, data, 28 );
|
||||
dumbfile_getnc( (char *) sample->name, 28, f );
|
||||
sample->name[ 28 ] = 0;
|
||||
|
||||
default_pan = data[ 0x1C ];
|
||||
default_volume = data[ 0x1D ];
|
||||
flags = data[ 0x1E ] | ( data[ 0x1F ] << 8 );
|
||||
length = data[ 0x20 ] | ( data[ 0x21 ] << 8 ) | ( data[ 0x22 ] << 16 ) | ( data[ 0x23 ] << 24 );
|
||||
loop_start = data[ 0x24 ] | ( data[ 0x25 ] << 8 ) | ( data[ 0x26 ] << 16 ) | ( data[ 0x27 ] << 24 );
|
||||
loop_end = data[ 0x28 ] | ( data[ 0x29 ] << 8 ) | ( data[ 0x2A ] << 16 ) | ( data[ 0x2B ] << 24 );
|
||||
sample_rate = data[ 0x2C ] | ( data[ 0x2D ] << 8 ) | ( data[ 0x2E ] << 16 ) | ( data[ 0x2F ] << 24 );
|
||||
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 = data[ 0 ] | ( data[ 1 ] << 8 ) | ( data[ 2 ] << 16 ) | ( data[ 3 ] << 24 );
|
||||
header_length = dumbfile_igetl( f );
|
||||
if ( header_length < 0x40 )
|
||||
return -1;
|
||||
if ( header_length + 4 > len )
|
||||
return -1;
|
||||
|
||||
data += 4;
|
||||
start += 4;
|
||||
len -= 4;
|
||||
|
||||
memcpy( sample->name, data, 32 );
|
||||
sample->name[ 32 ] = 0;
|
||||
dumbfile_getnc( (char *) sample->name, 32, f );
|
||||
|
||||
default_pan = data[ 0x20 ] | ( data[ 0x21 ] << 8 );
|
||||
default_volume = data[ 0x22 ] | ( data[ 0x23 ] << 8 );
|
||||
flags = data[ 0x24 ] | ( data[ 0x25 ] << 8 ); /* | ( data[ 0x26 ] << 16 ) | ( data[ 0x27 ] << 24 );*/
|
||||
length = data[ 0x28 ] | ( data[ 0x29 ] << 8 ) | ( data[ 0x2A ] << 16 ) | ( data[ 0x2B ] << 24 );
|
||||
loop_start = data[ 0x2C ] | ( data[ 0x2D ] << 8 ) | ( data[ 0x2E ] << 16 ) | ( data[ 0x2F ] << 24 );
|
||||
loop_end = data[ 0x30 ] | ( data[ 0x31 ] << 8 ) | ( data[ 0x32 ] << 16 ) | ( data[ 0x33 ] << 24 );
|
||||
sample_rate = data[ 0x34 ] | ( data[ 0x35 ] << 8 ) | ( data[ 0x36 ] << 16 ) | ( data[ 0x37 ] << 24 );
|
||||
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;
|
||||
|
@ -85,9 +87,6 @@ static int it_riff_am_process_sample( IT_SAMPLE * sample, const unsigned char *
|
|||
default_volume = default_volume * 64 / 32767;
|
||||
}
|
||||
|
||||
/*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] )
|
||||
return -1;*/
|
||||
|
||||
if ( ! length ) {
|
||||
sample->flags &= ~IT_SAMPLE_EXISTS;
|
||||
return 0;
|
||||
|
@ -138,43 +137,49 @@ static int it_riff_am_process_sample( IT_SAMPLE * sample, const unsigned char *
|
|||
if ( ! sample->data )
|
||||
return -1;
|
||||
|
||||
memcpy( sample->data, data + header_length, length_bytes );
|
||||
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, const unsigned char * data, int len, int ver )
|
||||
static int it_riff_am_process_pattern( IT_PATTERN * pattern, DUMBFILE * f, int len, int ver )
|
||||
{
|
||||
int nrows, row, pos;
|
||||
int nrows, row;
|
||||
long start, end;
|
||||
unsigned flags;
|
||||
int p, q, r;
|
||||
IT_ENTRY * entry;
|
||||
|
||||
nrows = data[0] + 1;
|
||||
nrows = dumbfile_getc( f ) + 1;
|
||||
|
||||
pattern->n_rows = nrows;
|
||||
|
||||
data += 1;
|
||||
len -= 1;
|
||||
|
||||
pattern->n_entries = 0;
|
||||
|
||||
row = 0;
|
||||
pos = 0;
|
||||
|
||||
while ( (row < nrows) && (pos < len) ) {
|
||||
if ( ! data[ pos ] ) {
|
||||
start = dumbfile_pos( f );
|
||||
end = start + len;
|
||||
|
||||
while ( (row < nrows) && !dumbfile_error( f ) && (dumbfile_pos( f ) < end) ) {
|
||||
p = dumbfile_getc( f );
|
||||
if ( ! p ) {
|
||||
++ row;
|
||||
++ pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
flags = data[ pos++ ] & 0xE0;
|
||||
flags = p & 0xE0;
|
||||
|
||||
if (flags) {
|
||||
if (flags) {
|
||||
++ pattern->n_entries;
|
||||
if (flags & 0x80) pos += 2;
|
||||
if (flags & 0x40) pos += 2;
|
||||
if (flags & 0x20) pos ++;
|
||||
if (flags & 0x80) dumbfile_skip( f, 2 );
|
||||
if (flags & 0x40) dumbfile_skip( f, 2 );
|
||||
if (flags & 0x20) dumbfile_skip( f, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,20 +193,22 @@ static int it_riff_am_process_pattern( IT_PATTERN * pattern, const unsigned char
|
|||
entry = pattern->entry;
|
||||
|
||||
row = 0;
|
||||
pos = 0;
|
||||
|
||||
while ( ( row < nrows ) && ( pos < len ) )
|
||||
dumbfile_seek( f, start, DFS_SEEK_SET );
|
||||
|
||||
while ( ( row < nrows ) && !dumbfile_error( f ) && ( dumbfile_pos( f ) < end ) )
|
||||
{
|
||||
if ( ! data[ pos ] )
|
||||
p = dumbfile_getc( f );
|
||||
|
||||
if ( ! p )
|
||||
{
|
||||
IT_SET_END_ROW( entry );
|
||||
++ entry;
|
||||
++ row;
|
||||
++ pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
flags = data[ pos++ ];
|
||||
flags = p;
|
||||
entry->channel = flags & 0x1F;
|
||||
entry->mask = 0;
|
||||
|
||||
|
@ -209,31 +216,33 @@ static int it_riff_am_process_pattern( IT_PATTERN * pattern, const unsigned char
|
|||
{
|
||||
if ( flags & 0x80 )
|
||||
{
|
||||
_dumb_it_xm_convert_effect( data[ pos + 1 ], data[ pos ], entry, 0 );
|
||||
pos += 2;
|
||||
q = dumbfile_getc( f );
|
||||
r = dumbfile_getc( f );
|
||||
_dumb_it_xm_convert_effect( r, q, entry, 0 );
|
||||
}
|
||||
|
||||
if ( flags & 0x40 )
|
||||
{
|
||||
if ( data[ pos ] )
|
||||
q = dumbfile_getc( f );
|
||||
r = dumbfile_getc( f );
|
||||
if ( q )
|
||||
{
|
||||
entry->mask |= IT_ENTRY_INSTRUMENT;
|
||||
entry->instrument = data[ pos ];
|
||||
entry->instrument = q;
|
||||
}
|
||||
if ( data[ pos + 1 ] )
|
||||
if ( r )
|
||||
{
|
||||
entry->mask |= IT_ENTRY_NOTE;
|
||||
entry->note = data[ pos + 1 ] - 1;
|
||||
entry->note = r - 1;
|
||||
}
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
if ( flags & 0x20 )
|
||||
{
|
||||
q = dumbfile_getc( f );
|
||||
entry->mask |= IT_ENTRY_VOLPAN;
|
||||
if ( ver == 0 ) entry->volpan = data[ pos ];
|
||||
else entry->volpan = data[ pos ] * 64 / 127;
|
||||
++ pos;
|
||||
if ( ver == 0 ) entry->volpan = q;
|
||||
else entry->volpan = q * 64 / 127;
|
||||
}
|
||||
|
||||
if (entry->mask) entry++;
|
||||
|
@ -253,14 +262,11 @@ static int it_riff_am_process_pattern( IT_PATTERN * pattern, const unsigned char
|
|||
return 0;
|
||||
}
|
||||
|
||||
static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( struct riff * stream )
|
||||
static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( DUMBFILE * f, struct riff * stream )
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
|
||||
int n, found;
|
||||
unsigned int o;
|
||||
|
||||
unsigned char * ptr;
|
||||
int n, o, p, found;
|
||||
|
||||
if ( ! stream ) goto error;
|
||||
|
||||
|
@ -275,7 +281,7 @@ static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( struct riff * stream )
|
|||
|
||||
found = 0;
|
||||
|
||||
for ( n = 0; (unsigned int)n < stream->chunk_count; ++n )
|
||||
for ( n = 0; (unsigned)n < stream->chunk_count; ++n )
|
||||
{
|
||||
struct riff_chunk * c = stream->chunks + n;
|
||||
switch( c->type )
|
||||
|
@ -291,23 +297,28 @@ static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( struct riff * stream )
|
|||
found |= 2;
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'P', 'A', 'T', 'T' ):
|
||||
ptr = ( unsigned char * ) c->data;
|
||||
if ( ptr[ 0 ] >= sigdata->n_patterns ) sigdata->n_patterns = ptr[ 0 ] + 1;
|
||||
o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
|
||||
if ( o + 5 > c->size ) goto error_sd;
|
||||
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;
|
||||
ptr = ( unsigned char * ) c->data;
|
||||
if ( ptr[ 1 ] >= sigdata->n_samples ) sigdata->n_samples = ptr[ 1 ] + 1;
|
||||
if ( c->size >= 0x121 && ( ptr[ 0xE1 ] == 'S' && ptr[ 0xE2 ] == 'A' &&
|
||||
ptr[ 0xE3 ] == 'M' && ptr[ 0xE4 ] == 'P' ) )
|
||||
{
|
||||
unsigned size = ptr[ 0xE5 ] | ( ptr[ 0xE6 ] << 8 ) | ( ptr[ 0xE7 ] << 16 ) | ( ptr[ 0xE8 ] << 24 );
|
||||
if ( size + 0xE1 + 8 > c->size ) goto error;
|
||||
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;
|
||||
|
@ -336,36 +347,41 @@ static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( struct riff * stream )
|
|||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
|
||||
sigdata->channel_pan[n ] = 16;
|
||||
sigdata->channel_pan[n+1] = 48;
|
||||
sigdata->channel_pan[n+2] = 48;
|
||||
sigdata->channel_pan[n+3] = 16;
|
||||
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 int)n < stream->chunk_count; ++n )
|
||||
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' ):
|
||||
ptr = ( unsigned char * ) c->data;
|
||||
memcpy( sigdata->name, c->data, 64 );
|
||||
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;
|
||||
if ( ! ( ptr[ 0x40 ] & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES;
|
||||
if ( ( ptr[ 0x40 ] & ~3 ) || ! ( ptr[ 0x40 ] & 2 ) ) goto error_usd; // unknown flags
|
||||
sigdata->n_pchannels = ptr[ 0x41 ];
|
||||
sigdata->speed = ptr[ 0x42 ];
|
||||
sigdata->tempo = ptr[ 0x43 ];
|
||||
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 );
|
||||
|
||||
sigdata->global_volume = ptr[ 0x48 ];
|
||||
dumbfile_skip( f, 4 );
|
||||
|
||||
if ( (int)c->size < 0x48 + sigdata->n_pchannels ) goto error_usd;
|
||||
sigdata->global_volume = dumbfile_getc( f );
|
||||
|
||||
for ( o = 0; (int)o < sigdata->n_pchannels; ++o )
|
||||
if ( c->size < 0x48 + (unsigned)sigdata->n_pchannels ) goto error_usd;
|
||||
|
||||
for ( o = 0; o < sigdata->n_pchannels; ++o )
|
||||
{
|
||||
sigdata->channel_pan[ o ] = ptr[ 0x49 + o ];
|
||||
if ( ptr[ 0x49 + o ] >= 128 )
|
||||
p = dumbfile_getc( f );
|
||||
sigdata->channel_pan[ o ] = p;
|
||||
if ( p >= 128 )
|
||||
{
|
||||
sigdata->channel_volume[ o ] = 0;
|
||||
}
|
||||
|
@ -389,43 +405,46 @@ static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( struct riff * stream )
|
|||
sample->name[ 0 ] = 0;
|
||||
}
|
||||
|
||||
for ( n = 0; (unsigned int)n < stream->chunk_count; ++n )
|
||||
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' ):
|
||||
ptr = ( unsigned char * ) c->data;
|
||||
sigdata->n_orders = ptr[ 0 ] + 1;
|
||||
if ( sigdata->n_orders + 1 > (int)c->size ) goto error_usd;
|
||||
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;
|
||||
memcpy( sigdata->order, ptr + 1, sigdata->n_orders );
|
||||
dumbfile_getnc( (char *) sigdata->order, sigdata->n_orders, f );
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'P', 'A', 'T', 'T' ):
|
||||
ptr = ( unsigned char * ) c->data;
|
||||
o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
|
||||
if ( it_riff_am_process_pattern( sigdata->pattern + ptr[ 0 ], ptr + 5, o, 0 ) ) goto error_usd;
|
||||
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;
|
||||
ptr = ( unsigned char * ) c->data;
|
||||
sample = sigdata->sample + ptr[ 1 ];
|
||||
if ( c->size >= 0x121 && ( ptr[ 0xE1 ] == 'S' && ptr[ 0xE2 ] == 'A' &&
|
||||
ptr[ 0xE3 ] == 'M' && ptr[ 0xE4 ] == 'P' ) )
|
||||
{
|
||||
unsigned size = ptr[ 0xE5 ] | ( ptr[ 0xE6 ] << 8 ) | ( ptr[ 0xE7 ] << 16 ) | ( ptr[ 0xE8 ] << 24 );
|
||||
if ( it_riff_am_process_sample( sample, ptr + 0xE1 + 8, size, 0 ) ) goto error_usd;
|
||||
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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy( sample->name, ptr + 2, 28 );
|
||||
sample->name[ 28 ] = 0;
|
||||
}
|
||||
}
|
||||
dumbfile_seek( f, c->offset + 2, DFS_SEEK_SET );
|
||||
dumbfile_getnc( (char *) sample->name, 28, f );
|
||||
sample->name[ 28 ] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -443,15 +462,13 @@ error:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
|
||||
static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( DUMBFILE * f, struct riff * stream )
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
|
||||
int n, o, p, found;
|
||||
|
||||
unsigned char * ptr;
|
||||
|
||||
if ( ! stream ) goto error;
|
||||
if ( ! f || ! stream ) goto error;
|
||||
|
||||
if ( stream->type != DUMB_ID( 'A', 'M', ' ', ' ' ) ) goto error;
|
||||
|
||||
|
@ -464,7 +481,7 @@ static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
|
|||
|
||||
found = 0;
|
||||
|
||||
for ( n = 0; (unsigned int)n < stream->chunk_count; ++n )
|
||||
for ( n = 0; (unsigned)n < stream->chunk_count; ++n )
|
||||
{
|
||||
struct riff_chunk * c = stream->chunks + n;
|
||||
switch( c->type )
|
||||
|
@ -481,19 +498,20 @@ static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
|
|||
break;
|
||||
|
||||
case DUMB_ID( 'P', 'A', 'T', 'T' ):
|
||||
ptr = ( unsigned char * ) c->data;
|
||||
if ( ptr[ 0 ] >= sigdata->n_patterns ) sigdata->n_patterns = ptr[ 0 ] + 1;
|
||||
o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
|
||||
if ( o + 5 > (int)c->size ) goto error_sd;
|
||||
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 = ( struct riff * ) c->data;
|
||||
struct riff * str = c->nested;
|
||||
switch ( str->type )
|
||||
{
|
||||
case DUMB_ID( 'A', 'I', ' ', ' ' ):
|
||||
for ( o = 0; (unsigned int)o < str->chunk_count; ++o )
|
||||
for ( o = 0; (unsigned)o < str->chunk_count; ++o )
|
||||
{
|
||||
struct riff_chunk * chk = str->chunks + o;
|
||||
switch( chk->type )
|
||||
|
@ -503,24 +521,26 @@ static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
|
|||
struct riff * temp;
|
||||
unsigned size;
|
||||
unsigned sample_found;
|
||||
ptr = ( unsigned char * ) chk->data;
|
||||
size = ptr[ 0 ] | ( ptr[ 1 ] << 8 ) | ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 );
|
||||
if ( size < 0x142 ) goto error;
|
||||
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;
|
||||
if ( ptr[ 5 ] >= sigdata->n_samples ) sigdata->n_samples = ptr[ 5 ] + 1;
|
||||
temp = riff_parse( ptr + 4 + size, chk->size - size - 4, 1 );
|
||||
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 int)p < temp->chunk_count; ++p )
|
||||
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;
|
||||
goto error_sd;
|
||||
}
|
||||
sample_found = 1;
|
||||
}
|
||||
|
@ -559,37 +579,42 @@ static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
|
|||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
|
||||
sigdata->channel_pan[n ] = 16;
|
||||
sigdata->channel_pan[n+1] = 48;
|
||||
sigdata->channel_pan[n+2] = 48;
|
||||
sigdata->channel_pan[n+3] = 16;
|
||||
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 int)n < stream->chunk_count; ++n )
|
||||
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' ):
|
||||
ptr = ( unsigned char * ) c->data;
|
||||
memcpy( sigdata->name, c->data, 64 );
|
||||
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;
|
||||
if ( ! ( ptr[ 0x40 ] & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES;
|
||||
if ( ( ptr[ 0x40 ] & ~3 ) || ! ( ptr[ 0x40 ] & 2 ) ) goto error_usd; // unknown flags
|
||||
sigdata->n_pchannels = ptr[ 0x41 ];
|
||||
sigdata->speed = ptr[ 0x42 ];
|
||||
sigdata->tempo = ptr[ 0x43 ];
|
||||
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 );
|
||||
|
||||
sigdata->global_volume = ptr[ 0x48 ];
|
||||
dumbfile_skip( f, 4 );
|
||||
|
||||
if ( (int)c->size < 0x48 + sigdata->n_pchannels ) goto error_usd;
|
||||
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 )
|
||||
{
|
||||
if ( ptr[ 0x49 + o ] <= 128 )
|
||||
p = dumbfile_getc( f );
|
||||
if ( p <= 128 )
|
||||
{
|
||||
sigdata->channel_pan[ o ] = ptr[ 0x49 + o ] / 2;
|
||||
sigdata->channel_pan[ o ] = p / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -615,33 +640,34 @@ static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
|
|||
sample->name[ 0 ] = 0;
|
||||
}
|
||||
|
||||
for ( n = 0; (unsigned int)n < stream->chunk_count; ++n )
|
||||
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' ):
|
||||
ptr = ( unsigned char * ) c->data;
|
||||
sigdata->n_orders = ptr[ 0 ] + 1;
|
||||
if ( sigdata->n_orders + 1 > (int)c->size ) goto error_usd;
|
||||
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;
|
||||
memcpy( sigdata->order, ptr + 1, sigdata->n_orders );
|
||||
dumbfile_getnc( (char *) sigdata->order, sigdata->n_orders, f );
|
||||
break;
|
||||
|
||||
case DUMB_ID( 'P', 'A', 'T', 'T' ):
|
||||
ptr = ( unsigned char * ) c->data;
|
||||
o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
|
||||
if ( it_riff_am_process_pattern( sigdata->pattern + ptr[ 0 ], ptr + 5, o, 1 ) ) goto error_usd;
|
||||
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 = ( struct riff * ) c->data;
|
||||
struct riff * str = c->nested;
|
||||
switch ( str->type )
|
||||
{
|
||||
case DUMB_ID('A', 'I', ' ', ' '):
|
||||
for ( o = 0; (unsigned int)o < str->chunk_count; ++o )
|
||||
for ( o = 0; (unsigned)o < str->chunk_count; ++o )
|
||||
{
|
||||
struct riff_chunk * chk = str->chunks + o;
|
||||
switch( chk->type )
|
||||
|
@ -652,16 +678,18 @@ static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
|
|||
unsigned size;
|
||||
unsigned sample_found;
|
||||
IT_SAMPLE * sample;
|
||||
ptr = ( unsigned char * ) chk->data;
|
||||
size = ptr[ 0 ] | ( ptr[ 1 ] << 8 ) | ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 );
|
||||
temp = riff_parse( ptr + 4 + size, chk->size - size - 4, 1 );
|
||||
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 + ptr[ 5 ];
|
||||
sample = sigdata->sample + p;
|
||||
if ( temp )
|
||||
{
|
||||
if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) )
|
||||
{
|
||||
for ( p = 0; (unsigned int)p < temp->chunk_count; ++p )
|
||||
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' ) )
|
||||
|
@ -671,7 +699,11 @@ static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
|
|||
riff_free( temp );
|
||||
goto error_usd;
|
||||
}
|
||||
if ( it_riff_am_process_sample( sigdata->sample + ptr[ 5 ], ( unsigned char * ) c->data, c->size, 1 ) )
|
||||
{
|
||||
riff_free( temp );
|
||||
goto error_usd;
|
||||
}
|
||||
if ( it_riff_am_process_sample( sample, f, c->size, 1 ) )
|
||||
{
|
||||
riff_free( temp );
|
||||
goto error_usd;
|
||||
|
@ -684,7 +716,8 @@ static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
|
|||
}
|
||||
if ( ! sample_found )
|
||||
{
|
||||
memcpy( sample->name, ptr + 6, 32 );
|
||||
dumbfile_seek( f, chk->offset + 6, DFS_SEEK_SET );
|
||||
dumbfile_getnc( (char *) sample->name, 32, f );
|
||||
sample->name[ 32 ] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -709,15 +742,14 @@ error:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
DUH *dumb_read_riff_amff( struct riff * stream )
|
||||
DUH *dumb_read_riff_amff( DUMBFILE * f, struct riff * stream )
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
int32 length;
|
||||
long length;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_riff_amff_load_sigdata( stream );
|
||||
sigdata = it_riff_amff_load_sigdata( f, stream );
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
@ -727,20 +759,20 @@ DUH *dumb_read_riff_amff( struct riff * stream )
|
|||
{
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
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( struct riff * stream )
|
||||
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( stream );
|
||||
sigdata = it_riff_am_load_sigdata( f, stream );
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
@ -748,7 +780,7 @@ DUH *dumb_read_riff_am( struct riff * stream )
|
|||
{
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
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 );
|
||||
|
|
557
dumb/src/it/readamf.c
Normal file
557
dumb/src/it/readamf.c
Normal file
|
@ -0,0 +1,557 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
29
dumb/src/it/readamf2.c
Normal file
29
dumb/src/it/readamf2.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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;
|
||||
}
|
132
dumb/src/it/readany.c
Normal file
132
dumb/src/it/readany.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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;
|
||||
}
|
29
dumb/src/it/readany2.c
Normal file
29
dumb/src/it/readany2.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/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;
|
||||
}
|
|
@ -35,7 +35,7 @@ static int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char
|
|||
|
||||
pattern->n_rows = 64;
|
||||
|
||||
if ( dumbfile_getnc( buffer, 64 * 8 * 4, f ) != 64 * 8 * 4 )
|
||||
if ( dumbfile_getnc( (char *) buffer, 64 * 8 * 4, f ) != 64 * 8 * 4 )
|
||||
return -1;
|
||||
|
||||
/* compute number of entries */
|
||||
|
@ -72,6 +72,13 @@ static int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char
|
|||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
|
@ -101,7 +108,7 @@ 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( sample->name, 22, f );
|
||||
dumbfile_getnc( (char *) sample->name, 22, f );
|
||||
sample->name[22] = 0;
|
||||
|
||||
sample->filename[0] = 0;
|
||||
|
@ -212,7 +219,7 @@ static DUMB_IT_SIGDATA *it_asy_load_sigdata(DUMBFILE *f)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if ( dumbfile_getnc( sigdata->order, sigdata->n_orders, f ) != sigdata->n_orders ||
|
||||
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 );
|
||||
|
@ -296,10 +303,11 @@ static DUMB_IT_SIGDATA *it_asy_load_sigdata(DUMBFILE *f)
|
|||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
|
||||
sigdata->channel_pan[i+0] = 16;
|
||||
sigdata->channel_pan[i+1] = 48;
|
||||
sigdata->channel_pan[i+2] = 48;
|
||||
sigdata->channel_pan[i+3] = 16;
|
||||
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);
|
||||
|
@ -323,7 +331,7 @@ DUH *DUMBEXPORT dumb_read_asy_quick(DUMBFILE *f)
|
|||
{
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
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);
|
||||
|
|
|
@ -24,22 +24,22 @@
|
|||
#include "internal/it.h"
|
||||
#include "internal/riff.h"
|
||||
|
||||
DUH *dumb_read_riff_dsmf( struct riff * stream );
|
||||
|
||||
static int it_riff_dsmf_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len )
|
||||
static int it_riff_dsmf_process_sample( IT_SAMPLE * sample, DUMBFILE * f, int len )
|
||||
{
|
||||
int flags;
|
||||
|
||||
memcpy( sample->filename, data, 13 );
|
||||
sample->filename[ 13 ] = 0;
|
||||
|
||||
flags = data[ 13 ] | ( data[ 14 ] << 8 );
|
||||
sample->default_volume = data[ 15 ];
|
||||
sample->length = data[ 16 ] | ( data[ 17 ] << 8 ) | ( data[ 18 ] << 16 ) | ( data[ 19 ] << 24 );
|
||||
sample->loop_start = data[ 20 ] | ( data[ 21 ] << 8 ) | ( data[ 22 ] << 16 ) | ( data[ 23 ] << 24 );
|
||||
sample->loop_end = data[ 24 ] | ( data[ 25 ] << 8 ) | ( data[ 26 ] << 16 ) | ( data[ 27 ] << 24 );
|
||||
sample->C5_speed = ( data[ 32 ] | ( data[ 33 ] << 8 ) ) * 2;
|
||||
memcpy( sample->name, data + 36, 28 );
|
||||
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 ] )
|
||||
|
@ -82,7 +82,7 @@ static int it_riff_dsmf_process_sample( IT_SAMPLE * sample, const unsigned char
|
|||
if ( ! sample->data )
|
||||
return -1;
|
||||
|
||||
memcpy( sample->data, data + 64, sample->length );
|
||||
dumbfile_getnc( sample->data, sample->length, f );
|
||||
|
||||
if ( ! ( flags & 2 ) )
|
||||
{
|
||||
|
@ -93,39 +93,42 @@ static int it_riff_dsmf_process_sample( IT_SAMPLE * sample, const unsigned char
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int it_riff_dsmf_process_pattern( IT_PATTERN * pattern, const unsigned char * data, int len )
|
||||
static int it_riff_dsmf_process_pattern( IT_PATTERN * pattern, DUMBFILE * f, int len )
|
||||
{
|
||||
int length, row, pos;
|
||||
int length, row;
|
||||
unsigned flags;
|
||||
long start, end;
|
||||
int p, q, r;
|
||||
IT_ENTRY * entry;
|
||||
|
||||
length = data[ 0 ] | ( data[ 1 ] << 8 );
|
||||
length = dumbfile_igetw( f );
|
||||
if ( length > len ) return -1;
|
||||
|
||||
data += 2;
|
||||
len = length - 2;
|
||||
|
||||
pattern->n_rows = 64;
|
||||
pattern->n_entries = 64;
|
||||
|
||||
row = 0;
|
||||
pos = 0;
|
||||
|
||||
while ( (row < 64) && (pos < len) ) {
|
||||
if ( ! data[ pos ] ) {
|
||||
start = dumbfile_pos( f );
|
||||
end = start + len;
|
||||
|
||||
while ( (row < 64) && !dumbfile_error( f ) && (dumbfile_pos( f ) < end) ) {
|
||||
p = dumbfile_getc( f );
|
||||
if ( ! p ) {
|
||||
++ row;
|
||||
++ pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
flags = data[ pos++ ] & 0xF0;
|
||||
flags = p & 0xF0;
|
||||
|
||||
if (flags) {
|
||||
++ pattern->n_entries;
|
||||
if (flags & 0x80) pos ++;
|
||||
if (flags & 0x40) pos ++;
|
||||
if (flags & 0x20) pos ++;
|
||||
if (flags & 0x10) pos += 2;
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,20 +140,21 @@ static int it_riff_dsmf_process_pattern( IT_PATTERN * pattern, const unsigned ch
|
|||
entry = pattern->entry;
|
||||
|
||||
row = 0;
|
||||
pos = 0;
|
||||
|
||||
while ( ( row < 64 ) && ( pos < len ) )
|
||||
if ( dumbfile_seek( f, start, DFS_SEEK_SET ) ) return -1;
|
||||
|
||||
while ( ( row < 64 ) && !dumbfile_error( f ) && ( dumbfile_pos( f ) < end ) )
|
||||
{
|
||||
if ( ! data[ pos ] )
|
||||
p = dumbfile_getc( f );
|
||||
if ( ! p )
|
||||
{
|
||||
IT_SET_END_ROW( entry );
|
||||
++ entry;
|
||||
++ row;
|
||||
++ pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
flags = data[ pos++ ];
|
||||
flags = p;
|
||||
entry->channel = flags & 0x0F;
|
||||
entry->mask = 0;
|
||||
|
||||
|
@ -158,35 +162,35 @@ static int it_riff_dsmf_process_pattern( IT_PATTERN * pattern, const unsigned ch
|
|||
{
|
||||
if ( flags & 0x80 )
|
||||
{
|
||||
if ( data[ pos ] )
|
||||
q = dumbfile_getc( f );
|
||||
if ( q )
|
||||
{
|
||||
entry->mask |= IT_ENTRY_NOTE;
|
||||
entry->note = data[ pos ] - 1;
|
||||
entry->note = q - 1;
|
||||
}
|
||||
++ pos;
|
||||
}
|
||||
|
||||
if ( flags & 0x40 )
|
||||
{
|
||||
if ( data[ pos ] )
|
||||
q = dumbfile_getc( f );
|
||||
if ( q )
|
||||
{
|
||||
entry->mask |= IT_ENTRY_INSTRUMENT;
|
||||
entry->instrument = data[ pos ];
|
||||
entry->instrument = q;
|
||||
}
|
||||
++ pos;
|
||||
}
|
||||
|
||||
if ( flags & 0x20 )
|
||||
{
|
||||
entry->mask |= IT_ENTRY_VOLPAN;
|
||||
entry->volpan = data[ pos ];
|
||||
++ pos;
|
||||
entry->volpan = dumbfile_getc( f );
|
||||
}
|
||||
|
||||
if ( flags & 0x10 )
|
||||
{
|
||||
_dumb_it_xm_convert_effect( data[ pos ], data[ pos + 1 ], entry, 0 );
|
||||
pos += 2;
|
||||
q = dumbfile_getc( f );
|
||||
r = dumbfile_getc( f );
|
||||
_dumb_it_xm_convert_effect( q, r, entry, 0 );
|
||||
}
|
||||
|
||||
if (entry->mask) entry++;
|
||||
|
@ -206,14 +210,12 @@ static int it_riff_dsmf_process_pattern( IT_PATTERN * pattern, const unsigned ch
|
|||
return 0;
|
||||
}
|
||||
|
||||
static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( struct riff * stream )
|
||||
static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( DUMBFILE * f, struct riff * stream )
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
|
||||
int n, o, found;
|
||||
|
||||
unsigned char * ptr;
|
||||
|
||||
if ( ! stream ) goto error;
|
||||
|
||||
if ( stream->type != DUMB_ID( 'D', 'S', 'M', 'F' ) ) goto error;
|
||||
|
@ -227,7 +229,7 @@ static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( struct riff * stream )
|
|||
|
||||
found = 0;
|
||||
|
||||
for ( n = 0; (unsigned int)n < stream->chunk_count; ++n )
|
||||
for ( n = 0; (unsigned)n < stream->chunk_count; ++n )
|
||||
{
|
||||
struct riff_chunk * c = stream->chunks + n;
|
||||
switch( c->type )
|
||||
|
@ -270,39 +272,42 @@ static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( struct riff * stream )
|
|||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
|
||||
sigdata->channel_pan[n ] = 16;
|
||||
sigdata->channel_pan[n+1] = 48;
|
||||
sigdata->channel_pan[n+2] = 48;
|
||||
sigdata->channel_pan[n+3] = 16;
|
||||
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 int)n < stream->chunk_count; ++n )
|
||||
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' ):
|
||||
ptr = ( unsigned char * ) c->data;
|
||||
memcpy( sigdata->name, c->data, 28 );
|
||||
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_WAS_AN_XM | IT_WAS_A_MOD | IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
|
||||
sigdata->n_orders = ptr[ 36 ] | ( ptr[ 37 ] << 8 );
|
||||
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 );
|
||||
sigdata->n_pchannels = ptr[ 42 ] | ( ptr[ 43 ] << 8 );
|
||||
sigdata->global_volume = ptr[ 44 ];
|
||||
sigdata->mixing_volume = ptr[ 45 ];
|
||||
sigdata->speed = ptr[ 46 ];
|
||||
sigdata->tempo = ptr[ 47 ];
|
||||
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 ] = ptr[ 48 + o ] / 2;
|
||||
sigdata->channel_pan[ o ] = dumbfile_getc( f ) / 2;
|
||||
}
|
||||
|
||||
sigdata->order = malloc( 128 );
|
||||
if ( ! sigdata->order ) goto error_usd;
|
||||
memcpy( sigdata->order, ptr + 64, 128 );
|
||||
dumbfile_getnc( (char *) sigdata->order, 128, f );
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -324,18 +329,20 @@ static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( struct riff * stream )
|
|||
sigdata->n_samples = 0;
|
||||
sigdata->n_patterns = 0;
|
||||
|
||||
for ( n = 0; (unsigned int)n < stream->chunk_count; ++n )
|
||||
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 ( it_riff_dsmf_process_pattern( sigdata->pattern + sigdata->n_patterns, ( unsigned char * ) c->data, c->size ) ) goto error_usd;
|
||||
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 ( it_riff_dsmf_process_sample( sigdata->sample + sigdata->n_samples, ( unsigned char * ) c->data, c->size ) ) goto error_usd;
|
||||
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;
|
||||
}
|
||||
|
@ -354,13 +361,13 @@ error:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
DUH *dumb_read_riff_dsmf( struct riff * stream )
|
||||
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( stream );
|
||||
sigdata = it_riff_dsmf_load_sigdata( f, stream );
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
@ -368,7 +375,7 @@ DUH *dumb_read_riff_dsmf( struct riff * stream )
|
|||
{
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
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 );
|
||||
|
|
|
@ -38,14 +38,14 @@ static int it_mod_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels,
|
|||
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(buffer + pos, 4*4, f);
|
||||
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(buffer + pos, 4*4, f);
|
||||
dumbfile_getnc((char *)buffer + pos, 4*4, f);
|
||||
|
||||
n_channels = 8;
|
||||
} else
|
||||
dumbfile_getnc(buffer, 64 * n_channels * 4, f);
|
||||
dumbfile_getnc((char *)buffer, 64 * n_channels * 4, f);
|
||||
|
||||
if (dumbfile_error(f))
|
||||
return -1;
|
||||
|
@ -118,7 +118,7 @@ static int it_mod_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels,
|
|||
|
||||
|
||||
|
||||
static int it_mod_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
|
||||
static int it_mod_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f, int stk)
|
||||
{
|
||||
int finetune, loop_start, loop_length;
|
||||
|
||||
|
@ -131,7 +131,7 @@ 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(sample->name, 22, f);
|
||||
dumbfile_getnc((char *)sample->name, 22, f);
|
||||
sample->name[22] = 0;
|
||||
|
||||
sample->filename[0] = 0;
|
||||
|
@ -141,7 +141,8 @@ assumed not to be an instrument name, and is probably a message.
|
|||
/** 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) << 1;
|
||||
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;
|
||||
|
@ -164,7 +165,7 @@ told to stop.
|
|||
sample->flags = IT_SAMPLE_EXISTS;
|
||||
|
||||
sample->default_pan = 0;
|
||||
sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 ); //(int32)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
|
||||
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
|
||||
|
||||
|
@ -270,209 +271,28 @@ static int it_mod_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f, uint32 fft)
|
|||
|
||||
|
||||
|
||||
typedef struct BUFFERED_MOD BUFFERED_MOD;
|
||||
|
||||
struct BUFFERED_MOD
|
||||
{
|
||||
unsigned char *buffered;
|
||||
int32 ptr, len;
|
||||
DUMBFILE *remaining;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int buffer_mod_skip(void *f, int32 n)
|
||||
{
|
||||
BUFFERED_MOD *bm = f;
|
||||
if (bm->buffered) {
|
||||
bm->ptr += n;
|
||||
if (bm->ptr >= bm->len) {
|
||||
free(bm->buffered);
|
||||
bm->buffered = NULL;
|
||||
return dumbfile_skip(bm->remaining, bm->ptr - bm->len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return dumbfile_skip(bm->remaining, n);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int buffer_mod_getc(void *f)
|
||||
{
|
||||
BUFFERED_MOD *bm = f;
|
||||
if (bm->buffered) {
|
||||
int rv = bm->buffered[bm->ptr++];
|
||||
if (bm->ptr >= bm->len) {
|
||||
free(bm->buffered);
|
||||
bm->buffered = NULL;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
return dumbfile_getc(bm->remaining);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int32 buffer_mod_getnc(char *ptr, int32 n, void *f)
|
||||
{
|
||||
BUFFERED_MOD *bm = f;
|
||||
if (bm->buffered) {
|
||||
int left = bm->len - bm->ptr;
|
||||
if (n >= left) {
|
||||
memcpy(ptr, bm->buffered + bm->ptr, left);
|
||||
free(bm->buffered);
|
||||
bm->buffered = NULL;
|
||||
if (n - left) {
|
||||
int rv = dumbfile_getnc(ptr + left, n - left, bm->remaining);
|
||||
return left + MAX(rv, 0);
|
||||
} else {
|
||||
return left;
|
||||
}
|
||||
}
|
||||
memcpy(ptr, bm->buffered + bm->ptr, n);
|
||||
bm->ptr += n;
|
||||
return n;
|
||||
}
|
||||
return dumbfile_getnc(ptr, n, bm->remaining);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void buffer_mod_close(void *f)
|
||||
{
|
||||
BUFFERED_MOD *bm = f;
|
||||
if (bm->buffered) free(bm->buffered);
|
||||
/* Do NOT close bm->remaining */
|
||||
free(f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUMBFILE_SYSTEM buffer_mod_dfs = {
|
||||
NULL,
|
||||
&buffer_mod_skip,
|
||||
&buffer_mod_getc,
|
||||
&buffer_mod_getnc,
|
||||
&buffer_mod_close
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define MOD_FFT_OFFSET (20 + 31*(22+2+1+1+2+2) + 1 + 1 + 128)
|
||||
|
||||
static DUMBFILE *dumbfile_buffer_mod(DUMBFILE *f, uint32 *fft)
|
||||
{
|
||||
BUFFERED_MOD *bm = malloc(sizeof(*bm));
|
||||
if (!bm) return NULL;
|
||||
|
||||
bm->buffered = malloc(MOD_FFT_OFFSET + 4);
|
||||
if (!bm->buffered) {
|
||||
free(bm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bm->len = dumbfile_getnc(bm->buffered, MOD_FFT_OFFSET + 4, f);
|
||||
|
||||
if (bm->len > 0) {
|
||||
if (bm->len >= MOD_FFT_OFFSET + 4)
|
||||
*fft = (uint32)bm->buffered[MOD_FFT_OFFSET ] << 24
|
||||
| (uint32)bm->buffered[MOD_FFT_OFFSET+1] << 16
|
||||
| (uint32)bm->buffered[MOD_FFT_OFFSET+2] << 8
|
||||
| (uint32)bm->buffered[MOD_FFT_OFFSET+3];
|
||||
else
|
||||
*fft = 0;
|
||||
bm->ptr = 0;
|
||||
} else {
|
||||
free(bm->buffered);
|
||||
bm->buffered = NULL;
|
||||
}
|
||||
|
||||
bm->remaining = f;
|
||||
|
||||
return dumbfile_open_ex(bm, &buffer_mod_dfs);
|
||||
}
|
||||
|
||||
static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, int n_samples, IT_SAMPLE *sample, int32 *total_sample_size, int32 *remain)
|
||||
{
|
||||
int32 read;
|
||||
int sample_number;
|
||||
BUFFERED_MOD *bm = malloc(sizeof(*bm));
|
||||
unsigned char *ptr;
|
||||
if (!bm) return NULL;
|
||||
|
||||
bm->buffered = malloc(32768);
|
||||
if (!bm->buffered) {
|
||||
free(bm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bm->len = 0;
|
||||
*remain = 0;
|
||||
|
||||
read = dumbfile_getnc(bm->buffered, 32768, f);
|
||||
|
||||
if (read >= 0) {
|
||||
bm->len += read;
|
||||
*remain += read;
|
||||
|
||||
while (read >= 32768) {
|
||||
bm->buffered = realloc(bm->buffered, *remain + 32768);
|
||||
if (!bm->buffered) {
|
||||
free(bm);
|
||||
return 0;
|
||||
}
|
||||
read = dumbfile_getnc(bm->buffered + *remain, 32768, f);
|
||||
if (read >= 0) {
|
||||
bm->len += read;
|
||||
*remain += read;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*remain) {
|
||||
bm->ptr = 0;
|
||||
ptr = bm->buffered + *remain;
|
||||
sample_number = n_samples - 1;
|
||||
*total_sample_size = 0;
|
||||
while (ptr > bm->buffered && sample_number >= 0) {
|
||||
if (sample[sample_number].flags & IT_SAMPLE_EXISTS) {
|
||||
ptr -= (sample[sample_number].length + 1) / 2 + 5 + 16;
|
||||
if (ptr >= bm->buffered && !memcmp(ptr, "ADPCM", 5)) { /* BAH */
|
||||
*total_sample_size += (sample[sample_number].length + 1) / 2 + 5 + 16;
|
||||
} else {
|
||||
*total_sample_size += sample[sample_number].length;
|
||||
ptr -= sample[sample_number].length - ((sample[sample_number].length + 1) / 2 + 5 + 16);
|
||||
}
|
||||
}
|
||||
sample_number--;
|
||||
}
|
||||
} else {
|
||||
free(bm->buffered);
|
||||
bm->buffered = NULL;
|
||||
}
|
||||
|
||||
bm->remaining = f;
|
||||
|
||||
return dumbfile_open_ex(bm, &buffer_mod_dfs);
|
||||
}
|
||||
|
||||
|
||||
static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
||||
static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict_)
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
int n_channels;
|
||||
int i;
|
||||
uint32 fft = 0;
|
||||
DUMBFILE *rem = NULL;
|
||||
uint32 fft;
|
||||
|
||||
f = dumbfile_buffer_mod(f, &fft);
|
||||
if (!f)
|
||||
return NULL;
|
||||
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) {
|
||||
dumbfile_close(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -481,10 +301,9 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
full 20 chars in length, it will be null-
|
||||
terminated.
|
||||
*/
|
||||
if (dumbfile_getnc(sigdata->name, 20, f) < 20) {
|
||||
if (dumbfile_getnc((char *)sigdata->name, 20, f) < 20) {
|
||||
free(sigdata);
|
||||
dumbfile_close(f);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
sigdata->name[20] = 0;
|
||||
|
||||
|
@ -567,11 +386,10 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
}
|
||||
|
||||
// moo
|
||||
if ( ( rstrict & 1 ) && sigdata->n_samples == 15 )
|
||||
if ( ( restrict_ & 1 ) && sigdata->n_samples == 15 )
|
||||
{
|
||||
free(sigdata);
|
||||
dumbfile_close(f);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->n_pchannels = n_channels ? n_channels : 8; /* special case for 0, see above */
|
||||
|
@ -579,8 +397,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
|
||||
if (!sigdata->sample) {
|
||||
free(sigdata);
|
||||
dumbfile_close(f);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->song_message = NULL;
|
||||
|
@ -596,10 +413,9 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
sigdata->sample[i].data = NULL;
|
||||
|
||||
for (i = 0; i < sigdata->n_samples; i++) {
|
||||
if (it_mod_read_sample_header(&sigdata->sample[i], f)) {
|
||||
if (it_mod_read_sample_header(&sigdata->sample[i], f, sigdata->n_samples == 15)) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -609,8 +425,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
|
||||
/* if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}*/
|
||||
|
||||
//if (sigdata->restart_position >= sigdata->n_orders)
|
||||
|
@ -619,13 +434,11 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
sigdata->order = malloc(128); /* We may need to scan the extra ones! */
|
||||
if (!sigdata->order) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
if (dumbfile_getnc(sigdata->order, 128, f) < 128) {
|
||||
if (dumbfile_getnc((char *)sigdata->order, 128, f) < 128) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
|
||||
|
@ -648,44 +461,67 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
|
||||
sigdata->n_patterns = -1;
|
||||
|
||||
if ( ( rstrict & 2 ) )
|
||||
if ( ( restrict_ & 2 ) )
|
||||
{
|
||||
int32 total_sample_size;
|
||||
int32 remain;
|
||||
rem = f;
|
||||
f = dumbfile_buffer_mod_2(rem, sigdata->n_samples, sigdata->sample, &total_sample_size, &remain);
|
||||
if (!f) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
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);
|
||||
dumbfile_close(f);
|
||||
dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
if (sigdata->order[i] > sigdata->n_patterns)
|
||||
sigdata->n_patterns = sigdata->order[i];
|
||||
}
|
||||
{
|
||||
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);
|
||||
dumbfile_close(f);
|
||||
if (rem) dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -698,8 +534,6 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
|
||||
if (!sigdata->pattern) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
if (rem) dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < sigdata->n_patterns; i++)
|
||||
|
@ -710,16 +544,12 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
unsigned char *buffer = malloc(256 * sigdata->n_pchannels); /* 64 rows * 4 bytes */
|
||||
if (!buffer) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
if (rem) dumbfile_close(rem);
|
||||
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);
|
||||
dumbfile_close(f);
|
||||
if (rem) dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -730,8 +560,6 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
for (i = 0; i < sigdata->n_samples; i++) {
|
||||
if (it_mod_read_sample_data(&sigdata->sample[i], f, fft)) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
if (rem) dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -754,10 +582,6 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
}
|
||||
}*/
|
||||
|
||||
dumbfile_close(f); /* Destroy the BUFFERED_MOD DUMBFILE we were using. */
|
||||
if (rem) dumbfile_close(rem); /* And the BUFFERED_MOD DUMBFILE used to pre-read the signature. */
|
||||
/* The DUMBFILE originally passed to our function is intact. */
|
||||
|
||||
/* 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;
|
||||
|
||||
|
@ -773,10 +597,11 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
|
||||
sigdata->channel_pan[i+0] = 16;
|
||||
sigdata->channel_pan[i+1] = 48;
|
||||
sigdata->channel_pan[i+2] = 48;
|
||||
sigdata->channel_pan[i+3] = 16;
|
||||
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);
|
||||
|
@ -786,13 +611,13 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
|||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_mod_quick(DUMBFILE *f, int rstrict)
|
||||
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, rstrict);
|
||||
sigdata = it_mod_load_sigdata(f, restrict_);
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
@ -800,7 +625,7 @@ DUH *DUMBEXPORT dumb_read_mod_quick(DUMBFILE *f, int rstrict)
|
|||
{
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
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);
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_mod(DUMBFILE *f, int rstrict)
|
||||
DUH *DUMBEXPORT dumb_read_mod(DUMBFILE *f, int restrict_)
|
||||
{
|
||||
DUH *duh = dumb_read_mod_quick(f, rstrict);
|
||||
DUH *duh = dumb_read_mod_quick(f, restrict_);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ static int it_mtm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
|
|||
{
|
||||
int finetune, flags;
|
||||
|
||||
dumbfile_getnc(sample->name, 22, f);
|
||||
dumbfile_getnc((char *)sample->name, 22, f);
|
||||
sample->name[22] = 0;
|
||||
|
||||
sample->filename[0] = 0;
|
||||
|
@ -125,7 +125,7 @@ static int it_mtm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
|
|||
}
|
||||
|
||||
sample->default_pan = 0;
|
||||
sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//(int32)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
|
||||
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
|
||||
|
||||
|
@ -195,7 +195,7 @@ static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int * version)
|
|||
sigdata = malloc(sizeof(*sigdata));
|
||||
if (!sigdata) goto error;
|
||||
|
||||
dumbfile_getnc(sigdata->name, 20, f);
|
||||
dumbfile_getnc((char *)sigdata->name, 20, f);
|
||||
sigdata->name[20] = 0;
|
||||
|
||||
n_tracks = dumbfile_igetw(f);
|
||||
|
@ -216,7 +216,7 @@ static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int * version)
|
|||
|
||||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
if (dumbfile_getnc(sigdata->channel_pan, 32, f) < 32) goto error_sd;
|
||||
if (dumbfile_getnc((char *)sigdata->channel_pan, 32, f) < 32) goto error_sd;
|
||||
|
||||
for (n = 0; n < 32; n++) {
|
||||
if (sigdata->channel_pan[n] <= 15) {
|
||||
|
@ -229,10 +229,11 @@ static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int * version)
|
|||
}
|
||||
|
||||
for (n = 32; n < DUMB_IT_N_CHANNELS; n += 4) {
|
||||
sigdata->channel_pan[n ] = 16;
|
||||
sigdata->channel_pan[n+1] = 48;
|
||||
sigdata->channel_pan[n+2] = 48;
|
||||
sigdata->channel_pan[n+3] = 16;
|
||||
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));
|
||||
|
@ -268,14 +269,14 @@ static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int * version)
|
|||
sigdata->order = malloc(sigdata->n_orders);
|
||||
if (!sigdata->order) goto error_usd;
|
||||
|
||||
if (dumbfile_getnc(sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) 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(track, 192 * n_tracks, f) < 192 * n_tracks) goto error_ft;
|
||||
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;
|
||||
|
@ -319,7 +320,6 @@ static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int * version)
|
|||
|
||||
size_t l;
|
||||
int m;
|
||||
|
||||
for (l = 0, n = 0; n <= o; n += 40) {
|
||||
l += strlen_max(&comment[n], 40) + 2;
|
||||
}
|
||||
|
@ -396,7 +396,7 @@ DUH *DUMBEXPORT dumb_read_mtm_quick(DUMBFILE *f)
|
|||
char version[16];
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
|
||||
tag[1][0] = "FORMAT";
|
||||
version[0] = 'M';
|
||||
version[1] = 'T';
|
||||
|
|
|
@ -322,8 +322,8 @@ unsigned get_chunk_count(IFF_CHUNKED *mod, unsigned type)
|
|||
static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f)
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
unsigned n_channels;
|
||||
unsigned i, j, k, l;
|
||||
int n_channels;
|
||||
int i, j, k, l;
|
||||
IFF_CHUNKED *mod;
|
||||
const IFF_CHUNK *chunk;
|
||||
|
||||
|
@ -403,12 +403,12 @@ static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f)
|
|||
|
||||
sigdata->n_instruments = 0;
|
||||
|
||||
for (i = 0; i < (unsigned)sigdata->n_samples; i++)
|
||||
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; i < (unsigned)sigdata->n_samples; i++) {
|
||||
for (i = 0; (unsigned)i < (unsigned)sigdata->n_samples; i++) {
|
||||
it_okt_read_sample_header(&sigdata->sample[i], chunk->data + 32 * i);
|
||||
}
|
||||
|
||||
|
@ -431,7 +431,7 @@ static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f)
|
|||
}
|
||||
|
||||
chunk = get_chunk_by_type(mod, DUMB_ID('P','A','T','T'), 0);
|
||||
if (!chunk || chunk->size < (unsigned)sigdata->n_orders) {
|
||||
if (!chunk || chunk->size < (unsigned)sigdata->n_orders) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
|
@ -471,11 +471,11 @@ static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f)
|
|||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < (unsigned)sigdata->n_patterns; i++)
|
||||
for (i = 0; (unsigned)i < (unsigned)sigdata->n_patterns; i++)
|
||||
sigdata->pattern[i].entry = NULL;
|
||||
|
||||
/* Read in the patterns */
|
||||
for (i = 0; i < (unsigned)sigdata->n_patterns; i++) {
|
||||
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);
|
||||
|
@ -486,7 +486,7 @@ static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f)
|
|||
|
||||
/* And finally, the sample data */
|
||||
k = get_chunk_count(mod, DUMB_ID('S','B','O','D'));
|
||||
for (i = 0, j = 0; i < (unsigned)sigdata->n_samples && j < k; i++) {
|
||||
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)) {
|
||||
|
@ -497,7 +497,7 @@ static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f)
|
|||
j++;
|
||||
}
|
||||
}
|
||||
for (; i < (unsigned)sigdata->n_samples; i++) {
|
||||
for (; (unsigned)i < (unsigned)sigdata->n_samples; i++) {
|
||||
sigdata->sample[i].flags = 0;
|
||||
}
|
||||
|
||||
|
@ -544,7 +544,7 @@ DUH *DUMBEXPORT dumb_read_okt_quick(DUMBFILE *f)
|
|||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_okt_load_sigdata(f);
|
||||
sigdata = it_okt_load_sigdata(f);
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
|
|
@ -33,19 +33,18 @@ static int CDECL psm_sample_compare(const void *e1, const void *e2)
|
|||
return a - b;
|
||||
}
|
||||
|
||||
static int it_old_psm_read_samples(IT_SAMPLE ** sample, DUMBFILE * f, int * num, const unsigned char * prebuffer, int32 data_pos, int32 data_size)
|
||||
static int it_old_psm_read_samples(IT_SAMPLE ** sample, DUMBFILE * f, int * num)
|
||||
{
|
||||
int n, o, pos, count = *num, true_num, snum, offset, flags, finetune, delta;
|
||||
int n, o, count = *num, true_num, snum, offset, flags, finetune, delta;
|
||||
|
||||
unsigned char * buffer, * sbuffer = 0;
|
||||
unsigned char * buffer;
|
||||
const unsigned char * sdata;
|
||||
int32 sample_bytes;
|
||||
|
||||
buffer = malloc(count * 64);
|
||||
if (!buffer) goto error;
|
||||
|
||||
if (dumbfile_getnc(buffer, count * 64, f) < count * 64) goto error_fb;
|
||||
|
||||
pos = dumbfile_pos(f);
|
||||
if (dumbfile_getnc((char *)buffer, count * 64, f) < count * 64) goto error_fb;
|
||||
|
||||
true_num = 0;
|
||||
|
||||
|
@ -94,9 +93,10 @@ static int it_old_psm_read_samples(IT_SAMPLE ** sample, DUMBFILE * f, int * num,
|
|||
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 < 16) {
|
||||
if (finetune & 15) {
|
||||
finetune &= 15;
|
||||
if (finetune >= 8) finetune -= 16;
|
||||
//s->C5_speed = (int32)((double)s->C5_speed * pow(DUMB_PITCH_BASE, finetune*32));
|
||||
//s->C5_speed = (long)((double)s->C5_speed * pow(DUMB_PITCH_BASE, finetune*32));
|
||||
s->finetune = finetune * 32;
|
||||
}
|
||||
else s->finetune = 0;
|
||||
|
@ -127,22 +127,12 @@ static int it_old_psm_read_samples(IT_SAMPLE ** sample, DUMBFILE * f, int * num,
|
|||
s->vibrato_waveform = IT_VIBRATO_SINE;
|
||||
s->max_resampling_quality = -1;
|
||||
|
||||
s->data = malloc(s->length * ((flags & 4) ? 2 : 1));
|
||||
sample_bytes = s->length * ((flags & 4) ? 2 : 1);
|
||||
s->data = malloc(sample_bytes);
|
||||
if (!s->data) goto error_fb;
|
||||
|
||||
if ((offset >= data_pos) &&
|
||||
((offset + s->length * ((flags & 4) ? 2 : 1)) <= (data_pos + data_size))) {
|
||||
sdata = prebuffer + offset - data_pos;
|
||||
} else if (offset >= pos) {
|
||||
if (dumbfile_skip(f, offset - pos)) goto error_fb;
|
||||
pos = offset;
|
||||
offset = s->length * ((flags & 4) ? 2 : 1);
|
||||
sbuffer = malloc(offset);
|
||||
if (!sbuffer) goto error_fb;
|
||||
if (dumbfile_getnc(sbuffer, offset, f) < offset) goto error_fsb;
|
||||
sdata = sbuffer;
|
||||
} else
|
||||
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) {
|
||||
|
@ -190,26 +180,19 @@ static int it_old_psm_read_samples(IT_SAMPLE ** sample, DUMBFILE * f, int * num,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sbuffer) {
|
||||
free(sbuffer);
|
||||
sbuffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
return 0;
|
||||
|
||||
error_fsb:
|
||||
if (sbuffer) free(sbuffer);
|
||||
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 sflags)
|
||||
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;
|
||||
|
||||
|
@ -217,12 +200,10 @@ static int it_old_psm_read_patterns(IT_PATTERN * pattern, DUMBFILE * f, int num,
|
|||
|
||||
IT_ENTRY * entry;
|
||||
|
||||
(void)sflags; /* Avoid unused parameter warning from GCC */
|
||||
|
||||
buffer = malloc(size);
|
||||
if (!buffer) goto error;
|
||||
|
||||
if (dumbfile_getnc(buffer, size, f) < size) goto error_fb;
|
||||
if (dumbfile_getnc((char *)buffer, size, f) < size) goto error_fb;
|
||||
|
||||
offset = 0;
|
||||
|
||||
|
@ -520,8 +501,6 @@ static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f)
|
|||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
|
||||
unsigned char * ptr = 0;
|
||||
|
||||
PSM_COMPONENT *component;
|
||||
int n_components = 0;
|
||||
|
||||
|
@ -532,7 +511,7 @@ static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f)
|
|||
sigdata = malloc(sizeof(*sigdata));
|
||||
if (!sigdata) goto error;
|
||||
|
||||
if (dumbfile_getnc(sigdata->name, 60, f) < 60 ||
|
||||
if (dumbfile_getnc((char *)sigdata->name, 60, f) < 60 ||
|
||||
sigdata->name[59] != 0x1A) goto error_sd;
|
||||
sigdata->name[59] = 0;
|
||||
|
||||
|
@ -619,43 +598,31 @@ static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f)
|
|||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
|
||||
sigdata->channel_pan[n ] = 16;
|
||||
sigdata->channel_pan[n+1] = 48;
|
||||
sigdata->channel_pan[n+2] = 48;
|
||||
sigdata->channel_pan[n+3] = 16;
|
||||
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;
|
||||
int32 data_pos, data_size;
|
||||
|
||||
/* Whee, sample data may be before the sample headers */
|
||||
|
||||
data_pos = dumbfile_pos(f);
|
||||
if (data_pos > component[n].offset) goto error_fc;
|
||||
|
||||
data_size = component[n].offset - data_pos;
|
||||
|
||||
if (data_size) {
|
||||
ptr = malloc(data_size);
|
||||
if (!ptr) goto error_fc;
|
||||
|
||||
if (dumbfile_getnc(ptr, data_size, f) < data_size) goto error_fp;
|
||||
}
|
||||
if ( dumbfile_seek(f, component[n].offset, DFS_SEEK_SET) ) goto error_fc;
|
||||
|
||||
switch (component[n].type) {
|
||||
|
||||
case PSM_COMPONENT_ORDERS:
|
||||
if (dumbfile_getnc(sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_fp;
|
||||
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_fp;
|
||||
if (dumbfile_igetw(f)) goto error_fp;
|
||||
goto error_fc;
|
||||
if (dumbfile_igetw(f)) goto error_fc;
|
||||
break;
|
||||
|
||||
case PSM_COMPONENT_PANPOS:
|
||||
if (dumbfile_getnc(sigdata->channel_pan, sigdata->n_pchannels, f) < sigdata->n_pchannels) goto error_fp;
|
||||
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;
|
||||
|
@ -663,11 +630,11 @@ static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f)
|
|||
break;
|
||||
|
||||
case PSM_COMPONENT_PATTERNS:
|
||||
if (it_old_psm_read_patterns(sigdata->pattern, f, sigdata->n_patterns, total_pattern_size, sigdata->n_pchannels, flags)) goto error_fp;
|
||||
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, ptr, data_pos, data_size)) goto error_fp;
|
||||
if (it_old_psm_read_samples(&sigdata->sample, f, &sigdata->n_samples)) goto error_fc;
|
||||
break;
|
||||
|
||||
case PSM_COMPONENT_COMMENTS:
|
||||
|
@ -675,17 +642,12 @@ static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f)
|
|||
o = dumbfile_igetw(f);
|
||||
if (o > 0) {
|
||||
sigdata->song_message = malloc(o + 1);
|
||||
if (dumbfile_getnc(sigdata->song_message, o, f) < o) goto error_fp;
|
||||
if (dumbfile_getnc((char *)sigdata->song_message, o, f) < o) goto error_fc;
|
||||
sigdata->song_message[o] = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
free(ptr);
|
||||
ptr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_dumb_it_fix_invalid_orders(sigdata);
|
||||
|
@ -694,8 +656,6 @@ static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f)
|
|||
|
||||
return sigdata;
|
||||
|
||||
error_fp:
|
||||
if (ptr) free(ptr);
|
||||
error_fc:
|
||||
free(component);
|
||||
error_usd:
|
||||
|
@ -721,7 +681,7 @@ DUH *DUMBEXPORT dumb_read_old_psm_quick(DUMBFILE *f)
|
|||
{
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
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);
|
||||
|
|
|
@ -24,7 +24,11 @@
|
|||
#include "internal/it.h"
|
||||
|
||||
#ifndef min
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf sprintf_s
|
||||
#endif
|
||||
|
||||
#define PSMV_OLD 940730
|
||||
|
@ -77,7 +81,7 @@ static int it_psm_process_sample(IT_SAMPLE * sample, const unsigned char * data,
|
|||
panpos = data[0x43];
|
||||
defvol = data[0x44];
|
||||
samplerate = data[0x49] | (data[0x4A] << 8) | (data[0x4B] << 16) | (data[0x4C] << 24);
|
||||
} else if (version == PSMV_NEW) {
|
||||
} else /*if (version == PSMV_NEW)*/ {
|
||||
memcpy(sample->name, data + 0x11, 34);
|
||||
sample->name[34] = 0;
|
||||
|
||||
|
@ -150,7 +154,7 @@ static int it_psm_process_pattern(IT_PATTERN * pattern, const unsigned char * da
|
|||
if (len < 10) return -1;
|
||||
data += 8;
|
||||
len -= 8;
|
||||
} else if (version == PSMV_NEW) {
|
||||
} else /*if (version == PSMV_NEW)*/ {
|
||||
if (len < 14) return -1;
|
||||
data += 12;
|
||||
len -= 12;
|
||||
|
@ -287,7 +291,7 @@ static int it_psm_process_pattern(IT_PATTERN * pattern, const unsigned char * da
|
|||
if (version == PSMV_OLD) {
|
||||
if ((data[pos] < 0x80)) entry->note = (data[pos]>>4)*12+(data[pos]&0x0f)+12;
|
||||
else entry->mask &= ~IT_ENTRY_NOTE;
|
||||
} else if (version == PSMV_NEW) {
|
||||
} else /*if (version == PSMV_NEW)*/ {
|
||||
if ((data[pos]) && (data[pos] < 84)) entry->note = data[pos] + 35;
|
||||
else entry->mask &= ~IT_ENTRY_NOTE;
|
||||
}
|
||||
|
@ -311,25 +315,25 @@ static int it_psm_process_pattern(IT_PATTERN * pattern, const unsigned char * da
|
|||
case 1:
|
||||
entry->effect = IT_VOLUME_SLIDE;
|
||||
if (version == PSMV_OLD) entry->effectvalue = ((length&0x1e)<<3) | 0xF;
|
||||
else if (version == PSMV_NEW) entry->effectvalue = (length<<4) | 0xF;
|
||||
else /*if (version == PSMV_NEW)*/ entry->effectvalue = (length<<4) | 0xF;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
entry->effect = IT_VOLUME_SLIDE;
|
||||
if (version == PSMV_OLD) entry->effectvalue = (length << 3) & 0xF0;
|
||||
else if (version == PSMV_NEW) entry->effectvalue = (length << 4) & 0xF0;
|
||||
else /*if (version == PSMV_NEW)*/ entry->effectvalue = (length << 4) & 0xF0;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
entry->effect = IT_VOLUME_SLIDE;
|
||||
if (version == PSMV_OLD) entry->effectvalue = (length >> 1) | 0xF0;
|
||||
else if (version == PSMV_NEW) entry->effectvalue = length | 0xF0;
|
||||
else /*if (version == PSMV_NEW)*/ entry->effectvalue = length | 0xF0;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
entry->effect = IT_VOLUME_SLIDE;
|
||||
if (version == PSMV_OLD) entry->effectvalue = (length >> 1) & 0xF;
|
||||
else if (version == PSMV_NEW) entry->effectvalue = length & 0xF;
|
||||
else /*if (version == PSMV_NEW)*/ entry->effectvalue = length & 0xF;
|
||||
break;
|
||||
|
||||
case 12:
|
||||
|
@ -337,7 +341,7 @@ static int it_psm_process_pattern(IT_PATTERN * pattern, const unsigned char * da
|
|||
if (version == PSMV_OLD) {
|
||||
if (length < 4) entry->effectvalue = length | 0xF0;
|
||||
else entry->effectvalue = length >> 2;
|
||||
} else if (version == PSMV_NEW) {
|
||||
} else /*if (version == PSMV_NEW)*/ {
|
||||
entry->effectvalue = length;
|
||||
}
|
||||
break;
|
||||
|
@ -347,7 +351,7 @@ static int it_psm_process_pattern(IT_PATTERN * pattern, const unsigned char * da
|
|||
if (version == PSMV_OLD) {
|
||||
if (length < 4) entry->effectvalue = length | 0xF0;
|
||||
else entry->effectvalue = length >> 2;
|
||||
} else if (version == PSMV_NEW) {
|
||||
} else /*if (version == PSMV_NEW)*/ {
|
||||
entry->effectvalue = length;
|
||||
}
|
||||
break;
|
||||
|
@ -355,7 +359,7 @@ static int it_psm_process_pattern(IT_PATTERN * pattern, const unsigned char * da
|
|||
case 15:
|
||||
entry->effect = IT_TONE_PORTAMENTO;
|
||||
if (version == PSMV_OLD) entry->effectvalue = length >> 2;
|
||||
else if (version == PSMV_NEW) entry->effectvalue = length;
|
||||
else /*if (version == PSMV_NEW)*/ entry->effectvalue = length;
|
||||
break;
|
||||
|
||||
case 0x15:
|
||||
|
@ -496,7 +500,7 @@ static DUMB_IT_SIGDATA *it_psm_load_sigdata(DUMBFILE *f, int * ver, int subsong)
|
|||
if (n) {
|
||||
ptr = malloc(n);
|
||||
if (!ptr) goto error_fc;
|
||||
if (dumbfile_getnc(ptr, n, f) < n)
|
||||
if (dumbfile_getnc((char *)ptr, n, f) < n)
|
||||
{
|
||||
free(ptr);
|
||||
goto error_fc;
|
||||
|
@ -655,10 +659,11 @@ static DUMB_IT_SIGDATA *it_psm_load_sigdata(DUMBFILE *f, int * ver, int subsong)
|
|||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
|
||||
sigdata->channel_pan[n ] = 16;
|
||||
sigdata->channel_pan[n+1] = 48;
|
||||
sigdata->channel_pan[n+2] = 48;
|
||||
sigdata->channel_pan[n+3] = 16;
|
||||
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_song_chunks; n++) {
|
||||
|
@ -688,7 +693,7 @@ static DUMB_IT_SIGDATA *it_psm_load_sigdata(DUMBFILE *f, int * ver, int subsong)
|
|||
memcpy(event[n_events].data, ptr + 1, 4);
|
||||
ptr += 5;
|
||||
length -= 5;
|
||||
} else if (found == PSMV_NEW) {
|
||||
} else /*if (found == PSMV_NEW)*/ {
|
||||
if (length < 9) goto error_ev;
|
||||
memcpy(event[n_events].data, ptr + 1, 8);
|
||||
ptr += 9;
|
||||
|
@ -808,7 +813,7 @@ static DUMB_IT_SIGDATA *it_psm_load_sigdata(DUMBFILE *f, int * ver, int subsong)
|
|||
n_patterns++;
|
||||
break;
|
||||
}
|
||||
} else if (found == PSMV_NEW) {
|
||||
} else /*if (found == PSMV_NEW)*/ {
|
||||
if (length < 12) goto error_ev;
|
||||
if (!pattcmp(ptr + 4, e->data, 8)) {
|
||||
if (it_psm_process_pattern(&sigdata->pattern[n_patterns], ptr, length, speed, bpm, pan, vol, found)) goto error_ev;
|
||||
|
@ -926,8 +931,10 @@ static DUMB_IT_SIGDATA *it_psm_load_sigdata(DUMBFILE *f, int * ver, int subsong)
|
|||
|
||||
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
|
||||
if (!sigdata->sample) goto error_ev;
|
||||
for (n = 0; n < sigdata->n_samples; n++)
|
||||
for (n = 0; n < sigdata->n_samples; n++) {
|
||||
sigdata->sample[n].data = NULL;
|
||||
sigdata->sample[n].flags = 0;
|
||||
}
|
||||
|
||||
o = 0;
|
||||
for (n = 0; n < n_chunks; n++) {
|
||||
|
@ -983,7 +990,7 @@ static int CDECL it_order_compare(const void *e1, const void *e2) {
|
|||
}
|
||||
|
||||
/*
|
||||
static int CDECL it_optimize_compare(const void *e1, const void *e2) {
|
||||
static int it_optimize_compare(const void *e1, const void *e2) {
|
||||
if (((const IT_ENTRY *)e1)->channel < ((const IT_ENTRY *)e2)->channel)
|
||||
return -1;
|
||||
|
||||
|
@ -1078,7 +1085,7 @@ static int it_pattern_compare(const IT_PATTERN * p1, const IT_PATTERN * p2) {
|
|||
static void dumb_it_optimize_orders(DUMB_IT_SIGDATA * sigdata) {
|
||||
int n, o, p;
|
||||
|
||||
//int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253;
|
||||
/*int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253;*/
|
||||
|
||||
unsigned char * order_list;
|
||||
int n_patterns;
|
||||
|
@ -1222,7 +1229,7 @@ int pattcmp( const unsigned char * a, const unsigned char * b, size_t l )
|
|||
|
||||
if ( i < l )
|
||||
{
|
||||
na = strtoul( a + i, &p, 10 );
|
||||
na = strtoul( (const char *)a + i, &p, 10 );
|
||||
if ( p == (const char *)a + i ) return 1;
|
||||
}
|
||||
|
||||
|
@ -1233,7 +1240,7 @@ int pattcmp( const unsigned char * a, const unsigned char * b, size_t l )
|
|||
|
||||
if ( j < l )
|
||||
{
|
||||
nb = strtoul( b + j, &p, 10 );
|
||||
nb = strtoul( (const char *)b + j, &p, 10 );
|
||||
if ( p == (const char *)b + j ) return -1;
|
||||
}
|
||||
|
||||
|
@ -1265,14 +1272,15 @@ DUH *DUMBEXPORT dumb_read_psm_quick(DUMBFILE *f, int subsong)
|
|||
char version[16];
|
||||
const char *tag[3][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
|
||||
tag[1][0] = "FORMAT";
|
||||
tag[1][1] = "PSM";
|
||||
if ( ver )
|
||||
{
|
||||
tag[2][0] = "FORMATVERSION";
|
||||
#if NEED_ITOA
|
||||
sprintf(version, "%d", ver);
|
||||
snprintf( version, 15, "%u", ver );
|
||||
version[15] = 0;
|
||||
#else
|
||||
itoa(ver, version, 10);
|
||||
#endif
|
||||
|
|
|
@ -26,30 +26,13 @@
|
|||
|
||||
|
||||
|
||||
/** WARNING: this is duplicated in itread.c */
|
||||
static int it_seek(DUMBFILE *f, int32 offset)
|
||||
{
|
||||
int32 pos = dumbfile_pos(f);
|
||||
|
||||
if (pos > offset)
|
||||
return -1;
|
||||
|
||||
if (pos < offset)
|
||||
if (dumbfile_skip(f, offset - pos))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int it_ptm_read_sample_header(IT_SAMPLE *sample, int32 *offset, DUMBFILE *f)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = dumbfile_getc(f);
|
||||
|
||||
dumbfile_getnc(sample->filename, 12, f);
|
||||
dumbfile_getnc((char *)sample->filename, 12, f);
|
||||
sample->filename[12] = 0;
|
||||
|
||||
sample->default_volume = dumbfile_getc(f);
|
||||
|
@ -67,7 +50,7 @@ static int it_ptm_read_sample_header(IT_SAMPLE *sample, int32 *offset, DUMBFILE
|
|||
/* GUSBegin, GUSLStart, GUSLEnd, GUSLoop, reserverd */
|
||||
dumbfile_skip(f, 4+4+4+1+1);
|
||||
|
||||
dumbfile_getnc(sample->name, 28, f);
|
||||
dumbfile_getnc((char *)sample->name, 28, f);
|
||||
sample->name[28] = 0;
|
||||
|
||||
/*
|
||||
|
@ -195,7 +178,7 @@ static int it_ptm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *
|
|||
pattern->n_entries++;
|
||||
if (b) {
|
||||
if (buflen + used[b] >= 65536) return -1;
|
||||
dumbfile_getnc(buffer + buflen, used[b], f);
|
||||
dumbfile_getnc((char *)buffer + buflen, used[b], f);
|
||||
buflen += used[b];
|
||||
} else {
|
||||
/* End of row */
|
||||
|
@ -351,7 +334,7 @@ static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f)
|
|||
if (!sigdata) return NULL;
|
||||
|
||||
/* Skip song name. */
|
||||
dumbfile_getnc(sigdata->name, 28, f);
|
||||
dumbfile_getnc((char *)sigdata->name, 28, f);
|
||||
sigdata->name[28] = 0;
|
||||
|
||||
if (dumbfile_getc(f) != 0x1A || dumbfile_igetw(f) != 0x203) {
|
||||
|
@ -446,7 +429,7 @@ static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f)
|
|||
}
|
||||
|
||||
/* Orders, byte each, length = sigdata->n_orders (should be even) */
|
||||
dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
|
||||
dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f);
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
component = malloc(768*sizeof(*component));
|
||||
|
@ -455,7 +438,7 @@ static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (it_seek(f, 352)) {
|
||||
if (dumbfile_seek(f, 352, DFS_SEEK_SET)) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -467,7 +450,7 @@ static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f)
|
|||
n_components++;
|
||||
}
|
||||
|
||||
if (it_seek(f, 608)) {
|
||||
if (dumbfile_seek(f, 608, DFS_SEEK_SET)) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -510,7 +493,7 @@ static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f)
|
|||
}
|
||||
|
||||
for (n = 0; n < n_components; n++) {
|
||||
if (it_seek(f, component[n].offset)) {
|
||||
if (dumbfile_seek(f, component[n].offset, DFS_SEEK_SET)) {
|
||||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
|
@ -560,7 +543,7 @@ DUH *DUMBEXPORT dumb_read_ptm_quick(DUMBFILE *f)
|
|||
{
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
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);
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
#include "internal/riff.h"
|
||||
|
||||
|
||||
DUH *dumb_read_riff_amff( struct riff * stream );
|
||||
DUH *dumb_read_riff_am( struct riff * stream );
|
||||
DUH *dumb_read_riff_dsmf( struct riff * stream );
|
||||
DUH *dumb_read_riff_amff( DUMBFILE * f, struct riff * stream );
|
||||
DUH *dumb_read_riff_am( DUMBFILE * f, struct riff * stream );
|
||||
DUH *dumb_read_riff_dsmf( DUMBFILE * f, struct riff * stream );
|
||||
|
||||
/* dumb_read_riff_quick(): reads a RIFF file into a DUH struct, returning a
|
||||
* pointer to the DUH struct. When you have finished with it, you must pass
|
||||
|
@ -34,37 +34,21 @@ DUH *DUMBEXPORT dumb_read_riff_quick( DUMBFILE * f )
|
|||
{
|
||||
DUH * duh;
|
||||
struct riff * stream;
|
||||
long size;
|
||||
|
||||
{
|
||||
unsigned char * buffer = 0;
|
||||
int32 size = 0;
|
||||
int32 read;
|
||||
do
|
||||
{
|
||||
buffer = realloc( buffer, 32768 + size );
|
||||
if ( ! buffer ) return 0;
|
||||
read = dumbfile_getnc( buffer + size, 32768, f );
|
||||
if ( read < 0 )
|
||||
{
|
||||
free( buffer );
|
||||
return 0;
|
||||
}
|
||||
size += read;
|
||||
}
|
||||
while ( read == 32768 );
|
||||
stream = riff_parse( buffer, size, 1 );
|
||||
if ( ! stream ) stream = riff_parse( buffer, size, 0 );
|
||||
free( buffer );
|
||||
}
|
||||
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( stream );
|
||||
duh = dumb_read_riff_am( f, stream );
|
||||
else if ( stream->type == DUMB_ID( 'A', 'M', 'F', 'F' ) )
|
||||
duh = dumb_read_riff_amff( stream );
|
||||
duh = dumb_read_riff_amff( f, stream );
|
||||
else if ( stream->type == DUMB_ID( 'D', 'S', 'M', 'F' ) )
|
||||
duh = dumb_read_riff_dsmf( stream );
|
||||
duh = dumb_read_riff_dsmf( f, stream );
|
||||
else duh = 0;
|
||||
|
||||
riff_free( stream );
|
||||
|
|
|
@ -24,26 +24,6 @@
|
|||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
||||
//#define S3M_BROKEN_OVERLAPPED_SAMPLES
|
||||
|
||||
/** WARNING: this is duplicated in itread.c */
|
||||
static int it_seek(DUMBFILE *f, int32 offset)
|
||||
{
|
||||
int32 pos = dumbfile_pos(f);
|
||||
|
||||
if (pos > offset) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pos < offset)
|
||||
if (dumbfile_skip(f, offset - pos))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int it_s3m_read_sample_header(IT_SAMPLE *sample, int32 *offset, unsigned char *pack, int cwtv, DUMBFILE *f)
|
||||
{
|
||||
unsigned char type;
|
||||
|
@ -51,13 +31,13 @@ static int it_s3m_read_sample_header(IT_SAMPLE *sample, int32 *offset, unsigned
|
|||
|
||||
type = dumbfile_getc(f);
|
||||
|
||||
dumbfile_getnc(sample->filename, 12, f);
|
||||
dumbfile_getnc((char *)sample->filename, 12, f);
|
||||
sample->filename[12] = 0;
|
||||
|
||||
if (type > 1) {
|
||||
/** WARNING: no adlib support */
|
||||
dumbfile_skip(f, 3 + 12 + 1 + 1 + 2 + 2 + 2 + 12);
|
||||
dumbfile_getnc(sample->name, 28, f);
|
||||
dumbfile_getnc((char *)sample->name, 28, f);
|
||||
sample->name[28] = 0;
|
||||
dumbfile_skip(f, 4);
|
||||
sample->flags &= ~IT_SAMPLE_EXISTS;
|
||||
|
@ -92,7 +72,7 @@ static int it_s3m_read_sample_header(IT_SAMPLE *sample, int32 *offset, unsigned
|
|||
/* Skip four unused bytes and three internal variables. */
|
||||
dumbfile_skip(f, 4+2+2+4);
|
||||
|
||||
dumbfile_getnc(sample->name, 28, f);
|
||||
dumbfile_getnc((char *)sample->name, 28, f);
|
||||
sample->name[28] = 0;
|
||||
|
||||
if (type == 0 || sample->length <= 0) {
|
||||
|
@ -214,7 +194,7 @@ static int it_s3m_read_sample_data(IT_SAMPLE *sample, int ffi, unsigned char pac
|
|||
|
||||
|
||||
|
||||
static int it_s3m_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int maxlen)
|
||||
static int it_s3m_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer)
|
||||
{
|
||||
int length;
|
||||
int buflen = 0;
|
||||
|
@ -246,18 +226,13 @@ static int it_s3m_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *
|
|||
* against buffer overflow, this method should work with all sensibly
|
||||
* written S3M files. If you find one for which it does not work, please
|
||||
* let me know at entheh@users.sf.net so I can look at it.
|
||||
*
|
||||
* "for a good reason" ? What's this nonsense? -kode54
|
||||
*
|
||||
*/
|
||||
|
||||
/* Discard the length. */
|
||||
/* read at most length bytes, in case of retarded crap */
|
||||
length = dumbfile_igetw(f);
|
||||
|
||||
if (maxlen)
|
||||
{
|
||||
maxlen -= 2;
|
||||
if (length > maxlen) length = maxlen;
|
||||
}
|
||||
|
||||
if (dumbfile_error(f) || !length)
|
||||
return -1;
|
||||
|
||||
|
@ -278,7 +253,7 @@ static int it_s3m_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *
|
|||
if (b) {
|
||||
if (buflen + used[b] >= 65536) return -1;
|
||||
if (buflen + used[b] <= length)
|
||||
dumbfile_getnc(buffer + buflen, used[b], f);
|
||||
dumbfile_getnc((char *)buffer + buflen, used[b], f);
|
||||
else
|
||||
memset(buffer + buflen, 0, used[b]);
|
||||
buflen += used[b];
|
||||
|
@ -478,7 +453,7 @@ static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
|
|||
sigdata = malloc(sizeof(*sigdata));
|
||||
if (!sigdata) return NULL;
|
||||
|
||||
dumbfile_getnc(sigdata->name, 28, f);
|
||||
dumbfile_getnc((char *)sigdata->name, 28, f);
|
||||
sigdata->name[28] = 0;
|
||||
|
||||
n = dumbfile_getc(f);
|
||||
|
@ -557,14 +532,13 @@ static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->global_volume = dumbfile_getc(f) * 16 / 11;
|
||||
if ( !sigdata->global_volume || sigdata->global_volume > 93 ) sigdata->global_volume = 93;
|
||||
sigdata->global_volume = dumbfile_getc(f);
|
||||
if ( !sigdata->global_volume || sigdata->global_volume > 64 ) sigdata->global_volume = 64;
|
||||
sigdata->speed = dumbfile_getc(f);
|
||||
if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
|
||||
sigdata->tempo = dumbfile_getc(f);
|
||||
master_volume = dumbfile_getc(f); // 7 bits; +128 for stereo
|
||||
//what do we do with master_volume? it's not the same as mixing volume...
|
||||
sigdata->mixing_volume = 48;
|
||||
sigdata->mixing_volume = master_volume & 127;
|
||||
|
||||
if (master_volume & 128) sigdata->flags |= IT_STEREO;
|
||||
|
||||
|
@ -583,12 +557,13 @@ static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
|
|||
/* Channel settings for 32 channels, 255=unused, +128=disabled */
|
||||
{
|
||||
int i;
|
||||
int sep = (7 * dumb_it_default_panning_separation + 50) / 100;
|
||||
for (i = 0; i < 32; i++) {
|
||||
int c = dumbfile_getc(f);
|
||||
if (!(c & (128 | 16))) { /* +128=disabled, +16=Adlib */
|
||||
if (sigdata->n_pchannels < i + 1) sigdata->n_pchannels = i + 1;
|
||||
sigdata->channel_volume[i] = 64;
|
||||
sigdata->channel_pan[i] = c & 8 ? 12 : 3;
|
||||
sigdata->channel_pan[i] = c & 8 ? 7 + sep : 7 - sep;
|
||||
/** WARNING: ah, but it should be 7 for mono... */
|
||||
} else {
|
||||
/** WARNING: this could be improved if we support channel muting... */
|
||||
|
@ -599,7 +574,7 @@ static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
|
|||
}
|
||||
|
||||
/* Orders, byte each, length = sigdata->n_orders (should be even) */
|
||||
dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
|
||||
dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f);
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
component = malloc(768*sizeof(*component));
|
||||
|
@ -673,45 +648,12 @@ static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Voila, I must deal with a very dumb S3M myself. This file refers to the same file offset twice
|
||||
* for two different patterns. Solution: Eliminate it.
|
||||
*/
|
||||
|
||||
for (n = 0; n < n_components; n++) {
|
||||
if (component[n].type == S3M_COMPONENT_PATTERN) {
|
||||
int m;
|
||||
for (m = n + 1; m < n_components; m++) {
|
||||
if (component[m].type == S3M_COMPONENT_PATTERN) {
|
||||
if (component[n].offset == component[m].offset) {
|
||||
int o, pattern;
|
||||
pattern = component[m].n;
|
||||
n_components--;
|
||||
for (o = m; o < n_components; o++) {
|
||||
component[o] = component[o + 1];
|
||||
}
|
||||
for (o = 0; o < sigdata->n_orders; o++) {
|
||||
if (sigdata->order[o] == pattern) {
|
||||
sigdata->order[o] = component[n].n;
|
||||
}
|
||||
}
|
||||
sigdata->pattern[pattern].n_rows = 64;
|
||||
sigdata->pattern[pattern].n_entries = 0;
|
||||
m--;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (n = 0; n < n_components; n++) {
|
||||
int32 offset = 0;
|
||||
int32 offset;
|
||||
int m;
|
||||
#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
|
||||
int last;
|
||||
#endif
|
||||
|
||||
if (it_seek(f, component[n].offset)) {
|
||||
offset = 0;
|
||||
if (dumbfile_seek(f, component[n].offset, DFS_SEEK_SET)) {
|
||||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
|
@ -721,7 +663,7 @@ static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
|
|||
switch (component[n].type) {
|
||||
|
||||
case S3M_COMPONENT_PATTERN:
|
||||
if (it_s3m_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) {
|
||||
if (it_s3m_read_pattern(&sigdata->pattern[component[n].n], f, buffer)) {
|
||||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
|
@ -759,41 +701,9 @@ static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
|
|||
|
||||
m = component[n].sampfirst;
|
||||
|
||||
#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
|
||||
last = -1;
|
||||
#endif
|
||||
|
||||
while (m >= 0) {
|
||||
// XXX
|
||||
#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
|
||||
if ( last >= 0 ) {
|
||||
if ( dumbfile_pos( f ) > component[m].offset ) {
|
||||
IT_SAMPLE * s1 = &sigdata->sample[component[last].n];
|
||||
IT_SAMPLE * s2 = &sigdata->sample[component[m].n];
|
||||
if ( ( s1->flags | s2->flags ) & ( IT_SAMPLE_16BIT | IT_SAMPLE_STEREO ) ) {
|
||||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
if ( component[m].offset >= component[last].offset &&
|
||||
component[m].offset + s2->length <= component[last].offset + s1->length ) {
|
||||
s2->left = malloc( s2->length );
|
||||
if ( ! s2->left ) {
|
||||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
memcpy( s2->left, ( const char * ) s1->left + component[m].offset - component[last].offset, s2->length );
|
||||
last = -1;
|
||||
}
|
||||
}
|
||||
} else last = 0;
|
||||
|
||||
if ( last >= 0 ) {
|
||||
#endif
|
||||
if (it_seek(f, component[m].offset)) {
|
||||
if (dumbfile_seek(f, component[m].offset, DFS_SEEK_SET)) {
|
||||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
|
@ -807,11 +717,6 @@ static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
|
||||
last = m;
|
||||
}
|
||||
#endif
|
||||
|
||||
m = component[m].sampnext;
|
||||
}
|
||||
}
|
||||
|
@ -846,7 +751,7 @@ DUH *DUMBEXPORT dumb_read_s3m_quick(DUMBFILE *f)
|
|||
char version[8];
|
||||
const char *tag[3][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
|
||||
tag[1][0] = "FORMAT";
|
||||
tag[1][1] = "S3M";
|
||||
tag[2][0] = "TRACKERVERSION";
|
||||
|
|
|
@ -25,13 +25,18 @@
|
|||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#define strnicmp strncasecmp
|
||||
#ifdef _MSC_VER
|
||||
#define strnicmp _strnicmp
|
||||
#else
|
||||
#if defined(unix) || defined(__unix__) || defined(__unix)
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#define strnicmp strncasecmp
|
||||
#endif
|
||||
|
||||
static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f, unsigned short *offset )
|
||||
{
|
||||
dumbfile_getnc( sample->filename, 12, f );
|
||||
dumbfile_getnc( (char *) sample->filename, 12, f );
|
||||
sample->filename[12] = 0;
|
||||
|
||||
memcpy( sample->name, sample->filename, 13 );
|
||||
|
@ -56,6 +61,7 @@ static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f, unsigned s
|
|||
/* Looks like no-existy. */
|
||||
sample->flags &= ~IT_SAMPLE_EXISTS;
|
||||
sample->length = 0;
|
||||
*offset = 0;
|
||||
return dumbfile_error( f );
|
||||
}
|
||||
|
||||
|
@ -81,7 +87,7 @@ static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f, unsigned s
|
|||
return dumbfile_error(f);
|
||||
}
|
||||
|
||||
static int it_stm_read_sample_data( IT_SAMPLE *sample, void *data_block, long offset )
|
||||
static int it_stm_read_sample_data( IT_SAMPLE *sample, DUMBFILE * f )
|
||||
{
|
||||
if ( ! sample->length ) return 0;
|
||||
|
||||
|
@ -89,9 +95,9 @@ static int it_stm_read_sample_data( IT_SAMPLE *sample, void *data_block, long of
|
|||
if (!sample->data)
|
||||
return -1;
|
||||
|
||||
memcpy( sample->data, (unsigned char*)data_block + offset, sample->length );
|
||||
dumbfile_getnc( sample->data, sample->length, f );
|
||||
|
||||
return 0;
|
||||
return dumbfile_error( f );
|
||||
}
|
||||
|
||||
static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer )
|
||||
|
@ -103,7 +109,7 @@ static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char
|
|||
|
||||
pattern->n_rows = 64;
|
||||
|
||||
if ( dumbfile_getnc( buffer, 64 * 4 * 4, f ) != 64 * 4 * 4 )
|
||||
if ( dumbfile_getnc( (char *) buffer, 64 * 4 * 4, f ) != 64 * 4 * 4 )
|
||||
return -1;
|
||||
|
||||
pattern->n_entries = 64;
|
||||
|
@ -190,17 +196,13 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version)
|
|||
|
||||
unsigned short sample_offset[ 31 ];
|
||||
|
||||
void *data_block;
|
||||
|
||||
int n;
|
||||
|
||||
long o, p, q;
|
||||
int n;
|
||||
|
||||
sigdata = malloc(sizeof(*sigdata));
|
||||
if (!sigdata) return NULL;
|
||||
|
||||
/* Skip song name. */
|
||||
dumbfile_getnc(sigdata->name, 20, f);
|
||||
dumbfile_getnc((char *)sigdata->name, 20, f);
|
||||
sigdata->name[20] = 0;
|
||||
|
||||
dumbfile_getnc(tracker_name, 8, f);
|
||||
|
@ -277,10 +279,11 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version)
|
|||
}
|
||||
|
||||
memset( sigdata->channel_volume, 64, 4 );
|
||||
sigdata->channel_pan[ 0 ] = 48;
|
||||
sigdata->channel_pan[ 1 ] = 16;
|
||||
sigdata->channel_pan[ 2 ] = 48;
|
||||
sigdata->channel_pan[ 3 ] = 16;
|
||||
n = 32 * dumb_it_default_panning_separation / 100;
|
||||
sigdata->channel_pan[ 0 ] = 32 + n;
|
||||
sigdata->channel_pan[ 1 ] = 32 - n;
|
||||
sigdata->channel_pan[ 2 ] = 32 + n;
|
||||
sigdata->channel_pan[ 3 ] = 32 - n;
|
||||
|
||||
for ( n = 0; n < sigdata->n_samples; ++n ) {
|
||||
if ( it_stm_read_sample_header( &sigdata->sample[ n ], f, &sample_offset[ n ] ) ) {
|
||||
|
@ -296,7 +299,7 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version)
|
|||
}
|
||||
|
||||
/* Orders, byte each, length = sigdata->n_orders (should be even) */
|
||||
dumbfile_getnc( sigdata->order, *version >= 0x200 ? 128 : 64, f );
|
||||
dumbfile_getnc( (char *) sigdata->order, *version >= 0x200 ? 128 : 64, f );
|
||||
if (*version < 0x200) memset( sigdata->order + 64, 0xFF, 64 );
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
|
@ -329,60 +332,21 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version)
|
|||
free( buffer );
|
||||
}
|
||||
|
||||
o = LONG_MAX;
|
||||
p = 0;
|
||||
|
||||
for ( n = 0; n < sigdata->n_samples; ++n ) {
|
||||
if ((sigdata->sample[ n ].flags & IT_SAMPLE_EXISTS) && sample_offset[ n ]) {
|
||||
q = ((long)sample_offset[ n ]) * 16;
|
||||
if (q < o) {
|
||||
o = q;
|
||||
}
|
||||
if (q + sigdata->sample[ n ].length > p) {
|
||||
p = q + sigdata->sample[ n ].length;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sigdata->sample[ n ].flags = 0;
|
||||
sigdata->sample[ n ].length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
data_block = malloc( p - o );
|
||||
if ( !data_block ) {
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( n = 0, q = o / 16; n < sigdata->n_samples; ++n ) {
|
||||
if ( sample_offset[ n ] ) {
|
||||
sample_offset[ n ] = (unsigned short)(sample_offset[ n ] - q);
|
||||
}
|
||||
}
|
||||
|
||||
q = o - dumbfile_pos( f );
|
||||
p -= o;
|
||||
o = 0;
|
||||
if ( q >= 0 ) dumbfile_skip( f, q );
|
||||
else {
|
||||
o = -q;
|
||||
memset ( data_block, 0, o );
|
||||
}
|
||||
if ( dumbfile_getnc( (char*)data_block + o, p - o, f ) != p - o ) {
|
||||
free( data_block );
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( n = 0; n < sigdata->n_samples; ++n ) {
|
||||
if ( it_stm_read_sample_data( &sigdata->sample[ n ], data_block, ((long)sample_offset[ n ]) * 16 ) ) {
|
||||
free( data_block );
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free( data_block );
|
||||
for ( n = 0; n < sigdata->n_samples; ++n ) {
|
||||
if ( sample_offset[ n ] )
|
||||
{
|
||||
if ( dumbfile_seek( f, sample_offset[ n ] * 16, DFS_SEEK_SET ) ||
|
||||
it_stm_read_sample_data( &sigdata->sample[ n ], f ) ) {
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sigdata->sample[ n ].flags = 0;
|
||||
sigdata->sample[ n ].length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_dumb_it_fix_invalid_orders(sigdata);
|
||||
|
||||
|
@ -405,7 +369,7 @@ DUH *DUMBEXPORT dumb_read_stm_quick(DUMBFILE *f)
|
|||
char version[16];
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
|
||||
tag[1][0] = "FORMAT";
|
||||
version[0] = 'S';
|
||||
version[1] = 'T';
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
#include "internal/dumbfile.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
@ -185,7 +186,7 @@ static void it_xm_convert_volume(int volume, IT_ENTRY *entry)
|
|||
|
||||
|
||||
|
||||
static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char **bufferptr, int *buffersize, int version)
|
||||
static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer, int version)
|
||||
{
|
||||
int size;
|
||||
int pos;
|
||||
|
@ -193,7 +194,6 @@ static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels,
|
|||
int row;
|
||||
int effect, effectvalue;
|
||||
IT_ENTRY *entry;
|
||||
unsigned char *buffer;
|
||||
|
||||
/* pattern header size */
|
||||
if (dumbfile_igetl(f) != ( version == 0x0102 ? 0x08 : 0x09 ) ) {
|
||||
|
@ -220,20 +220,12 @@ static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels,
|
|||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
if (size > *buffersize) {
|
||||
if (*bufferptr != NULL) {
|
||||
free(*bufferptr);
|
||||
}
|
||||
*bufferptr = malloc(size);
|
||||
*buffersize = size;
|
||||
}
|
||||
buffer = *bufferptr;
|
||||
if (buffer == NULL) {
|
||||
TRACE("XM error: out of memory reading pattern\n");
|
||||
if (size > 1280 * n_channels) {
|
||||
TRACE("XM error: pattern data size > %d bytes\n", 1280 * n_channels);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dumbfile_getnc(buffer, size, f) < size)
|
||||
if (dumbfile_getnc((char *)buffer, size, f) < size)
|
||||
return -1;
|
||||
|
||||
/* compute number of entries */
|
||||
|
@ -378,15 +370,7 @@ struct LIMITED_XM
|
|||
DUMBFILE *remaining;
|
||||
};
|
||||
|
||||
/* XXX */
|
||||
struct DUMBFILE
|
||||
{
|
||||
DUMBFILE_SYSTEM *dfs;
|
||||
void *file;
|
||||
long pos;
|
||||
};
|
||||
|
||||
static int limit_xm_resize(void *f, long n)
|
||||
static int DUMBCALLBACK limit_xm_resize(void *f, long n)
|
||||
{
|
||||
DUMBFILE *df = f;
|
||||
LIMITED_XM *lx = df->file;
|
||||
|
@ -398,7 +382,7 @@ static int limit_xm_resize(void *f, long n)
|
|||
memset( buffered + lx->allocated, 0, n - lx->allocated );
|
||||
lx->allocated = n;
|
||||
}
|
||||
if ( dumbfile_getnc( lx->buffered, n, lx->remaining ) < n ) return -1;
|
||||
if ( dumbfile_getnc( (char *)lx->buffered, n, lx->remaining ) < n ) return -1;
|
||||
} else if (!n) {
|
||||
if ( lx->buffered ) free( lx->buffered );
|
||||
lx->buffered = NULL;
|
||||
|
@ -409,14 +393,14 @@ static int limit_xm_resize(void *f, long n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int limit_xm_skip_end(void *f, int32 n)
|
||||
static int DUMBCALLBACK limit_xm_skip_end(void *f, int32 n)
|
||||
{
|
||||
DUMBFILE *df = f;
|
||||
LIMITED_XM *lx = df->file;
|
||||
return dumbfile_skip( lx->remaining, n );
|
||||
}
|
||||
|
||||
static int limit_xm_skip(void *f, int32 n)
|
||||
static int DUMBCALLBACK limit_xm_skip(void *f, long n)
|
||||
{
|
||||
LIMITED_XM *lx = f;
|
||||
lx->ptr += n;
|
||||
|
@ -425,7 +409,7 @@ static int limit_xm_skip(void *f, int32 n)
|
|||
|
||||
|
||||
|
||||
static int limit_xm_getc(void *f)
|
||||
static int DUMBCALLBACK limit_xm_getc(void *f)
|
||||
{
|
||||
LIMITED_XM *lx = f;
|
||||
if (lx->ptr >= lx->allocated) {
|
||||
|
@ -436,7 +420,7 @@ static int limit_xm_getc(void *f)
|
|||
|
||||
|
||||
|
||||
static int32 limit_xm_getnc(char *ptr, int32 n, void *f)
|
||||
static int32 DUMBCALLBACK limit_xm_getnc(char *ptr, int32 n, void *f)
|
||||
{
|
||||
LIMITED_XM *lx = f;
|
||||
int left;
|
||||
|
@ -457,7 +441,7 @@ static int32 limit_xm_getnc(char *ptr, int32 n, void *f)
|
|||
|
||||
|
||||
|
||||
static void limit_xm_close(void *f)
|
||||
static void DUMBCALLBACK limit_xm_close(void *f)
|
||||
{
|
||||
LIMITED_XM *lx = f;
|
||||
if (lx->buffered) free(lx->buffered);
|
||||
|
@ -467,12 +451,32 @@ static void limit_xm_close(void *f)
|
|||
|
||||
|
||||
|
||||
/* These two can be stubs since this implementation doesn't use seeking */
|
||||
static int DUMBCALLBACK limit_xm_seek(void *f, long n)
|
||||
{
|
||||
(void)f;
|
||||
(void)n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static long DUMBCALLBACK limit_xm_get_size(void *f)
|
||||
{
|
||||
(void)f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUMBFILE_SYSTEM limit_xm_dfs = {
|
||||
NULL,
|
||||
&limit_xm_skip,
|
||||
&limit_xm_getc,
|
||||
&limit_xm_getnc,
|
||||
&limit_xm_close
|
||||
&limit_xm_close,
|
||||
&limit_xm_seek,
|
||||
&limit_xm_get_size
|
||||
};
|
||||
|
||||
static DUMBFILE *dumbfile_limit_xm(DUMBFILE *f)
|
||||
|
@ -513,9 +517,9 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA
|
|||
|
||||
if ( limit_xm_resize( f, size - 4 ) < 0 ) return -1;
|
||||
|
||||
dumbfile_getnc(instrument->name, 22, f);
|
||||
dumbfile_getnc((char *)instrument->name, 22, f);
|
||||
instrument->name[22] = 0;
|
||||
trim_whitespace(instrument->name, 22);
|
||||
trim_whitespace((char *)instrument->name, 22);
|
||||
instrument->filename[0] = 0;
|
||||
dumbfile_skip(f, 1); /* Instrument type. Should be 0, but seems random. */
|
||||
extra->n_samples = dumbfile_igetw(f);
|
||||
|
@ -673,9 +677,9 @@ static int it_xm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
|
|||
|
||||
reserved = dumbfile_getc(f);
|
||||
|
||||
dumbfile_getnc(sample->name, 22, f);
|
||||
dumbfile_getnc((char *)sample->name, 22, f);
|
||||
sample->name[22] = 0;
|
||||
trim_whitespace(sample->name, 22);
|
||||
trim_whitespace((char *)sample->name, 22);
|
||||
|
||||
sample->filename[0] = 0;
|
||||
|
||||
|
@ -763,13 +767,22 @@ static int it_xm_read_sample_data(IT_SAMPLE *sample, unsigned char roguebytes, D
|
|||
{
|
||||
int old;
|
||||
int32 i;
|
||||
// long truncated_size;
|
||||
int n_channels;
|
||||
int32 datasizebytes;
|
||||
void *ibuffer;
|
||||
|
||||
if (!(sample->flags & IT_SAMPLE_EXISTS))
|
||||
return dumbfile_skip(f, roguebytes);
|
||||
|
||||
#if 0
|
||||
/* 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 && roguebytes != 4) {
|
||||
truncated_size = sample->length - sample->loop_end;
|
||||
sample->length = sample->loop_end;
|
||||
} else {
|
||||
truncated_size = 0;
|
||||
}
|
||||
#endif
|
||||
n_channels = sample->flags & IT_SAMPLE_STEREO ? 2 : 1;
|
||||
datasizebytes = sample->length;
|
||||
|
||||
|
@ -848,7 +861,7 @@ static int it_xm_read_sample_data(IT_SAMPLE *sample, unsigned char roguebytes, D
|
|||
* players that don't know about it (and FastTracker 2 itself), the two
|
||||
* channels are not stored interleaved but rather, one after the other. */
|
||||
int old_r = 0;
|
||||
ibuffer = malloc(sample->length << ((sample->flags & IT_SAMPLE_16BIT) ? 2 : 1));
|
||||
void *ibuffer = malloc(sample->length << ((sample->flags & IT_SAMPLE_16BIT) ? 2 : 1));
|
||||
if (ibuffer == NULL)
|
||||
{
|
||||
/* No memory => ignore stereo bits at the end */
|
||||
|
@ -925,12 +938,12 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
return NULL;
|
||||
|
||||
/* song name */
|
||||
if (dumbfile_getnc(sigdata->name, 20, f) < 20) {
|
||||
if (dumbfile_getnc((char *)sigdata->name, 20, f) < 20) {
|
||||
free(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
sigdata->name[20] = 0;
|
||||
trim_whitespace(sigdata->name, 20);
|
||||
trim_whitespace((char *)sigdata->name, 20);
|
||||
|
||||
if (dumbfile_getc(f) != 0x1A) {
|
||||
TRACE("XM error: 0x1A not found\n");
|
||||
|
@ -986,6 +999,16 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
|
||||
sigdata->tempo = dumbfile_igetw(f);
|
||||
|
||||
// FT2 always clips restart position against the song length
|
||||
if (sigdata->restart_position > sigdata->n_orders)
|
||||
sigdata->restart_position = sigdata->n_orders;
|
||||
// And FT2 starts playback on order 0, regardless of length,
|
||||
// and only checks if the next order is greater than or equal
|
||||
// to this, not the current pattern. Work around this with
|
||||
// DUMB's playback core by overriding a zero length with one.
|
||||
if (sigdata->n_orders == 0)
|
||||
sigdata->n_orders = 1;
|
||||
|
||||
/* sanity checks */
|
||||
// XXX
|
||||
i = header_size - 4 - 2 * 8; /* Maximum number of orders expected */
|
||||
|
@ -1003,7 +1026,7 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
|
||||
dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f);
|
||||
dumbfile_skip(f, i - sigdata->n_orders);
|
||||
|
||||
if (dumbfile_error(f)) {
|
||||
|
@ -1027,13 +1050,14 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
sigdata->pattern[i].entry = NULL;
|
||||
|
||||
{
|
||||
unsigned char *buffer = NULL;
|
||||
int buffersize = 0;
|
||||
unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */
|
||||
if (!buffer) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < sigdata->n_patterns; i++) {
|
||||
if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, &buffer, &buffersize, * version) != 0) {
|
||||
if (buffer != NULL) {
|
||||
free(buffer);
|
||||
}
|
||||
if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer, * version) != 0) {
|
||||
free(buffer);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1271,13 +1295,15 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
sigdata->pattern[i].entry = NULL;
|
||||
|
||||
{
|
||||
unsigned char *buffer = NULL;
|
||||
int buffersize = 0;
|
||||
unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */
|
||||
if (!buffer) {
|
||||
free(roguebytes);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < sigdata->n_patterns; i++) {
|
||||
if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, &buffer, &buffersize, * version) != 0) {
|
||||
if (buffer != NULL) {
|
||||
free(buffer);
|
||||
}
|
||||
if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer, * version) != 0) {
|
||||
free(buffer);
|
||||
free(roguebytes);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
|
@ -1486,7 +1512,7 @@ DUH *DUMBEXPORT dumb_read_xm_quick(DUMBFILE *f)
|
|||
char version[16];
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
|
||||
tag[1][0] = "FORMAT";
|
||||
version[0] = 'X';
|
||||
version[1] = 'M';
|
||||
|
|
|
@ -1,243 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* combine.c - The combining (COMB) signal type. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* This takes multiple monaural signals and | \ / /
|
||||
* combines them into a single multichannel | ' /
|
||||
* signal. It assumes the correct number of \__/
|
||||
* channels is passed. An ASSERT() is in place
|
||||
* to check the number of channels when you
|
||||
* compile with -DDEBUGMODE. As an exception, if one channel is passed the
|
||||
* signals are all mixed together.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
#define SIGTYPE_COMBINING DUMB_ID('C','O','M','B')
|
||||
|
||||
|
||||
|
||||
typedef struct COMBINING_SIGNAL
|
||||
{
|
||||
int n_signals;
|
||||
int sig[ZERO_SIZE];
|
||||
}
|
||||
COMBINING_SIGNAL;
|
||||
|
||||
|
||||
|
||||
typedef struct COMBINING_SAMPINFO
|
||||
{
|
||||
int n_signals;
|
||||
int downmix;
|
||||
DUH_SIGNAL_SAMPINFO *csampinfo[ZERO_SIZE];
|
||||
}
|
||||
COMBINING_SAMPINFO;
|
||||
|
||||
|
||||
|
||||
static void *combining_load_signal(DUH *duh, DUMBFILE *file)
|
||||
{
|
||||
COMBINING_SIGNAL *signal;
|
||||
int n_signals;
|
||||
|
||||
(void)duh;
|
||||
|
||||
n_signals = dumbfile_getc(file);
|
||||
|
||||
/* No point in combining only one signal! */
|
||||
if (dumbfile_error(file) || n_signals <= 1)
|
||||
return NULL;
|
||||
|
||||
signal = malloc(sizeof(*signal) + n_signals * sizeof(*signal->sig));
|
||||
if (!signal)
|
||||
return NULL;
|
||||
|
||||
signal->n_signals = n_signals;
|
||||
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < signal->n_signals; n++) {
|
||||
signal->sig[n] = dumbfile_igetl(file);
|
||||
if (dumbfile_error(file)) {
|
||||
free(signal);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void *combining_start_samples(DUH *duh, void *signal, int n_channels, long pos)
|
||||
{
|
||||
#define signal ((COMBINING_SIGNAL *)signal)
|
||||
|
||||
COMBINING_SAMPINFO *sampinfo;
|
||||
|
||||
sampinfo = malloc(sizeof(*sampinfo) + signal->n_signals * sizeof(*sampinfo->csampinfo));
|
||||
if (!sampinfo)
|
||||
return NULL;
|
||||
|
||||
sampinfo->n_signals = signal->n_signals;
|
||||
if (n_channels == 1)
|
||||
sampinfo->downmix = 1;
|
||||
else if (n_channels == signal->n_signals)
|
||||
sampinfo->downmix = 0;
|
||||
else {
|
||||
TRACE("Combining signal discrepancy: %d signals, %d channels.\n", signal->n_signals, n_channels);
|
||||
free(sampinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
{
|
||||
int worthwhile = 0;
|
||||
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < signal->n_signals; n++) {
|
||||
sampinfo->csampinfo[n] = duh_signal_start_samples(duh, signal->sig[n], 1, pos);
|
||||
if (sampinfo->csampinfo[n])
|
||||
worthwhile = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!worthwhile) {
|
||||
free(sampinfo);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return sampinfo;
|
||||
|
||||
#undef signal
|
||||
}
|
||||
|
||||
|
||||
|
||||
static long combining_render_samples(
|
||||
void *sampinfo,
|
||||
float volume, float delta,
|
||||
long size, sample_t **samples
|
||||
)
|
||||
{
|
||||
#define sampinfo ((COMBINING_SAMPINFO *)sampinfo)
|
||||
|
||||
long max_size;
|
||||
|
||||
int n;
|
||||
|
||||
if (sampinfo->downmix)
|
||||
volume /= sampinfo->n_signals;
|
||||
|
||||
max_size = duh_signal_render_samples(sampinfo->csampinfo[0], volume, delta, size, samples);
|
||||
|
||||
if (sampinfo->downmix) {
|
||||
|
||||
long s;
|
||||
long sz;
|
||||
|
||||
sample_t *sampbuf = malloc(size * sizeof(sample_t));
|
||||
|
||||
if (!sampbuf)
|
||||
return 0;
|
||||
|
||||
for (n = 1; n < sampinfo->n_signals; n++) {
|
||||
sz = duh_signal_render_samples(sampinfo->csampinfo[n], volume, delta, size, &sampbuf);
|
||||
if (sz > max_size) {
|
||||
for (s = max_size; s < sz; s++)
|
||||
samples[0][s] = sampbuf[s];
|
||||
sz = max_size;
|
||||
max_size = s;
|
||||
}
|
||||
for (s = 0; s < sz; s++)
|
||||
samples[0][s] += sampbuf[s];
|
||||
}
|
||||
|
||||
free(sampbuf);
|
||||
|
||||
} else {
|
||||
|
||||
long *sz = malloc(size * sizeof(*sz));
|
||||
long s;
|
||||
|
||||
if (!sz)
|
||||
return 0;
|
||||
|
||||
sz[0] = max_size;
|
||||
|
||||
for (n = 1; n < sampinfo->n_signals; n++) {
|
||||
sz[n] = duh_signal_render_samples(sampinfo->csampinfo[n], volume, delta, size, samples + n);
|
||||
if (sz[n] > max_size)
|
||||
max_size = sz[n];
|
||||
}
|
||||
|
||||
for (n = 0; n < sampinfo->n_signals; n++)
|
||||
for (s = sz[n]; s < max_size; s++)
|
||||
samples[n][s] = 0;
|
||||
|
||||
free(sz);
|
||||
|
||||
}
|
||||
|
||||
return max_size;
|
||||
|
||||
#undef sampinfo
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void combining_end_samples(void *sampinfo)
|
||||
{
|
||||
#define sampinfo ((COMBINING_SAMPINFO *)sampinfo)
|
||||
|
||||
int n;
|
||||
|
||||
for (n = 0; n < sampinfo->n_signals; n++)
|
||||
duh_signal_end_samples(sampinfo->csampinfo[n]);
|
||||
|
||||
free(sampinfo);
|
||||
|
||||
#undef sampinfo
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void combining_unload_signal(void *signal)
|
||||
{
|
||||
free(signal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static DUH_SIGTYPE_DESC sigtype_combining = {
|
||||
SIGTYPE_COMBINING,
|
||||
&combining_load_signal,
|
||||
&combining_start_samples,
|
||||
NULL,
|
||||
&combining_render_samples,
|
||||
&combining_end_samples,
|
||||
&combining_unload_signal
|
||||
};
|
||||
|
||||
|
||||
void dumb_register_sigtype_combining(void)
|
||||
{
|
||||
dumb_register_sigtype(&sigtype_combining);
|
||||
}
|
|
@ -1,340 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* sample.c - The sample (SAMP) signal type. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* This only supports monaural samples. For | \ / /
|
||||
* multiple channels, use multiple samples and | ' /
|
||||
* a combining signal (COMB). \__/
|
||||
*/
|
||||
|
||||
/* NOTE: filters need not be credited yet, as they will be moved elsewhere. */
|
||||
/** WARNING don't forget to move these filters somewhere */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
/** WARNING move these things somewhere useful, for DUH writing - this applies to other signal types too */
|
||||
#define SIGTYPE_SAMPLE DUMB_ID('S','A','M','P')
|
||||
|
||||
|
||||
|
||||
#define SAMPFLAG_16BIT 1 /* sample in file is 16 bit, rather than 8 bit */
|
||||
#define SAMPFLAG_LOOP 2 /* loop indefinitely */
|
||||
#define SAMPFLAG_XLOOP 4 /* loop x times; only relevant if LOOP not set */
|
||||
#define SAMPFLAG_PINGPONG 8 /* loop back and forth, if LOOP or XLOOP set */
|
||||
|
||||
|
||||
/* SAMPPARAM_N_LOOPS: add 'value' iterations to the loop. 'value' is assumed
|
||||
* to be positive.
|
||||
*/
|
||||
#define SAMPPARAM_N_LOOPS 0
|
||||
|
||||
|
||||
|
||||
typedef struct SAMPLE_SIGDATA
|
||||
{
|
||||
long size;
|
||||
int flags;
|
||||
long loop_start;
|
||||
long loop_end;
|
||||
sample_t *samples;
|
||||
}
|
||||
SAMPLE_SIGDATA;
|
||||
|
||||
|
||||
|
||||
typedef struct SAMPLE_SIGRENDERER
|
||||
{
|
||||
SAMPLE_SIGDATA *sigdata;
|
||||
int n_channels;
|
||||
DUMB_RESAMPLER r;
|
||||
int n_loops;
|
||||
}
|
||||
SAMPLE_SIGRENDERER;
|
||||
|
||||
|
||||
|
||||
static sigdata_t *sample_load_sigdata(DUH *duh, DUMBFILE *file)
|
||||
{
|
||||
SAMPLE_SIGDATA *sigdata;
|
||||
long size;
|
||||
long n;
|
||||
int flags;
|
||||
|
||||
(void)duh;
|
||||
|
||||
size = dumbfile_igetl(file);
|
||||
|
||||
if (dumbfile_error(file) || size <= 0)
|
||||
return NULL;
|
||||
|
||||
flags = dumbfile_getc(file);
|
||||
if (flags < 0)
|
||||
return NULL;
|
||||
|
||||
sigdata = malloc(sizeof(*sigdata));
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
sigdata->samples = malloc(size * sizeof(sample_t));
|
||||
if (!sigdata->samples) {
|
||||
free(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->size = size;
|
||||
sigdata->flags = flags;
|
||||
|
||||
if (sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) {
|
||||
sigdata->loop_start = dumbfile_igetl(file);
|
||||
|
||||
if (dumbfile_error(file) || (unsigned long)sigdata->loop_start >= (unsigned long)size) {
|
||||
free(sigdata->samples);
|
||||
free(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sigdata->flags & SAMPFLAG_LOOP)
|
||||
sigdata->loop_end = size;
|
||||
else {
|
||||
sigdata->loop_end = dumbfile_igetl(file);
|
||||
|
||||
if (dumbfile_error(file) || sigdata->loop_end <= sigdata->loop_start || sigdata->loop_end > size) {
|
||||
free(sigdata->samples);
|
||||
free(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sigdata->loop_start = 0;
|
||||
sigdata->loop_end = size;
|
||||
}
|
||||
|
||||
if (sigdata->flags & SAMPFLAG_16BIT) {
|
||||
for (n = 0; n < size; n++) {
|
||||
int m = dumbfile_igetw(file);
|
||||
if (m < 0) {
|
||||
free(sigdata->samples);
|
||||
free(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
sigdata->samples[n] = (int)(signed short)m << 8;
|
||||
}
|
||||
} else {
|
||||
for (n = 0; n < size; n++) {
|
||||
int m = dumbfile_getc(file);
|
||||
if (m < 0) {
|
||||
free(sigdata->samples);
|
||||
free(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
sigdata->samples[n] = (int)(signed char)m << 16;
|
||||
}
|
||||
}
|
||||
|
||||
return sigdata;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void sample_pickup(DUMB_RESAMPLER *r, void *data)
|
||||
{
|
||||
SAMPLE_SIGRENDERER *sigrenderer = data;
|
||||
|
||||
if (!(sigrenderer->sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP))) {
|
||||
r->dir = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(sigrenderer->sigdata->flags & SAMPFLAG_LOOP) && sigrenderer->n_loops == 0) {
|
||||
r->dir = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sigrenderer->sigdata->flags & SAMPFLAG_PINGPONG) {
|
||||
if (r->dir < 0) {
|
||||
r->pos = (r->start << 1) - 1 - r->pos;
|
||||
r->subpos ^= 65535;
|
||||
r->dir = 1;
|
||||
} else {
|
||||
r->pos = (r->end << 1) - 1 - r->pos;
|
||||
r->subpos ^= 65535;
|
||||
r->dir = -1;
|
||||
}
|
||||
} else
|
||||
r->pos -= r->end - r->start;
|
||||
|
||||
if (!(sigrenderer->sigdata->flags & SAMPFLAG_LOOP)) {
|
||||
if (sigrenderer->n_loops > 0) {
|
||||
sigrenderer->n_loops--;
|
||||
if (sigrenderer->n_loops == 0) {
|
||||
r->start = 0;
|
||||
r->end = sigrenderer->sigdata->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static sigrenderer_t *sample_start_sigrenderer(DUH *duh, sigdata_t *data, int n_channels, long pos)
|
||||
{
|
||||
SAMPLE_SIGDATA *sigdata = data;
|
||||
SAMPLE_SIGRENDERER *sigrenderer;
|
||||
|
||||
(void)duh;
|
||||
|
||||
sigrenderer = malloc(sizeof(*sigrenderer));
|
||||
if (!sigrenderer) return NULL;
|
||||
|
||||
sigrenderer->sigdata = data;
|
||||
sigrenderer->n_channels = n_channels;
|
||||
dumb_reset_resampler(&sigrenderer->r, sigdata->samples, pos, 0, sigdata->size);
|
||||
sigrenderer->r.pickup = &sample_pickup;
|
||||
sigrenderer->r.pickup_data = sigrenderer;
|
||||
sigrenderer->n_loops = 0;
|
||||
|
||||
return sigrenderer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
/* The name says it all ;-) */
|
||||
static void sample_cheap_low_pass_filter(sample *src, long size, float max_freq) {
|
||||
|
||||
long i;
|
||||
float fact = max_freq / 44100.0f;
|
||||
|
||||
for (i = 0; i < size-1; i++) {
|
||||
float d = src[i+1] - src[i];
|
||||
if (d > fact)
|
||||
src[i+1] += fact - d;
|
||||
else if (d < -fact)
|
||||
src[i+1] += -d - fact;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Dithering with noise shaping filter. Set shape = 0 for no shaping. */
|
||||
static void sample_dither_filter(float *src, long size, float shape) {
|
||||
float r1 = 0, r2 = 0;
|
||||
float s1 = 0, s2 = 0; /* Feedback buffer */
|
||||
float o = 0.5f / 255;
|
||||
float tmp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
r2 = r1;
|
||||
r1 = rand() / (float)RAND_MAX;
|
||||
|
||||
tmp = src[i] + shape * (s1 + s1 - s2);
|
||||
src[i] = tmp + o * (r1 - r2);
|
||||
src[i] = MID(-1.0f, src[i], 1.0f);
|
||||
|
||||
s2 = s1;
|
||||
s1 = tmp - src[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static void sample_sigrenderer_set_sigparam(sigrenderer_t *data, unsigned char id, long value)
|
||||
{
|
||||
SAMPLE_SIGRENDERER *sigrenderer = data;
|
||||
|
||||
if (id == SAMPPARAM_N_LOOPS) {
|
||||
if ((sigrenderer->sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) == SAMPFLAG_XLOOP) {
|
||||
sigrenderer->n_loops += value;
|
||||
sigrenderer->r.start = sigrenderer->n_loops ? sigrenderer->sigdata->loop_start : 0;
|
||||
sigrenderer->r.end = sigrenderer->n_loops ? sigrenderer->sigdata->loop_end : sigrenderer->sigdata->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static long sample_sigrenderer_get_samples(
|
||||
sigrenderer_t *data,
|
||||
float volume, float delta,
|
||||
long size, sample_t **samples
|
||||
)
|
||||
{
|
||||
SAMPLE_SIGRENDERER *sigrenderer = data;
|
||||
|
||||
DUMB_RESAMPLER initial_r = sigrenderer->r;
|
||||
|
||||
long s = dumb_resample(&sigrenderer->r, samples[0], size, volume, delta);
|
||||
|
||||
int n;
|
||||
for (n = 1; n < sigrenderer->n_channels; n++) {
|
||||
sigrenderer->r = initial_r;
|
||||
dumb_resample(&sigrenderer->r, samples[n], size, volume, delta);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void sample_sigrenderer_get_current_sample(sigrenderer_t *data, float volume, sample_t *samples)
|
||||
{
|
||||
SAMPLE_SIGRENDERER *sigrenderer = data;
|
||||
int n;
|
||||
for (n = 0; n < sigrenderer->n_channels; n++)
|
||||
samples[n] = dumb_resample_get_current_sample(&sigrenderer->r, volume);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void sample_end_sigrenderer(sigrenderer_t *sigrenderer)
|
||||
{
|
||||
free(sigrenderer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void sample_unload_sigdata(sigdata_t *data)
|
||||
{
|
||||
SAMPLE_SIGDATA *sigdata = data;
|
||||
free(sigdata->samples);
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static DUH_SIGTYPE_DESC sigtype_sample = {
|
||||
SIGTYPE_SAMPLE,
|
||||
&sample_load_sigdata,
|
||||
&sample_start_sigrenderer,
|
||||
&sample_sigrenderer_set_sigparam,
|
||||
&sample_sigrenderer_get_samples,
|
||||
&sample_sigrenderer_get_current_sample,
|
||||
&sample_end_sigrenderer,
|
||||
&sample_unload_sigdata
|
||||
};
|
||||
|
||||
|
||||
|
||||
void dumb_register_sigtype_sample(void)
|
||||
{
|
||||
dumb_register_sigtype(&sigtype_sample);
|
||||
}
|
|
@ -1,592 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* sequence.c - The sequence (SEQU) signal type. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
#define SIGTYPE_SEQUENCE DUMB_ID('S','E','Q','U')
|
||||
|
||||
|
||||
|
||||
/* We have 256 intervals per semitone, 12 * 256 per octave
|
||||
2 ** (1 / (12 * 256)) = 1.000225659305069791926712241547647863626
|
||||
|
||||
pow(DUMB_PITCH_BASE, x) = 1.5
|
||||
x = log2(1.5) / log2(DUMB_PITCH_BASE)
|
||||
x = log2(1.5) * 12 * 256
|
||||
x = 1797.004802
|
||||
cf.
|
||||
x = 7 * 256 = 1792
|
||||
|
||||
so, for the perfect fifth temperament, use an interval of 1797.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Sequencing format
|
||||
* -----------------
|
||||
*
|
||||
* NOTE: A LOT OF THIS IS NOW REDUNDANT. PLEASE REFER TO duhspecs.txt.
|
||||
*
|
||||
* When a signal is initiated, it claims a reference number. If any other
|
||||
* currently playing signal has the same number, that signal becomes
|
||||
* anonymous and inaccessible; that is, if multiple signals were initiated
|
||||
* with the same reference, the reference belongs to the most recent.
|
||||
*
|
||||
* Signals can be stopped, or have their pitch, volume or parameters changed,
|
||||
* using the reference number. A signal may stop prematurely if it runs out
|
||||
* of data, in which case the reference number becomes void, and operations
|
||||
* on it will be ignored. Such a situation will not flag any kind of warning,
|
||||
* since it may be the result of inaccuracies when resampling.
|
||||
*
|
||||
* The sequence consists of a series of commands. All commands begin with a
|
||||
* long int, which is the time to wait after the last command (or the
|
||||
* beginning of the sequence) before executing this command. 65536 represents
|
||||
* one second. A time of -1 (or in fact any negative time) terminates the
|
||||
* sequence, but any currently playing signals will continue until they run
|
||||
* out. Make sure no non-terminating signals are playing when the sequence
|
||||
* ends!
|
||||
*
|
||||
* The time, if nonnegative, is followed by one byte indicating the type of
|
||||
* command. This byte can have the following values:
|
||||
*
|
||||
* SEQUENCE_START_SIGNAL
|
||||
* unsigned char ref; - Reference. Need more than 256? Use two sequences,
|
||||
* and get your brain seen to.
|
||||
* int sig; - The index of the signal to initiate.
|
||||
* long pos; - The position at which to start. 65536 represents one second.
|
||||
* unsigned short volume; - Volume. 65535 represents the maximum volume, so
|
||||
* you will want to go lower than this if you are
|
||||
* playing more than one signal at once.
|
||||
* signed short pitch; - Pitch. 0 represents a frequency of 65536 Hz. Scale
|
||||
* is logarithmic. Add 256 to increase pitch by one
|
||||
* semitone in the even temperament, or add 12*256 to
|
||||
* increase pitch by one octave in any temperament
|
||||
* (i.e. double the frequency).
|
||||
*
|
||||
* SEQUENCE_SET_VOLUME
|
||||
* unsigned char ref;
|
||||
* unsigned short volume;
|
||||
*
|
||||
* SEQUENCE_SET_PITCH
|
||||
* unsigned char ref;
|
||||
* signed short pitch;
|
||||
*
|
||||
* SEQUENCE_SET_PARAMETER
|
||||
* unsigned char ref;
|
||||
* unsigned char id;
|
||||
* long value;
|
||||
* - see the description of the set_parameter function pointer for
|
||||
* information on 'id' and 'value'.
|
||||
*
|
||||
* SEQUENCE_STOP_SIGNAL
|
||||
* unsigned char ref;
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define SEQUENCE_START_SIGNAL 0
|
||||
#define SEQUENCE_SET_VOLUME 1
|
||||
#define SEQUENCE_SET_PITCH 2
|
||||
#define SEQUENCE_SET_PARAMETER 3
|
||||
#define SEQUENCE_STOP_SIGNAL 4
|
||||
|
||||
|
||||
|
||||
typedef struct SEQUENCE_PLAYING
|
||||
{
|
||||
struct SEQUENCE_PLAYING *next;
|
||||
|
||||
DUH_SIGNAL_SAMPINFO *sampinfo;
|
||||
|
||||
int ref;
|
||||
|
||||
int pitch;
|
||||
int volume;
|
||||
}
|
||||
SEQUENCE_PLAYING;
|
||||
|
||||
|
||||
|
||||
typedef struct SEQUENCE_SAMPINFO
|
||||
{
|
||||
DUH *duh;
|
||||
|
||||
int n_channels;
|
||||
|
||||
unsigned char *signal;
|
||||
|
||||
long time_left;
|
||||
int sub_time_left;
|
||||
|
||||
SEQUENCE_PLAYING *playing;
|
||||
}
|
||||
SEQUENCE_SAMPINFO;
|
||||
|
||||
|
||||
|
||||
#define sequence_c(signal) ((int)*((*(signal))++))
|
||||
|
||||
|
||||
static int sequence_w(unsigned char **signal)
|
||||
{
|
||||
int v = (*signal)[0] | ((*signal)[1] << 8);
|
||||
*signal += 2;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
static long sequence_l(unsigned char **signal)
|
||||
{
|
||||
long v = (*signal)[0] | ((*signal)[1] << 8) | ((*signal)[2] << 16) | ((*signal)[3] << 24);
|
||||
*signal += 4;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
static long sequence_cl(unsigned char **signal)
|
||||
{
|
||||
long v = sequence_c(signal);
|
||||
if (v & 0x80) {
|
||||
v &= 0x7F;
|
||||
v |= sequence_c(signal) << 7;
|
||||
if (v & 0x4000) {
|
||||
v &= 0x3FFF;
|
||||
v |= sequence_c(signal) << 14;
|
||||
if (v & 0x200000) {
|
||||
v &= 0x1FFFFF;
|
||||
v |= sequence_c(signal) << 21;
|
||||
if (v & 0x10000000) {
|
||||
v &= 0x0FFFFFFF;
|
||||
v |= sequence_c(signal) << 28;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void *sequence_load_signal(DUH *duh, DUMBFILE *file)
|
||||
{
|
||||
long size;
|
||||
unsigned char *signal;
|
||||
|
||||
(void)duh;
|
||||
|
||||
size = dumbfile_igetl(file);
|
||||
if (dumbfile_error(file) || size <= 0)
|
||||
return NULL;
|
||||
|
||||
signal = malloc(size);
|
||||
if (!signal)
|
||||
return NULL;
|
||||
|
||||
if (dumbfile_getnc((char *)signal, size, file) < size) {
|
||||
free(signal);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static long render(
|
||||
SEQUENCE_SAMPINFO *sampinfo,
|
||||
float volume, float delta,
|
||||
long pos, long size, sample_t **samples
|
||||
)
|
||||
{
|
||||
sample_t **splptr;
|
||||
|
||||
SEQUENCE_PLAYING **playing_p = &sampinfo->playing;
|
||||
|
||||
long max_size = 0;
|
||||
long part_size;
|
||||
|
||||
int n;
|
||||
long i;
|
||||
|
||||
for (n = 0; n < sampinfo->n_channels; n++)
|
||||
memset(samples[n] + pos, 0, size * sizeof(sample_t));
|
||||
|
||||
splptr = malloc(sampinfo->n_channels * sizeof(*splptr));
|
||||
if (!splptr)
|
||||
return 0;
|
||||
|
||||
splptr[0] = malloc(sampinfo->n_channels * size * sizeof(sample_t));
|
||||
if (!splptr[0]) {
|
||||
free(splptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (n = 1; n < sampinfo->n_channels; n++)
|
||||
splptr[n] = splptr[n - 1] + size;
|
||||
|
||||
while (*playing_p) {
|
||||
SEQUENCE_PLAYING *playing = *playing_p;
|
||||
|
||||
part_size = duh_signal_render_samples(
|
||||
playing->sampinfo,
|
||||
volume * (float)playing->volume * (1.0f / 65535.0f),
|
||||
(float)(pow(DUMB_PITCH_BASE, playing->pitch) * delta),
|
||||
size, splptr
|
||||
);
|
||||
|
||||
for (n = 0; n < sampinfo->n_channels; n++)
|
||||
for (i = 0; i < part_size; i++)
|
||||
samples[n][pos+i] += splptr[n][i];
|
||||
|
||||
if (part_size > max_size)
|
||||
max_size = part_size;
|
||||
|
||||
if (part_size < size) {
|
||||
*playing_p = playing->next;
|
||||
duh_signal_end_samples(playing->sampinfo);
|
||||
free(playing);
|
||||
} else
|
||||
playing_p = &playing->next;
|
||||
}
|
||||
|
||||
free(splptr[0]);
|
||||
free(splptr);
|
||||
|
||||
return max_size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 'offset' is added to the position at which the signal should start. It is
|
||||
* currently assumed to be positive, and is currently only used when seeking
|
||||
* forwards in the sequence.
|
||||
*/
|
||||
static void sequence_command(SEQUENCE_SAMPINFO *sampinfo, long offset)
|
||||
{
|
||||
int command = sequence_c(&sampinfo->signal);
|
||||
|
||||
if (command == SEQUENCE_START_SIGNAL) {
|
||||
|
||||
int ref = sequence_c(&sampinfo->signal);
|
||||
int sig = sequence_cl(&sampinfo->signal);
|
||||
long pos = sequence_cl(&sampinfo->signal);
|
||||
int volume = sequence_w(&sampinfo->signal);
|
||||
int pitch = (int)(signed short)sequence_w(&sampinfo->signal);
|
||||
|
||||
SEQUENCE_PLAYING *playing = sampinfo->playing;
|
||||
|
||||
while (playing) {
|
||||
if (playing->ref == ref)
|
||||
playing->ref = -1;
|
||||
playing = playing->next;
|
||||
}
|
||||
|
||||
playing = malloc(sizeof(SEQUENCE_PLAYING));
|
||||
|
||||
if (playing) {
|
||||
playing->sampinfo = duh_signal_start_samples(sampinfo->duh, sig, sampinfo->n_channels, pos + offset);
|
||||
|
||||
if (playing->sampinfo) {
|
||||
playing->ref = ref;
|
||||
playing->pitch = pitch;
|
||||
playing->volume = volume;
|
||||
|
||||
playing->next = sampinfo->playing;
|
||||
sampinfo->playing = playing;
|
||||
} else
|
||||
free(playing);
|
||||
}
|
||||
|
||||
} else if (command == SEQUENCE_SET_VOLUME) {
|
||||
|
||||
int ref = sequence_c(&sampinfo->signal);
|
||||
int volume = sequence_w(&sampinfo->signal);
|
||||
|
||||
SEQUENCE_PLAYING *playing = sampinfo->playing;
|
||||
|
||||
while (playing) {
|
||||
if (playing->ref == ref) {
|
||||
playing->volume = volume;
|
||||
break;
|
||||
}
|
||||
playing = playing->next;
|
||||
}
|
||||
|
||||
} else if (command == SEQUENCE_SET_PITCH) {
|
||||
|
||||
int ref = sequence_c(&sampinfo->signal);
|
||||
int pitch = (int)(signed short)sequence_w(&sampinfo->signal);
|
||||
|
||||
SEQUENCE_PLAYING *playing = sampinfo->playing;
|
||||
|
||||
while (playing) {
|
||||
if (playing->ref == ref) {
|
||||
playing->pitch = pitch;
|
||||
break;
|
||||
}
|
||||
playing = playing->next;
|
||||
}
|
||||
|
||||
} else if (command == SEQUENCE_SET_PARAMETER) {
|
||||
|
||||
int ref = sequence_c(&sampinfo->signal);
|
||||
unsigned char id = sequence_c(&sampinfo->signal);
|
||||
long value = sequence_l(&sampinfo->signal);
|
||||
|
||||
SEQUENCE_PLAYING *playing = sampinfo->playing;
|
||||
|
||||
while (playing) {
|
||||
if (playing->ref == ref) {
|
||||
duh_signal_set_parameter(playing->sampinfo, id, value);
|
||||
break;
|
||||
}
|
||||
playing = playing->next;
|
||||
}
|
||||
|
||||
} else if (command == SEQUENCE_STOP_SIGNAL) {
|
||||
|
||||
int ref = sequence_c(&sampinfo->signal);
|
||||
|
||||
SEQUENCE_PLAYING **playing_p = &sampinfo->playing;
|
||||
|
||||
while (*playing_p) {
|
||||
SEQUENCE_PLAYING *playing = *playing_p;
|
||||
|
||||
if (playing->ref == ref) {
|
||||
duh_signal_end_samples(playing->sampinfo);
|
||||
*playing_p = playing->next;
|
||||
free(playing);
|
||||
break;
|
||||
}
|
||||
|
||||
playing_p = &playing->next;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
TRACE("Error in sequence: unknown command %d.\n", command);
|
||||
sampinfo->signal = NULL;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void *sequence_start_samples(DUH *duh, void *signal, int n_channels, long pos)
|
||||
{
|
||||
SEQUENCE_SAMPINFO *sampinfo;
|
||||
long time = sequence_cl((unsigned char **)&signal);
|
||||
|
||||
if (time < 0)
|
||||
return NULL;
|
||||
|
||||
sampinfo = malloc(sizeof(SEQUENCE_SAMPINFO));
|
||||
if (!sampinfo)
|
||||
return NULL;
|
||||
|
||||
sampinfo->duh = duh;
|
||||
sampinfo->n_channels = n_channels;
|
||||
sampinfo->signal = signal;
|
||||
sampinfo->playing = NULL;
|
||||
|
||||
/* Seek to 'pos'. */
|
||||
while (time < pos) {
|
||||
pos -= time;
|
||||
|
||||
sequence_command(sampinfo, pos);
|
||||
|
||||
time = sequence_cl(&sampinfo->signal);
|
||||
|
||||
if (time < 0) {
|
||||
sampinfo->signal = NULL;
|
||||
return sampinfo;
|
||||
}
|
||||
}
|
||||
|
||||
sampinfo->time_left = time - pos;
|
||||
sampinfo->sub_time_left = 0;
|
||||
|
||||
return sampinfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static long sequence_render_samples(
|
||||
void *sampinfo,
|
||||
float volume, float delta,
|
||||
long size, sample_t **samples
|
||||
)
|
||||
{
|
||||
|
||||
#define sampinfo ((SEQUENCE_SAMPINFO *)sampinfo)
|
||||
|
||||
long pos = 0;
|
||||
|
||||
int dt = (int)(delta * 65536.0f + 0.5f);
|
||||
|
||||
long todo;
|
||||
LONG_LONG t;
|
||||
|
||||
while (sampinfo->signal) {
|
||||
todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt);
|
||||
|
||||
if (todo >= size)
|
||||
break;
|
||||
|
||||
if (todo) {
|
||||
render(sampinfo, volume, delta, pos, todo, samples);
|
||||
|
||||
pos += todo;
|
||||
size -= todo;
|
||||
|
||||
todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt);
|
||||
t = sampinfo->sub_time_left - (LONG_LONG)todo * dt;
|
||||
sampinfo->sub_time_left = (long)t & 65535;
|
||||
sampinfo->time_left += (long)(t >> 16);
|
||||
}
|
||||
|
||||
sequence_command(sampinfo, 0);
|
||||
|
||||
todo = sequence_cl(&sampinfo->signal);
|
||||
|
||||
if (todo >= 0)
|
||||
sampinfo->time_left += todo;
|
||||
else
|
||||
sampinfo->signal = NULL;
|
||||
}
|
||||
|
||||
if (sampinfo->signal) {
|
||||
render(sampinfo, volume, delta, pos, size, samples);
|
||||
|
||||
pos += size;
|
||||
|
||||
t = sampinfo->sub_time_left - (LONG_LONG)size * dt;
|
||||
sampinfo->sub_time_left = (long)t & 65535;
|
||||
sampinfo->time_left += (long)(t >> 16);
|
||||
} else
|
||||
pos += render(sampinfo, volume, delta, pos, size, samples);
|
||||
|
||||
return pos;
|
||||
|
||||
|
||||
/** WARNING - remove this... */
|
||||
#if 0
|
||||
float size_unified = size * delta;
|
||||
|
||||
int n;
|
||||
|
||||
sample_t **samples2 = malloc(sampinfo->n_channels * sizeof(*samples2));
|
||||
memcpy(samples2, samples, sampinfo->n_channels * sizeof(*samples2));
|
||||
|
||||
while (sampinfo->signal && sampinfo->time < size_unified) {
|
||||
|
||||
{
|
||||
long sz = (long)(sampinfo->time / delta);
|
||||
|
||||
if (sz)
|
||||
render(sampinfo, volume, delta, sz, samples2);
|
||||
|
||||
for (n = 0; n < sampinfo->n_channels; n++)
|
||||
samples2[n] += sz;
|
||||
|
||||
size -= sz;
|
||||
pos += sz;
|
||||
|
||||
sampinfo->time -= sz * delta;
|
||||
}
|
||||
|
||||
sequence_command(sampinfo, 0);
|
||||
|
||||
{
|
||||
long time = sequence_cl(&sampinfo->signal);
|
||||
|
||||
if (time >= 0)
|
||||
sampinfo->time += (float)time;
|
||||
else
|
||||
sampinfo->signal = NULL;
|
||||
}
|
||||
|
||||
size_unified = size * delta;
|
||||
}
|
||||
|
||||
if (sampinfo->signal) {
|
||||
render(sampinfo, volume, delta, size, samples2);
|
||||
sampinfo->time -= size_unified;
|
||||
pos += size;
|
||||
} else
|
||||
pos += render(sampinfo, volume, delta, size, samples2);
|
||||
|
||||
free(samples2);
|
||||
|
||||
return pos;
|
||||
#endif
|
||||
|
||||
#undef sampinfo
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void sequence_end_samples(void *sampinfo)
|
||||
{
|
||||
SEQUENCE_PLAYING *playing = ((SEQUENCE_SAMPINFO *)sampinfo)->playing;
|
||||
|
||||
while (playing) {
|
||||
SEQUENCE_PLAYING *next = playing->next;
|
||||
|
||||
duh_signal_end_samples(playing->sampinfo);
|
||||
free(playing);
|
||||
|
||||
playing = next;
|
||||
}
|
||||
|
||||
free(sampinfo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void sequence_unload_signal(void *signal)
|
||||
{
|
||||
free(signal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static DUH_SIGTYPE_DESC sigtype_sequence = {
|
||||
SIGTYPE_SEQUENCE,
|
||||
&sequence_load_signal,
|
||||
&sequence_start_samples,
|
||||
NULL,
|
||||
&sequence_render_samples,
|
||||
&sequence_end_samples,
|
||||
&sequence_unload_signal
|
||||
};
|
||||
|
||||
|
||||
|
||||
void dumb_register_sigtype_sequence(void)
|
||||
{
|
||||
dumb_register_sigtype(&sigtype_sequence);
|
||||
}
|
|
@ -1,206 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* sterpan.c - The stereo pan (SPAN) signal type. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* This takes a single monaural signal and | \ / /
|
||||
* expands it to two channels, applying a | ' /
|
||||
* stereo pan in the process. The stereo pan \__/
|
||||
* is generated by delaying and damping the
|
||||
* channel opposite the sound source. If only
|
||||
* one channel is requested of this signal, it will simply chain to the other
|
||||
* signal.
|
||||
*
|
||||
* In order for the delay to work properly, this must be played at 65536 Hz.
|
||||
* The pitch at which you want the sample to play can be passed in parameter
|
||||
* #1. Parameter #0 specifies the panning position, -256 to 256.
|
||||
*
|
||||
* NOTE: THIS IS NOT HOW IT WORKS AT THE MOMENT. AT THE MOMENT, THIS ROUTINE
|
||||
* SIMPLY VARIES THE VOLUMES.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
#define SIGTYPE_STEREOPAN DUMB_ID('S','P','A','N')
|
||||
|
||||
|
||||
|
||||
#define SPANPARAM_PAN 0
|
||||
|
||||
|
||||
|
||||
typedef struct STEREOPAN_SIGNAL
|
||||
{
|
||||
int sig;
|
||||
}
|
||||
STEREOPAN_SIGNAL;
|
||||
|
||||
|
||||
|
||||
typedef struct STEREOPAN_SAMPINFO
|
||||
{
|
||||
float pan;
|
||||
int stereo;
|
||||
DUH_SIGNAL_SAMPINFO *csampinfo;
|
||||
}
|
||||
STEREOPAN_SAMPINFO;
|
||||
|
||||
|
||||
|
||||
static void *stereopan_load_signal(DUH *duh, DUMBFILE *file)
|
||||
{
|
||||
STEREOPAN_SIGNAL *signal;
|
||||
|
||||
(void)duh;
|
||||
|
||||
signal = malloc(sizeof(*signal));
|
||||
|
||||
if (!signal)
|
||||
return NULL;
|
||||
|
||||
signal->sig = dumbfile_igetl(file);
|
||||
|
||||
if (dumbfile_error(file)) {
|
||||
free(signal);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void *stereopan_start_samples(DUH *duh, void *signal, int n_channels, long pos)
|
||||
{
|
||||
STEREOPAN_SAMPINFO *sampinfo;
|
||||
|
||||
#define signal ((STEREOPAN_SIGNAL *)signal)
|
||||
|
||||
if ((unsigned int)(n_channels - 1) >= 2) {
|
||||
TRACE("Stereo pan signal requiring 1 or 2 channels called with %d channels.\n", n_channels);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sampinfo = malloc(sizeof(*sampinfo));
|
||||
if (!sampinfo)
|
||||
return NULL;
|
||||
|
||||
sampinfo->pan = 0;
|
||||
|
||||
sampinfo->stereo = n_channels - 1;
|
||||
|
||||
sampinfo->csampinfo = duh_signal_start_samples(duh, signal->sig, 1, pos);
|
||||
if (!sampinfo->csampinfo) {
|
||||
free(sampinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#undef signal
|
||||
|
||||
return sampinfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void stereopan_set_parameter(void *sampinfo, unsigned char id, long value)
|
||||
{
|
||||
#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo)
|
||||
|
||||
if (id == SPANPARAM_PAN && value >= -256 && value <= 256)
|
||||
sampinfo->pan = value * (1.0f / 256.0f);
|
||||
|
||||
#undef sampinfo
|
||||
}
|
||||
|
||||
|
||||
|
||||
static long stereopan_render_samples(
|
||||
void *sampinfo,
|
||||
float volume, float delta,
|
||||
long size, sample_t **samples
|
||||
)
|
||||
{
|
||||
#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo)
|
||||
|
||||
if (!sampinfo->stereo)
|
||||
return duh_signal_render_samples(sampinfo->csampinfo, volume, delta, size, samples);
|
||||
|
||||
if (sampinfo->pan >= 0) {
|
||||
long sz = duh_signal_render_samples(sampinfo->csampinfo, volume * (1.0f + sampinfo->pan), delta, size, samples + 1);
|
||||
long s;
|
||||
int vol;
|
||||
|
||||
volume = (1.0f - sampinfo->pan) / (1.0f + sampinfo->pan);
|
||||
vol = (int)(volume * 65536 + 0.5);
|
||||
|
||||
for (s = 0; s < sz; s++)
|
||||
samples[0][s] = (samples[1][s] * vol) >> 16;
|
||||
|
||||
return sz;
|
||||
} else {
|
||||
long sz = duh_signal_render_samples(sampinfo->csampinfo, volume * (1.0f - sampinfo->pan), delta, size, samples);
|
||||
long s;
|
||||
int vol;
|
||||
|
||||
volume = (1.0f + sampinfo->pan) / (1.0f - sampinfo->pan);
|
||||
vol = (int)(volume * 65536 + 0.5);
|
||||
|
||||
for (s = 0; s < sz; s++)
|
||||
samples[1][s] = (samples[0][s] * vol) >> 16;
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
#undef sampinfo
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void stereopan_end_samples(void *sampinfo)
|
||||
{
|
||||
#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo)
|
||||
|
||||
duh_signal_end_samples(sampinfo->csampinfo);
|
||||
free(sampinfo);
|
||||
|
||||
#undef sampinfo
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void stereopan_unload_signal(void *signal)
|
||||
{
|
||||
free(signal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static DUH_SIGTYPE_DESC sigtype_stereopan = {
|
||||
SIGTYPE_STEREOPAN,
|
||||
&stereopan_load_signal,
|
||||
&stereopan_start_samples,
|
||||
&stereopan_set_parameter,
|
||||
&stereopan_render_samples,
|
||||
&stereopan_end_samples,
|
||||
&stereopan_unload_signal
|
||||
};
|
||||
|
||||
|
||||
|
||||
void dumb_register_sigtype_stereopan(void)
|
||||
{
|
||||
dumb_register_sigtype(&sigtype_stereopan);
|
||||
}
|
|
@ -1,824 +0,0 @@
|
|||
#ifdef FORTIFY
|
||||
#include "fortify.h"
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef MSS
|
||||
#include "mss.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "allegro.h"
|
||||
#include "modulus.h"
|
||||
#include "typedef.hpp"
|
||||
|
||||
int detect_it(char *f) {
|
||||
int sig;
|
||||
PACKFILE *fn = pack_fopen(f, "rb");
|
||||
|
||||
if (fn == NULL)
|
||||
return FALSE;
|
||||
|
||||
sig = pack_mgetl(fn);
|
||||
if (sig != AL_ID('I','M','P','M')) {
|
||||
pack_fclose(fn);
|
||||
return FALSE;
|
||||
}
|
||||
pack_fclose(fn);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MODULUS *create_it() {
|
||||
MODULUS *m = (MODULUS*)malloc(sizeof(MODULUS));
|
||||
if (!m)
|
||||
return NULL;
|
||||
memset(m, 0, sizeof(MODULUS));
|
||||
return m;
|
||||
}
|
||||
|
||||
void destroy_it(MODULUS *j) {
|
||||
|
||||
if (song->Music == j)
|
||||
stop_it();
|
||||
|
||||
//remove patterns:
|
||||
for (int i=0; i<j->NumPatterns; i++) {
|
||||
free(j->Pattern[i].Note);
|
||||
}
|
||||
if (j->Pattern)
|
||||
free(j->Pattern);
|
||||
//remove instruments;
|
||||
if (j->Instrument)
|
||||
free(j->Instrument);
|
||||
//remove samples;
|
||||
for (int i=0; i<j->NumSamples; i++) {
|
||||
destroy_sample(j->Sample[i].Sample);
|
||||
}
|
||||
if (j->Sample)
|
||||
free(j->Sample);
|
||||
//remove orders:
|
||||
if (j->Order)
|
||||
free(j->Order);
|
||||
//remove channels:
|
||||
for (int i=0; i<64; i++) {
|
||||
if (j->Channel[i].VChannel) {
|
||||
MODULUS_VCHANNEL *vchn = song->Music->Channel[i].VChannel;
|
||||
MODULUS_VCHANNEL *prev = NULL;
|
||||
|
||||
if (!vchn)
|
||||
continue;
|
||||
|
||||
for (;;) {
|
||||
deallocate_voice(vchn->voice);
|
||||
|
||||
prev = vchn;
|
||||
vchn = vchn->next;
|
||||
free(prev);
|
||||
|
||||
if (!vchn)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(j);
|
||||
}
|
||||
|
||||
//#define DEBUG_IT_SIZE
|
||||
|
||||
int get_module_size(MODULUS *j) {
|
||||
int a, b, c, d = 0, e;
|
||||
a = sizeof(MODULUS) + j->NumOrders;
|
||||
b = j->NumInstruments * sizeof(MODULUS_INSTRUMENT);
|
||||
c = j->NumSamples * sizeof(MODULUS_SAMPLE);
|
||||
|
||||
for (int i=0; i<j->NumSamples; i++)
|
||||
d += j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1);
|
||||
|
||||
e = 4 + sizeof(MODULUS_PATTERN) * j->NumPatterns;
|
||||
|
||||
for (int i=0; i<j->NumPatterns; i++)
|
||||
e += j->Pattern[i].NumNotes * sizeof(MODULUS_NOTE);
|
||||
#ifdef DEBUG_IT_SIZE
|
||||
printf("Base: %i, Instruments(%i): %i, Samples(%i): %i, Data: %i, Patterns(%i): %i\n", a, j->NumInstruments, b, j->NumSamples, c, d, j->NumPatterns, e);
|
||||
#endif
|
||||
|
||||
return a+b+c+d+e;
|
||||
}
|
||||
|
||||
#define MAX_IT_CHN 64
|
||||
|
||||
//#define DEBUG_HEADER
|
||||
//#define DEBUG_INSTRUMENTS
|
||||
//#define DEBUG_SAMPLES
|
||||
//#define DEBUG_PATTERNS
|
||||
|
||||
static dword *sourcebuf = NULL;
|
||||
static dword *sourcepos = NULL;
|
||||
static byte rembits = 0;
|
||||
|
||||
int readblock(PACKFILE *f) {
|
||||
long size;
|
||||
int c = pack_igetw(f);
|
||||
if (c == -1)
|
||||
return 0;
|
||||
size = c;
|
||||
|
||||
sourcebuf = (dword*)malloc(size+4);
|
||||
if (!sourcebuf)
|
||||
return 0;
|
||||
|
||||
c = pack_fread(sourcebuf, size, f);
|
||||
if (c < 1) {
|
||||
free(sourcebuf);
|
||||
sourcebuf = NULL;
|
||||
return 0;
|
||||
}
|
||||
sourcepos = sourcebuf;
|
||||
rembits = 32;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void freeblock() {
|
||||
if (sourcebuf)
|
||||
free(sourcebuf);
|
||||
sourcebuf = NULL;
|
||||
}
|
||||
|
||||
dword readbits(char b) {
|
||||
dword val;
|
||||
if (b <= rembits) {
|
||||
val = *sourcepos & ((1 << b) - 1);
|
||||
*sourcepos >>= b;
|
||||
rembits -= b;
|
||||
}
|
||||
else {
|
||||
dword nbits = b - rembits;
|
||||
val = *sourcepos;
|
||||
sourcepos++;
|
||||
val |= ((*sourcepos & ((1 << nbits) - 1)) << rembits);
|
||||
*sourcepos >>= nbits;
|
||||
rembits = 32 - nbits;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void decompress8(PACKFILE *f, void *data, int len, int tver) {
|
||||
char *destbuf = (char*)data;
|
||||
char *destpos = destbuf;
|
||||
int blocklen, blockpos;
|
||||
byte bitwidth;
|
||||
word val;
|
||||
char d1, d2;
|
||||
|
||||
memset(destbuf, 0, len);
|
||||
|
||||
while (len>0) {
|
||||
//Read a block of compressed data:
|
||||
if (!readblock(f))
|
||||
return;
|
||||
//Set up a few variables
|
||||
blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes
|
||||
blockpos = 0;
|
||||
bitwidth = 9;
|
||||
d1 = d2 = 0;
|
||||
//Start the decompression:
|
||||
while (blockpos < blocklen) {
|
||||
//Read a value:
|
||||
val = readbits(bitwidth);
|
||||
//Check for bit width change:
|
||||
|
||||
if (bitwidth < 7) { //Method 1:
|
||||
if (val == (1 << (bitwidth - 1))) {
|
||||
val = readbits(3) + 1;
|
||||
bitwidth = (val < bitwidth) ? val : val + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (bitwidth < 9) { //Method 2
|
||||
byte border = (0xFF >> (9 - bitwidth)) - 4;
|
||||
|
||||
if (val > border && val <= (border + 8)) {
|
||||
val -= border;
|
||||
bitwidth = (val < bitwidth) ? val : val + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (bitwidth == 9) { //Method 3
|
||||
if (val & 0x100) {
|
||||
bitwidth = (val + 1) & 0xFF;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else { //Illegal width, abort ?
|
||||
freeblock();
|
||||
return;
|
||||
}
|
||||
|
||||
//Expand the value to signed byte:
|
||||
char v; //The sample value:
|
||||
if (bitwidth < 8) {
|
||||
byte shift = 8 - bitwidth;
|
||||
v = (val << shift);
|
||||
v >>= shift;
|
||||
}
|
||||
else
|
||||
v = (char)val;
|
||||
|
||||
//And integrate the sample value
|
||||
//(It always has to end with integration doesn't it ? ;-)
|
||||
d1 += v;
|
||||
d2 += d1;
|
||||
|
||||
//Store !
|
||||
*destpos = ((tver == 0x215) ? d2 : d1);
|
||||
destpos++;
|
||||
blockpos++;
|
||||
}
|
||||
freeblock();
|
||||
len -= blocklen;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void decompress16(PACKFILE *f, void *data, int len, int tver) {
|
||||
//make the output buffer:
|
||||
short *destbuf = (short*)data;
|
||||
short *destpos = destbuf;
|
||||
int blocklen, blockpos;
|
||||
byte bitwidth;
|
||||
long val;
|
||||
short d1, d2;
|
||||
|
||||
memset(destbuf, 0, len);
|
||||
|
||||
while (len>0) {
|
||||
//Read a block of compressed data:
|
||||
if (!readblock(f))
|
||||
return;
|
||||
//Set up a few variables
|
||||
blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes
|
||||
blockpos = 0;
|
||||
bitwidth = 17;
|
||||
d1 = d2 = 0;
|
||||
//Start the decompression:
|
||||
while (blockpos < blocklen) {
|
||||
val = readbits(bitwidth);
|
||||
//Check for bit width change:
|
||||
|
||||
if (bitwidth < 7) { //Method 1:
|
||||
if (val == (1 << (bitwidth - 1))) {
|
||||
val = readbits(4) + 1;
|
||||
bitwidth = (val < bitwidth) ? val : val + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (bitwidth < 17) { //Method 2
|
||||
word border = (0xFFFF >> (17 - bitwidth)) - 8;
|
||||
|
||||
if (val > border && val <= (border + 16)) {
|
||||
val -= border;
|
||||
bitwidth = val < bitwidth ? val : val + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (bitwidth == 17) { //Method 3
|
||||
if (val & 0x10000) {
|
||||
bitwidth = (val + 1) & 0xFF;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else { //Illegal width, abort ?
|
||||
freeblock();
|
||||
return;
|
||||
}
|
||||
|
||||
//Expand the value to signed byte:
|
||||
short v; //The sample value:
|
||||
if (bitwidth < 16) {
|
||||
byte shift = 16 - bitwidth;
|
||||
v = (val << shift);
|
||||
v >>= shift;
|
||||
}
|
||||
else
|
||||
v = (short)val;
|
||||
|
||||
//And integrate the sample value
|
||||
//(It always has to end with integration doesn't it ? ;-)
|
||||
d1 += v;
|
||||
d2 += d1;
|
||||
|
||||
//Store !
|
||||
*destpos = ((tver == 0x215) ? d2 : d1);
|
||||
destpos++;
|
||||
blockpos++;
|
||||
}
|
||||
freeblock();
|
||||
len -= blocklen;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
MODULUS *load_it(char *file) {
|
||||
PACKFILE *f;
|
||||
MODULUS *j = create_it();
|
||||
int tver, tver2, flag, msglen, msgoffs;
|
||||
int *insoffs = NULL, *samoffs = NULL, *patoffs = NULL;
|
||||
|
||||
if (!j)
|
||||
return NULL;
|
||||
|
||||
if (!detect_it(file))
|
||||
return NULL;
|
||||
|
||||
f = pack_fopen(file, "rb");
|
||||
|
||||
if (!f) {
|
||||
#ifdef DEBUG_HEADER
|
||||
printf("Error Opening!\n");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pack_fseek(f, 30);
|
||||
pack_igetw(f); //I have no idea...
|
||||
|
||||
j->NumOrders = pack_igetw(f);
|
||||
j->NumInstruments = pack_igetw(f);
|
||||
j->NumSamples = pack_igetw(f);
|
||||
j->NumPatterns = pack_igetw(f);
|
||||
|
||||
#ifdef DEBUG_HEADER
|
||||
printf("Loading IT: %i Orders %i Instruments, %i Samples, %i Patterns\n", j->NumOrders, j->NumInstruments, j->NumSamples, j->NumPatterns);
|
||||
#endif
|
||||
|
||||
tver = pack_igetw(f);
|
||||
j->Version = tver2 = pack_igetw(f);
|
||||
|
||||
#ifdef DEBUG_HEADER
|
||||
printf("Tracker ver: %X, %X\n", tver, tver2);
|
||||
#endif
|
||||
|
||||
j->Flags = pack_igetw(f);
|
||||
flag = pack_igetw(f);
|
||||
|
||||
j->GlobalVolume = pack_getc(f);
|
||||
j->MixVolume = pack_getc(f);
|
||||
j->Speed = pack_getc(f);
|
||||
j->Tempo = pack_getc(f);
|
||||
j->PanningSeperation = pack_getc(f);
|
||||
|
||||
#ifdef DEBUG_HEADER
|
||||
printf("Global Volume: %i, Mixing Volume: %i, Speed: %i, Tempo: %i, PanSep: %i\n", j->GlobalVolume, j->MixVolume, j->Speed, j->Tempo, j->PanningSeperation);
|
||||
#endif
|
||||
|
||||
pack_getc(f); //Damn....I need more info on this.
|
||||
|
||||
msglen = pack_igetw(f);
|
||||
msgoffs = pack_igetl(f);
|
||||
|
||||
pack_fseek(f, 4);
|
||||
|
||||
#ifdef DEBUG_HEADER
|
||||
printf("Channel Pan:");
|
||||
#endif
|
||||
|
||||
for (int i=0; i<MAX_IT_CHN; i++) {
|
||||
j->Channel[i].Pan = pack_getc(f);
|
||||
#ifdef DEBUG_HEADER
|
||||
printf(" %i", j->Channel[i].Pan);
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_HEADER
|
||||
printf("\nChannel Vol:");
|
||||
#endif
|
||||
for (int i=0; i<MAX_IT_CHN; i++) {
|
||||
j->Channel[i].Volume = pack_getc(f);
|
||||
#ifdef DEBUG_HEADER
|
||||
printf(" %i", j->Channel[i].Volume);
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_HEADER
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
j->Order = (unsigned char *)malloc(j->NumOrders);
|
||||
pack_fread(j->Order, j->NumOrders, f);
|
||||
|
||||
if (j->NumInstruments)
|
||||
insoffs = (int*)malloc(4 * j->NumInstruments);
|
||||
if (j->NumSamples)
|
||||
samoffs = (int*)malloc(4 * j->NumSamples);
|
||||
if (j->NumPatterns)
|
||||
patoffs = (int*)malloc(4 * j->NumPatterns);
|
||||
|
||||
pack_fread(insoffs, 4 * j->NumInstruments, f);
|
||||
pack_fread(samoffs, 4 * j->NumSamples, f);
|
||||
pack_fread(patoffs, 4 * j->NumPatterns, f);
|
||||
|
||||
if (flag&1) { //Song message attached
|
||||
//Ignore.
|
||||
}
|
||||
if (flag & 4) { //skip something:
|
||||
short u;
|
||||
char dummy[8];
|
||||
u = pack_igetw(f);
|
||||
for (int i=0; i<u; u++)
|
||||
pack_fread(dummy, 8, f);
|
||||
}
|
||||
if (flag & 8) { //MIDI commands ???
|
||||
char dummy[33];
|
||||
for (int i=0; i<9+16+128; i++)
|
||||
pack_fread(dummy, 32, f);
|
||||
|
||||
}
|
||||
|
||||
if (j->NumInstruments)
|
||||
j->Instrument = (MODULUS_INSTRUMENT*)malloc(sizeof(MODULUS_INSTRUMENT) * j->NumInstruments);
|
||||
#ifdef DEBUG_INSTRUMENTS
|
||||
if (!j->Instrument)
|
||||
printf("No Mem for Instruments!\n");
|
||||
#endif
|
||||
|
||||
|
||||
for (int i=0; i<j->NumInstruments; i++) {
|
||||
pack_fclose(f);
|
||||
f = pack_fopen(file, "rb");
|
||||
#ifdef DEBUG_INSTRUMENTS
|
||||
if (!f)
|
||||
printf("Error Opening!\n");
|
||||
#endif
|
||||
pack_fseek(f, insoffs[i] + 17);
|
||||
|
||||
j->Instrument[i].NewNoteAction = pack_getc(f);
|
||||
j->Instrument[i].DuplicateCheckType = pack_getc(f);
|
||||
j->Instrument[i].DuplicateCheckAction = pack_getc(f);
|
||||
j->Instrument[i].FadeOut = pack_igetw(f);
|
||||
j->Instrument[i].PitchPanSeperation = pack_getc(f);
|
||||
j->Instrument[i].PitchPanCenter = pack_getc(f);
|
||||
j->Instrument[i].GlobalVolume = pack_getc(f);
|
||||
j->Instrument[i].DefaultPan = pack_getc(f);
|
||||
#ifdef DEBUG_INSTRUMENTS
|
||||
printf("I%02i @ 0x%X, NNA %i, DCT %i, DCA %i, FO %i, PPS %i, PPC %i, GVol %i, DPan %i\n", i, insoffs[i], j->Instrument[i].NewNoteAction, j->Instrument[i].DuplicateCheckType, j->Instrument[i].DuplicateCheckAction, j->Instrument[i].FadeOut, j->Instrument[i].PitchPanSeperation, j->Instrument[i].PitchPanCenter, j->Instrument[i].GlobalVolume, j->Instrument[i].DefaultPan);
|
||||
#endif
|
||||
|
||||
pack_fseek(f, 38);
|
||||
|
||||
for (int k=0; k<120; k++) {
|
||||
j->Instrument[i].NoteNote[k] = pack_getc(f);
|
||||
j->Instrument[i].NoteSample[k] = pack_getc(f) - 1;
|
||||
}
|
||||
|
||||
j->Instrument[i].VolumeEnvelope.Flag = pack_getc(f);
|
||||
j->Instrument[i].VolumeEnvelope.NumNodes = pack_getc(f);
|
||||
j->Instrument[i].VolumeEnvelope.LoopBegin = pack_getc(f);
|
||||
j->Instrument[i].VolumeEnvelope.LoopEnd = pack_getc(f);
|
||||
j->Instrument[i].VolumeEnvelope.SustainLoopBegin = pack_getc(f);
|
||||
j->Instrument[i].VolumeEnvelope.SustainLoopEnd = pack_getc(f);
|
||||
for (int k=0; k<j->Instrument[i].VolumeEnvelope.NumNodes; k++) {
|
||||
j->Instrument[i].VolumeEnvelope.NodeY[k] = pack_getc(f);
|
||||
j->Instrument[i].VolumeEnvelope.NodeTick[k] = pack_igetw(f);
|
||||
}
|
||||
pack_fseek(f, 75 - j->Instrument[i].VolumeEnvelope.NumNodes * 3);
|
||||
|
||||
j->Instrument[i].PanningEnvelope.Flag = pack_getc(f);
|
||||
j->Instrument[i].PanningEnvelope.NumNodes = pack_getc(f);
|
||||
j->Instrument[i].PanningEnvelope.LoopBegin = pack_getc(f);
|
||||
j->Instrument[i].PanningEnvelope.LoopEnd = pack_getc(f);
|
||||
j->Instrument[i].PanningEnvelope.SustainLoopBegin = pack_getc(f);
|
||||
j->Instrument[i].PanningEnvelope.SustainLoopEnd = pack_getc(f);
|
||||
for (int k=0; k<j->Instrument[i].PanningEnvelope.NumNodes; k++) {
|
||||
j->Instrument[i].PanningEnvelope.NodeY[k] = pack_getc(f);
|
||||
j->Instrument[i].PanningEnvelope.NodeTick[k] = pack_igetw(f);
|
||||
}
|
||||
pack_fseek(f, 75 - j->Instrument[i].PanningEnvelope.NumNodes * 3);
|
||||
|
||||
j->Instrument[i].PitchEnvelope.Flag = pack_getc(f);
|
||||
j->Instrument[i].PitchEnvelope.NumNodes = pack_getc(f);
|
||||
j->Instrument[i].PitchEnvelope.LoopBegin = pack_getc(f);
|
||||
j->Instrument[i].PitchEnvelope.LoopEnd = pack_getc(f);
|
||||
j->Instrument[i].PitchEnvelope.SustainLoopBegin = pack_getc(f);
|
||||
j->Instrument[i].PitchEnvelope.SustainLoopEnd = pack_getc(f);
|
||||
for (int k=0; k<j->Instrument[i].PitchEnvelope.NumNodes; k++) {
|
||||
j->Instrument[i].PitchEnvelope.NodeY[k] = pack_getc(f);
|
||||
j->Instrument[i].PitchEnvelope.NodeTick[k] = pack_igetw(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (j->NumSamples)
|
||||
j->Sample = (MODULUS_SAMPLE*)malloc(sizeof(MODULUS_SAMPLE) * j->NumSamples);
|
||||
|
||||
#ifdef DEBUG_SAMPLES
|
||||
if (!j->Sample)
|
||||
printf("No Mem for Samples!\n");
|
||||
#endif
|
||||
|
||||
for (int i=0; i<j->NumSamples; i++) {
|
||||
int sam_samptr, convert;
|
||||
|
||||
pack_fclose(f);
|
||||
f = pack_fopen(file, "rb");
|
||||
#ifdef DEBUG_SAMPLES
|
||||
if (!f)
|
||||
printf("Error opening!\n");
|
||||
#endif
|
||||
|
||||
pack_fseek(f, samoffs[i] + 17);
|
||||
|
||||
j->Sample[i].GlobalVolume = pack_getc(f);
|
||||
j->Sample[i].Flag = pack_getc(f);
|
||||
j->Sample[i].Volume = pack_getc(f);
|
||||
|
||||
#ifdef DEBUG_SAMPLES
|
||||
printf("S%02i @ 0x%X, Vol: %i/%i, Flag: %i", i, samoffs[i], j->Sample[i].GlobalVolume, j->Sample[i].Volume, j->Sample[i].Flag);
|
||||
#endif
|
||||
|
||||
pack_fseek(f, 26);
|
||||
|
||||
convert = pack_getc(f);
|
||||
pack_getc(f); //Panning ?
|
||||
|
||||
j->Sample[i].SampleLength = pack_igetl(f);
|
||||
j->Sample[i].LoopBegin = pack_igetl(f);
|
||||
j->Sample[i].LoopEnd = pack_igetl(f);
|
||||
j->Sample[i].C5Speed = pack_igetl(f);
|
||||
j->Sample[i].SustainLoopBegin = pack_igetl(f);
|
||||
j->Sample[i].SustainLoopEnd = pack_igetl(f);
|
||||
|
||||
#ifdef DEBUG_SAMPLES
|
||||
printf(", SLen: %i, LpB: %i, LpE: %i, C5S: %i\n", j->Sample[i].SampleLength, j->Sample[i].LoopBegin, j->Sample[i].LoopEnd, j->Sample[i].C5Speed);
|
||||
#endif
|
||||
|
||||
sam_samptr = pack_igetl(f);
|
||||
|
||||
j->Sample[i].VibratoSpeed = pack_getc(f);
|
||||
j->Sample[i].VibratoDepth = pack_getc(f);
|
||||
j->Sample[i].VibratoRate = pack_getc(f);
|
||||
j->Sample[i].VibratoWaveForm = pack_getc(f);
|
||||
|
||||
#ifdef DEBUG_SAMPLES
|
||||
printf("SusLpB: %i, SusLpE: %i, VibSp: %i, VibDep: %i, VibWav: %i, VibRat: %i\n", j->Sample[i].SustainLoopBegin, j->Sample[i].SustainLoopEnd, j->Sample[i].VibratoSpeed, j->Sample[i].VibratoDepth, j->Sample[i].VibratoWaveForm, j->Sample[i].VibratoRate);
|
||||
#endif
|
||||
|
||||
if (j->Sample[i].Flag & 1 == 0)
|
||||
continue;
|
||||
|
||||
pack_fclose(f);
|
||||
f = pack_fopen(file, "rb");
|
||||
pack_fseek(f, sam_samptr);
|
||||
|
||||
int len = j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1);
|
||||
|
||||
#ifdef DEBUG_SAMPLES
|
||||
printf("Len: %i, Size: %i KB\n", j->Sample[i].SampleLength, len/1024);
|
||||
#endif
|
||||
|
||||
SAMPLE *sam = create_sample(j->Sample[i].Flag & 2 ? 16 : 8, j->Sample[i].Flag & 4 ? TRUE : FALSE, j->Sample[i].C5Speed, j->Sample[i].SampleLength);
|
||||
|
||||
if (j->Sample[i].Flag & 8) { // If the sample is packed, then we must unpack it
|
||||
if (j->Sample[i].Flag & 2)
|
||||
decompress16(f, sam->data, j->Sample[i].SampleLength, tver2);
|
||||
else
|
||||
decompress8(f, sam->data, j->Sample[i].SampleLength, tver2);
|
||||
} else {
|
||||
pack_fread(sam->data, len, f);
|
||||
}
|
||||
|
||||
if (j->Sample[i].Flag & SAMPLE_USELOOP) {
|
||||
sam->loop_start = j->Sample[i].LoopBegin;
|
||||
sam->loop_end = j->Sample[i].LoopEnd;
|
||||
}
|
||||
|
||||
j->Sample[i].Sample = sam;
|
||||
|
||||
void *dat = sam->data;
|
||||
|
||||
if (convert & 2) { //Change the byte order for 16-bit samples:
|
||||
if (sam->bits == 16) {
|
||||
for (int k=0; k<len; k+=2) {
|
||||
int l = ((char*)dat)[k];
|
||||
((char*)dat)[k] = ((char*)dat)[k+1];
|
||||
((char*)dat)[k+1] = l;
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int k=0; k<len; k+=2) {
|
||||
int l = ((char*)dat)[k];
|
||||
((char*)dat)[k] = ((char*)dat)[k+1];
|
||||
((char*)dat)[k+1] = l;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (convert & 1) { //Convert to unsigned
|
||||
if (sam->bits == 8) {
|
||||
for (int k=0; k<len; k++) {
|
||||
((char*)dat)[k] ^= 0x80;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int k=0; k<(len>>1); k++) {
|
||||
((short*)dat)[k] ^= 0x8000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (j->NumPatterns)
|
||||
j->Pattern = (MODULUS_PATTERN*)malloc(sizeof(MODULUS_PATTERN) * j->NumPatterns);
|
||||
unsigned char *buf = (unsigned char*)alloca(65536);
|
||||
unsigned char *cmask = (unsigned char*)alloca(64),
|
||||
*cnote = (unsigned char*)alloca(64),
|
||||
*cinstrument = (unsigned char*)alloca(64),
|
||||
*cvol = (unsigned char*)alloca(64),
|
||||
*ccom = (unsigned char*)alloca(64),
|
||||
*ccomval = (unsigned char*)alloca(64);
|
||||
|
||||
for (int i=0; i<j->NumPatterns; i++) {
|
||||
int numnotes = 0, len, pos = 0, mask = 0, chn = 0;
|
||||
|
||||
memset(cmask, 0, 64);
|
||||
memset(cnote, 0, 64);
|
||||
memset(cinstrument, 0, 64);
|
||||
memset(cvol, 0, 64);
|
||||
memset(ccom, 0, 64);
|
||||
memset(ccomval, 0, 64);
|
||||
|
||||
pack_fclose(f);
|
||||
f = pack_fopen(file, "rb");
|
||||
pack_fseek(f, patoffs[i]);
|
||||
|
||||
len = pack_igetw(f);
|
||||
j->Pattern[i].NumRows = pack_igetw(f);
|
||||
|
||||
pack_fseek(f, 4);
|
||||
pack_fread(buf, len, f);
|
||||
|
||||
while (pos < len) {
|
||||
int b = buf[pos];
|
||||
pos++;
|
||||
if (!b) { //If end of row:
|
||||
numnotes++;
|
||||
continue;
|
||||
}
|
||||
chn = (b - 1) & 63;
|
||||
|
||||
if (b & 128) {
|
||||
mask = buf[pos];
|
||||
pos++;
|
||||
cmask[chn] = mask;
|
||||
}
|
||||
else
|
||||
mask = cmask[chn];
|
||||
|
||||
if (mask)
|
||||
numnotes++;
|
||||
if (mask & 1)
|
||||
pos++;
|
||||
if (mask & 2)
|
||||
pos++;
|
||||
if (mask & 4)
|
||||
pos++;
|
||||
if (mask & 8)
|
||||
pos+=2; //Guessing here
|
||||
}
|
||||
j->Pattern[i].NumNotes = numnotes;
|
||||
j->Pattern[i].Note = (MODULUS_NOTE*)malloc(sizeof(MODULUS_NOTE) * numnotes);
|
||||
memset(j->Pattern[i].Note, 0, sizeof(MODULUS_NOTE) * numnotes);
|
||||
|
||||
pos = 0;
|
||||
memset(cmask, 0, 64);
|
||||
mask = 0;
|
||||
numnotes = 0;
|
||||
while (pos < len) {
|
||||
int b = buf[pos];
|
||||
#ifdef DEBUG_PATTERNS
|
||||
printf("NumNote: %i ", numnotes);
|
||||
#endif
|
||||
|
||||
pos++;
|
||||
if (!b) { //If end of row:
|
||||
j->Pattern[i].Note[numnotes].Channel = -1;
|
||||
numnotes++;
|
||||
#ifdef DEBUG_PATTERNS
|
||||
printf("Channel: -1\n");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
chn = (b - 1) & 63;
|
||||
|
||||
if (b & 128) {
|
||||
mask = buf[pos];
|
||||
pos++;
|
||||
cmask[chn] = mask;
|
||||
}
|
||||
else
|
||||
mask = cmask[chn];
|
||||
#ifdef DEBUG_PATTERNS
|
||||
printf("Channel: %i Mask: %i ", chn, mask);
|
||||
#endif
|
||||
|
||||
if (mask)
|
||||
j->Pattern[i].Note[numnotes].Channel = chn;
|
||||
|
||||
if (mask & 1) {
|
||||
j->Pattern[i].Note[numnotes].Note = buf[pos];
|
||||
j->Pattern[i].Note[numnotes].Mask |= 1;
|
||||
cnote[chn] = buf[pos];
|
||||
#ifdef DEBUG_PATTERNS
|
||||
printf("Note: %i ", buf[pos]);
|
||||
#endif
|
||||
pos++;
|
||||
}
|
||||
if (mask & 2) {
|
||||
j->Pattern[i].Note[numnotes].Instrument = buf[pos];
|
||||
j->Pattern[i].Note[numnotes].Mask |= 2;
|
||||
cinstrument[chn] = buf[pos];
|
||||
#ifdef DEBUG_PATTERNS
|
||||
printf("Inst: %i ", buf[pos]);
|
||||
#endif
|
||||
pos++;
|
||||
}
|
||||
if (mask & 4) {
|
||||
if (buf[pos] <= 64 || (buf[pos] >= 128 && buf[pos] <= 192))
|
||||
if (buf[pos] <= 64) {
|
||||
j->Pattern[i].Note[numnotes].Volume = buf[pos];
|
||||
j->Pattern[i].Note[numnotes].Mask |= 4;
|
||||
}
|
||||
else {
|
||||
j->Pattern[i].Note[numnotes].Panning = buf[pos] - 128;
|
||||
j->Pattern[i].Note[numnotes].Mask |= 8;
|
||||
}
|
||||
#ifdef DEBUG_PATTERNS
|
||||
printf("Vol: %i ", buf[pos]);
|
||||
#endif
|
||||
cvol[chn] = buf[pos];
|
||||
pos++;
|
||||
}
|
||||
if (mask & 8) {
|
||||
j->Pattern[i].Note[numnotes].Command = buf[pos];
|
||||
j->Pattern[i].Note[numnotes].CommandValue = buf[pos+1];
|
||||
j->Pattern[i].Note[numnotes].Mask |= 16;
|
||||
ccom[chn] = buf[pos];
|
||||
ccomval[chn] = buf[pos+1];
|
||||
#ifdef DEBUG_PATTERNS
|
||||
printf("Com: %i CommArg: %i ", buf[pos], buf[pos+1]);
|
||||
#endif
|
||||
pos+=2;
|
||||
}
|
||||
if (mask & 16) {
|
||||
j->Pattern[i].Note[numnotes].Note = cnote[chn];
|
||||
j->Pattern[i].Note[numnotes].Mask |= 1;
|
||||
#ifdef DEBUG_PATTERNS
|
||||
printf("LNote: %i ", cnote[chn]);
|
||||
#endif
|
||||
}
|
||||
if (mask & 32) {
|
||||
j->Pattern[i].Note[numnotes].Instrument = cinstrument[chn];
|
||||
j->Pattern[i].Note[numnotes].Mask |= 2;
|
||||
#ifdef DEBUG_PATTERNS
|
||||
printf("LInst: %i ", cinstrument[chn]);
|
||||
#endif
|
||||
}
|
||||
if (mask & 64) {
|
||||
if (cvol[chn] <= 64 || (cvol[chn] >= 128 && cvol[chn] <= 192))
|
||||
if (cvol[chn] <= 64) {
|
||||
j->Pattern[i].Note[numnotes].Volume = cvol[chn];
|
||||
j->Pattern[i].Note[numnotes].Mask |= 4;
|
||||
}
|
||||
else {
|
||||
j->Pattern[i].Note[numnotes].Panning = cvol[chn] - 128;
|
||||
j->Pattern[i].Note[numnotes].Mask |= 8;
|
||||
}
|
||||
#ifdef DEBUG_PATTERNS
|
||||
printf("LVol: %i ", cvol[chn]);
|
||||
#endif
|
||||
}
|
||||
if (mask & 128) {
|
||||
j->Pattern[i].Note[numnotes].Command = ccom[chn];
|
||||
j->Pattern[i].Note[numnotes].CommandValue = ccomval[chn];
|
||||
j->Pattern[i].Note[numnotes].Mask |= 16;
|
||||
#ifdef DEBUG_PATTERNS
|
||||
printf("LCom: %i LComArg: %i ", ccom[chn], ccomval[chn]);
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_PATTERNS
|
||||
printf("\n");
|
||||
#endif
|
||||
if (mask)
|
||||
numnotes++;
|
||||
#ifdef DEBUG_PATTERNS
|
||||
rest(1000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (insoffs)
|
||||
free(insoffs);
|
||||
if (samoffs)
|
||||
free(samoffs);
|
||||
if (patoffs)
|
||||
free(patoffs);
|
||||
|
||||
return j;
|
||||
}
|
|
@ -1,193 +0,0 @@
|
|||
|
||||
#define MUSIC_IT AL_ID('I','M','P','M')
|
||||
|
||||
typedef struct MODULUS_MUSIC_INFO {
|
||||
char Name[29];
|
||||
int Type;
|
||||
} MODULUS_MUSIC_INFO;
|
||||
|
||||
#define ENVELOPE_ON 1
|
||||
#define ENVELOPE_LOOP_ON 2
|
||||
#define ENVELOPE_SUSTAINLOOP 4
|
||||
|
||||
typedef struct MODULUS_ENVELOPE {
|
||||
unsigned char Flag,
|
||||
NumNodes,
|
||||
LoopBegin, LoopEnd, SustainLoopBegin, SustainLoopEnd; //in nodes.
|
||||
char NodeY[25];
|
||||
short NodeTick[25];
|
||||
} MODULUS_ENVELOPE;
|
||||
|
||||
typedef struct MODULUS_VENVELOPE {
|
||||
char CurNode;
|
||||
unsigned char CurTick;
|
||||
char End;
|
||||
//float CVolume;
|
||||
MODULUS_ENVELOPE *Envelope;
|
||||
} MODULUS_VENVELOPE;
|
||||
|
||||
#define NNA_NOTECUT 1
|
||||
#define NNA_NOTECONTINUE 2
|
||||
#define NNA_NOTEOFF 3
|
||||
#define NNA_NOTEFADE 4
|
||||
|
||||
#define DCT_OFF 0
|
||||
#define DCT_NOTE 1
|
||||
#define DCT_SAMPLE 2
|
||||
#define DCT_INSTRUMENT 3
|
||||
|
||||
#define DCA_CUT 0
|
||||
#define DCA_NOTEOFF 1
|
||||
#define DCA_NOTEFADE 2
|
||||
|
||||
typedef struct MOULUS_INSTRUMENT {
|
||||
unsigned char Flag;
|
||||
char VolumeLoopNodeStart, VolumeLoopNodeEnd;
|
||||
char SustainLoopNodeStart, SustainLoopNodeEnd;
|
||||
char DuplicateCheckType;
|
||||
char DuplicateCheckAction;
|
||||
char NewNoteAction;
|
||||
int FadeOut;
|
||||
|
||||
unsigned char PitchPanSeperation, //0->64, Bit7: Don't use
|
||||
PitchPanCenter; //Note, from C-0 to B-9
|
||||
unsigned char GlobalVolume, //0->128
|
||||
DefaultPan; //0->64, Bit7: Don't use
|
||||
|
||||
|
||||
unsigned char NoteSample[120];
|
||||
unsigned char NoteNote[120];
|
||||
|
||||
MODULUS_ENVELOPE VolumeEnvelope, PanningEnvelope, PitchEnvelope;
|
||||
} MODULUS_INSTRUMENT;
|
||||
|
||||
#define SAMPLE_HASSAMPLE 1
|
||||
#define SAMPLE_16BIT 2
|
||||
#define SAMPLE_STEREO 4
|
||||
#define SAMPLE_USELOOP 16
|
||||
#define SAMPLE_USESUSTAINLOOP 32
|
||||
#define SAMPLE_PINGPONGLOOP 64
|
||||
#define SAMPLE_PINGPONGSUSTAINLOOP 128
|
||||
|
||||
#define VIBRATO_SINE 0
|
||||
#define VIBRATO_RAMPDOWN 1
|
||||
#define VIBRATO_SQUARE 2
|
||||
#define VIBRATO_RANDOM 3
|
||||
|
||||
typedef struct MODULUS_SAMPLE {
|
||||
unsigned char GlobalVolume; //0->64
|
||||
unsigned char Flag;
|
||||
unsigned char Volume;
|
||||
int SampleLength; //in samples, not bytes !
|
||||
int LoopBegin, LoopEnd; //in samples
|
||||
int SustainLoopBegin, SustainLoopEnd;
|
||||
int C5Speed; //Number of bytes/sec for C-5
|
||||
|
||||
SAMPLE *Sample;
|
||||
|
||||
char VibratoSpeed; //0->64
|
||||
char VibratoDepth; //0->64
|
||||
char VibratoWaveForm;
|
||||
char VibratoRate; //0->64
|
||||
} MODULUS_SAMPLE;
|
||||
|
||||
typedef struct MODULUS_NOTE {
|
||||
char Mask; //If Bit0: Note, Bit1: Instrument, Bit2: Volume, Bit3: Panning, Bit4: Command
|
||||
char Channel; //if -1, then end of row.
|
||||
unsigned char Note;
|
||||
char Instrument;
|
||||
unsigned char Volume, Panning;
|
||||
unsigned char Command, CommandValue;
|
||||
} MODULUS_NOTE;
|
||||
|
||||
typedef struct MODULUS_PATTERN {
|
||||
int NumRows;
|
||||
int NumNotes;
|
||||
MODULUS_NOTE *Note;
|
||||
} MODULUS_PATTERN;
|
||||
|
||||
typedef struct MODULUS_VCHANNEL {
|
||||
MODULUS_SAMPLE *Sample; //NULL is unused
|
||||
char voice;
|
||||
char ChannelVolume;
|
||||
char NoteOn;
|
||||
char NNA;
|
||||
short FadeOutCount, FadeOut;
|
||||
float MixVolume, MixPan;
|
||||
MODULUS_VENVELOPE *VVolumeEnvelope, *VPanningEnvelope, *VPitchEnvelope;
|
||||
MODULUS_VCHANNEL *next, *prev;
|
||||
} MODULUS_VCHANNEL;
|
||||
|
||||
typedef struct MODULUS_CHANNEL {
|
||||
unsigned char Volume; //0->64
|
||||
unsigned char Pan; //0->32->64, 100 = surround, Bit7: Disable
|
||||
char LastNote, LastInstrument, LastSample;
|
||||
MODULUS_VCHANNEL *VChannel;
|
||||
} MODULUS_CHANNEL;
|
||||
|
||||
#define FLAG_STEREO 1
|
||||
#define FLAG_USEINSTRUMENTS 4
|
||||
#define FLAG_LINEARSLIDES 8
|
||||
#define FLAG_OLDEFFECT 16
|
||||
|
||||
typedef struct MODULUS {
|
||||
MODULUS_INSTRUMENT *Instrument;
|
||||
MODULUS_SAMPLE *Sample;
|
||||
MODULUS_PATTERN *Pattern;
|
||||
|
||||
int NumOrders;
|
||||
int NumInstruments;
|
||||
int NumSamples;
|
||||
int NumPatterns;
|
||||
int Flags;
|
||||
short Version;
|
||||
char GlobalVolume;
|
||||
char MixVolume;
|
||||
unsigned char Speed, Tempo;
|
||||
char PanningSeperation;
|
||||
|
||||
unsigned char *Order;
|
||||
|
||||
MODULUS_CHANNEL Channel[64];
|
||||
|
||||
} MODULUS;
|
||||
|
||||
#define COMMAND_SET_SONG_SPEED 1
|
||||
#define COMMAND_JUMP_TO_ORDER 2
|
||||
#define COMMAND_PATTERN_BREAK_TO_ROW 3
|
||||
#define COMMAND_SET_CHANNEL_VOLUME 13
|
||||
#define COMMAND_SET_SONG_TEMPO 20
|
||||
#define COMMAND_SET_GLOBAL_VOLUME 22
|
||||
|
||||
typedef struct MODULUS_PLAY {
|
||||
MODULUS *Music;
|
||||
int Loop, Tick;
|
||||
int CurOrder, CurPattern, CurPos;
|
||||
int Command, CommandVal0, CommandVal1, CommandVal2;
|
||||
int pos;
|
||||
} MODULUS_PLAY;
|
||||
extern MODULUS_PLAY *song;
|
||||
|
||||
extern int IT_Play_Method;
|
||||
|
||||
MODULUS *load_it(char*);
|
||||
int get_module_size(MODULUS *);
|
||||
|
||||
int play_it(MODULUS *j, int loop);
|
||||
void install_modulus();
|
||||
void set_mix_volume(int i);
|
||||
|
||||
void stop_it();
|
||||
int is_music_done();
|
||||
void destroy_it(MODULUS *j);
|
||||
|
||||
//Should be internal:
|
||||
extern MODULUS_PLAY *song;
|
||||
extern int note_freq[120];
|
||||
|
||||
extern void MOD_Interrupt(...);
|
||||
extern int MOD_Poller(void*);
|
||||
|
||||
#define IT_TIMER 0
|
||||
#define IT_POLL 1
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
typedef unsigned int dword;
|
141
dumb/todo.txt
141
dumb/todo.txt
|
@ -1,141 +0,0 @@
|
|||
al_duh_get_volume()
|
||||
|
||||
* [23:25:12] <Mahogny> I prefer an API datagram :)
|
||||
|
||||
* Create a glossary of terms like 'render', 'sigrenderer', etc.?
|
||||
|
||||
* Consider the order in which stuff appears in dumb.h, and dumb.txt?
|
||||
|
||||
|
||||
PROPOSED CHANGE OF TERMINOLOGY:
|
||||
|
||||
Current situation:
|
||||
|
||||
A DUH comprises a number of "signals". A signal is an entity capable of
|
||||
producing a stream of audio. When a signal is called upon to generate
|
||||
sound, it may in turn call upon any other signals in the DUH and use the
|
||||
sound from those in generating its own.
|
||||
|
||||
There are a number of "sigtypes", including 'SAMP' (a sample) and 'SEQU'
|
||||
(a sequence). Every signal in a DUH must be of one of these known types.
|
||||
Every sigtype is characterised by a four-byte identifier and the
|
||||
following function prototypes:
|
||||
|
||||
typedef void signal_t;
|
||||
typedef void sampinfo_t;
|
||||
|
||||
signal_t *load_signal(DUH *duh, DUMBFILE *file);
|
||||
sampinfo_t *start_samples(DUH *duh, signal_t *signal, int n_channels, long pos);
|
||||
void set_parameter(sampinfo_t *sampinfo, unsigned char id, long value);
|
||||
long render_samples(sampinfo_t *sampinfo, float volume, float delta, long size, sample_t **samples);
|
||||
void end_samples(sampinfo_t *sampinfo);
|
||||
void unload_signal(signal_t *signal);
|
||||
|
||||
When a signal in a DUH needs to be loaded, DUMB's core first checks the
|
||||
identifier. If it is unknown, load_duh() fails. Each known sigtype will
|
||||
have pointers to the above functions, so DUMB's core will then call the
|
||||
load_signal() function. This loads the "signal", which could consist of
|
||||
sample data, or sequence data (like the patterns in a music module).
|
||||
(There's ambiguity here; we use the word "signal" for the whole entity
|
||||
and also for the specific data that distinguish it from other signals of
|
||||
the same sigtype.)
|
||||
|
||||
Once a signal is in memory, it can be used to generate sound. Its
|
||||
start_samples() function is called for that, and a "sampinfo" block is
|
||||
returned; this will contain the current position and any necessary state
|
||||
information. render_samples() generates sound, and end_samples() destroys
|
||||
the sampinfo block.
|
||||
|
||||
DUMB's support for existing file formats is implemented as follows. First
|
||||
a signal_t is constructed manually by reading the file. Then the special
|
||||
make_duh() function is called. This creates a DUH struct with just one
|
||||
signal in it, the one we just created. We provide all the above
|
||||
functions, except load_signal(), since that has been bypassed. DUMB's
|
||||
core now has our start_samples() etc. function for generating the sound,
|
||||
and it has our unload_signal() function for getting the file out of
|
||||
memory when we're done.
|
||||
|
||||
It is possible with some sigtypes to adjust their sound using
|
||||
"parameters". set_parameter() is called for this. An example would be
|
||||
changing the cut-off frequency for a signal that acts as a filter. I plan
|
||||
to add a second version of this function that takes a pointer. This would
|
||||
be used when manipulating DUHs in code; an example is when installing a
|
||||
callback function for a music module file. It couldn't be used by a file
|
||||
on disk.
|
||||
|
||||
This terminology is far from intuitive. Here are some proposals:
|
||||
|
||||
- The things DUHs are made of can still be called "signals".
|
||||
- The types of signal can still be called "sigtypes" ("signal types").
|
||||
- The signal-specific data can be called the "sigdata" ("signal data").
|
||||
- The sampinfo block can be renamed to a "sigrenderer" ("signal renderer").
|
||||
- The parameters can be called "sigparams" ("signal parameters").
|
||||
|
||||
This way we have some consistency between different parts of the library;
|
||||
the API for rendering a DUH as a whole uses the term "renderer". We also
|
||||
have a full name and an abbreviation for each term.
|
||||
|
||||
Any advances on this?
|
||||
|
||||
---
|
||||
|
||||
Todo/Wishlist:
|
||||
|
||||
* MOD/XM loading - change the effect memory system; it isn't robust when it
|
||||
comes to remembering stuff from one pattern to the next.
|
||||
* --- IMPORTANT --- Put link to IT in docs: http://www.noisemusic.org/it/
|
||||
* --- IMPORTANT --- Twist the sample decompression algorithm around, since
|
||||
it was derived from a GPL'd algorithm. We don't want
|
||||
to have to put it under GPL! :) ... or, find out that it
|
||||
wasn't originally written under the GPL and then credit
|
||||
the bloke who wrote it :)
|
||||
* MMX resamplers and downsamplers
|
||||
* Ability to load *.it, *.xm directly into DUH structs (IT done)
|
||||
* Ability to embed IT compressed samples... no, it's copyrighted. Let's do
|
||||
our own :)
|
||||
* Ability to embed ITs themselves (? not sure how useful that is)
|
||||
* Remove cit.c
|
||||
* Check all return values. I think the Winamp plug-in needs looking at...
|
||||
* resample.c - it seems x*y is safe if 0<=x<=65535 and -32768<=y<=32768 or
|
||||
vice versa. Check this is true on all compilers. If so, make
|
||||
use of it to gain more accuracy.
|
||||
* DUMB_IDs should always be long or always be int...
|
||||
* Decide whether the load_signal function really needs the DUH parameter...
|
||||
* Allow for DUH modularity; different pieces share samples etc.
|
||||
|
||||
* Fix makefile so it can manage without alld - or put note in the FAQ that
|
||||
ppl must build alld
|
||||
* Arrange to detect file types by extension (probably not by content though)
|
||||
* Change aldmbd to aldmd in makefiles to maintain 8.3 compatibility
|
||||
* Put dumb_resampling_quality and dumb_it_max_to_mix in howto.txt
|
||||
* More info in howto.txt, in particular that install_sound() is needed...
|
||||
* Add a sanity check for restart_position?
|
||||
* Note in docs to let entheh know if you release a game using DUMB
|
||||
|
||||
|
||||
STUFF TO FIX FOR THE FIRST RELEASE
|
||||
==================================
|
||||
|
||||
General
|
||||
-------
|
||||
* Naming is a bit confusing sometimes...
|
||||
* What to do about ASSERT() and TRACE() - they were hacked in when
|
||||
the lib was split from Allegro, and they need replacing.
|
||||
* Add some constants to dumb.h (DUMB_VERSION_STR etc.)
|
||||
|
||||
entheh
|
||||
------
|
||||
* Update docs, write more docs (a lot to do here!)
|
||||
* Go through, eliminate warnings, resolve some "/** WARNING" comments
|
||||
(they used to be #warning but Bob complained :)
|
||||
* Program it to calculate the length of IT and S3M files (currently
|
||||
always set to 10 minutes IIRC)
|
||||
|
||||
Bob
|
||||
---
|
||||
* dumb_resample() now has a volume parameter, so there are some extra
|
||||
floating-point multiply ops that could possibly be optimised.
|
||||
|
||||
tjaden
|
||||
------
|
||||
* Test on Linux when it's all ready plz :)
|
3
dumb/vc6/dumb/.gitignore
vendored
Normal file
3
dumb/vc6/dumb/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.user
|
||||
Debug
|
||||
Release
|
2007
dumb/vc6/dumb/dumb.vcproj
Normal file
2007
dumb/vc6/dumb/dumb.vcproj
Normal file
File diff suppressed because it is too large
Load diff
218
dumb/vc6/dumb/dumb.vcxproj
Normal file
218
dumb/vc6/dumb/dumb.vcxproj
Normal file
|
@ -0,0 +1,218 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{612D360C-A51B-4B34-8F49-33F42A2957F5}</ProjectGuid>
|
||||
<RootNamespace>dumb</RootNamespace>
|
||||
<SccProjectName>
|
||||
</SccProjectName>
|
||||
<SccLocalPath>
|
||||
</SccLocalPath>
|
||||
<SccProvider>
|
||||
</SccProvider>
|
||||
<SccAuxPath>
|
||||
</SccAuxPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.21006.1</_ProjectFileVersion>
|
||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_USE_SSE;RESAMPLER_DECORATE=dumb;BARRAY_DECORATE=dumb;_DEBUG;WIN32;_LIB;DUMB_DECLARE_DEPRECATED;DEBUGMODE=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<CompileAs>Default</CompileAs>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0409</Culture>
|
||||
</ResourceCompile>
|
||||
<Lib>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<AdditionalIncludeDirectories>../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_USE_SSE;RESAMPLER_DECORATE=dumb;BARRAY_DECORATE=dumb;NDEBUG;WIN32;_LIB;DUMB_DECLARE_DEPRECATED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<CompileAs>Default</CompileAs>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0409</Culture>
|
||||
</ResourceCompile>
|
||||
<Lib>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\core\atexit.c" />
|
||||
<ClCompile Include="..\..\src\core\duhlen.c" />
|
||||
<ClCompile Include="..\..\src\core\duhtag.c" />
|
||||
<ClCompile Include="..\..\src\core\dumbfile.c" />
|
||||
<ClCompile Include="..\..\src\core\loadduh.c" />
|
||||
<ClCompile Include="..\..\src\core\makeduh.c" />
|
||||
<ClCompile Include="..\..\src\core\rawsig.c" />
|
||||
<ClCompile Include="..\..\src\core\readduh.c" />
|
||||
<ClCompile Include="..\..\src\core\register.c" />
|
||||
<ClCompile Include="..\..\src\core\rendduh.c" />
|
||||
<ClCompile Include="..\..\src\core\rendsig.c" />
|
||||
<ClCompile Include="..\..\src\core\unload.c" />
|
||||
<ClCompile Include="..\..\src\helpers\barray.c" />
|
||||
<ClCompile Include="..\..\src\helpers\clickrem.c" />
|
||||
<ClCompile Include="..\..\src\helpers\resampler.c" />
|
||||
<ClCompile Include="..\..\src\helpers\lpc.c" />
|
||||
<ClCompile Include="..\..\src\helpers\memfile.c" />
|
||||
<ClCompile Include="..\..\src\helpers\resample.c" />
|
||||
<ClCompile Include="..\..\src\helpers\riff.c" />
|
||||
<ClCompile Include="..\..\src\helpers\sampbuf.c" />
|
||||
<ClCompile Include="..\..\src\helpers\silence.c" />
|
||||
<ClCompile Include="..\..\src\helpers\stdfile.c" />
|
||||
<ClCompile Include="..\..\src\helpers\tarray.c" />
|
||||
<ClCompile Include="..\..\src\it\itmisc.c" />
|
||||
<ClCompile Include="..\..\src\it\itorder.c" />
|
||||
<ClCompile Include="..\..\src\it\itrender.c" />
|
||||
<ClCompile Include="..\..\src\it\itunload.c" />
|
||||
<ClCompile Include="..\..\src\it\loadany.c" />
|
||||
<ClCompile Include="..\..\src\it\loadany2.c" />
|
||||
<ClCompile Include="..\..\src\it\loadokt.c" />
|
||||
<ClCompile Include="..\..\src\it\loadokt2.c" />
|
||||
<ClCompile Include="..\..\src\it\ptmeffect.c" />
|
||||
<ClCompile Include="..\..\src\it\readany.c" />
|
||||
<ClCompile Include="..\..\src\it\readany2.c" />
|
||||
<ClCompile Include="..\..\src\it\readokt.c" />
|
||||
<ClCompile Include="..\..\src\it\readokt2.c" />
|
||||
<ClCompile Include="..\..\src\it\xmeffect.c" />
|
||||
<ClCompile Include="..\..\src\it\itload.c" />
|
||||
<ClCompile Include="..\..\src\it\itload2.c" />
|
||||
<ClCompile Include="..\..\src\it\load669.c" />
|
||||
<ClCompile Include="..\..\src\it\load6692.c" />
|
||||
<ClCompile Include="..\..\src\it\loadamf.c" />
|
||||
<ClCompile Include="..\..\src\it\loadamf2.c" />
|
||||
<ClCompile Include="..\..\src\it\loadasy.c" />
|
||||
<ClCompile Include="..\..\src\it\loadasy2.c" />
|
||||
<ClCompile Include="..\..\src\it\loadmod.c" />
|
||||
<ClCompile Include="..\..\src\it\loadmod2.c" />
|
||||
<ClCompile Include="..\..\src\it\loadmtm.c" />
|
||||
<ClCompile Include="..\..\src\it\loadmtm2.c" />
|
||||
<ClCompile Include="..\..\src\it\loadoldpsm.c" />
|
||||
<ClCompile Include="..\..\src\it\loadoldpsm2.c" />
|
||||
<ClCompile Include="..\..\src\it\loadpsm.c" />
|
||||
<ClCompile Include="..\..\src\it\loadpsm2.c" />
|
||||
<ClCompile Include="..\..\src\it\loadptm.c" />
|
||||
<ClCompile Include="..\..\src\it\loadptm2.c" />
|
||||
<ClCompile Include="..\..\src\it\loadriff.c" />
|
||||
<ClCompile Include="..\..\src\it\loadriff2.c" />
|
||||
<ClCompile Include="..\..\src\it\loads3m.c" />
|
||||
<ClCompile Include="..\..\src\it\loads3m2.c" />
|
||||
<ClCompile Include="..\..\src\it\loadstm.c" />
|
||||
<ClCompile Include="..\..\src\it\loadstm2.c" />
|
||||
<ClCompile Include="..\..\src\it\loadxm.c" />
|
||||
<ClCompile Include="..\..\src\it\loadxm2.c" />
|
||||
<ClCompile Include="..\..\src\it\itread.c" />
|
||||
<ClCompile Include="..\..\src\it\itread2.c" />
|
||||
<ClCompile Include="..\..\src\it\read669.c" />
|
||||
<ClCompile Include="..\..\src\it\read6692.c" />
|
||||
<ClCompile Include="..\..\src\it\readam.c" />
|
||||
<ClCompile Include="..\..\src\it\readamf.c" />
|
||||
<ClCompile Include="..\..\src\it\readamf2.c" />
|
||||
<ClCompile Include="..\..\src\it\readasy.c" />
|
||||
<ClCompile Include="..\..\src\it\readdsmf.c" />
|
||||
<ClCompile Include="..\..\src\it\readmod.c" />
|
||||
<ClCompile Include="..\..\src\it\readmod2.c" />
|
||||
<ClCompile Include="..\..\src\it\readmtm.c" />
|
||||
<ClCompile Include="..\..\src\it\readoldpsm.c" />
|
||||
<ClCompile Include="..\..\src\it\readpsm.c" />
|
||||
<ClCompile Include="..\..\src\it\readptm.c" />
|
||||
<ClCompile Include="..\..\src\it\readriff.c" />
|
||||
<ClCompile Include="..\..\src\it\reads3m.c" />
|
||||
<ClCompile Include="..\..\src\it\reads3m2.c" />
|
||||
<ClCompile Include="..\..\src\it\readstm.c" />
|
||||
<ClCompile Include="..\..\src\it\readstm2.c" />
|
||||
<ClCompile Include="..\..\src\it\readxm.c" />
|
||||
<ClCompile Include="..\..\src\it\readxm2.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\helpers\resamp2.inc">
|
||||
<FileType>Document</FileType>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="..\..\src\helpers\resamp3.inc">
|
||||
<FileType>Document</FileType>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="..\..\src\helpers\resample.inc">
|
||||
<FileType>Document</FileType>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\include\dumb.h" />
|
||||
<ClInclude Include="..\..\include\internal\barray.h" />
|
||||
<ClInclude Include="..\..\include\internal\dumb.h" />
|
||||
<ClInclude Include="..\..\include\internal\dumbfile.h" />
|
||||
<ClInclude Include="..\..\include\internal\fir_resampler.h" />
|
||||
<ClInclude Include="..\..\include\internal\it.h" />
|
||||
<ClInclude Include="..\..\include\internal\resampler.h" />
|
||||
<ClInclude Include="..\..\include\internal\lpc.h" />
|
||||
<ClInclude Include="..\..\include\internal\riff.h" />
|
||||
<ClInclude Include="..\..\include\internal\stack_alloc.h" />
|
||||
<ClInclude Include="..\..\include\internal\tarray.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
332
dumb/vc6/dumb/dumb.vcxproj.filters
Normal file
332
dumb/vc6/dumb/dumb.vcxproj.filters
Normal file
|
@ -0,0 +1,332 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="include">
|
||||
<UniqueIdentifier>{419c5e1f-2bf4-473a-b2e5-2e531285aa62}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="include\internal">
|
||||
<UniqueIdentifier>{44b333b3-1607-4820-82bc-e4c21a40e31a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{0b122556-3781-4ef3-87fe-ffa5fb50b493}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\core">
|
||||
<UniqueIdentifier>{e961cd19-26f6-4df0-b895-e099d3e81db9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\helpers">
|
||||
<UniqueIdentifier>{82e35139-08ff-4e99-a3ce-2254d7427ec4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\it">
|
||||
<UniqueIdentifier>{5f7fc0f6-4008-4166-83ad-e5d914718bd0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\it\loaders">
|
||||
<UniqueIdentifier>{0fd0715e-5824-4419-aa5b-2d4272d222ce}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\it\readers">
|
||||
<UniqueIdentifier>{b9e26fe7-6056-4580-b2c6-10e6116d4129}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\core\atexit.c">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\duhlen.c">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\duhtag.c">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\dumbfile.c">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\loadduh.c">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\makeduh.c">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\rawsig.c">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\readduh.c">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\register.c">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\rendduh.c">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\rendsig.c">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\unload.c">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\helpers\barray.c">
|
||||
<Filter>src\helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\helpers\clickrem.c">
|
||||
<Filter>src\helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\helpers\lpc.c">
|
||||
<Filter>src\helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\helpers\memfile.c">
|
||||
<Filter>src\helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\helpers\resample.c">
|
||||
<Filter>src\helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\helpers\riff.c">
|
||||
<Filter>src\helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\helpers\sampbuf.c">
|
||||
<Filter>src\helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\helpers\silence.c">
|
||||
<Filter>src\helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\helpers\stdfile.c">
|
||||
<Filter>src\helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\itload.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\itload2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\itmisc.c">
|
||||
<Filter>src\it</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\itorder.c">
|
||||
<Filter>src\it</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\itread.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\itread2.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\itrender.c">
|
||||
<Filter>src\it</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\itunload.c">
|
||||
<Filter>src\it</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\load669.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\load6692.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadamf.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadamf2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadasy.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadasy2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadmod.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadmod2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadmtm.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadmtm2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadoldpsm.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadoldpsm2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadpsm.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadpsm2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadptm.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadptm2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadriff.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadriff2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loads3m.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loads3m2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadstm.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadstm2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadxm.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadxm2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\ptmeffect.c">
|
||||
<Filter>src\it</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\read669.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\read6692.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readam.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readamf.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readamf2.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readasy.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readdsmf.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readmod.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readmod2.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readmtm.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readoldpsm.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readpsm.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readptm.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readriff.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\reads3m.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\reads3m2.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readstm.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readstm2.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readxm.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readxm2.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\xmeffect.c">
|
||||
<Filter>src\it</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readokt.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readokt2.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadokt.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadokt2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadany.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\loadany2.c">
|
||||
<Filter>src\it\loaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readany.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\it\readany2.c">
|
||||
<Filter>src\it\readers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\helpers\resampler.c">
|
||||
<Filter>src\helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\helpers\tarray.c">
|
||||
<Filter>src\helpers</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\include\dumb.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\internal\barray.h">
|
||||
<Filter>include\internal</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\internal\dumb.h">
|
||||
<Filter>include\internal</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\internal\dumbfile.h">
|
||||
<Filter>include\internal</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\internal\fir_resampler.h">
|
||||
<Filter>include\internal</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\internal\it.h">
|
||||
<Filter>include\internal</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\internal\lpc.h">
|
||||
<Filter>include\internal</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\internal\riff.h">
|
||||
<Filter>include\internal</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\internal\stack_alloc.h">
|
||||
<Filter>include\internal</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\internal\resampler.h">
|
||||
<Filter>include\internal</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\internal\tarray.h">
|
||||
<Filter>include\internal</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\helpers\resamp3.inc">
|
||||
<Filter>src\helpers</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="..\..\src\helpers\resamp2.inc">
|
||||
<Filter>src\helpers</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="..\..\src\helpers\resample.inc">
|
||||
<Filter>src\helpers</Filter>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
</Project>
|
File diff suppressed because it is too large
Load diff
|
@ -18,7 +18,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|||
|
||||
#include "blargg_source.h"
|
||||
|
||||
unsigned const resampler_extra = 256;
|
||||
//unsigned const resampler_extra = 256;
|
||||
|
||||
Dual_Resampler::Dual_Resampler() :
|
||||
sample_buf_size(0),
|
||||
|
@ -71,6 +71,7 @@ void Dual_Resampler::play_frame_( Blip_Buffer& blip_buf, dsample_t* out )
|
|||
|
||||
long count = resampler.read( sample_buf.begin(), sample_buf_size );
|
||||
assert( count == (long) sample_buf_size );
|
||||
(void)count; // Silence warning in non-debug build
|
||||
|
||||
mix_samples( blip_buf, out );
|
||||
blip_buf.remove_samples( pair_count );
|
||||
|
|
|
@ -39,7 +39,7 @@ int const ram_addr = 0x2000;
|
|||
// status flags
|
||||
int const st_n = 0x80;
|
||||
int const st_v = 0x40;
|
||||
int const st_t = 0x20;
|
||||
//unused: int const st_t = 0x20;
|
||||
int const st_b = 0x10;
|
||||
int const st_d = 0x08;
|
||||
int const st_i = 0x04;
|
||||
|
|
|
@ -529,7 +529,7 @@ BOOST::uint8_t* Snes_Spc::run_until_( time_t end_time )\
|
|||
return ®S [r_cpuio0];\
|
||||
}
|
||||
|
||||
int const cpu_lag_max = 12 - 1; // DIV YA,X takes 12 clocks
|
||||
#define cpu_lag_max (12 - 1) // DIV YA,X takes 12 clocks
|
||||
|
||||
void Snes_Spc::end_frame( time_t end_time )
|
||||
{
|
||||
|
|
|
@ -19,18 +19,16 @@ if( NOT MSVC AND NOT APPLE )
|
|||
if( NOT CMAKE_CROSSCOMPILING )
|
||||
add_executable( arithchk arithchk.c )
|
||||
endif( NOT CMAKE_CROSSCOMPILING )
|
||||
get_target_property( ARITHCHK_EXE arithchk LOCATION )
|
||||
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/arith.h
|
||||
COMMAND ${ARITHCHK_EXE} >${CMAKE_CURRENT_BINARY_DIR}/arith.h
|
||||
COMMAND arithchk >${CMAKE_CURRENT_BINARY_DIR}/arith.h
|
||||
DEPENDS arithchk )
|
||||
|
||||
if( NOT CMAKE_CROSSCOMPILING )
|
||||
add_executable( qnan qnan.c arith.h )
|
||||
set( CROSS_EXPORTS ${CROSS_EXPORTS} arithchk qnan PARENT_SCOPE )
|
||||
endif( NOT CMAKE_CROSSCOMPILING )
|
||||
get_target_property( QNAN_EXE qnan LOCATION )
|
||||
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gd_qnan.h
|
||||
COMMAND ${QNAN_EXE} >${CMAKE_CURRENT_BINARY_DIR}/gd_qnan.h
|
||||
COMMAND qnan >${CMAKE_CURRENT_BINARY_DIR}/gd_qnan.h
|
||||
DEPENDS qnan )
|
||||
|
||||
set( GEN_FP_FILES arith.h gd_qnan.h )
|
||||
|
@ -44,7 +42,4 @@ add_library( gdtoa
|
|||
misc.c
|
||||
)
|
||||
target_link_libraries( gdtoa )
|
||||
if( GEN_FP_DEPS )
|
||||
add_dependencies( gdtoa ${GEN_FP_DEPS} )
|
||||
endif( GEN_FP_DEPS )
|
||||
|
||||
|
|
|
@ -2086,7 +2086,7 @@ void LzmaEnc_Finish(CLzmaEncHandle pp)
|
|||
if (p->mtMode)
|
||||
MatchFinderMt_ReleaseStream(&p->matchFinderMt);
|
||||
#else
|
||||
pp = pp;
|
||||
(void)pp;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue