mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-02-15 08:41:46 +00:00
Merge remote-tracking branch 'gzdoom/master' into newmaster
# Conflicts: # src/scripting/vmthunks.cpp
This commit is contained in:
commit
ce6c7d2a87
481 changed files with 29217 additions and 15859 deletions
43
.travis.yml
43
.travis.yml
|
@ -16,7 +16,7 @@ matrix:
|
|||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9"
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode10.2
|
||||
osx_image: xcode11.2
|
||||
env:
|
||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9"
|
||||
|
||||
|
@ -40,18 +40,6 @@ matrix:
|
|||
- libsdl2-dev
|
||||
- libgtk2.0-dev
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- GCC_VERSION=5
|
||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-Wno-maybe-uninitialized"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-5
|
||||
- libsdl2-dev
|
||||
- libgtk-3-dev
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
|
@ -66,20 +54,6 @@ matrix:
|
|||
- libsdl2-dev
|
||||
- libgtk2.0-dev
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- GCC_VERSION=7
|
||||
- CMAKE_OPTIONS="-DCMAKE_CXX_FLAGS=-Wno-implicit-fallthrough"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-7
|
||||
- libsdl2-dev
|
||||
- libgtk-3-dev
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
|
@ -107,15 +81,26 @@ matrix:
|
|||
- g++-9
|
||||
- libsdl2-dev
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env:
|
||||
- CLANG_VERSION=3.6
|
||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=RelWithDebInfo"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.6
|
||||
- libsdl2-dev
|
||||
- libgtk2.0-dev
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env:
|
||||
- CLANG_VERSION=8
|
||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=MinSizeRel -DDYN_OPENAL=NO -DDYN_SNDFILE=NO -DDYN_MPG123=NO -DDYN_FLUIDSYNTH=NO"
|
||||
- CMAKE_OPTIONS="-DDYN_OPENAL=NO -DDYN_SNDFILE=NO -DDYN_MPG123=NO -DDYN_FLUIDSYNTH=NO"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-xenial-8
|
||||
packages:
|
||||
- clang-8
|
||||
|
|
|
@ -143,6 +143,35 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
|||
set( PROFILE 0 CACHE BOOL "Enable profiling with gprof for Debug and RelWithDebInfo build types." )
|
||||
endif()
|
||||
|
||||
# Fast math flags, required by some subprojects
|
||||
set( ZD_FASTMATH_FLAG "" )
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
set( ZD_FASTMATH_FLAG "-ffast-math -ffp-contract=fast" )
|
||||
elseif( MSVC )
|
||||
set( ZD_FASTMATH_FLAG "/fp:fast" )
|
||||
endif()
|
||||
|
||||
macro( use_fast_math )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ZD_FASTMATH_FLAG}" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ZD_FASTMATH_FLAG}" )
|
||||
endmacro()
|
||||
|
||||
include( CheckFunctionExists )
|
||||
|
||||
macro( require_stricmp )
|
||||
CHECK_FUNCTION_EXISTS( stricmp STRICMP_EXISTS )
|
||||
if( NOT STRICMP_EXISTS )
|
||||
add_definitions( -Dstricmp=strcasecmp )
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro( require_strnicmp )
|
||||
CHECK_FUNCTION_EXISTS( strnicmp STRNICMP_EXISTS )
|
||||
if( NOT STRNICMP_EXISTS )
|
||||
add_definitions( -Dstrnicmp=strncasecmp )
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
option( NO_OPENAL "Disable OpenAL sound support" OFF )
|
||||
|
||||
find_package( BZip2 )
|
||||
|
@ -305,14 +334,6 @@ if (HAVE_VULKAN)
|
|||
add_subdirectory( libraries/glslang/OGLCompilersDLL )
|
||||
endif()
|
||||
|
||||
# Fast math flags, required by some subprojects
|
||||
set( ZD_FASTMATH_FLAG "" )
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
set( ZD_FASTMATH_FLAG "-ffast-math -ffp-contract=fast" )
|
||||
elseif( MSVC )
|
||||
set( ZD_FASTMATH_FLAG "/fp:fast" )
|
||||
endif()
|
||||
|
||||
if( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB )
|
||||
message( STATUS "Using system zlib, includes found at ${ZLIB_INCLUDE_DIR}" )
|
||||
else()
|
||||
|
@ -383,6 +404,13 @@ else()
|
|||
endif()
|
||||
|
||||
set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/lzma/C" )
|
||||
set( ADL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/adlmidi" )
|
||||
set( OPN_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/opnmidi" )
|
||||
set( TIMIDITYPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/timidityplus" )
|
||||
set( TIMIDITY_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/timidity" )
|
||||
set( WILDMIDI_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/wildmidi" )
|
||||
set( OPLSYNTH_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/oplsynth" )
|
||||
set( ZMUSIC_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zmusic" )
|
||||
|
||||
if( NOT CMAKE_CROSSCOMPILING )
|
||||
if( NOT CROSS_EXPORTS )
|
||||
|
@ -400,10 +428,22 @@ install(DIRECTORY docs/
|
|||
DESTINATION ${INSTALL_DOCS_PATH}
|
||||
COMPONENT "Documentation")
|
||||
|
||||
option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ON )
|
||||
option( DYN_OPENAL "Dynamically load OpenAL" ON )
|
||||
option( DYN_SNDFILE "Dynamically load libsndfile" ON )
|
||||
option( DYN_MPG123 "Dynamically load libmpg123" ON )
|
||||
|
||||
add_subdirectory( libraries/lzma )
|
||||
add_subdirectory( tools )
|
||||
add_subdirectory( libraries/dumb )
|
||||
add_subdirectory( libraries/gdtoa )
|
||||
add_subdirectory( libraries/adlmidi )
|
||||
add_subdirectory( libraries/opnmidi )
|
||||
add_subdirectory( libraries/timidity )
|
||||
add_subdirectory( libraries/timidityplus )
|
||||
add_subdirectory( libraries/wildmidi )
|
||||
add_subdirectory( libraries/oplsynth )
|
||||
add_subdirectory( libraries/zmusic )
|
||||
add_subdirectory( wadsrc )
|
||||
add_subdirectory( wadsrc_bm )
|
||||
add_subdirectory( wadsrc_lights )
|
||||
|
|
|
@ -11,6 +11,9 @@ The majority of original code uses a BSD-like lincese. See bsd.txt.
|
|||
The OpenGL renderer is released under the LGPL v3, except some bits
|
||||
of code that were inherited fro ZDoomGL.
|
||||
|
||||
Some code was taken from the Eternity Engine.
|
||||
Copyright (c) James Haley, Stephen McGranahan, et al.
|
||||
|
||||
This software is based in part on the work of the Independent JPEG Group.
|
||||
|
||||
This software uses the 'zlib' general purpose compression library by
|
||||
|
|
23
libraries/adlmidi/CMakeLists.txt
Normal file
23
libraries/adlmidi/CMakeLists.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
make_release_only()
|
||||
use_fast_math()
|
||||
|
||||
add_definitions(-DADLMIDI_DISABLE_MIDI_SEQUENCER)
|
||||
|
||||
add_library( adl STATIC
|
||||
adldata.cpp
|
||||
adlmidi.cpp
|
||||
adlmidi_load.cpp
|
||||
adlmidi_midiplay.cpp
|
||||
adlmidi_opl3.cpp
|
||||
adlmidi_private.cpp
|
||||
chips/dosbox/dbopl.cpp
|
||||
chips/dosbox_opl3.cpp
|
||||
chips/nuked/nukedopl3_174.c
|
||||
chips/nuked/nukedopl3.c
|
||||
chips/nuked_opl3.cpp
|
||||
chips/nuked_opl3_v174.cpp
|
||||
wopl/wopl_file.c
|
||||
)
|
||||
target_link_libraries( adl )
|
|
@ -504,9 +504,9 @@ ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn)
|
|||
{
|
||||
if(!device)
|
||||
return;
|
||||
MidiPlayer *play = GET_MIDI_PLAYER(device);
|
||||
assert(play);
|
||||
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
|
||||
MidiPlayer *play = GET_MIDI_PLAYER(device);
|
||||
assert(play);
|
||||
play->m_sequencer.setLoopEnabled(loopEn != 0);
|
||||
#else
|
||||
ADL_UNUSED(loopEn);
|
|
@ -2,10 +2,6 @@ cmake_minimum_required( VERSION 2.8.7 )
|
|||
|
||||
make_release_only()
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fomit-frame-pointer" )
|
||||
endif()
|
||||
|
||||
add_definitions( -DBZ_NO_STDIO )
|
||||
add_library( bz2 STATIC
|
||||
blocksort.c
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
make_release_only()
|
||||
use_fast_math()
|
||||
|
||||
include( CheckFunctionExists )
|
||||
include( CheckCXXCompilerFlag )
|
||||
|
@ -14,9 +15,6 @@ if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
|
|||
endif()
|
||||
endif()
|
||||
|
||||
# Enable fast flag for dumb
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ZD_FASTMATH_FLAG}" )
|
||||
|
||||
CHECK_FUNCTION_EXISTS( itoa ITOA_EXISTS )
|
||||
if( NOT ITOA_EXISTS )
|
||||
add_definitions( -DNEED_ITOA=1 )
|
||||
|
|
|
@ -802,6 +802,8 @@ DUH *make_duh(
|
|||
|
||||
void DUMBEXPORT duh_set_length(DUH *duh, int32 length);
|
||||
|
||||
extern short *(*dumb_decode_vorbis)(int outlen, const void *oggstream, int sizebytes);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
extern short *DUMBCALLBACK dumb_decode_vorbis(int outlen, const void *oggstream, int sizebytes);
|
||||
short * (*dumb_decode_vorbis)(int outlen, const void *oggstream, int sizebytes);
|
||||
|
||||
/** TODO:
|
||||
|
||||
|
@ -830,7 +830,7 @@ static int it_xm_read_sample_data(IT_SAMPLE *sample, unsigned char roguebytes, D
|
|||
sample->loop_start >>= 1;
|
||||
sample->loop_end >>= 1;
|
||||
}
|
||||
output = dumb_decode_vorbis(outlen, (char *)sample->data + 4, datasizebytes - 4);
|
||||
output = dumb_decode_vorbis? dumb_decode_vorbis(outlen, (char *)sample->data + 4, datasizebytes - 4) : NULL;
|
||||
if (output != NULL)
|
||||
{
|
||||
free(sample->data);
|
||||
|
|
|
@ -32,8 +32,7 @@ if( MSVC )
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4101 /wd4800 /wd4702 /wd4706 /wd4805 /wd4310 /wd4244 /wd4456 /wd4459 /wd4146 /wd4127 /wd4458 /wd4267 /wd4804")
|
||||
endif()
|
||||
|
||||
# Enable fast flag for GME
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ZD_FASTMATH_FLAG}" )
|
||||
use_fast_math()
|
||||
|
||||
# Default emulators to build (all of them! ;)
|
||||
# [ZDoom] No options, enable all of them by default.
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
|||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
||||
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||
|
||||
/*
|
||||
Last validated with zexall 2006.11.14 2:19 PM
|
||||
|
@ -162,11 +162,6 @@ static byte const ed_dd_timing [0x100] = {
|
|||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
};
|
||||
|
||||
// even on x86, using short and unsigned char was slower
|
||||
typedef int fint16;
|
||||
typedef unsigned fuint16;
|
||||
typedef unsigned fuint8;
|
||||
|
||||
bool Kss_Cpu::run( cpu_time_t end_time )
|
||||
{
|
||||
set_end_time( end_time );
|
||||
|
@ -183,10 +178,10 @@ bool Kss_Cpu::run( cpu_time_t end_time )
|
|||
rg = this->r.b;
|
||||
|
||||
cpu_time_t s_time = s.time;
|
||||
fuint16 pc = r.pc;
|
||||
fuint16 sp = r.sp;
|
||||
fuint16 ix = r.ix; // TODO: keep in memory for direct access?
|
||||
fuint16 iy = r.iy;
|
||||
uint_fast32_t pc = r.pc;
|
||||
uint_fast32_t sp = r.sp;
|
||||
uint_fast32_t ix = r.ix; // TODO: keep in memory for direct access?
|
||||
uint_fast32_t iy = r.iy;
|
||||
int flags = r.b.flags;
|
||||
|
||||
goto loop;
|
||||
|
@ -208,7 +203,7 @@ loop:
|
|||
uint8_t const* instr = s.read [pc >> page_shift];
|
||||
#define GET_ADDR() GET_LE16( instr )
|
||||
|
||||
fuint8 opcode;
|
||||
uint_fast8_t opcode;
|
||||
|
||||
// TODO: eliminate this special case
|
||||
#if BLARGG_NONPORTABLE
|
||||
|
@ -241,7 +236,7 @@ loop:
|
|||
11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F
|
||||
};
|
||||
|
||||
fuint16 data;
|
||||
uint_fast16_t data;
|
||||
data = base_timing [opcode];
|
||||
if ( (s_time += data) >= 0 )
|
||||
goto possibly_out_of_time;
|
||||
|
@ -297,7 +292,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0x3A:{// LD A,(addr)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint_fast16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
rg.a = READ( addr );
|
||||
goto loop;
|
||||
|
@ -385,7 +380,7 @@ possibly_out_of_time:
|
|||
|
||||
case 0xCD:{// CALL addr
|
||||
call_taken:
|
||||
fuint16 addr = pc + 2;
|
||||
uint_fast16_t addr = pc + 2;
|
||||
pc = GET_ADDR();
|
||||
sp = uint16_t (sp - 2);
|
||||
WRITE_WORD( sp, addr );
|
||||
|
@ -501,7 +496,7 @@ possibly_out_of_time:
|
|||
add_hl_data: {
|
||||
blargg_ulong sum = rp.hl + data;
|
||||
data ^= rp.hl;
|
||||
rp.hl = (uint16_t)sum;
|
||||
rp.hl = sum;
|
||||
flags = (flags & (S80 | Z40 | V04)) |
|
||||
(sum >> 16) |
|
||||
(sum >> 8 & (F20 | F08)) |
|
||||
|
@ -691,21 +686,21 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0x2A:{// LD HL,(addr)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint_fast16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
rp.hl = READ_WORD( addr );
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x32:{// LD (addr),A
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint_fast16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
WRITE( addr, rg.a );
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x22:{// LD (addr),HL
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint_fast16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
WRITE_WORD( addr, rp.hl );
|
||||
goto loop;
|
||||
|
@ -728,7 +723,7 @@ possibly_out_of_time:
|
|||
// Rotate
|
||||
|
||||
case 0x07:{// RLCA
|
||||
fuint16 temp = rg.a;
|
||||
uint_fast16_t temp = rg.a;
|
||||
temp = (temp << 1) | (temp >> 7);
|
||||
flags = (flags & (S80 | Z40 | P04)) |
|
||||
(temp & (F20 | F08 | C01));
|
||||
|
@ -737,7 +732,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
case 0x0F:{// RRCA
|
||||
fuint16 temp = rg.a;
|
||||
uint_fast16_t temp = rg.a;
|
||||
flags = (flags & (S80 | Z40 | P04)) |
|
||||
(temp & C01);
|
||||
temp = (temp << 7) | (temp >> 1);
|
||||
|
@ -756,7 +751,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
case 0x1F:{// RRA
|
||||
fuint16 temp = (flags << 7) | (rg.a >> 1);
|
||||
uint_fast16_t temp = (flags << 7) | (rg.a >> 1);
|
||||
flags = (flags & (S80 | Z40 | P04)) |
|
||||
(temp & (F20 | F08)) |
|
||||
(rg.a & C01);
|
||||
|
@ -766,7 +761,7 @@ possibly_out_of_time:
|
|||
|
||||
// Misc
|
||||
case 0x2F:{// CPL
|
||||
fuint16 temp = ~rg.a;
|
||||
uint_fast16_t temp = ~rg.a;
|
||||
flags = (flags & (S80 | Z40 | P04 | C01)) |
|
||||
(temp & (F20 | F08)) |
|
||||
(H10 | N02);
|
||||
|
@ -792,21 +787,21 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0xE3:{// EX (SP),HL
|
||||
fuint16 temp = READ_WORD( sp );
|
||||
uint_fast16_t temp = READ_WORD( sp );
|
||||
WRITE_WORD( sp, rp.hl );
|
||||
rp.hl = temp;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0xEB:{// EX DE,HL
|
||||
fuint16 temp = rp.hl;
|
||||
uint_fast16_t temp = rp.hl;
|
||||
rp.hl = rp.de;
|
||||
rp.de = temp;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0xD9:{// EXX DE,HL
|
||||
fuint16 temp = r.alt.w.bc;
|
||||
uint_fast16_t temp = r.alt.w.bc;
|
||||
r.alt.w.bc = rp.bc;
|
||||
rp.bc = temp;
|
||||
|
||||
|
@ -847,7 +842,7 @@ possibly_out_of_time:
|
|||
// Rotate left
|
||||
|
||||
#define RLC( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
uint_fast8_t result = read;\
|
||||
result = uint8_t (result << 1) | (result >> 7);\
|
||||
flags = SZ28P( result ) | (result & C01);\
|
||||
write;\
|
||||
|
@ -866,7 +861,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define RL( read, write ) {\
|
||||
fuint16 result = (read << 1) | (flags & C01);\
|
||||
uint_fast16_t result = (read << 1) | (flags & C01);\
|
||||
flags = SZ28PC( result );\
|
||||
write;\
|
||||
goto loop;\
|
||||
|
@ -884,7 +879,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define SLA( read, add, write ) {\
|
||||
fuint16 result = (read << 1) | add;\
|
||||
uint_fast16_t result = (read << 1) | add;\
|
||||
flags = SZ28PC( result );\
|
||||
write;\
|
||||
goto loop;\
|
||||
|
@ -915,7 +910,7 @@ possibly_out_of_time:
|
|||
// Rotate right
|
||||
|
||||
#define RRC( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
uint_fast8_t result = read;\
|
||||
flags = result & C01;\
|
||||
result = uint8_t (result << 7) | (result >> 1);\
|
||||
flags |= SZ28P( result );\
|
||||
|
@ -935,8 +930,8 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define RR( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
fuint8 temp = result & C01;\
|
||||
uint_fast8_t result = read;\
|
||||
uint_fast8_t temp = result & C01;\
|
||||
result = uint8_t (flags << 7) | (result >> 1);\
|
||||
flags = SZ28P( result ) | temp;\
|
||||
write;\
|
||||
|
@ -955,7 +950,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define SRA( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
uint_fast8_t result = read;\
|
||||
flags = result & C01;\
|
||||
result = (result & 0x80) | (result >> 1);\
|
||||
flags |= SZ28P( result );\
|
||||
|
@ -975,7 +970,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define SRL( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
uint_fast8_t result = read;\
|
||||
flags = result & C01;\
|
||||
result >>= 1;\
|
||||
flags |= SZ28P( result );\
|
||||
|
@ -1083,7 +1078,7 @@ possibly_out_of_time:
|
|||
blargg_ulong sum = temp + (flags & C01);
|
||||
flags = ~data >> 2 & N02;
|
||||
if ( flags )
|
||||
sum = (blargg_ulong)-(blargg_long)sum;
|
||||
sum = -sum;
|
||||
sum += rp.hl;
|
||||
temp ^= rp.hl;
|
||||
temp ^= sum;
|
||||
|
@ -1091,7 +1086,7 @@ possibly_out_of_time:
|
|||
(temp >> 8 & H10) |
|
||||
(sum >> 8 & (S80 | F20 | F08)) |
|
||||
((temp - -0x8000) >> 14 & V04);
|
||||
rp.hl = (uint16_t)sum;
|
||||
rp.hl = sum;
|
||||
if ( (uint16_t) sum )
|
||||
goto loop;
|
||||
flags |= Z40;
|
||||
|
@ -1119,7 +1114,7 @@ possibly_out_of_time:
|
|||
case 0x43: // LD (ADDR),BC
|
||||
case 0x53: // LD (ADDR),DE
|
||||
temp = R16( data, 4, 0x43 );
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint_fast16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
WRITE_WORD( addr, temp );
|
||||
goto loop;
|
||||
|
@ -1127,21 +1122,21 @@ possibly_out_of_time:
|
|||
|
||||
case 0x4B: // LD BC,(ADDR)
|
||||
case 0x5B:{// LD DE,(ADDR)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint_fast16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
R16( data, 4, 0x4B ) = READ_WORD( addr );
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x7B:{// LD SP,(ADDR)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint_fast16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
sp = READ_WORD( addr );
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x67:{// RRD
|
||||
fuint8 temp = READ( rp.hl );
|
||||
uint_fast8_t temp = READ( rp.hl );
|
||||
WRITE( rp.hl, (rg.a << 4) | (temp >> 4) );
|
||||
temp = (rg.a & 0xF0) | (temp & 0x0F);
|
||||
flags = (flags & C01) | SZ28P( temp );
|
||||
|
@ -1150,7 +1145,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
case 0x6F:{// RLD
|
||||
fuint8 temp = READ( rp.hl );
|
||||
uint_fast8_t temp = READ( rp.hl );
|
||||
WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) );
|
||||
temp = (rg.a & 0xF0) | (temp >> 4);
|
||||
flags = (flags & C01) | SZ28P( temp );
|
||||
|
@ -1174,7 +1169,7 @@ possibly_out_of_time:
|
|||
case 0xA1: // CPI
|
||||
case 0xB1: // CPIR
|
||||
inc = +1;
|
||||
fuint16 addr = rp.hl;
|
||||
uint_fast16_t addr = rp.hl;
|
||||
rp.hl = addr + inc;
|
||||
int temp = READ( addr );
|
||||
|
||||
|
@ -1207,7 +1202,7 @@ possibly_out_of_time:
|
|||
case 0xA0: // LDI
|
||||
case 0xB0: // LDIR
|
||||
inc = +1;
|
||||
fuint16 addr = rp.hl;
|
||||
uint_fast16_t addr = rp.hl;
|
||||
rp.hl = addr + inc;
|
||||
int temp = READ( addr );
|
||||
|
||||
|
@ -1239,7 +1234,7 @@ possibly_out_of_time:
|
|||
case 0xA3: // OUTI
|
||||
case 0xB3: // OTIR
|
||||
inc = +1;
|
||||
fuint16 addr = rp.hl;
|
||||
uint_fast16_t addr = rp.hl;
|
||||
rp.hl = addr + inc;
|
||||
int temp = READ( addr );
|
||||
|
||||
|
@ -1265,7 +1260,7 @@ possibly_out_of_time:
|
|||
case 0xB2: // INIR
|
||||
inc = +1;
|
||||
|
||||
fuint16 addr = rp.hl;
|
||||
uint_fast16_t addr = rp.hl;
|
||||
rp.hl = addr + inc;
|
||||
|
||||
int temp = IN( rp.bc );
|
||||
|
@ -1330,7 +1325,7 @@ possibly_out_of_time:
|
|||
|
||||
//////////////////////////////////////// DD/FD prefix
|
||||
{
|
||||
fuint16 ixy;
|
||||
uint_fast16_t ixy;
|
||||
case 0xDD:
|
||||
ixy = ix;
|
||||
goto ix_prefix;
|
||||
|
@ -1526,7 +1521,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0x22:{// LD (ADDR),IXY
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint_fast16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
WRITE_WORD( addr, ixy );
|
||||
goto loop;
|
||||
|
@ -1538,7 +1533,7 @@ possibly_out_of_time:
|
|||
goto set_ixy;
|
||||
|
||||
case 0x2A:{// LD IXY,(addr)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint_fast16_t addr = GET_ADDR();
|
||||
ixy = READ_WORD( addr );
|
||||
pc += 2;
|
||||
goto set_ixy;
|
||||
|
@ -1562,7 +1557,7 @@ possibly_out_of_time:
|
|||
case 0x3E: goto srl_data_addr; // SRL (IXY)
|
||||
|
||||
CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp)
|
||||
fuint8 temp = READ( data );
|
||||
uint_fast8_t temp = READ( data );
|
||||
int masked = temp & 1 << (data2 >> 3 & 7);
|
||||
flags = (flags & C01) | H10 |
|
||||
(masked & S80) |
|
||||
|
@ -1664,7 +1659,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0xE3:{// EX (SP),IXY
|
||||
fuint16 temp = READ_WORD( sp );
|
||||
uint_fast16_t temp = READ_WORD( sp );
|
||||
WRITE_WORD( sp, ixy );
|
||||
ixy = temp;
|
||||
goto set_ixy;
|
||||
|
|
|
@ -64,6 +64,8 @@ Music_Emu::Music_Emu()
|
|||
equalizer_.treble = -1.0;
|
||||
equalizer_.bass = 60;
|
||||
|
||||
emu_autoload_playback_limit_ = true;
|
||||
|
||||
static const char* const names [] = {
|
||||
"Voice 1", "Voice 2", "Voice 3", "Voice 4",
|
||||
"Voice 5", "Voice 6", "Voice 7", "Voice 8"
|
||||
|
@ -187,6 +189,16 @@ void Music_Emu::end_track_if_error( blargg_err_t err )
|
|||
}
|
||||
}
|
||||
|
||||
bool Music_Emu::autoload_playback_limit() const
|
||||
{
|
||||
return emu_autoload_playback_limit_;
|
||||
}
|
||||
|
||||
void Music_Emu::set_autoload_playback_limit( bool do_autoload_limit )
|
||||
{
|
||||
emu_autoload_playback_limit_ = do_autoload_limit;
|
||||
}
|
||||
|
||||
// Tell/Seek
|
||||
|
||||
blargg_long Music_Emu::msec_to_samples( blargg_long msec ) const
|
||||
|
|
|
@ -13,7 +13,7 @@ public:
|
|||
|
||||
// Set output sample rate. Must be called only once before loading file.
|
||||
blargg_err_t set_sample_rate( long sample_rate );
|
||||
|
||||
|
||||
// specifies if all 8 voices get rendered to their own stereo channel
|
||||
// default implementation of Music_Emu always returns not supported error (i.e. no multichannel support by default)
|
||||
// derived emus must override this if they support multichannel rendering
|
||||
|
@ -40,8 +40,8 @@ public:
|
|||
|
||||
// Names of voices
|
||||
const char** voice_names() const;
|
||||
|
||||
bool multi_channel() const;
|
||||
|
||||
bool multi_channel() const;
|
||||
|
||||
// Track status/control
|
||||
|
||||
|
@ -67,6 +67,13 @@ public:
|
|||
// true. Fade time can be changed while track is playing.
|
||||
void set_fade( long start_msec, long length_msec = 8000 );
|
||||
|
||||
// Controls whether or not to automatically load and obey track length
|
||||
// metadata for supported emulators.
|
||||
//
|
||||
// @since 0.6.2.
|
||||
bool autoload_playback_limit() const;
|
||||
void set_autoload_playback_limit( bool do_autoload_limit );
|
||||
|
||||
// Disable automatic end-of-track detection and skipping of silence at beginning
|
||||
void ignore_silence( bool disable = true );
|
||||
|
||||
|
@ -134,7 +141,7 @@ protected:
|
|||
double gain() const { return gain_; }
|
||||
double tempo() const { return tempo_; }
|
||||
void remute_voices();
|
||||
blargg_err_t set_multi_channel_( bool is_enabled );
|
||||
blargg_err_t set_multi_channel_( bool is_enabled );
|
||||
|
||||
virtual blargg_err_t set_sample_rate_( long sample_rate ) = 0;
|
||||
virtual void set_equalizer_( equalizer_t const& ) { }
|
||||
|
@ -158,10 +165,10 @@ private:
|
|||
double tempo_;
|
||||
double gain_;
|
||||
bool multi_channel_;
|
||||
|
||||
|
||||
// returns the number of output channels, i.e. usually 2 for stereo, unlesss multi_channel_ == true
|
||||
int out_channels() const { return this->multi_channel() ? 2*8 : 2; }
|
||||
|
||||
|
||||
long sample_rate_;
|
||||
blargg_long msec_to_samples( blargg_long msec ) const;
|
||||
|
||||
|
@ -170,6 +177,7 @@ private:
|
|||
blargg_long out_time; // number of samples played since start of track
|
||||
blargg_long emu_time; // number of samples emulator has generated since start of track
|
||||
bool emu_track_ended_; // emulator has reached end of track
|
||||
bool emu_autoload_playback_limit_; // whether to load and obey track length by default
|
||||
volatile bool track_ended_;
|
||||
void clear_track_vars();
|
||||
void end_track_if_error( blargg_err_t );
|
||||
|
|
|
@ -299,6 +299,12 @@ blargg_err_t Spc_Emu::start_track_( int track )
|
|||
RETURN_ERR( apu.load_spc( file_data, file_size ) );
|
||||
filter.set_gain( (int) (gain() * SPC_Filter::gain_unit) );
|
||||
apu.clear_echo();
|
||||
track_info_t spc_info;
|
||||
RETURN_ERR( track_info_( &spc_info, track ) );
|
||||
|
||||
// Set a default track length, need a non-zero fadeout
|
||||
if ( autoload_playback_limit() && ( spc_info.length > 0 ) )
|
||||
set_fade ( spc_info.length, 50 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -103,10 +103,10 @@ BLARGG_EXPORT gme_type_t gme_identify_extension( const char* extension_ )
|
|||
char const* end = strrchr( extension_, '.' );
|
||||
if ( end )
|
||||
extension_ = end + 1;
|
||||
|
||||
|
||||
char extension [6];
|
||||
to_uppercase( extension_, sizeof extension, extension );
|
||||
|
||||
|
||||
for ( gme_type_t const* types = gme_type_list(); *types; types++ )
|
||||
if ( !strcmp( extension, (*types)->extension_ ) )
|
||||
return *types;
|
||||
|
@ -133,30 +133,30 @@ BLARGG_EXPORT gme_err_t gme_identify_file( const char* path, gme_type_t* type_ou
|
|||
RETURN_ERR( in.read( header, sizeof header ) );
|
||||
*type_out = gme_identify_extension( gme_identify_header( header ) );
|
||||
}
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT gme_err_t gme_open_data( void const* data, long size, Music_Emu** out, int sample_rate )
|
||||
{
|
||||
require( (data || !size) && out );
|
||||
*out = 0;
|
||||
|
||||
|
||||
gme_type_t file_type = 0;
|
||||
if ( size >= 4 )
|
||||
file_type = gme_identify_extension( gme_identify_header( data ) );
|
||||
if ( !file_type )
|
||||
return gme_wrong_file_type;
|
||||
|
||||
|
||||
Music_Emu* emu = gme_new_emu( file_type, sample_rate );
|
||||
CHECK_ALLOC( emu );
|
||||
|
||||
|
||||
gme_err_t err = gme_load_data( emu, data, size );
|
||||
|
||||
|
||||
if ( err )
|
||||
delete emu;
|
||||
else
|
||||
*out = emu;
|
||||
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -164,13 +164,13 @@ BLARGG_EXPORT gme_err_t gme_open_file( const char* path, Music_Emu** out, int sa
|
|||
{
|
||||
require( path && out );
|
||||
*out = 0;
|
||||
|
||||
|
||||
GME_FILE_READER in;
|
||||
RETURN_ERR( in.open( path ) );
|
||||
|
||||
|
||||
char header [4];
|
||||
int header_size = 0;
|
||||
|
||||
|
||||
gme_type_t file_type = gme_identify_extension( path );
|
||||
if ( !file_type )
|
||||
{
|
||||
|
@ -180,23 +180,33 @@ BLARGG_EXPORT gme_err_t gme_open_file( const char* path, Music_Emu** out, int sa
|
|||
}
|
||||
if ( !file_type )
|
||||
return gme_wrong_file_type;
|
||||
|
||||
|
||||
Music_Emu* emu = gme_new_emu( file_type, sample_rate );
|
||||
CHECK_ALLOC( emu );
|
||||
|
||||
|
||||
// optimization: avoids seeking/re-reading header
|
||||
Remaining_Reader rem( header, header_size, &in );
|
||||
gme_err_t err = emu->load( rem );
|
||||
in.close();
|
||||
|
||||
|
||||
if ( err )
|
||||
delete emu;
|
||||
else
|
||||
*out = emu;
|
||||
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT void gme_set_autoload_playback_limit( Music_Emu *emu, int do_autoload_limit )
|
||||
{
|
||||
emu->set_autoload_playback_limit( do_autoload_limit != 0 );
|
||||
}
|
||||
|
||||
BLARGG_EXPORT int gme_autoload_playback_limit( Music_Emu *const emu )
|
||||
{
|
||||
return emu->autoload_playback_limit();
|
||||
}
|
||||
|
||||
// Used to implement gme_new_emu and gme_new_emu_multi_channel
|
||||
Music_Emu* gme_internal_new_emu_( gme_type_t type, int rate, bool multi_channel )
|
||||
{
|
||||
|
@ -204,7 +214,7 @@ Music_Emu* gme_internal_new_emu_( gme_type_t type, int rate, bool multi_channel
|
|||
{
|
||||
if ( rate == gme_info_only )
|
||||
return type->new_info();
|
||||
|
||||
|
||||
Music_Emu* me = type->new_emu();
|
||||
if ( me )
|
||||
{
|
||||
|
@ -224,7 +234,7 @@ Music_Emu* gme_internal_new_emu_( gme_type_t type, int rate, bool multi_channel
|
|||
if ( me->effects_buffer )
|
||||
me->set_buffer( me->effects_buffer );
|
||||
}
|
||||
|
||||
|
||||
if ( !(type->flags_ & 1) || me->effects_buffer )
|
||||
#endif
|
||||
{
|
||||
|
@ -276,30 +286,30 @@ BLARGG_EXPORT int gme_track_count( Music_Emu const* me ) { return me->track_coun
|
|||
struct gme_info_t_ : gme_info_t
|
||||
{
|
||||
track_info_t info;
|
||||
|
||||
|
||||
BLARGG_DISABLE_NOTHROW
|
||||
};
|
||||
|
||||
BLARGG_EXPORT gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, int track )
|
||||
{
|
||||
*out = NULL;
|
||||
|
||||
|
||||
gme_info_t_* info = BLARGG_NEW gme_info_t_;
|
||||
CHECK_ALLOC( info );
|
||||
|
||||
|
||||
gme_err_t err = me->track_info( &info->info, track );
|
||||
if ( err )
|
||||
{
|
||||
gme_free_info( info );
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
#define COPY(name) info->name = info->info.name;
|
||||
|
||||
|
||||
COPY( length );
|
||||
COPY( intro_length );
|
||||
COPY( loop_length );
|
||||
|
||||
|
||||
info->i4 = -1;
|
||||
info->i5 = -1;
|
||||
info->i6 = -1;
|
||||
|
@ -312,7 +322,7 @@ BLARGG_EXPORT gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, i
|
|||
info->i13 = -1;
|
||||
info->i14 = -1;
|
||||
info->i15 = -1;
|
||||
|
||||
|
||||
info->s7 = "";
|
||||
info->s8 = "";
|
||||
info->s9 = "";
|
||||
|
@ -322,7 +332,7 @@ BLARGG_EXPORT gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, i
|
|||
info->s13 = "";
|
||||
info->s14 = "";
|
||||
info->s15 = "";
|
||||
|
||||
|
||||
COPY( system );
|
||||
COPY( game );
|
||||
COPY( song );
|
||||
|
@ -330,9 +340,9 @@ BLARGG_EXPORT gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, i
|
|||
COPY( copyright );
|
||||
COPY( comment );
|
||||
COPY( dumper );
|
||||
|
||||
|
||||
#undef COPY
|
||||
|
||||
|
||||
info->play_length = info->length;
|
||||
if ( info->play_length <= 0 )
|
||||
{
|
||||
|
@ -340,9 +350,9 @@ BLARGG_EXPORT gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, i
|
|||
if ( info->play_length <= 0 )
|
||||
info->play_length = 150 * 1000; // 2.5 minutes
|
||||
}
|
||||
|
||||
|
||||
*out = info;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,25 @@ void gme_delete( Music_Emu* );
|
|||
Fade time can be changed while track is playing. */
|
||||
void gme_set_fade( Music_Emu*, int start_msec );
|
||||
|
||||
/**
|
||||
* If do_autoload_limit is nonzero, then automatically load track length
|
||||
* metadata (if present) and terminate playback once the track length has been
|
||||
* reached. Otherwise playback will continue for an arbitrary period of time
|
||||
* until a prolonged period of silence is detected.
|
||||
*
|
||||
* Not all individual emulators support this setting.
|
||||
*
|
||||
* By default, playback limits are loaded and applied.
|
||||
*
|
||||
* @since 0.6.2
|
||||
*/
|
||||
void gme_set_autoload_playback_limit( Music_Emu *, int do_autoload_limit );
|
||||
|
||||
/** See gme_set_autoload_playback_limit.
|
||||
* @since 0.6.2
|
||||
*/
|
||||
int gme_autoload_playback_limit( Music_Emu const* );
|
||||
|
||||
/* True if a track has reached its end */
|
||||
int gme_track_ended( Music_Emu const* );
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
make_release_only()
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ZD_FASTMATH_FLAG}" )
|
||||
use_fast_math()
|
||||
|
||||
# Request C++11
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.1)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
make_release_only()
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ZD_FASTMATH_FLAG}" )
|
||||
use_fast_math()
|
||||
|
||||
if(WIN32)
|
||||
add_subdirectory(OSDependent/Windows)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
make_release_only()
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ZD_FASTMATH_FLAG}" )
|
||||
use_fast_math()
|
||||
|
||||
# Request C++11
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.1)
|
||||
|
|
|
@ -493,7 +493,7 @@ public:
|
|||
// Add a branch to the continue_target of the current (innermost) loop.
|
||||
void createLoopContinue();
|
||||
|
||||
// Add an exit (e.g. "break") from the innermost loop that we're currently
|
||||
// Add an exit(e.g. "break") from the innermost loop that we're currently
|
||||
// in.
|
||||
void createLoopExit();
|
||||
|
||||
|
|
|
@ -2,10 +2,6 @@ cmake_minimum_required( VERSION 2.8.7 )
|
|||
|
||||
make_release_only()
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fomit-frame-pointer" )
|
||||
endif()
|
||||
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_7ZIP_PPMD_SUPPPORT" )
|
||||
|
||||
set( LZMA_FILES
|
||||
|
|
379
libraries/music_common/fileio.h
Normal file
379
libraries/music_common/fileio.h
Normal file
|
@ -0,0 +1,379 @@
|
|||
/*
|
||||
The common sound font reader interface. Used by GUS, Timidity++ and WildMidi
|
||||
backends for reading sound font configurations.
|
||||
|
||||
The FileInterface is also used by streaming sound formats.
|
||||
|
||||
Copyright (C) 2019 Christoph Oelckers
|
||||
|
||||
This program 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 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#if defined _WIN32 && !defined _WINDOWS_ // only define this if windows.h is not included.
|
||||
// I'd rather not include Windows.h for just this. This header is not supposed to pollute everything it touches.
|
||||
extern "C" __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned CodePage, unsigned long dwFlags, const char* lpMultiByteStr, int cbMultiByte, const wchar_t* lpWideCharStr, int cchWideChar);
|
||||
enum
|
||||
{
|
||||
CP_UTF8 = 65001
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace MusicIO
|
||||
{
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// This class defines a common file wrapper interface which allows these
|
||||
// libraries to work with any kind of file access API, e.g. stdio (provided below),
|
||||
// Win32, POSIX, iostream or custom implementations (like GZDoom's FileReader.)
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FileInterface
|
||||
{
|
||||
std::string filename;
|
||||
long length = -1;
|
||||
|
||||
// It's really too bad that the using code requires long instead of size_t.
|
||||
// Fortunately 2GB files are unlikely to come by here.
|
||||
protected:
|
||||
//
|
||||
virtual ~FileInterface() {}
|
||||
public:
|
||||
virtual char* gets(char* buff, int n) = 0;
|
||||
virtual long read(void* buff, int32_t size, int32_t nitems) = 0;
|
||||
long read(void* buff, int32_t size) { return read(buff, 1, size); }
|
||||
virtual long seek(long offset, int whence) = 0;
|
||||
virtual long tell() = 0;
|
||||
virtual void close()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
long filelength()
|
||||
{
|
||||
if (length == -1)
|
||||
{
|
||||
long pos = tell();
|
||||
seek(0, SEEK_END);
|
||||
length = tell();
|
||||
seek(pos, SEEK_SET);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Inplementation of the FileInterface for stdio's FILE*.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct StdioFileReader : public FileInterface
|
||||
{
|
||||
FILE* f = nullptr;
|
||||
|
||||
~StdioFileReader()
|
||||
{
|
||||
if (f) fclose(f);
|
||||
}
|
||||
char* gets(char* buff, int n) override
|
||||
{
|
||||
if (!f) return nullptr;
|
||||
return fgets(buff, n, f);
|
||||
}
|
||||
long read(void* buff, int32_t size, int32_t nitems) override
|
||||
{
|
||||
if (!f) return 0;
|
||||
return (long)fread(buff, size, nitems, f);
|
||||
}
|
||||
long seek(long offset, int whence) override
|
||||
{
|
||||
if (!f) return 0;
|
||||
return fseek(f, offset, whence);
|
||||
}
|
||||
long tell() override
|
||||
{
|
||||
if (!f) return 0;
|
||||
return ftell(f);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Inplementation of the FileInterface for a block of memory
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct MemoryReader : public FileInterface
|
||||
{
|
||||
const uint8_t *mData;
|
||||
long mLength;
|
||||
long mPos;
|
||||
|
||||
MemoryReader(const uint8_t *data, long length)
|
||||
: mData(data), mLength(length), mPos(0)
|
||||
{
|
||||
}
|
||||
|
||||
char* gets(char* strbuf, int len) override
|
||||
{
|
||||
if (len > mLength - mPos) len = mLength - mPos;
|
||||
if (len <= 0) return NULL;
|
||||
|
||||
char *p = strbuf;
|
||||
while (len > 1)
|
||||
{
|
||||
if (mData[mPos] == 0)
|
||||
{
|
||||
mPos++;
|
||||
break;
|
||||
}
|
||||
if (mData[mPos] != '\r')
|
||||
{
|
||||
*p++ = mData[mPos];
|
||||
len--;
|
||||
if (mData[mPos] == '\n')
|
||||
{
|
||||
mPos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mPos++;
|
||||
}
|
||||
if (p == strbuf) return nullptr;
|
||||
*p++ = 0;
|
||||
return strbuf;
|
||||
}
|
||||
long read(void* buff, int32_t size, int32_t nitems) override
|
||||
{
|
||||
long len = long(size) * nitems;
|
||||
if (len > mLength - mPos) len = mLength - mPos;
|
||||
if (len < 0) len = 0;
|
||||
memcpy(buff, mData + mPos, len);
|
||||
mPos += len;
|
||||
return len / size;
|
||||
}
|
||||
long seek(long offset, int whence) override
|
||||
{
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_CUR:
|
||||
offset += mPos;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
offset += mLength;
|
||||
break;
|
||||
|
||||
}
|
||||
if (offset < 0 || offset > mLength) return -1;
|
||||
mPos = offset;
|
||||
return 0;
|
||||
}
|
||||
long tell() override
|
||||
{
|
||||
return mPos;
|
||||
}
|
||||
protected:
|
||||
MemoryReader() {}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Inplementation of the FileInterface for an std::vector owned by the reader
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct VectorReader : public MemoryReader
|
||||
{
|
||||
std::vector<uint8_t> mVector;
|
||||
|
||||
template <class getFunc>
|
||||
VectorReader(getFunc getter) // read contents to a buffer and return a reader to it
|
||||
{
|
||||
getter(mVector);
|
||||
mData = mVector.data();
|
||||
mLength = (long)mVector.size();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// The follpwing two functions are needed to allow using UTF-8 in the file interface.
|
||||
// fopen on Windows is only safe for ASCII,
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
#ifdef _WIN32
|
||||
inline std::wstring wideString(const char *filename)
|
||||
{
|
||||
std::wstring filePathW;
|
||||
auto len = strlen(filename);
|
||||
filePathW.resize(len);
|
||||
int newSize = MultiByteToWideChar(CP_UTF8, 0, filename, (int)len, const_cast<wchar_t*>(filePathW.c_str()), (int)len);
|
||||
filePathW.resize(newSize);
|
||||
return filePathW;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline FILE* utf8_fopen(const char* filename, const char *mode)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
return fopen(filename, mode);
|
||||
#else
|
||||
auto fn = wideString(filename);
|
||||
auto mo = wideString(mode);
|
||||
return _wfopen(fn.c_str(), mo.c_str());
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
inline bool fileExists(const char *fn)
|
||||
{
|
||||
FILE *f = utf8_fopen(fn, "rb");
|
||||
if (!f) return false;
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// This class providea a framework for reading sound fonts.
|
||||
// This is needed when the sound font data is not read from
|
||||
// the file system. e.g. zipped GUS patch sets.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class SoundFontReaderInterface
|
||||
{
|
||||
public:
|
||||
virtual ~SoundFontReaderInterface() {}
|
||||
virtual struct FileInterface* open_file(const char* fn) = 0;
|
||||
virtual void add_search_path(const char* path) = 0;
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// A basic sound font reader for reading data from the file system.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FileSystemSoundFontReader : public SoundFontReaderInterface
|
||||
{
|
||||
protected:
|
||||
std::vector<std::string> mPaths;
|
||||
std::string mBaseFile;
|
||||
bool mAllowAbsolutePaths;
|
||||
|
||||
bool IsAbsPath(const char *name)
|
||||
{
|
||||
if (name[0] == '/' || name[0] == '\\') return true;
|
||||
#ifdef _WIN32
|
||||
/* [A-Za-z]: (for Windows) */
|
||||
if (isalpha(name[0]) && name[1] == ':') return true;
|
||||
#endif /* _WIN32 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
FileSystemSoundFontReader(const char *configfilename, bool allowabs = false)
|
||||
{
|
||||
// Note that this does not add the directory the base file is in to the search path!
|
||||
// The caller of this has to do it themselves!
|
||||
mBaseFile = configfilename;
|
||||
mAllowAbsolutePaths = allowabs;
|
||||
}
|
||||
|
||||
struct FileInterface* open_file(const char* fn) override
|
||||
{
|
||||
FILE *f = nullptr;
|
||||
std::string fullname;
|
||||
if (!fn)
|
||||
{
|
||||
f = utf8_fopen(mBaseFile.c_str(), "rt");
|
||||
fullname = mBaseFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!IsAbsPath(fn))
|
||||
{
|
||||
for(int i = (int)mPaths.size()-1; i>=0; i--)
|
||||
{
|
||||
fullname = mPaths[i] + fn;
|
||||
f = utf8_fopen(fullname.c_str(), "rt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!f) f = fopen(fn, "rt");
|
||||
}
|
||||
if (!f) return nullptr;
|
||||
auto tf = new StdioFileReader;
|
||||
tf->f = f;
|
||||
tf->filename = fullname;
|
||||
return tf;
|
||||
}
|
||||
|
||||
void add_search_path(const char* path) override
|
||||
{
|
||||
std::string p = path;
|
||||
if (p.back() != '/' && p.back() != '\\') p += '/'; // always let it end with a slash.
|
||||
mPaths.push_back(p);
|
||||
}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// This reader exists to trick Timidity config readers into accepting
|
||||
// a loose SF2 file by providing a fake config pointing to the given file.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class SF2Reader : public FileSystemSoundFontReader
|
||||
{
|
||||
std::string mMainConfigForSF2;
|
||||
|
||||
public:
|
||||
SF2Reader(const char *filename)
|
||||
: FileSystemSoundFontReader(filename)
|
||||
{
|
||||
mMainConfigForSF2 = "soundfont \"" + mBaseFile + "\"\n";
|
||||
}
|
||||
|
||||
struct FileInterface* open_file(const char* fn) override
|
||||
{
|
||||
if (fn == nullptr)
|
||||
{
|
||||
return new MemoryReader((uint8_t*)mMainConfigForSF2.c_str(), (long)mMainConfigForSF2.length());
|
||||
}
|
||||
else return FileSystemSoundFontReader::open_file(fn);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
26
libraries/oplsynth/CMakeLists.txt
Normal file
26
libraries/oplsynth/CMakeLists.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
use_fast_math()
|
||||
require_stricmp()
|
||||
require_strnicmp()
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -fomit-frame-pointer" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
|
||||
endif()
|
||||
|
||||
include_directories( oplsynth )
|
||||
|
||||
file( GLOB HEADER_FILES
|
||||
oplsynth/*.h
|
||||
)
|
||||
add_library( oplsynth STATIC
|
||||
fmopl.cpp
|
||||
musicblock.cpp
|
||||
nukedopl3.cpp
|
||||
opl_mus_player.cpp
|
||||
OPL3.cpp
|
||||
oplio.cpp
|
||||
dosbox/opl.cpp
|
||||
)
|
||||
target_link_libraries( oplsynth )
|
|
@ -44,16 +44,17 @@
|
|||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits>
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "opl.h"
|
||||
#include "m_random.h"
|
||||
#include "xs_Float.h"
|
||||
|
||||
static FRandom pr_opl3;
|
||||
#include "opl3_Float.h"
|
||||
|
||||
#define VOLUME_MUL 0.3333
|
||||
|
||||
static const double OPL_PI = 3.14159265358979323846; // matches value in gcc v2 math.h
|
||||
|
||||
namespace JavaOPL3
|
||||
{
|
||||
|
||||
|
@ -1645,7 +1646,8 @@ double HighHatOperator::getOperatorOutput(OPL3 *OPL3, double modulator) {
|
|||
// Top Cymbal, so we use the parent method and modify its output
|
||||
// accordingly afterwards.
|
||||
double operatorOutput = TopCymbalOperator::getOperatorOutput(OPL3, modulator, topCymbalOperatorPhase);
|
||||
if(operatorOutput == 0) operatorOutput = pr_opl3.GenRand_Real1()*envelope;
|
||||
double randval = rand() / (double)RAND_MAX;
|
||||
if(operatorOutput == 0) operatorOutput = randval*envelope;
|
||||
return operatorOutput;
|
||||
}
|
||||
|
||||
|
@ -1667,7 +1669,8 @@ double SnareDrumOperator::getOperatorOutput(OPL3 *OPL3, double modulator) {
|
|||
|
||||
double operatorOutput = getOutput(modulator, phase, waveform);
|
||||
|
||||
double noise = pr_opl3.GenRand_Real1() * envelope;
|
||||
double randval = rand() / (double)RAND_MAX;
|
||||
double noise = randval * envelope;
|
||||
|
||||
if(operatorOutput/envelope != 1 && operatorOutput/envelope != -1) {
|
||||
if(operatorOutput > 0) operatorOutput = noise;
|
||||
|
@ -1777,7 +1780,7 @@ void OPL3DataStruct::loadTremoloTable()
|
|||
void OperatorDataStruct::loadWaveforms() {
|
||||
int i;
|
||||
// 1st waveform: sinusoid.
|
||||
double theta = 0, thetaIncrement = 2*M_PI / 1024;
|
||||
double theta = 0, thetaIncrement = 2*OPL_PI / 1024;
|
||||
|
||||
for(i=0, theta=0; i<1024; i++, theta += thetaIncrement)
|
||||
waveforms[0][i] = sin(theta);
|
|
@ -24,12 +24,11 @@
|
|||
* Ken Silverman's official web site: "http://www.advsys.net/ken"
|
||||
*/
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "../opl.h"
|
||||
#include "../oplsynth/opl.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "m_random.h"
|
||||
|
||||
static FRandom pr_opl;
|
||||
|
||||
typedef uintptr_t Bitu;
|
||||
typedef intptr_t Bits;
|
||||
|
@ -153,7 +152,7 @@ void operator_advance_drums(op_type* op_pt1, Bit32s vib1, op_type* op_pt2, Bit32
|
|||
Bit32u c3 = op_pt3->tcount/FIXEDPT;
|
||||
Bit32u phasebit = (((c1 & 0x88) ^ ((c1<<5) & 0x80)) | ((c3 ^ (c3<<2)) & 0x20)) ? 0x02 : 0x00;
|
||||
|
||||
Bit32u noisebit = pr_opl.GenRand32() & 1;
|
||||
Bit32u noisebit = rand() & 1;
|
||||
|
||||
Bit32u snare_phase_bit = (Bit32u)(((Bitu)((op_pt1->tcount/FIXEDPT) / 0x100))&1);
|
||||
|
|
@ -155,7 +155,6 @@ typedef struct operator_struct {
|
|||
class DBOPL : public OPLEmul
|
||||
{
|
||||
private:
|
||||
Bitu chip_num;
|
||||
op_type op[MAXOPERATORS];
|
||||
|
||||
Bits int_samplerate;
|
|
@ -83,6 +83,8 @@ Revision History:
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
//#include "driver.h" /* use M.A.M.E. */
|
||||
#include "opl.h"
|
||||
|
||||
|
@ -550,8 +552,6 @@ static const int8_t lfo_pm_table[8*8*2] = {
|
|||
};
|
||||
|
||||
|
||||
/* lock level of common table */
|
||||
static int num_lock = 0;
|
||||
|
||||
/* work table */
|
||||
static signed int phase_modulation; /* phase modulation input (SLOT 2) */
|
||||
|
@ -1615,7 +1615,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
FString GetVoiceString(void *chip)
|
||||
std::string GetVoiceString(void *chip)
|
||||
{
|
||||
FM_OPL *OPL = (FM_OPL *)chip;
|
||||
char out[9*3];
|
||||
|
@ -1636,7 +1636,7 @@ public:
|
|||
out[i*3+1] = color;
|
||||
out[i*3+2] = '*';
|
||||
}
|
||||
return FString (out, 9*3);
|
||||
return std::string (out, 9*3);
|
||||
}
|
||||
};
|
||||
|
|
@ -29,8 +29,6 @@
|
|||
#include <string.h>
|
||||
#include "musicblock.h"
|
||||
|
||||
#include "c_cvars.h"
|
||||
|
||||
musicBlock::musicBlock ()
|
||||
{
|
||||
memset (this, 0, sizeof(*this));
|
||||
|
@ -186,7 +184,7 @@ void musicBlock::voiceKeyOn(uint32_t slot, uint32_t channo, GenMidiInstrument *i
|
|||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
CVAR(Bool, opl_singlevoice, 0, 0)
|
||||
bool opl_singlevoice;
|
||||
|
||||
void musicBlock::noteOn(uint32_t channel, uint8_t key, int volume)
|
||||
{
|
|
@ -37,23 +37,22 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "opl_mus_player.h"
|
||||
#include "opl.h"
|
||||
#include "w_wad.h"
|
||||
#include "templates.h"
|
||||
#include "c_cvars.h"
|
||||
#include "o_swap.h"
|
||||
|
||||
|
||||
#define IMF_RATE 700.0
|
||||
|
||||
EXTERN_CVAR (Int, opl_numchips)
|
||||
|
||||
OPLmusicBlock::OPLmusicBlock()
|
||||
OPLmusicBlock::OPLmusicBlock(int core, int numchips)
|
||||
{
|
||||
currentCore = core;
|
||||
scoredata = NULL;
|
||||
NextTickIn = 0;
|
||||
LastOffset = 0;
|
||||
NumChips = MIN(*opl_numchips, 2);
|
||||
NumChips = std::min(numchips, 2);
|
||||
Looping = false;
|
||||
FullPan = false;
|
||||
io = NULL;
|
||||
|
@ -65,11 +64,10 @@ OPLmusicBlock::~OPLmusicBlock()
|
|||
delete io;
|
||||
}
|
||||
|
||||
void OPLmusicBlock::ResetChips ()
|
||||
void OPLmusicBlock::ResetChips (int numchips)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(ChipAccess);
|
||||
io->Reset ();
|
||||
NumChips = io->Init(MIN(*opl_numchips, 2), FullPan);
|
||||
NumChips = io->Init(currentCore, std::min(numchips, 2), FullPan, false);
|
||||
}
|
||||
|
||||
void OPLmusicBlock::Restart()
|
||||
|
@ -80,31 +78,26 @@ void OPLmusicBlock::Restart()
|
|||
LastOffset = 0;
|
||||
}
|
||||
|
||||
OPLmusicFile::OPLmusicFile (FileReader &reader)
|
||||
: ScoreLen ((int)reader.GetLength())
|
||||
OPLmusicFile::OPLmusicFile (const void *data, size_t length, int core, int numchips, const char *&errormessage)
|
||||
: OPLmusicBlock(core, numchips), ScoreLen ((int)length)
|
||||
{
|
||||
if (io == NULL)
|
||||
static char errorbuffer[80];
|
||||
errormessage = nullptr;
|
||||
if (io == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
scoredata = new uint8_t[ScoreLen];
|
||||
memcpy(scoredata, data, length);
|
||||
|
||||
if (reader.Read(scoredata, ScoreLen) != ScoreLen)
|
||||
{
|
||||
fail: delete[] scoredata;
|
||||
scoredata = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 == (NumChips = io->Init(NumChips)))
|
||||
if (0 == (NumChips = io->Init(core, NumChips, false, false)))
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// Check for RDosPlay raw OPL format
|
||||
if (((uint32_t *)scoredata)[0] == MAKE_ID('R','A','W','A') &&
|
||||
((uint32_t *)scoredata)[1] == MAKE_ID('D','A','T','A'))
|
||||
if (!memcmp(scoredata, "RAWADATA", 8))
|
||||
{
|
||||
RawPlayer = RDosPlay;
|
||||
if (*(uint16_t *)(scoredata + 8) == 0)
|
||||
|
@ -114,26 +107,27 @@ fail: delete[] scoredata;
|
|||
SamplesPerTick = LittleShort(*(uint16_t *)(scoredata + 8)) / ADLIB_CLOCK_MUL;
|
||||
}
|
||||
// Check for DosBox OPL dump
|
||||
else if (((uint32_t *)scoredata)[0] == MAKE_ID('D','B','R','A') &&
|
||||
((uint32_t *)scoredata)[1] == MAKE_ID('W','O','P','L'))
|
||||
else if (!memcmp(scoredata, "DBRAWOPL", 8))
|
||||
{
|
||||
if (LittleShort(((uint16_t *)scoredata)[5]) == 1)
|
||||
{
|
||||
RawPlayer = DosBox1;
|
||||
SamplesPerTick = OPL_SAMPLE_RATE / 1000;
|
||||
ScoreLen = MIN<int>(ScoreLen - 24, LittleLong(((uint32_t *)scoredata)[4])) + 24;
|
||||
ScoreLen = std::min<int>(ScoreLen - 24, LittleLong(((uint32_t *)scoredata)[4])) + 24;
|
||||
}
|
||||
else if (((uint32_t *)scoredata)[2] == MAKE_ID(2,0,0,0))
|
||||
else if (LittleLong(((uint32_t *)scoredata)[2]) == 2)
|
||||
{
|
||||
bool okay = true;
|
||||
if (scoredata[21] != 0)
|
||||
{
|
||||
Printf("Unsupported DOSBox Raw OPL format %d\n", scoredata[20]);
|
||||
snprintf(errorbuffer, 80, "Unsupported DOSBox Raw OPL format %d\n", scoredata[20]);
|
||||
errormessage = errorbuffer;
|
||||
okay = false;
|
||||
}
|
||||
if (scoredata[22] != 0)
|
||||
{
|
||||
Printf("Unsupported DOSBox Raw OPL compression %d\n", scoredata[21]);
|
||||
snprintf(errorbuffer, 80, "Unsupported DOSBox Raw OPL compression %d\n", scoredata[21]);
|
||||
errormessage = errorbuffer;
|
||||
okay = false;
|
||||
}
|
||||
if (!okay)
|
||||
|
@ -141,17 +135,17 @@ fail: delete[] scoredata;
|
|||
RawPlayer = DosBox2;
|
||||
SamplesPerTick = OPL_SAMPLE_RATE / 1000;
|
||||
int headersize = 0x1A + scoredata[0x19];
|
||||
ScoreLen = MIN<int>(ScoreLen - headersize, LittleLong(((uint32_t *)scoredata)[3]) * 2) + headersize;
|
||||
ScoreLen = std::min<int>(ScoreLen - headersize, LittleLong(((uint32_t *)scoredata)[3]) * 2) + headersize;
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Unsupported DOSBox Raw OPL version %d.%d\n", LittleShort(((uint16_t *)scoredata)[4]), LittleShort(((uint16_t *)scoredata)[5]));
|
||||
snprintf(errorbuffer, 80, "Unsupported DOSBox Raw OPL version %d.%d\n", LittleShort(((uint16_t *)scoredata)[4]), LittleShort(((uint16_t *)scoredata)[5]));
|
||||
errormessage = errorbuffer;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
// Check for modified IMF format (includes a header)
|
||||
else if (((uint32_t *)scoredata)[0] == MAKE_ID('A','D','L','I') &&
|
||||
scoredata[4] == 'B' && scoredata[5] == 1)
|
||||
else if (!memcmp(scoredata, "ADLIB\1", 6))
|
||||
{
|
||||
int songlen;
|
||||
uint8_t *max = scoredata + ScoreLen;
|
||||
|
@ -167,9 +161,7 @@ fail: delete[] scoredata;
|
|||
if (score < max) score++; // Skip unknown byte
|
||||
if (score + 8 > max)
|
||||
{ // Not enough room left for song data
|
||||
delete[] scoredata;
|
||||
scoredata = NULL;
|
||||
return;
|
||||
goto fail;
|
||||
}
|
||||
songlen = LittleLong(*(uint32_t *)score);
|
||||
if (songlen != 0 && (songlen +=4) < ScoreLen - (score - scoredata))
|
||||
|
@ -179,10 +171,18 @@ fail: delete[] scoredata;
|
|||
}
|
||||
else
|
||||
{
|
||||
errormessage = "Unknown OPL format";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
Restart ();
|
||||
return;
|
||||
|
||||
fail:
|
||||
delete[] scoredata;
|
||||
scoredata = nullptr;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
OPLmusicFile::~OPLmusicFile ()
|
||||
|
@ -254,12 +254,10 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
|
|||
|
||||
memset(buff, 0, numbytes);
|
||||
|
||||
std::lock_guard<std::mutex> lock(ChipAccess);
|
||||
while (numsamples > 0)
|
||||
{
|
||||
double ticky = NextTickIn;
|
||||
int tick_in = int(NextTickIn);
|
||||
int samplesleft = MIN(numsamples, tick_in);
|
||||
int samplesleft = std::min(numsamples, tick_in);
|
||||
size_t i;
|
||||
|
||||
if (samplesleft > 0)
|
||||
|
@ -269,7 +267,6 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
|
|||
io->chips[i]->Update(samples1, samplesleft);
|
||||
}
|
||||
OffsetSamples(samples1, samplesleft << stereoshift);
|
||||
assert(NextTickIn == ticky);
|
||||
NextTickIn -= samplesleft;
|
||||
assert (NextTickIn >= 0);
|
||||
numsamples -= samplesleft;
|
||||
|
@ -364,7 +361,7 @@ void OPLmusicBlock::OffsetSamples(float *buff, int count)
|
|||
}
|
||||
else
|
||||
{
|
||||
ramp = MIN(count, MAX(196, largest_at));
|
||||
ramp = std::min(count, std::max(196, largest_at));
|
||||
step = (offset - LastOffset) / ramp;
|
||||
}
|
||||
offset = LastOffset;
|
||||
|
@ -528,40 +525,3 @@ int OPLmusicFile::PlayTick ()
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
ADD_STAT (opl)
|
||||
{
|
||||
return YM3812GetVoiceString ();
|
||||
}
|
||||
*/
|
||||
|
||||
OPLmusicFile::OPLmusicFile(const OPLmusicFile *source, const char *filename)
|
||||
{
|
||||
ScoreLen = source->ScoreLen;
|
||||
scoredata = new uint8_t[ScoreLen];
|
||||
memcpy(scoredata, source->scoredata, ScoreLen);
|
||||
SamplesPerTick = source->SamplesPerTick;
|
||||
RawPlayer = source->RawPlayer;
|
||||
score = source->score;
|
||||
NumChips = source->NumChips;
|
||||
WhichChip = 0;
|
||||
if (io != NULL)
|
||||
{
|
||||
delete io;
|
||||
}
|
||||
io = new DiskWriterIO(filename);
|
||||
NumChips = io->Init(NumChips);
|
||||
Restart();
|
||||
}
|
||||
|
||||
void OPLmusicFile::Dump()
|
||||
{
|
||||
int time;
|
||||
|
||||
time = PlayTick();
|
||||
while (time != 0)
|
||||
{
|
||||
io->WriteDelay(time);
|
||||
time = PlayTick();
|
||||
}
|
||||
}
|
|
@ -24,16 +24,15 @@
|
|||
//
|
||||
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
|
||||
#include "genmidi.h"
|
||||
#include "oplio.h"
|
||||
#include "opl.h"
|
||||
#include "c_cvars.h"
|
||||
#include "templates.h"
|
||||
|
||||
const double HALF_PI = (M_PI*0.5);
|
||||
|
||||
EXTERN_CVAR(Int, opl_core)
|
||||
extern int current_opl_core;
|
||||
const double HALF_PI = (3.14159265358979323846 * 0.5);
|
||||
|
||||
OPLio::~OPLio()
|
||||
{
|
||||
|
@ -53,11 +52,11 @@ void OPLio::WriteDelay(int ticks)
|
|||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
int OPLio::Init(uint32_t numchips, bool stereo, bool initopl3)
|
||||
int OPLio::Init(int core, uint32_t numchips, bool stereo, bool initopl3)
|
||||
{
|
||||
assert(numchips >= 1 && numchips <= countof(chips));
|
||||
assert(numchips >= 1 && numchips <= OPL_NUM_VOICES);
|
||||
uint32_t i;
|
||||
IsOPL3 = (current_opl_core == 1 || current_opl_core == 2 || current_opl_core == 3);
|
||||
IsOPL3 = (core == 1 || core == 2 || core == 3);
|
||||
|
||||
memset(chips, 0, sizeof(chips));
|
||||
if (IsOPL3)
|
||||
|
@ -66,7 +65,7 @@ int OPLio::Init(uint32_t numchips, bool stereo, bool initopl3)
|
|||
}
|
||||
for (i = 0; i < numchips; ++i)
|
||||
{
|
||||
OPLEmul *chip = IsOPL3 ? (current_opl_core == 1 ? DBOPLCreate(stereo) : (current_opl_core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo);
|
||||
OPLEmul *chip = IsOPL3 ? (core == 1 ? DBOPLCreate(stereo) : (core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo);
|
||||
if (chip == NULL)
|
||||
{
|
||||
break;
|
||||
|
@ -116,12 +115,12 @@ void OPLio::WriteInitState(bool initopl3)
|
|||
|
||||
void OPLio::Reset(void)
|
||||
{
|
||||
for (size_t i = 0; i < countof(chips); ++i)
|
||||
for (auto &c : chips)
|
||||
{
|
||||
if (chips[i] != NULL)
|
||||
if (c != nullptr)
|
||||
{
|
||||
delete chips[i];
|
||||
chips[i] = NULL;
|
||||
delete c;
|
||||
c = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -350,7 +349,7 @@ void OPLio::WriteVolume(uint32_t channel, struct GenMidiVoice *voice, uint32_t v
|
|||
{
|
||||
if (voice != nullptr)
|
||||
{
|
||||
uint32_t full_volume = volumetable[MIN<uint32_t>(127, (uint32_t)((uint64_t)vol1*vol2*vol3) / (127 * 127))];
|
||||
uint32_t full_volume = volumetable[std::min<uint32_t>(127, (uint32_t)((uint64_t)vol1*vol2*vol3) / (127 * 127))];
|
||||
int reg_volume2 = ((0x3f - voice->carrier.level) * full_volume) / 128;
|
||||
reg_volume2 = (0x3f - reg_volume2) | voice->carrier.scale;
|
||||
WriteOperator(OPL_REGS_LEVEL, channel, 1, reg_volume2);
|
|
@ -1,4 +1,17 @@
|
|||
#include "doomtype.h"
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
// With versions of GCC newer than 4.2, it appears it was determined that the
|
||||
// cost of an unaligned pointer on PPC was high enough to add padding to the
|
||||
// end of packed structs. For whatever reason __packed__ and pragma pack are
|
||||
// handled differently in this regard. Note that this only needs to be applied
|
||||
// to types which are used in arrays or sizeof is needed. This also prevents
|
||||
// code from taking references to the struct members.
|
||||
#define FORCE_PACKED __attribute__((__packed__))
|
||||
#else
|
||||
#define FORCE_PACKED
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct genmidi_op_t
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include "doomtype.h"
|
||||
#include <stdint.h>
|
||||
#include "genmidi.h"
|
||||
#include "oplio.h"
|
||||
|
255
libraries/oplsynth/oplsynth/o_swap.h
Normal file
255
libraries/oplsynth/oplsynth/o_swap.h
Normal file
|
@ -0,0 +1,255 @@
|
|||
//
|
||||
// DESCRIPTION:
|
||||
// Endianess handling, swapping 16bit and 32bit.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __M_SWAP_H__
|
||||
#define __M_SWAP_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// Endianess handling.
|
||||
// WAD files are stored little endian.
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <libkern/OSByteOrder.h>
|
||||
|
||||
inline short LittleShort(short x)
|
||||
{
|
||||
return (short)OSSwapLittleToHostInt16((uint16_t)x);
|
||||
}
|
||||
|
||||
inline unsigned short LittleShort(unsigned short x)
|
||||
{
|
||||
return OSSwapLittleToHostInt16(x);
|
||||
}
|
||||
|
||||
inline short LittleShort(int x)
|
||||
{
|
||||
return OSSwapLittleToHostInt16((uint16_t)x);
|
||||
}
|
||||
|
||||
inline unsigned short LittleShort(unsigned int x)
|
||||
{
|
||||
return OSSwapLittleToHostInt16((uint16_t)x);
|
||||
}
|
||||
|
||||
inline int LittleLong(int x)
|
||||
{
|
||||
return OSSwapLittleToHostInt32((uint32_t)x);
|
||||
}
|
||||
|
||||
inline unsigned int LittleLong(unsigned int x)
|
||||
{
|
||||
return OSSwapLittleToHostInt32(x);
|
||||
}
|
||||
|
||||
inline short BigShort(short x)
|
||||
{
|
||||
return (short)OSSwapBigToHostInt16((uint16_t)x);
|
||||
}
|
||||
|
||||
inline unsigned short BigShort(unsigned short x)
|
||||
{
|
||||
return OSSwapBigToHostInt16(x);
|
||||
}
|
||||
|
||||
inline int BigLong(int x)
|
||||
{
|
||||
return OSSwapBigToHostInt32((uint32_t)x);
|
||||
}
|
||||
|
||||
inline unsigned int BigLong(unsigned int x)
|
||||
{
|
||||
return OSSwapBigToHostInt32(x);
|
||||
}
|
||||
|
||||
#elif defined __BIG_ENDIAN__
|
||||
|
||||
// Swap 16bit, that is, MSB and LSB byte.
|
||||
// No masking with 0xFF should be necessary.
|
||||
inline short LittleShort (short x)
|
||||
{
|
||||
return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8));
|
||||
}
|
||||
|
||||
inline unsigned short LittleShort (unsigned short x)
|
||||
{
|
||||
return (unsigned short)((x>>8) | (x<<8));
|
||||
}
|
||||
|
||||
inline short LittleShort (int x)
|
||||
{
|
||||
return LittleShort((short)x);
|
||||
}
|
||||
|
||||
inline unsigned short LittleShort (unsigned int x)
|
||||
{
|
||||
return LittleShort((unsigned short)x);
|
||||
}
|
||||
|
||||
// Swapping 32bit.
|
||||
inline unsigned int LittleLong (unsigned int x)
|
||||
{
|
||||
return (unsigned int)(
|
||||
(x>>24)
|
||||
| ((x>>8) & 0xff00)
|
||||
| ((x<<8) & 0xff0000)
|
||||
| (x<<24));
|
||||
}
|
||||
|
||||
inline int LittleLong (int x)
|
||||
{
|
||||
return (int)(
|
||||
(((unsigned int)x)>>24)
|
||||
| ((((unsigned int)x)>>8) & 0xff00)
|
||||
| ((((unsigned int)x)<<8) & 0xff0000)
|
||||
| (((unsigned int)x)<<24));
|
||||
}
|
||||
|
||||
inline short BigShort(short x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
inline unsigned short BigShort(unsigned short x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
inline unsigned int BigLong(unsigned int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
inline int BigLong(int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline short LittleShort(short x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
inline unsigned short LittleShort(unsigned short x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
inline unsigned int LittleLong(unsigned int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
inline int LittleLong(int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
inline short BigShort(short x)
|
||||
{
|
||||
return (short)_byteswap_ushort((unsigned short)x);
|
||||
}
|
||||
|
||||
inline unsigned short BigShort(unsigned short x)
|
||||
{
|
||||
return _byteswap_ushort(x);
|
||||
}
|
||||
|
||||
inline int BigLong(int x)
|
||||
{
|
||||
return (int)_byteswap_ulong((unsigned long)x);
|
||||
}
|
||||
|
||||
inline unsigned int BigLong(unsigned int x)
|
||||
{
|
||||
return (unsigned int)_byteswap_ulong((unsigned long)x);
|
||||
}
|
||||
#pragma warning (default: 4035)
|
||||
|
||||
#else
|
||||
|
||||
inline short BigShort (short x)
|
||||
{
|
||||
return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8));
|
||||
}
|
||||
|
||||
inline unsigned short BigShort (unsigned short x)
|
||||
{
|
||||
return (unsigned short)((x>>8) | (x<<8));
|
||||
}
|
||||
|
||||
inline unsigned int BigLong (unsigned int x)
|
||||
{
|
||||
return (unsigned int)(
|
||||
(x>>24)
|
||||
| ((x>>8) & 0xff00)
|
||||
| ((x<<8) & 0xff0000)
|
||||
| (x<<24));
|
||||
}
|
||||
|
||||
inline int BigLong (int x)
|
||||
{
|
||||
return (int)(
|
||||
(((unsigned int)x)>>24)
|
||||
| ((((unsigned int)x)>>8) & 0xff00)
|
||||
| ((((unsigned int)x)<<8) & 0xff0000)
|
||||
| (((unsigned int)x)<<24));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // __BIG_ENDIAN__
|
||||
|
||||
// These may be destructive so they should create errors
|
||||
unsigned long BigLong(unsigned long) = delete;
|
||||
long BigLong(long) = delete;
|
||||
unsigned long LittleLong(unsigned long) = delete;
|
||||
long LittleLong(long) = delete;
|
||||
|
||||
|
||||
// Data accessors, since some data is highly likely to be unaligned.
|
||||
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
|
||||
inline int GetShort(const unsigned char *foo)
|
||||
{
|
||||
return *(const short *)foo;
|
||||
}
|
||||
inline int GetInt(const unsigned char *foo)
|
||||
{
|
||||
return *(const int *)foo;
|
||||
}
|
||||
#else
|
||||
inline int GetShort(const unsigned char *foo)
|
||||
{
|
||||
return short(foo[0] | (foo[1] << 8));
|
||||
}
|
||||
inline int GetInt(const unsigned char *foo)
|
||||
{
|
||||
return int(foo[0] | (foo[1] << 8) | (foo[2] << 16) | (foo[3] << 24));
|
||||
}
|
||||
#endif
|
||||
inline int GetBigInt(const unsigned char *foo)
|
||||
{
|
||||
return int((foo[0] << 24) | (foo[1] << 16) | (foo[2] << 8) | foo[3]);
|
||||
}
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
inline int GetNativeInt(const unsigned char *foo)
|
||||
{
|
||||
return GetBigInt(foo);
|
||||
}
|
||||
#else
|
||||
inline int GetNativeInt(const unsigned char *foo)
|
||||
{
|
||||
return GetInt(foo);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __M_SWAP_H__
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef OPL_H
|
||||
#define OPL_H
|
||||
|
||||
#include "zstring.h"
|
||||
|
||||
// Abstract base class for OPL emulators
|
||||
|
||||
class OPLEmul
|
238
libraries/oplsynth/oplsynth/opl3_Float.h
Normal file
238
libraries/oplsynth/oplsynth/opl3_Float.h
Normal file
|
@ -0,0 +1,238 @@
|
|||
// ====================================================================================================================
|
||||
// ====================================================================================================================
|
||||
// xs_Float.h
|
||||
//
|
||||
// Source: "Know Your FPU: Fixing Floating Fast"
|
||||
// http://www.stereopsis.com/sree/fpu2006.html
|
||||
//
|
||||
// xs_CRoundToInt: Round toward nearest, but ties round toward even (just like FISTP)
|
||||
// xs_ToInt: Round toward zero, just like the C (int) cast
|
||||
// xs_FloorToInt: Round down
|
||||
// xs_CeilToInt: Round up
|
||||
// xs_RoundToInt: Round toward nearest, but ties round up
|
||||
// ====================================================================================================================
|
||||
// ====================================================================================================================
|
||||
#ifndef _xs_FLOAT_H_
|
||||
#define _xs_FLOAT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// ====================================================================================================================
|
||||
// Defines
|
||||
// ====================================================================================================================
|
||||
#ifndef _xs_DEFAULT_CONVERSION
|
||||
#define _xs_DEFAULT_CONVERSION 0
|
||||
#endif //_xs_DEFAULT_CONVERSION
|
||||
|
||||
|
||||
#if __BIG_ENDIAN__
|
||||
#define _xs_iexp_ 0
|
||||
#define _xs_iman_ 1
|
||||
#else
|
||||
#define _xs_iexp_ 1 //intel is little endian
|
||||
#define _xs_iman_ 0
|
||||
#endif //BigEndian_
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define finline inline
|
||||
#else
|
||||
#define finline __forceinline
|
||||
#endif
|
||||
|
||||
typedef double real64;
|
||||
|
||||
|
||||
union _xs_doubleints
|
||||
{
|
||||
real64 val;
|
||||
uint32_t ival[2];
|
||||
};
|
||||
|
||||
#if 0
|
||||
#define _xs_doublecopysgn(a,b) ((int32_t*)&a)[_xs_iexp_]&=~(((int32_t*)&b)[_xs_iexp_]&0x80000000)
|
||||
#define _xs_doubleisnegative(a) ((((int32_t*)&a)[_xs_iexp_])|0x80000000)
|
||||
#endif
|
||||
|
||||
// ====================================================================================================================
|
||||
// Constants
|
||||
// ====================================================================================================================
|
||||
const real64 _xs_doublemagic = real64 (6755399441055744.0); //2^52 * 1.5, uses limited precisicion to floor
|
||||
const real64 _xs_doublemagicdelta = (1.5e-8); //almost .5f = .5f + 1e^(number of exp bit)
|
||||
const real64 _xs_doublemagicroundeps = (.5f-_xs_doublemagicdelta); //almost .5f = .5f - 1e^(number of exp bit)
|
||||
|
||||
|
||||
// ====================================================================================================================
|
||||
// Prototypes
|
||||
// ====================================================================================================================
|
||||
static int32_t xs_CRoundToInt (real64 val, real64 dmr = _xs_doublemagic);
|
||||
static int32_t xs_ToInt (real64 val, real64 dme = -_xs_doublemagicroundeps);
|
||||
static int32_t xs_FloorToInt (real64 val, real64 dme = _xs_doublemagicroundeps);
|
||||
static int32_t xs_CeilToInt (real64 val, real64 dme = _xs_doublemagicroundeps);
|
||||
static int32_t xs_RoundToInt (real64 val);
|
||||
|
||||
//int32_t versions
|
||||
finline static int32_t xs_CRoundToInt (int32_t val) {return val;}
|
||||
finline static int32_t xs_ToInt (int32_t val) {return val;}
|
||||
|
||||
|
||||
|
||||
// ====================================================================================================================
|
||||
// Fix Class
|
||||
// ====================================================================================================================
|
||||
template <int32_t N> class xs_Fix
|
||||
{
|
||||
public:
|
||||
typedef int32_t Fix;
|
||||
|
||||
// ====================================================================================================================
|
||||
// Basic Conversion from Numbers
|
||||
// ====================================================================================================================
|
||||
finline static Fix ToFix (int32_t val) {return val<<N;}
|
||||
finline static Fix ToFix (real64 val) {return xs_ConvertToFixed(val);}
|
||||
|
||||
// ====================================================================================================================
|
||||
// Basic Conversion to Numbers
|
||||
// ====================================================================================================================
|
||||
finline static real64 ToReal (Fix f) {return real64(f)/real64(1<<N);}
|
||||
finline static int32_t ToInt (Fix f) {return f>>N;}
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
// ====================================================================================================================
|
||||
// Helper function - mainly to preserve _xs_DEFAULT_CONVERSION
|
||||
// ====================================================================================================================
|
||||
finline static int32_t xs_ConvertToFixed (real64 val)
|
||||
{
|
||||
#if _xs_DEFAULT_CONVERSION==0
|
||||
return xs_CRoundToInt(val, _xs_doublemagic/(1<<N));
|
||||
#else
|
||||
return (long)((val)*(1<<N));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
finline static int32_t xs_ToFixed(int32_t n, real64 val)
|
||||
{
|
||||
#if _xs_DEFAULT_CONVERSION==0
|
||||
return xs_CRoundToInt(val, _xs_doublemagic/(1<<n));
|
||||
#else
|
||||
return (long)((val)*(1<<N));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// ====================================================================================================================
|
||||
// ====================================================================================================================
|
||||
// Inline implementation
|
||||
// ====================================================================================================================
|
||||
// ====================================================================================================================
|
||||
finline static int32_t xs_CRoundToInt(real64 val, real64 dmr)
|
||||
{
|
||||
#if _xs_DEFAULT_CONVERSION==0
|
||||
_xs_doubleints uval;
|
||||
uval.val = val + dmr;
|
||||
return uval.ival[_xs_iman_];
|
||||
#else
|
||||
return int32_t(floor(val+.5));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ====================================================================================================================
|
||||
finline static int32_t xs_ToInt(real64 val, real64 dme)
|
||||
{
|
||||
/* unused - something else I tried...
|
||||
_xs_doublecopysgn(dme,val);
|
||||
return xs_CRoundToInt(val+dme);
|
||||
return 0;
|
||||
*/
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
// VC++ 2005's standard cast is a little bit faster than this
|
||||
// magic number code. (Which is pretty amazing!) SSE has the
|
||||
// fastest C-style float->int conversion, but unfortunately,
|
||||
// checking for SSE support every time you need to do a
|
||||
// conversion completely negates its performance advantage.
|
||||
return int32_t(val);
|
||||
#else
|
||||
#if _xs_DEFAULT_CONVERSION==0
|
||||
return (val<0) ? xs_CRoundToInt(val-dme) :
|
||||
xs_CRoundToInt(val+dme);
|
||||
#else
|
||||
return int32_t(val);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ====================================================================================================================
|
||||
finline static int32_t xs_FloorToInt(real64 val, real64 dme)
|
||||
{
|
||||
#if _xs_DEFAULT_CONVERSION==0
|
||||
return xs_CRoundToInt (val - dme);
|
||||
#else
|
||||
return floor(val);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ====================================================================================================================
|
||||
finline static int32_t xs_CeilToInt(real64 val, real64 dme)
|
||||
{
|
||||
#if _xs_DEFAULT_CONVERSION==0
|
||||
return xs_CRoundToInt (val + dme);
|
||||
#else
|
||||
return ceil(val);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ====================================================================================================================
|
||||
finline static int32_t xs_RoundToInt(real64 val)
|
||||
{
|
||||
#if _xs_DEFAULT_CONVERSION==0
|
||||
// Yes, it is important that two fadds be generated, so you cannot override the dmr
|
||||
// passed to xs_CRoundToInt with _xs_doublemagic + _xs_doublemagicdelta. If you do,
|
||||
// you'll end up with Banker's Rounding again.
|
||||
return xs_CRoundToInt (val + _xs_doublemagicdelta);
|
||||
#else
|
||||
return floor(val+.5);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ====================================================================================================================
|
||||
// ====================================================================================================================
|
||||
// Unsigned variants
|
||||
// ====================================================================================================================
|
||||
// ====================================================================================================================
|
||||
finline static uint32_t xs_CRoundToUInt(real64 val)
|
||||
{
|
||||
return (uint32_t)xs_CRoundToInt(val);
|
||||
}
|
||||
|
||||
finline static uint32_t xs_FloorToUInt(real64 val)
|
||||
{
|
||||
return (uint32_t)xs_FloorToInt(val);
|
||||
}
|
||||
|
||||
finline static uint32_t xs_CeilToUInt(real64 val)
|
||||
{
|
||||
return (uint32_t)xs_CeilToInt(val);
|
||||
}
|
||||
|
||||
finline static uint32_t xs_RoundToUInt(real64 val)
|
||||
{
|
||||
return (uint32_t)xs_RoundToInt(val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ====================================================================================================================
|
||||
// ====================================================================================================================
|
||||
#endif // _xs_FLOAT_H_
|
|
@ -1,16 +1,17 @@
|
|||
#pragma once
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "musicblock.h"
|
||||
|
||||
class FileReader;
|
||||
|
||||
class OPLmusicBlock : public musicBlock
|
||||
{
|
||||
public:
|
||||
OPLmusicBlock();
|
||||
OPLmusicBlock(int core, int numchips);
|
||||
virtual ~OPLmusicBlock();
|
||||
|
||||
bool ServiceStream(void *buff, int numbytes);
|
||||
void ResetChips();
|
||||
void ResetChips(int numchips);
|
||||
|
||||
virtual void Restart();
|
||||
|
||||
|
@ -20,31 +21,28 @@ protected:
|
|||
|
||||
uint8_t *score;
|
||||
uint8_t *scoredata;
|
||||
int playingcount;
|
||||
double NextTickIn;
|
||||
double SamplesPerTick;
|
||||
int NumChips;
|
||||
bool Looping;
|
||||
double LastOffset;
|
||||
int playingcount;
|
||||
int NumChips;
|
||||
int currentCore;
|
||||
bool Looping;
|
||||
bool FullPan;
|
||||
|
||||
std::mutex ChipAccess;
|
||||
};
|
||||
|
||||
class OPLmusicFile : public OPLmusicBlock
|
||||
{
|
||||
public:
|
||||
OPLmusicFile(FileReader &reader);
|
||||
OPLmusicFile(const OPLmusicFile *source, const char *filename);
|
||||
OPLmusicFile(const void *data, size_t length, int core, int numchips, const char *&errormessage);
|
||||
virtual ~OPLmusicFile();
|
||||
|
||||
bool IsValid() const;
|
||||
void SetLooping(bool loop);
|
||||
void Restart();
|
||||
void Dump();
|
||||
|
||||
protected:
|
||||
OPLmusicFile() {}
|
||||
OPLmusicFile(int core, int numchips) : OPLmusicBlock(core, numchips) {}
|
||||
int PlayTick();
|
||||
|
||||
enum { RDosPlay, IMF, DosBox1, DosBox2 } RawPlayer;
|
|
@ -55,6 +55,7 @@ enum
|
|||
};
|
||||
|
||||
struct GenMidiVoice;
|
||||
struct genmidi_op_t;
|
||||
|
||||
struct OPLio
|
||||
{
|
||||
|
@ -72,7 +73,7 @@ struct OPLio
|
|||
void MuteChannel(uint32_t chan);
|
||||
void StopPlayback();
|
||||
|
||||
virtual int Init(uint32_t numchips, bool stereo = false, bool initopl3 = false);
|
||||
virtual int Init(int core, uint32_t numchips, bool stereo, bool initopl3);
|
||||
virtual void Reset();
|
||||
virtual void WriteRegister(int which, uint32_t reg, uint8_t data);
|
||||
virtual void SetClockRate(double samples_per_tick);
|
||||
|
@ -84,18 +85,6 @@ struct OPLio
|
|||
bool IsOPL3;
|
||||
};
|
||||
|
||||
struct DiskWriterIO : public OPLio
|
||||
{
|
||||
DiskWriterIO(const char *filename);
|
||||
~DiskWriterIO();
|
||||
|
||||
int Init(uint32_t numchips, bool notused, bool initopl3);
|
||||
void SetClockRate(double samples_per_tick);
|
||||
void WriteDelay(int ticks);
|
||||
|
||||
FString Filename;
|
||||
};
|
||||
|
||||
struct OPLChannel
|
||||
{
|
||||
uint32_t Instrument;
|
25
libraries/opnmidi/CMakeLists.txt
Normal file
25
libraries/opnmidi/CMakeLists.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
make_release_only()
|
||||
use_fast_math()
|
||||
|
||||
# we play with out own sequencer
|
||||
add_definitions(-DOPNMIDI_DISABLE_MIDI_SEQUENCER)
|
||||
|
||||
# Disable OPNMIDI's experimental yet emulator (using of it has some issues and missing notes in playback)
|
||||
add_definitions(-DOPNMIDI_DISABLE_GX_EMULATOR)
|
||||
|
||||
add_library( opn STATIC
|
||||
chips/gens_opn2.cpp
|
||||
chips/gens/Ym2612_Emu.cpp
|
||||
chips/mame/mame_ym2612fm.c
|
||||
chips/mame_opn2.cpp
|
||||
chips/nuked_opn2.cpp
|
||||
chips/nuked/ym3438.c
|
||||
opnmidi.cpp
|
||||
opnmidi_load.cpp
|
||||
opnmidi_midiplay.cpp
|
||||
opnmidi_opn2.cpp
|
||||
opnmidi_private.cpp
|
||||
wopn/wopn_file.c )
|
||||
target_link_libraries( opn )
|
|
@ -361,9 +361,9 @@ OPNMIDI_EXPORT void opn2_setLoopEnabled(OPN2_MIDIPlayer *device, int loopEn)
|
|||
{
|
||||
if(!device)
|
||||
return;
|
||||
MidiPlayer *play = GET_MIDI_PLAYER(device);
|
||||
assert(play);
|
||||
#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
|
||||
MidiPlayer *play = GET_MIDI_PLAYER(device);
|
||||
assert(play);
|
||||
play->m_sequencer.setLoopEnabled(loopEn != 0);
|
||||
#else
|
||||
ADL_UNUSED(loopEn);
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue