Switched to OPL emulation to DOSBox dbopl emulator.
Fixed SB Pro v2. Clarified GPL license in readme.txt.
This commit is contained in:
parent
31bc0ef789
commit
78f2d4a229
13 changed files with 1985 additions and 5609 deletions
|
|
@ -1,5 +1,7 @@
|
|||
PCem v8.1
|
||||
|
||||
PCem is licensed under the GPL, see COPYING for more details.
|
||||
|
||||
Changes since v8:
|
||||
|
||||
- Fixed various issues with ROM detection/loading
|
||||
|
|
@ -403,8 +405,8 @@ introduced in 1987. Has two Philips SAA1099, giving 12 voices of square waves pl
|
|||
voices. In stereo!
|
||||
|
||||
Adlib
|
||||
Has a Yamaha YM3812, giving 9 voices of 2 op FM, or 6 voices plus a useless section. PCem
|
||||
uses Jarek Burczynski's emulator for this.
|
||||
Has a Yamaha YM3812, giving 9 voices of 2 op FM, or 6 voices plus a rhythm section. PCem
|
||||
uses the DOSBox dbopl emulator.
|
||||
|
||||
Adlib Gold
|
||||
OPL3 with YM318Z 12-bit digital section. Possibly some bugs (not a lot of software to test).
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
VPATH = . mame
|
||||
VPATH = . dosbox
|
||||
CPP = g++.exe
|
||||
CC = gcc.exe
|
||||
WINDRES = windres.exe
|
||||
|
|
@ -9,7 +9,7 @@ OBJ = 386.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o \
|
|||
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o model.o \
|
||||
mouse.o mouse_ps2.o mouse_serial.o neat.o nvr.o olivetti_m24.o \
|
||||
opti.o pc.o pci.o pic.o piix.o pit.o ppi.o rom.o serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o \
|
||||
sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o \
|
||||
sound_adlibgold.o sound_cms.o sound_dbopl.o sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o \
|
||||
sound_pas16.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o \
|
||||
sound_wss.o soundopenal.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o \
|
||||
vid_ati_mach64.o vid_ati18800.o vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o \
|
||||
|
|
@ -20,7 +20,7 @@ OBJ = 386.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o \
|
|||
vid_tandy.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o vid_vga.o \
|
||||
vid_voodoo.o video.o wd76c10.o win.o win-d3d.o win-d3d-fs.o win-ddraw.o win-ddraw-fs.o win-keyboard.o win-midi.o \
|
||||
win-mouse.o win-timer.o win-video.o x86seg.o x87.o xtide.o pc.res
|
||||
FMOBJ = fmopl.o ymf262.o
|
||||
FMOBJ = dbopl.o
|
||||
|
||||
|
||||
LIBS = -mwindows -lwinmm -lalut -lopenal32 -lddraw -ldinput -ldxguid -ld3d9
|
||||
|
|
|
|||
1520
src/dosbox/dbopl.cpp
Normal file
1520
src/dosbox/dbopl.cpp
Normal file
File diff suppressed because it is too large
Load diff
273
src/dosbox/dbopl.h
Normal file
273
src/dosbox/dbopl.h
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* Copyright (C) 2002-2010 The DOSBox Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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.
|
||||
*/
|
||||
|
||||
//#include "adlib.h"
|
||||
//#include "dosbox.h"
|
||||
#include <stdint.h>
|
||||
typedef signed int Bits;
|
||||
typedef unsigned int Bitu;
|
||||
typedef int8_t Bit8s;
|
||||
typedef uint8_t Bit8u;
|
||||
typedef int16_t Bit16s;
|
||||
typedef uint16_t Bit16u;
|
||||
typedef int32_t Bit32s;
|
||||
typedef uint32_t Bit32u;
|
||||
|
||||
#define INLINE inline
|
||||
|
||||
#define GCC_UNLIKELY(x) (x)
|
||||
|
||||
//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume
|
||||
#define WAVE_HANDLER 10
|
||||
//Use a logarithmic wavetable with an exponential table for volume
|
||||
#define WAVE_TABLELOG 11
|
||||
//Use a linear wavetable with a multiply table for volume
|
||||
#define WAVE_TABLEMUL 12
|
||||
|
||||
//Select the type of wave generator routine
|
||||
#define DBOPL_WAVE WAVE_TABLEMUL
|
||||
|
||||
namespace DBOPL {
|
||||
|
||||
struct Chip;
|
||||
struct Operator;
|
||||
struct Channel;
|
||||
|
||||
#if (DBOPL_WAVE == WAVE_HANDLER)
|
||||
typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume );
|
||||
#endif
|
||||
|
||||
typedef Bits ( DBOPL::Operator::*VolumeHandler) ( );
|
||||
typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output );
|
||||
|
||||
//Different synth modes that can generate blocks of data
|
||||
typedef enum {
|
||||
sm2AM,
|
||||
sm2FM,
|
||||
sm3AM,
|
||||
sm3FM,
|
||||
sm4Start,
|
||||
sm3FMFM,
|
||||
sm3AMFM,
|
||||
sm3FMAM,
|
||||
sm3AMAM,
|
||||
sm6Start,
|
||||
sm2Percussion,
|
||||
sm3Percussion,
|
||||
} SynthMode;
|
||||
|
||||
//Shifts for the values contained in chandata variable
|
||||
enum {
|
||||
SHIFT_KSLBASE = 16,
|
||||
SHIFT_KEYCODE = 24,
|
||||
};
|
||||
|
||||
struct Operator {
|
||||
public:
|
||||
//Masks for operator 20 values
|
||||
enum {
|
||||
MASK_KSR = 0x10,
|
||||
MASK_SUSTAIN = 0x20,
|
||||
MASK_VIBRATO = 0x40,
|
||||
MASK_TREMOLO = 0x80,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
OFF,
|
||||
RELEASE,
|
||||
SUSTAIN,
|
||||
DECAY,
|
||||
ATTACK,
|
||||
} State;
|
||||
|
||||
VolumeHandler volHandler;
|
||||
|
||||
#if (DBOPL_WAVE == WAVE_HANDLER)
|
||||
WaveHandler waveHandler; //Routine that generate a wave
|
||||
#else
|
||||
Bit16s* waveBase;
|
||||
Bit32u waveMask;
|
||||
Bit32u waveStart;
|
||||
#endif
|
||||
Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index
|
||||
Bit32u waveAdd; //The base frequency without vibrato
|
||||
Bit32u waveCurrent; //waveAdd + vibratao
|
||||
|
||||
Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this
|
||||
Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove?
|
||||
Bit32u vibrato; //Scaled up vibrato strength
|
||||
Bit32s sustainLevel; //When stopping at sustain level stop here
|
||||
Bit32s totalLevel; //totalLevel is added to every generated volume
|
||||
Bit32u currentLevel; //totalLevel + tremolo
|
||||
Bit32s volume; //The currently active volume
|
||||
|
||||
Bit32u attackAdd; //Timers for the different states of the envelope
|
||||
Bit32u decayAdd;
|
||||
Bit32u releaseAdd;
|
||||
Bit32u rateIndex; //Current position of the evenlope
|
||||
|
||||
Bit8u rateZero; //Bits for the different states of the envelope having no changes
|
||||
Bit8u keyOn; //Bitmask of different values that can generate keyon
|
||||
//Registers, also used to check for changes
|
||||
Bit8u reg20, reg40, reg60, reg80, regE0;
|
||||
//Active part of the envelope we're in
|
||||
Bit8u state;
|
||||
//0xff when tremolo is enabled
|
||||
Bit8u tremoloMask;
|
||||
//Strength of the vibrato
|
||||
Bit8u vibStrength;
|
||||
//Keep track of the calculated KSR so we can check for changes
|
||||
Bit8u ksr;
|
||||
private:
|
||||
void SetState( Bit8u s );
|
||||
void UpdateAttack( const Chip* chip );
|
||||
void UpdateRelease( const Chip* chip );
|
||||
void UpdateDecay( const Chip* chip );
|
||||
public:
|
||||
void UpdateAttenuation();
|
||||
void UpdateRates( const Chip* chip );
|
||||
void UpdateFrequency( );
|
||||
|
||||
void Write20( const Chip* chip, Bit8u val );
|
||||
void Write40( const Chip* chip, Bit8u val );
|
||||
void Write60( const Chip* chip, Bit8u val );
|
||||
void Write80( const Chip* chip, Bit8u val );
|
||||
void WriteE0( const Chip* chip, Bit8u val );
|
||||
|
||||
bool Silent() const;
|
||||
void Prepare( const Chip* chip );
|
||||
|
||||
void KeyOn( Bit8u mask);
|
||||
void KeyOff( Bit8u mask);
|
||||
|
||||
template< State state>
|
||||
Bits TemplateVolume( );
|
||||
|
||||
Bit32s RateForward( Bit32u add );
|
||||
Bitu ForwardWave();
|
||||
Bitu ForwardVolume();
|
||||
|
||||
Bits GetSample( Bits modulation );
|
||||
Bits GetWave( Bitu index, Bitu vol );
|
||||
public:
|
||||
Operator();
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
Operator op[2];
|
||||
inline Operator* Op( Bitu index ) {
|
||||
return &( ( this + (index >> 1) )->op[ index & 1 ]);
|
||||
}
|
||||
SynthHandler synthHandler;
|
||||
Bit32u chanData; //Frequency/octave and derived values
|
||||
Bit32s old[2]; //Old data for feedback
|
||||
|
||||
Bit8u feedback; //Feedback shift
|
||||
Bit8u regB0; //Register values to check for changes
|
||||
Bit8u regC0;
|
||||
//This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel
|
||||
Bit8u fourMask;
|
||||
Bit8s maskLeft; //Sign extended values for both channel's panning
|
||||
Bit8s maskRight;
|
||||
|
||||
//Forward the channel data to the operators of the channel
|
||||
void SetChanData( const Chip* chip, Bit32u data );
|
||||
//Change in the chandata, check for new values and if we have to forward to operators
|
||||
void UpdateFrequency( const Chip* chip, Bit8u fourOp );
|
||||
void WriteA0( const Chip* chip, Bit8u val );
|
||||
void WriteB0( const Chip* chip, Bit8u val );
|
||||
void WriteC0( const Chip* chip, Bit8u val );
|
||||
void ResetC0( const Chip* chip );
|
||||
|
||||
//call this for the first channel
|
||||
template< bool opl3Mode >
|
||||
void GeneratePercussion( Chip* chip, Bit32s* output );
|
||||
|
||||
//Generate blocks of data in specific modes
|
||||
template<SynthMode mode>
|
||||
Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output );
|
||||
Channel();
|
||||
};
|
||||
|
||||
struct Chip {
|
||||
//This is used as the base counter for vibrato and tremolo
|
||||
Bit32u lfoCounter;
|
||||
Bit32u lfoAdd;
|
||||
|
||||
|
||||
Bit32u noiseCounter;
|
||||
Bit32u noiseAdd;
|
||||
Bit32u noiseValue;
|
||||
|
||||
//Frequency scales for the different multiplications
|
||||
Bit32u freqMul[16];
|
||||
//Rates for decay and release for rate of this chip
|
||||
Bit32u linearRates[76];
|
||||
//Best match attack rates for the rate of this chip
|
||||
Bit32u attackRates[76];
|
||||
|
||||
//18 channels with 2 operators each
|
||||
Channel chan[18];
|
||||
|
||||
Bit8u reg104;
|
||||
Bit8u reg08;
|
||||
Bit8u reg04;
|
||||
Bit8u regBD;
|
||||
Bit8u vibratoIndex;
|
||||
Bit8u tremoloIndex;
|
||||
Bit8s vibratoSign;
|
||||
Bit8u vibratoShift;
|
||||
Bit8u tremoloValue;
|
||||
Bit8u vibratoStrength;
|
||||
Bit8u tremoloStrength;
|
||||
//Mask for allowed wave forms
|
||||
Bit8u waveFormMask;
|
||||
//0 or -1 when enabled
|
||||
Bit8s opl3Active;
|
||||
|
||||
int is_opl3;
|
||||
|
||||
//Return the maximum amount of samples before and LFO change
|
||||
Bit32u ForwardLFO( Bit32u samples );
|
||||
Bit32u ForwardNoise();
|
||||
|
||||
void WriteBD( Bit8u val );
|
||||
void WriteReg(Bit32u reg, Bit8u val );
|
||||
|
||||
Bit32u WriteAddr( Bit32u port, Bit8u val );
|
||||
|
||||
void GenerateBlock2( Bitu samples, Bit32s* output );
|
||||
void GenerateBlock3( Bitu samples, Bit32s* output );
|
||||
|
||||
void Generate( Bit32u samples );
|
||||
void Setup( Bit32u r, int chip_is_opl3 );
|
||||
|
||||
Chip();
|
||||
};
|
||||
|
||||
/*struct Handler : public Adlib::Handler {
|
||||
DBOPL::Chip chip;
|
||||
virtual Bit32u WriteAddr( Bit32u port, Bit8u val );
|
||||
virtual void WriteReg( Bit32u addr, Bit8u val );
|
||||
virtual void Generate( MixerChannel* chan, Bitu samples );
|
||||
virtual void Init( Bitu rate );
|
||||
};*/
|
||||
|
||||
void InitTables( void );
|
||||
|
||||
}; //Namespace
|
||||
2613
src/mame/fmopl.c
2613
src/mame/fmopl.c
File diff suppressed because it is too large
Load diff
126
src/mame/fmopl.h
126
src/mame/fmopl.h
|
|
@ -1,126 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef __FMOPL_H__
|
||||
#define __FMOPL_H__
|
||||
|
||||
#ifndef STUFF
|
||||
#define STUFF
|
||||
typedef int64_t attotime;
|
||||
#define ATTOTIME_IN_HZ(x) (1000000000/(x))
|
||||
#define attotime_mul(x,y) ((x)*(y))
|
||||
#define attotime_to_double(x) ((double)(x)/1000000000.0)
|
||||
#define attotime_zero 0
|
||||
|
||||
#define running_device void
|
||||
#define INLINE static
|
||||
//#define M_PI 3.142
|
||||
#endif
|
||||
|
||||
/* --- select emulation chips --- */
|
||||
#define BUILD_YM3812 (1)
|
||||
#define BUILD_YM3526 (0)
|
||||
#define BUILD_Y8950 (0)
|
||||
|
||||
/* select output bits size of output : 8 or 16 */
|
||||
#define OPL_SAMPLE_BITS 16
|
||||
|
||||
/* compiler dependence */
|
||||
#ifndef __OSDCOMM_H__
|
||||
#define __OSDCOMM_H__
|
||||
typedef unsigned char UINT8; /* unsigned 8bit */
|
||||
typedef unsigned short UINT16; /* unsigned 16bit */
|
||||
typedef unsigned int UINT32; /* unsigned 32bit */
|
||||
typedef signed char INT8; /* signed 8bit */
|
||||
typedef signed short INT16; /* signed 16bit */
|
||||
typedef signed int INT32; /* signed 32bit */
|
||||
#endif /* __OSDCOMM_H__ */
|
||||
|
||||
typedef signed short OPLSAMPLE;
|
||||
/*
|
||||
#if (OPL_SAMPLE_BITS==16)
|
||||
typedef INT16 OPLSAMPLE;
|
||||
#endif
|
||||
#if (OPL_SAMPLE_BITS==8)
|
||||
typedef INT8 OPLSAMPLE;
|
||||
#endif
|
||||
*/
|
||||
|
||||
typedef void (*OPL_TIMERHANDLER)(void *param,int timer,attotime period);
|
||||
typedef void (*OPL_IRQHANDLER)(void *param,int irq);
|
||||
typedef void (*OPL_UPDATEHANDLER)(void *param,int min_interval_us);
|
||||
typedef void (*OPL_PORTHANDLER_W)(void *param,unsigned char data);
|
||||
typedef unsigned char (*OPL_PORTHANDLER_R)(void *param);
|
||||
|
||||
|
||||
#if BUILD_YM3812
|
||||
|
||||
void *ym3812_init(running_device *device, UINT32 clock, UINT32 rate);
|
||||
void ym3812_shutdown(void *chip);
|
||||
void ym3812_reset_chip(void *chip);
|
||||
int ym3812_write(void *chip, int a, int v);
|
||||
unsigned char ym3812_read(void *chip, int a);
|
||||
int ym3812_timer_over(void *chip, int c);
|
||||
void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length);
|
||||
|
||||
void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param);
|
||||
void ym3812_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param);
|
||||
void ym3812_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param);
|
||||
|
||||
#endif /* BUILD_YM3812 */
|
||||
|
||||
|
||||
#if BUILD_YM3526
|
||||
|
||||
/*
|
||||
** Initialize YM3526 emulator(s).
|
||||
**
|
||||
** 'num' is the number of virtual YM3526's to allocate
|
||||
** 'clock' is the chip clock in Hz
|
||||
** 'rate' is sampling rate
|
||||
*/
|
||||
void *ym3526_init(running_device *device, UINT32 clock, UINT32 rate);
|
||||
/* shutdown the YM3526 emulators*/
|
||||
void ym3526_shutdown(void *chip);
|
||||
void ym3526_reset_chip(void *chip);
|
||||
int ym3526_write(void *chip, int a, int v);
|
||||
unsigned char ym3526_read(void *chip, int a);
|
||||
int ym3526_timer_over(void *chip, int c);
|
||||
/*
|
||||
** Generate samples for one of the YM3526's
|
||||
**
|
||||
** 'which' is the virtual YM3526 number
|
||||
** '*buffer' is the output buffer pointer
|
||||
** 'length' is the number of samples that should be generated
|
||||
*/
|
||||
void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length);
|
||||
|
||||
void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param);
|
||||
void ym3526_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param);
|
||||
void ym3526_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param);
|
||||
|
||||
#endif /* BUILD_YM3526 */
|
||||
|
||||
|
||||
#if BUILD_Y8950
|
||||
|
||||
/* Y8950 port handlers */
|
||||
void y8950_set_port_handler(void *chip, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, void *param);
|
||||
void y8950_set_keyboard_handler(void *chip, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, void *param);
|
||||
void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size );
|
||||
|
||||
void * y8950_init(running_device *device, UINT32 clock, UINT32 rate);
|
||||
void y8950_shutdown(void *chip);
|
||||
void y8950_reset_chip(void *chip);
|
||||
int y8950_write(void *chip, int a, int v);
|
||||
unsigned char y8950_read (void *chip, int a);
|
||||
int y8950_timer_over(void *chip, int c);
|
||||
void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length);
|
||||
|
||||
void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param);
|
||||
void y8950_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param);
|
||||
void y8950_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param);
|
||||
|
||||
#endif /* BUILD_Y8950 */
|
||||
|
||||
|
||||
#endif /* __FMOPL_H__ */
|
||||
2730
src/mame/ymf262.c
2730
src/mame/ymf262.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,62 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef __YMF262_H__
|
||||
#define __YMF262_H__
|
||||
|
||||
#ifndef STUFF
|
||||
#define STUFF
|
||||
typedef int64_t attotime;
|
||||
#define ATTOTIME_IN_HZ(x) (1000000000/(x))
|
||||
#define attotime_mul(x,y) ((x)*(y))
|
||||
#define attotime_to_double(x) ((double)(x)/1000000000.0)
|
||||
#define attotime_zero 0
|
||||
|
||||
#define running_device void
|
||||
#define INLINE static
|
||||
//#define M_PI 3.142
|
||||
#endif
|
||||
|
||||
/* select number of output bits: 8 or 16 */
|
||||
#define OPL3_SAMPLE_BITS 16
|
||||
|
||||
/* compiler dependence */
|
||||
#ifndef __OSDCOMM_H__
|
||||
#define __OSDCOMM_H__
|
||||
typedef unsigned char UINT8; /* unsigned 8bit */
|
||||
typedef unsigned short UINT16; /* unsigned 16bit */
|
||||
typedef unsigned int UINT32; /* unsigned 32bit */
|
||||
typedef signed char INT8; /* signed 8bit */
|
||||
typedef signed short INT16; /* signed 16bit */
|
||||
typedef signed int INT32; /* signed 32bit */
|
||||
#endif
|
||||
|
||||
typedef signed short OPL3SAMPLE;
|
||||
//typedef stream_sample_t OPL3SAMPLE;
|
||||
/*
|
||||
#if (OPL3_SAMPLE_BITS==16)
|
||||
typedef INT16 OPL3SAMPLE;
|
||||
#endif
|
||||
#if (OPL3_SAMPLE_BITS==8)
|
||||
typedef INT8 OPL3SAMPLE;
|
||||
#endif
|
||||
*/
|
||||
|
||||
typedef void (*OPL3_TIMERHANDLER)(void *param,int timer,attotime period);
|
||||
typedef void (*OPL3_IRQHANDLER)(void *param,int irq);
|
||||
typedef void (*OPL3_UPDATEHANDLER)(void *param,int min_interval_us);
|
||||
|
||||
|
||||
void *ymf262_init(running_device *device, int clock, int rate);
|
||||
void ymf262_shutdown(void *chip);
|
||||
void ymf262_reset_chip(void *chip);
|
||||
int ymf262_write(void *chip, int a, int v);
|
||||
unsigned char ymf262_read(void *chip, int a);
|
||||
int ymf262_timer_over(void *chip, int c);
|
||||
void ymf262_update_one(void *chip, OPL3SAMPLE **buffers, int length);
|
||||
|
||||
void ymf262_set_timer_handler(void *chip, OPL3_TIMERHANDLER TimerHandler, void *param);
|
||||
void ymf262_set_irq_handler(void *chip, OPL3_IRQHANDLER IRQHandler, void *param);
|
||||
void ymf262_set_update_handler(void *chip, OPL3_UPDATEHANDLER UpdateHandler, void *param);
|
||||
|
||||
|
||||
#endif /* __YMF262_H__ */
|
||||
|
|
@ -34,7 +34,7 @@ static SOUND_CARD sound_cards[] =
|
|||
{"Sound Blaster 1.5", &sb_15_device},
|
||||
{"Sound Blaster 2.0", &sb_2_device},
|
||||
{"Sound Blaster Pro v1", &sb_pro_v1_device},
|
||||
{"Sound Blaster Pro v2", &sb_pro_v1_device},
|
||||
{"Sound Blaster Pro v2", &sb_pro_v2_device},
|
||||
{"Sound Blaster 16", &sb_16_device},
|
||||
{"Sound Blaster AWE32", &sb_awe32_device},
|
||||
{"Adlib Gold", &adgold_device},
|
||||
|
|
|
|||
144
src/sound_dbopl.cc
Normal file
144
src/sound_dbopl.cc
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
#include "dosbox/dbopl.h"
|
||||
#include "sound_dbopl.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
DBOPL::Chip chip;
|
||||
int addr;
|
||||
int timer[2];
|
||||
uint8_t timer_ctrl;
|
||||
uint8_t status_mask;
|
||||
uint8_t status;
|
||||
int is_opl3;
|
||||
|
||||
void (*timer_callback)(void *param, int timer, int64_t period);
|
||||
void *timer_param;
|
||||
} opl[2];
|
||||
|
||||
enum
|
||||
{
|
||||
STATUS_TIMER_1 = 0x40,
|
||||
STATUS_TIMER_2 = 0x20,
|
||||
STATUS_TIMER_ALL = 0x80
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CTRL_IRQ_RESET = 0x80,
|
||||
CTRL_TIMER1_MASK = 0x40,
|
||||
CTRL_TIMER2_MASK = 0x20,
|
||||
CTRL_TIMER2_CTRL = 0x02,
|
||||
CTRL_TIMER1_CTRL = 0x01
|
||||
};
|
||||
|
||||
void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3)
|
||||
{
|
||||
DBOPL::InitTables();
|
||||
opl[nr].chip.Setup(48000, is_opl3);
|
||||
opl[nr].timer_callback = timer_callback;
|
||||
opl[nr].timer_param = timer_param;
|
||||
opl[nr].is_opl3 = is_opl3;
|
||||
}
|
||||
|
||||
void opl_status_update(int nr)
|
||||
{
|
||||
if (opl[nr].status & (STATUS_TIMER_1 | STATUS_TIMER_2) & opl[nr].status_mask)
|
||||
opl[nr].status |= STATUS_TIMER_ALL;
|
||||
else
|
||||
opl[nr].status &= ~STATUS_TIMER_ALL;
|
||||
}
|
||||
|
||||
void opl_timer_over(int nr, int timer)
|
||||
{
|
||||
if (!timer)
|
||||
{
|
||||
opl[nr].status |= STATUS_TIMER_1;
|
||||
opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
opl[nr].status |= STATUS_TIMER_2;
|
||||
opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16);
|
||||
}
|
||||
|
||||
opl_status_update(nr);
|
||||
}
|
||||
|
||||
void opl_write(int nr, uint16_t addr, uint8_t val)
|
||||
{
|
||||
if (!(addr & 1))
|
||||
opl[nr].addr = (int)opl[nr].chip.WriteAddr(addr, val) & (opl[nr].is_opl3 ? 0x1ff : 0xff);
|
||||
else
|
||||
{
|
||||
opl[nr].chip.WriteReg(opl[nr].addr, val);
|
||||
|
||||
switch (opl[nr].addr)
|
||||
{
|
||||
case 0x02: /*Timer 1*/
|
||||
opl[nr].timer[0] = 256 - val;
|
||||
break;
|
||||
case 0x03: /*Timer 2*/
|
||||
opl[nr].timer[1] = 256 - val;
|
||||
break;
|
||||
case 0x04: /*Timer control*/
|
||||
if (val & CTRL_IRQ_RESET) /*IRQ reset*/
|
||||
{
|
||||
opl[nr].status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2);
|
||||
opl_status_update(nr);
|
||||
return;
|
||||
}
|
||||
if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER1_CTRL)
|
||||
{
|
||||
if (val & CTRL_TIMER1_CTRL)
|
||||
opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4);
|
||||
else
|
||||
opl[nr].timer_callback(opl[nr].timer_param, 0, 0);
|
||||
}
|
||||
if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER2_CTRL)
|
||||
{
|
||||
if (val & CTRL_TIMER2_CTRL)
|
||||
opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16);
|
||||
else
|
||||
opl[nr].timer_callback(opl[nr].timer_param, 1, 0);
|
||||
}
|
||||
opl[nr].status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80;
|
||||
opl[nr].timer_ctrl = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint8_t opl_read(int nr, uint16_t addr)
|
||||
{
|
||||
if (!(addr & 1))
|
||||
{
|
||||
return (opl[nr].status & opl[nr].status_mask) | 0x06;
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
void opl2_update(int nr, int16_t *buffer, int samples)
|
||||
{
|
||||
int c;
|
||||
Bit32s buffer_32[samples];
|
||||
|
||||
opl[nr].chip.GenerateBlock2(samples, buffer_32);
|
||||
|
||||
for (c = 0; c < samples; c++)
|
||||
buffer[c] = (int16_t)buffer_32[c];
|
||||
}
|
||||
|
||||
void opl3_update(int nr, int16_t *bufferl, int16_t *bufferr, int samples)
|
||||
{
|
||||
int c;
|
||||
Bit32s buffer_32[samples*2];
|
||||
|
||||
opl[nr].chip.GenerateBlock3(samples, buffer_32);
|
||||
|
||||
for (c = 0; c < samples; c++)
|
||||
{
|
||||
bufferl[c] = (int16_t)buffer_32[c*2];
|
||||
bufferr[c] = (int16_t)buffer_32[(c*2)+1];
|
||||
}
|
||||
}
|
||||
12
src/sound_dbopl.h
Normal file
12
src/sound_dbopl.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3);
|
||||
void opl_write(int nr, uint16_t addr, uint8_t val);
|
||||
uint8_t opl_read(int nr, uint16_t addr);
|
||||
void opl_timer_over(int nr, int timer);
|
||||
void opl2_update(int nr, int16_t *buffer, int samples);
|
||||
void opl3_update(int nr, int16_t *bufferl, int16_t *bufferr, int samples);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
#include "ibm.h"
|
||||
#include "io.h"
|
||||
#include "sound_opl.h"
|
||||
#include "sound_dbopl.h"
|
||||
|
||||
/*Interfaces between PCem and the actual OPL emulator*/
|
||||
|
||||
|
|
@ -12,14 +13,14 @@ uint8_t opl2_read(uint16_t a, void *priv)
|
|||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
cycles -= (int)(isa_timing * 8);
|
||||
return ym3812_read(opl->YM3812[0], a);
|
||||
return opl_read(0, a);
|
||||
}
|
||||
void opl2_write(uint16_t a, uint8_t v, void *priv)
|
||||
{
|
||||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
ym3812_write(opl->YM3812[0],a,v);
|
||||
ym3812_write(opl->YM3812[1],a,v);
|
||||
opl_write(0, a, v);
|
||||
opl_write(1, a, v);
|
||||
}
|
||||
|
||||
uint8_t opl2_l_read(uint16_t a, void *priv)
|
||||
|
|
@ -27,13 +28,13 @@ uint8_t opl2_l_read(uint16_t a, void *priv)
|
|||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
cycles -= (int)(isa_timing * 8);
|
||||
return ym3812_read(opl->YM3812[0], a);
|
||||
return opl_read(0, a);
|
||||
}
|
||||
void opl2_l_write(uint16_t a, uint8_t v, void *priv)
|
||||
{
|
||||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
ym3812_write(opl->YM3812[0],a,v);
|
||||
opl_write(0, a, v);
|
||||
}
|
||||
|
||||
uint8_t opl2_r_read(uint16_t a, void *priv)
|
||||
|
|
@ -41,13 +42,13 @@ uint8_t opl2_r_read(uint16_t a, void *priv)
|
|||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
cycles -= (int)(isa_timing * 8);
|
||||
return ym3812_read(opl->YM3812[1], a);
|
||||
return opl_read(1, a);
|
||||
}
|
||||
void opl2_r_write(uint16_t a, uint8_t v, void *priv)
|
||||
{
|
||||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
ym3812_write(opl->YM3812[1],a,v);
|
||||
opl_write(1, a, v);
|
||||
}
|
||||
|
||||
uint8_t opl3_read(uint16_t a, void *priv)
|
||||
|
|
@ -55,20 +56,20 @@ uint8_t opl3_read(uint16_t a, void *priv)
|
|||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
cycles -= (int)(isa_timing * 8);
|
||||
return ymf262_read(opl->YMF262, a);
|
||||
return opl_read(0, a);
|
||||
}
|
||||
void opl3_write(uint16_t a, uint8_t v, void *priv)
|
||||
{
|
||||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
ymf262_write(opl->YMF262, a, v);
|
||||
opl_write(0, a, v);
|
||||
}
|
||||
|
||||
|
||||
void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr)
|
||||
{
|
||||
ym3812_update_one(opl->YM3812[0], bufl, 1);
|
||||
ym3812_update_one(opl->YM3812[1], bufr, 1);
|
||||
opl2_update(0, bufl, 1);
|
||||
opl2_update(1, bufr, 1);
|
||||
|
||||
opl->filtbuf[0] = *bufl = ((*bufl) / 4) + ((opl->filtbuf[0] * 11) / 16);
|
||||
opl->filtbuf[1] = *bufr = ((*bufr) / 4) + ((opl->filtbuf[1] * 11) / 16);
|
||||
|
|
@ -76,31 +77,31 @@ void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr)
|
|||
if (opl->timers_enable[0][0])
|
||||
{
|
||||
opl->timers[0][0]--;
|
||||
if (opl->timers[0][0] < 0) ym3812_timer_over(opl->YM3812[0], 0);
|
||||
if (opl->timers[0][0] < 0) opl_timer_over(0, 0);
|
||||
}
|
||||
if (opl->timers_enable[0][1])
|
||||
{
|
||||
opl->timers[0][1]--;
|
||||
if (opl->timers[0][1] < 0) ym3812_timer_over(opl->YM3812[0], 1);
|
||||
if (opl->timers[0][1] < 0) opl_timer_over(0, 1);
|
||||
}
|
||||
if (opl->timers_enable[1][0])
|
||||
{
|
||||
opl->timers[1][0]--;
|
||||
if (opl->timers[1][0] < 0) ym3812_timer_over(opl->YM3812[1], 0);
|
||||
if (opl->timers[1][0] < 0) opl_timer_over(1, 0);
|
||||
}
|
||||
if (opl->timers_enable[1][1])
|
||||
{
|
||||
opl->timers[1][1]--;
|
||||
if (opl->timers[1][1] < 0) ym3812_timer_over(opl->YM3812[1], 1);
|
||||
if (opl->timers[1][1] < 0) opl_timer_over(1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr)
|
||||
{
|
||||
ymf262_update_one(opl->YMF262, opl->bufs, 1);
|
||||
opl3_update(0, bufl, bufr, 1);
|
||||
|
||||
opl->filtbuf[0] = *bufl = ((opl->bufs[0][0]) / 4) + ((opl->filtbuf[0] * 11) / 16);
|
||||
opl->filtbuf[1] = *bufr = ((opl->bufs[1][0]) / 4) + ((opl->filtbuf[1] * 11) / 16);
|
||||
opl->filtbuf[0] = *bufl = ((*bufl) / 4) + ((opl->filtbuf[0] * 11) / 16);
|
||||
opl->filtbuf[1] = *bufr = ((*bufr) / 4) + ((opl->filtbuf[1] * 11) / 16);
|
||||
|
||||
if (opl->timers_enable[0][0])
|
||||
{
|
||||
|
|
@ -108,7 +109,7 @@ void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr)
|
|||
if (opl->timers[0][0] < 0)
|
||||
{
|
||||
opl->timers_enable[0][0] = 0;
|
||||
ymf262_timer_over(opl->YMF262, 0);
|
||||
opl_timer_over(0, 0);
|
||||
}
|
||||
}
|
||||
if (opl->timers_enable[0][1])
|
||||
|
|
@ -117,12 +118,12 @@ void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr)
|
|||
if (opl->timers[0][1] < 0)
|
||||
{
|
||||
opl->timers_enable[0][1] = 0;
|
||||
ymf262_timer_over(opl->YMF262, 1);
|
||||
opl_timer_over(0, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ym3812_timer_set_0(void *param, int timer, attotime period)
|
||||
void ym3812_timer_set_0(void *param, int timer, int64_t period)
|
||||
{
|
||||
opl_t *opl = (opl_t *)param;
|
||||
|
||||
|
|
@ -130,7 +131,7 @@ void ym3812_timer_set_0(void *param, int timer, attotime period)
|
|||
if (!opl->timers[0][timer]) opl->timers[0][timer] = 1;
|
||||
opl->timers_enable[0][timer] = period ? 1 : 0;
|
||||
}
|
||||
void ym3812_timer_set_1(void *param, int timer, attotime period)
|
||||
void ym3812_timer_set_1(void *param, int timer, int64_t period)
|
||||
{
|
||||
opl_t *opl = (opl_t *)param;
|
||||
|
||||
|
|
@ -139,7 +140,7 @@ void ym3812_timer_set_1(void *param, int timer, attotime period)
|
|||
opl->timers_enable[1][timer] = period ? 1 : 0;
|
||||
}
|
||||
|
||||
void ymf262_timer_set(void *param, int timer, attotime period)
|
||||
void ymf262_timer_set(void *param, int timer, int64_t period)
|
||||
{
|
||||
opl_t *opl = (opl_t *)param;
|
||||
|
||||
|
|
@ -150,46 +151,12 @@ void ymf262_timer_set(void *param, int timer, attotime period)
|
|||
|
||||
void opl2_init(opl_t *opl)
|
||||
{
|
||||
opl->bufs[0] = (int16_t *)malloc(4);
|
||||
opl->bufs[1] = (int16_t *)malloc(4);
|
||||
opl->bufs[2] = (int16_t *)malloc(4);
|
||||
opl->bufs[3] = (int16_t *)malloc(4);
|
||||
|
||||
opl->YM3812[0] = ym3812_init(NULL, 3579545, 48000);
|
||||
ym3812_reset_chip(opl->YM3812[0]);
|
||||
ym3812_set_timer_handler(opl->YM3812[0], ym3812_timer_set_0, opl);
|
||||
|
||||
opl->YM3812[1] = ym3812_init(NULL, 3579545, 48000);
|
||||
ym3812_reset_chip(opl->YM3812[1]);
|
||||
ym3812_set_timer_handler(opl->YM3812[1], ym3812_timer_set_1, opl);
|
||||
opl_init(ym3812_timer_set_0, opl, 0, 0);
|
||||
opl_init(ym3812_timer_set_1, opl, 1, 0);
|
||||
}
|
||||
|
||||
void opl3_init(opl_t *opl)
|
||||
{
|
||||
opl->bufs[0] = (int16_t *)malloc(4);
|
||||
opl->bufs[1] = (int16_t *)malloc(4);
|
||||
opl->bufs[2] = (int16_t *)malloc(4);
|
||||
opl->bufs[3] = (int16_t *)malloc(4);
|
||||
|
||||
opl->YMF262 = ymf262_init(NULL, 3579545 * 4, 48000);
|
||||
ymf262_reset_chip(opl->YMF262);
|
||||
ymf262_set_timer_handler(opl->YMF262, ymf262_timer_set, opl);
|
||||
opl_init(ymf262_timer_set, opl, 0, 1);
|
||||
}
|
||||
|
||||
void opl2_close(opl_t *opl)
|
||||
{
|
||||
free(opl->bufs[0]);
|
||||
free(opl->bufs[1]);
|
||||
|
||||
ym3812_shutdown(opl->YM3812[0]);
|
||||
ym3812_shutdown(opl->YM3812[1]);
|
||||
}
|
||||
|
||||
void opl3_close(opl_t *opl)
|
||||
{
|
||||
free(opl->bufs[0]);
|
||||
free(opl->bufs[1]);
|
||||
|
||||
ym3812_shutdown(opl->YM3812[0]);
|
||||
ymf262_shutdown(opl->YMF262);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,13 @@
|
|||
#include "mame/fmopl.h"
|
||||
#include "mame/ymf262.h"
|
||||
|
||||
typedef struct opl_t
|
||||
{
|
||||
void *YM3812[2];
|
||||
void *YMF262;
|
||||
int chip_nr[2];
|
||||
|
||||
int timers[2][2];
|
||||
int timers_enable[2][2];
|
||||
|
||||
int16_t *bufs[4];
|
||||
int16_t filtbuf[2];
|
||||
} opl_t;
|
||||
|
||||
uint8_t opl_read(uint16_t a, void *priv);
|
||||
void opl_write(uint16_t a, uint8_t v, void *priv);
|
||||
|
||||
uint8_t opl2_read(uint16_t a, void *priv);
|
||||
void opl2_write(uint16_t a, uint8_t v, void *priv);
|
||||
uint8_t opl2_l_read(uint16_t a, void *priv);
|
||||
|
|
@ -30,6 +22,3 @@ void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr);
|
|||
|
||||
void opl2_init(opl_t *opl);
|
||||
void opl3_init(opl_t *opl);
|
||||
|
||||
void opl2_close(opl_t *opl);
|
||||
void opl3_close(opl_t *opl);
|
||||
|
|
|
|||
Loading…
Reference in a new issue