Merge remote-tracking branch 'gzdoom/master' into newmaster

# Conflicts:
#	src/scripting/vmthunks.cpp
This commit is contained in:
Major Cooke 2019-10-18 12:58:10 -05:00
commit ce6c7d2a87
481 changed files with 29217 additions and 15859 deletions

View file

@ -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

View file

@ -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 )

View file

@ -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

View 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 )

View file

@ -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);

View file

@ -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

View file

@ -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 )

View file

@ -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
}

View file

@ -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);

View file

@ -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.

View file

@ -94,14 +94,14 @@ bool Hes_Cpu::run( hes_time_t end_time )
state_t s = this->state_;
this->state = &s;
// even on x86, using s.time in place of s_time was slower
int16_t s_time = s.time;
blargg_long s_time = s.time;
// registers
uint16_t pc = r.pc;
uint8_t a = r.a;
uint8_t x = r.x;
uint8_t y = r.y;
uint16_t sp;
uint_fast16_t pc = r.pc;
uint_fast8_t a = r.a;
uint_fast8_t x = r.x;
uint_fast8_t y = r.y;
uint_fast16_t sp;
SET_SP( r.sp );
#define IS_NEG (nz & 0x8080)
@ -120,11 +120,11 @@ bool Hes_Cpu::run( hes_time_t end_time )
nz |= ~in & st_z;\
} while ( 0 )
uint8_t status;
uint16_t c; // carry set if (c & 0x100) != 0
uint16_t nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
uint_fast8_t status;
uint_fast16_t c; // carry set if (c & 0x100) != 0
uint_fast16_t nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
{
uint8_t temp = r.status;
uint_fast8_t temp = r.status;
SET_STATUS( temp );
}
@ -153,7 +153,7 @@ loop:
check( (unsigned) x < 0x100 );
uint8_t const* instr = s.code_map [pc >> page_shift];
uint8_t opcode;
uint_fast8_t opcode;
// TODO: eliminate this special case
#if BLARGG_NONPORTABLE
@ -187,7 +187,7 @@ loop:
4,7,7,17,2,4,6,7,2,5,4,2,2,5,7,6 // F
}; // 0x00 was 8
uint16_t data;
uint_fast16_t data;
data = clock_table [opcode];
if ( (s_time += data) >= 0 )
goto possibly_out_of_time;
@ -224,7 +224,7 @@ possibly_out_of_time:
// TODO: more efficient way to handle negative branch that wraps PC around
#define BRANCH( cond )\
{\
int16_t offset = (int8_t) data;\
int_fast16_t offset = (int8_t) data;\
pc++;\
if ( !(cond) ) goto branch_not_taken;\
pc = uint16_t (pc + offset);\
@ -277,7 +277,7 @@ possibly_out_of_time:
case 0xCF:
case 0xDF:
case 0xEF: {
uint16_t t = 0x101 * READ_LOW( data );
uint_fast16_t t = 0x101 * READ_LOW( data );
t ^= 0xFF;
pc++;
data = GET_MSB();
@ -305,7 +305,7 @@ possibly_out_of_time:
goto branch_taken;
case 0x20: { // JSR
uint16_t temp = pc + 1;
uint_fast16_t temp = pc + 1;
pc = GET_ADDR();
WRITE_LOW( 0x100 | (sp - 1), temp >> 8 );
sp = (sp - 2) | 0x100;
@ -326,7 +326,7 @@ possibly_out_of_time:
case 0xBD:{// LDA abs,X
PAGE_CROSS_PENALTY( data + x );
uint16_t addr = GET_ADDR() + x;
uint_fast16_t addr = GET_ADDR() + x;
pc += 2;
CPU_READ_FAST( this, addr, TIME, nz );
a = nz;
@ -334,7 +334,7 @@ possibly_out_of_time:
}
case 0x9D:{// STA abs,X
uint16_t addr = GET_ADDR() + x;
uint_fast16_t addr = GET_ADDR() + x;
pc += 2;
CPU_WRITE_FAST( this, addr, a, TIME );
goto loop;
@ -348,7 +348,7 @@ possibly_out_of_time:
goto loop;
case 0xAE:{// LDX abs
uint16_t addr = GET_ADDR();
uint_fast16_t addr = GET_ADDR();
pc += 2;
CPU_READ_FAST( this, addr, TIME, nz );
x = nz;
@ -363,7 +363,7 @@ possibly_out_of_time:
// Load/store
{
uint16_t addr;
uint_fast16_t addr;
case 0x91: // STA (ind),Y
addr = 0x100 * READ_LOW( uint8_t (data + 1) );
addr += READ_LOW( data ) + y;
@ -389,7 +389,7 @@ possibly_out_of_time:
}
{
uint16_t addr;
uint_fast16_t addr;
case 0xA1: // LDA (ind,X)
data = uint8_t (data + x);
case 0xB2: // LDA (ind)
@ -419,7 +419,7 @@ possibly_out_of_time:
case 0xBE:{// LDX abs,y
PAGE_CROSS_PENALTY( data + y );
uint16_t addr = GET_ADDR() + y;
uint_fast16_t addr = GET_ADDR() + y;
pc += 2;
FLUSH_TIME();
x = nz = READ( addr );
@ -443,7 +443,7 @@ possibly_out_of_time:
case 0x3C: // BIT abs,x
data += x;
case 0x2C:{// BIT abs
uint16_t addr;
uint_fast16_t addr;
ADD_PAGE( addr );
FLUSH_TIME();
nz = READ( addr );
@ -466,7 +466,7 @@ possibly_out_of_time:
goto loop;
{
uint16_t addr;
uint_fast16_t addr;
case 0xB3: // TST abs,x
addr = GET_MSB() + x;
@ -499,7 +499,7 @@ possibly_out_of_time:
goto loop;
{
uint16_t addr;
uint_fast16_t addr;
case 0x0C: // TSB abs
case 0x1C: // TRB abs
addr = GET_ADDR();
@ -604,7 +604,7 @@ possibly_out_of_time:
data += x;
PAGE_CROSS_PENALTY( data );
case 0xAC:{// LDY abs
uint16_t addr = data + 0x100 * GET_MSB();
uint_fast16_t addr = data + 0x100 * GET_MSB();
pc += 2;
FLUSH_TIME();
y = nz = READ( addr );
@ -613,7 +613,7 @@ possibly_out_of_time:
}
{
uint8_t temp;
uint_fast8_t temp;
case 0x8C: // STY abs
temp = y;
goto store_abs;
@ -621,7 +621,7 @@ possibly_out_of_time:
case 0x8E: // STX abs
temp = x;
store_abs:
uint16_t addr = GET_ADDR();
uint_fast16_t addr = GET_ADDR();
pc += 2;
FLUSH_TIME();
WRITE( addr, temp );
@ -632,7 +632,7 @@ possibly_out_of_time:
// Compare
case 0xEC:{// CPX abs
uint16_t addr = GET_ADDR();
uint_fast16_t addr = GET_ADDR();
pc++;
FLUSH_TIME();
data = READ( addr );
@ -651,7 +651,7 @@ possibly_out_of_time:
goto loop;
case 0xCC:{// CPY abs
uint16_t addr = GET_ADDR();
uint_fast16_t addr = GET_ADDR();
pc++;
FLUSH_TIME();
data = READ( addr );
@ -678,7 +678,7 @@ possibly_out_of_time:
data = 0x100 * READ_LOW( uint8_t (data + 1) ) + READ_LOW( data );\
goto ptr##op;\
case op + 0x0C:{/* (ind),y */\
uint16_t temp = READ_LOW( data ) + y;\
uint_fast16_t temp = READ_LOW( data ) + y;\
PAGE_CROSS_PENALTY( temp );\
data = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\
goto ptr##op;\
@ -736,8 +736,8 @@ possibly_out_of_time:
adc_imm: {
if ( status & st_d )
debug_printf( "Decimal mode not supported\n" );
int16_t carry = c >> 8 & 1;
int16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend
int_fast16_t carry = c >> 8 & 1;
int_fast16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend
status &= ~st_v;
status |= ov >> 2 & 0x40;
c = nz = a + data + carry;
@ -765,7 +765,7 @@ possibly_out_of_time:
case 0x2A: { // ROL A
nz = a << 1;
int16_t temp = c >> 8 & 1;
int_fast16_t temp = c >> 8 & 1;
c = nz;
nz |= temp;
a = (uint8_t) nz;
@ -871,7 +871,7 @@ possibly_out_of_time:
case 0xD6: // DEC zp,x
data = uint8_t (data + x);
case 0xC6: // DEC zp
nz = (uint16_t) -1;
nz = (unsigned) -1;
add_nz_zp:
nz += READ_LOW( data );
write_nz_zp:
@ -896,7 +896,7 @@ possibly_out_of_time:
case 0xCE: // DEC abs
data = GET_ADDR();
dec_ptr:
nz = (uint16_t) -1;
nz = (unsigned) -1;
inc_common:
FLUSH_TIME();
nz += READ( data );
@ -936,7 +936,7 @@ possibly_out_of_time:
goto loop;
#define SWAP_REGS( r1, r2 ) {\
uint8_t t = r1;\
uint_fast8_t t = r1;\
r1 = r2;\
r2 = t;\
goto loop;\
@ -978,7 +978,7 @@ possibly_out_of_time:
goto loop;
case 0x40:{// RTI
uint8_t temp = READ_LOW( sp );
uint_fast8_t temp = READ_LOW( sp );
pc = READ_LOW( 0x100 | (sp - 0xFF) );
pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100;
sp = (sp - 0xFD) | 0x100;
@ -1012,8 +1012,8 @@ possibly_out_of_time:
goto loop;
case 0x28:{// PLP
uint8_t temp = POP();
uint8_t changed = status ^ temp;
uint_fast8_t temp = POP();
uint_fast8_t changed = status ^ temp;
SET_STATUS( temp );
if ( !(changed & st_i) )
goto loop; // I flag didn't change
@ -1024,7 +1024,7 @@ possibly_out_of_time:
#undef POP
case 0x08: { // PHP
uint8_t temp;
uint_fast8_t temp;
CALC_STATUS( temp );
PUSH( temp | st_b );
goto loop;
@ -1033,7 +1033,7 @@ possibly_out_of_time:
// Flags
case 0x38: // SEC
c = (uint16_t) ~0;
c = (unsigned) ~0;
goto loop;
case 0x18: // CLC
@ -1101,7 +1101,7 @@ possibly_out_of_time:
// Special
case 0x53:{// TAM
uint8_t const bits = data; // avoid using data across function call
uint_fast8_t const bits = data; // avoid using data across function call
pc++;
for ( int i = 0; i < 8; i++ )
if ( bits & (1 << i) )
@ -1125,7 +1125,7 @@ possibly_out_of_time:
case 0x03: // ST0
case 0x13: // ST1
case 0x23:{// ST2
uint16_t addr = opcode >> 4;
uint_fast16_t addr = opcode >> 4;
if ( addr )
addr++;
pc++;
@ -1147,7 +1147,7 @@ possibly_out_of_time:
goto loop;
case 0xF4: { // SET
//uint16_t operand = GET_MSB();
//fuint16 operand = GET_MSB();
debug_printf( "SET not handled\n" );
//switch ( data )
//{
@ -1159,10 +1159,10 @@ possibly_out_of_time:
// Block transfer
{
uint16_t in_alt;
int16_t in_inc;
uint16_t out_alt;
int16_t out_inc;
uint_fast16_t in_alt;
int_fast16_t in_inc;
uint_fast16_t out_alt;
int_fast16_t out_inc;
case 0xE3: // TIA
in_alt = 0;
@ -1193,8 +1193,8 @@ possibly_out_of_time:
in_alt = 0;
out_alt = 0;
bxfer:
uint16_t in = GET_LE16( instr + 0 );
uint16_t out = GET_LE16( instr + 2 );
uint_fast16_t in = GET_LE16( instr + 0 );
uint_fast16_t out = GET_LE16( instr + 2 );
int count = GET_LE16( instr + 4 );
if ( !count )
count = 0x10000;
@ -1206,7 +1206,7 @@ possibly_out_of_time:
do
{
// TODO: reads from $0800-$1400 in I/O page return 0 and don't access I/O
uint8_t t = READ( in );
uint_fast8_t t = READ( in );
in += in_inc;
in &= 0xFFFF;
s.time += 6;
@ -1246,7 +1246,7 @@ interrupt:
pc = GET_LE16( &READ_PROG( 0xFFF0 ) + result_ );
sp = (sp - 3) | 0x100;
uint8_t temp;
uint_fast8_t temp;
CALC_STATUS( temp );
if ( result_ == 6 )
temp |= st_b;
@ -1283,7 +1283,7 @@ out_of_time:
r.y = y;
{
uint8_t temp;
uint_fast8_t temp;
CALC_STATUS( temp );
r.status = temp;
}
@ -1293,4 +1293,3 @@ out_of_time:
return illegal_encountered;
}

View file

@ -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;

View file

@ -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

View file

@ -41,7 +41,7 @@ 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& ) { }
@ -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 );

View file

@ -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;
}

View file

@ -197,6 +197,16 @@ BLARGG_EXPORT gme_err_t gme_open_file( const char* path, Music_Emu** out, int sa
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 )
{

View file

@ -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* );

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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();

View file

@ -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

View 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);
}
};
}

View 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 )

View file

@ -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);

View file

@ -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);

View file

@ -155,7 +155,6 @@ typedef struct operator_struct {
class DBOPL : public OPLEmul
{
private:
Bitu chip_num;
op_type op[MAXOPERATORS];
Bits int_samplerate;

View file

@ -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);
}
};

View file

@ -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)
{

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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

View file

@ -1,5 +1,5 @@
#pragma once
#include "doomtype.h"
#include <stdint.h>
#include "genmidi.h"
#include "oplio.h"

View 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__

View file

@ -1,8 +1,6 @@
#ifndef OPL_H
#define OPL_H
#include "zstring.h"
// Abstract base class for OPL emulators
class OPLEmul

View 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_

View file

@ -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;

View file

@ -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;

View 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 )

View file

@ -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