1
0
Fork 0

Add the integer dosbox opl

Combine all the adlib stuff in 1 module


Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@3352
This commit is contained in:
Sjoerd van der Berg 2009-04-25 09:55:50 +00:00
parent 150dd14433
commit dff27bb2c4
4 changed files with 1860 additions and 90 deletions

View file

@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* $Id: adlib.cpp,v 1.34 2009-04-17 17:24:47 c2woody Exp $ */
/* $Id: adlib.cpp,v 1.35 2009-04-25 09:55:50 harekiet Exp $ */
#include <stdlib.h>
#include <string.h>
@ -24,15 +24,12 @@
#include <sys/types.h>
#include <dirent.h>
#include "dosbox.h"
#include "inout.h"
#include "mixer.h"
#include "pic.h"
#include "hardware.h"
#include "adlib.h"
#include "setup.h"
#include "mapper.h"
#include "adlib.h"
#include "mem.h"
#include "dbopl.h"
/*
Thanks to vdmsound for nice simple way to implement this
@ -188,6 +185,7 @@ namespace old_OPL3 {
}
#define RAW_SIZE 1024
@ -548,8 +546,8 @@ void Module::PortWrite( Bitu port, Bitu val, Bitu iolen ) {
//Keep track of last write time
lastUsed = PIC_Ticks;
//Maybe only enable with a keyon?
if ( !chan->enabled ) {
chan->Enable(true);
if ( !mixerChan->enabled ) {
mixerChan->Enable(true);
}
if ( port&1 ) {
switch ( mode ) {
@ -641,121 +639,165 @@ void Module::Init( Mode m ) {
}
}
Module::Module() {
reg.dual[0] = 0;
reg.dual[1] = 0;
reg.normal = 0;
}
}; //namespace
}; //Adlib Namespace
static Adlib::Module module;
static Adlib::Module* module = 0;
static void OPL_CallBack(Bitu len) {
module.handler->Generate( module.chan, len );
module->handler->Generate( module->mixerChan, len );
//Disable the sound generation after 30 seconds of silence
if ((PIC_Ticks-module.lastUsed) > 30000) {
module.chan->Enable(false);
if ((PIC_Ticks - module->lastUsed) > 30000) {
module->mixerChan->Enable(false);
}
}
static Bitu OPL_Read(Bitu port,Bitu iolen) {
return module.PortRead( port, iolen );
return module->PortRead( port, iolen );
}
void OPL_Write(Bitu port,Bitu val,Bitu iolen) {
module.PortWrite( port, val, iolen );
module->PortWrite( port, val, iolen );
}
/*
Save the current state of the operators as instruments in an reality adlib tracker file
*/
static void SaveRad() {
char b[16 * 1024];
int w = 0;
FILE* handle = OpenCaptureFile("RAD Capture",".rad");
if ( !handle )
return;
//Header
fwrite( "RAD by REALiTY!!", 1, 16, handle );
b[w++] = 0x10; //version
b[w++] = 0x06; //default speed and no description
//Write 18 instuments for all operators in the cache
for ( int i = 0; i < 18; i++ ) {
Bit8u* set = module->cache + ( i / 9 ) * 256;
Bitu offset = ((i % 9) / 3) * 8 + (i % 3);
Bit8u* base = set + offset;
b[w++] = 1 + i; //instrument number
b[w++] = base[0x23];
b[w++] = base[0x20];
b[w++] = base[0x43];
b[w++] = base[0x40];
b[w++] = base[0x63];
b[w++] = base[0x60];
b[w++] = base[0x83];
b[w++] = base[0x80];
b[w++] = set[0xc0 + (i % 9)];
b[w++] = base[0xe3];
b[w++] = base[0xe0];
}
b[w++] = 0; //instrument 0, no more instruments following
b[w++] = 1; //1 pattern following
//Zero out the remaing part of the file a bit to make rad happy
for ( int i = 0; i < 64; i++ ) {
b[w++] = 0;
}
fwrite( b, 1, w, handle );
fclose( handle );
};
static void OPL_SaveRawEvent(bool pressed) {
if (!pressed)
return;
// SaveRad();return;
/* Check for previously opened wave file */
if ( module.capture ) {
delete module.capture;
module.capture = 0;
if ( module->capture ) {
delete module->capture;
module->capture = 0;
LOG_MSG("Stopped Raw OPL capturing.");
} else {
LOG_MSG("Preparing to capture Raw OPL, will start with first note played.");
module.capture = new Adlib::Capture( &module.cache );
module->capture = new Adlib::Capture( &module->cache );
}
}
class OPL: public Module_base {
private:
IO_ReadHandleObject ReadHandler[3];
IO_WriteHandleObject WriteHandler[3];
MixerObject MixerChan;
public:
static OPL_Mode oplmode;
namespace Adlib {
OPL(Section* configuration):Module_base(configuration) {
Section_prop * section=static_cast<Section_prop *>(configuration);
Bitu base = section->Get_hex("sbbase");
Bitu rate = section->Get_int("oplrate");
std::string oplemu( section->Get_string( "oplemu" ) );
Module::Module( Section* configuration ) : Module_base(configuration) {
reg.dual[0] = 0;
reg.dual[1] = 0;
reg.normal = 0;
handler = 0;
capture = 0;
module.chan = MixerChan.Install(OPL_CallBack,rate,"FM");
if (oplemu == "old") {
if ( oplmode == OPL_opl2 ) {
module.handler = new old_OPL2::Handler();
} else {
module.handler = new old_OPL3::Handler();
}
Section_prop * section=static_cast<Section_prop *>(configuration);
Bitu base = section->Get_hex("sbbase");
Bitu rate = section->Get_int("oplrate");
std::string oplemu( section->Get_string( "oplemu" ) );
mixerChan = mixerObject.Install(OPL_CallBack,rate,"FM");
if (oplemu == "old") {
if ( oplmode == OPL_opl2 ) {
handler = new old_OPL2::Handler();
} else {
if ( oplmode == OPL_opl2 ) {
module.handler = new OPL2::Handler();
} else {
module.handler = new OPL3::Handler();
}
handler = new old_OPL3::Handler();
}
module.handler->Init( rate );
Bit8u portRange = 4; //opl2 will set this to 2
switch ( oplmode ) {
case OPL_opl2:
portRange = 2;
module.Init( Adlib::MODE_OPL2 );
break;
case OPL_dualopl2:
module.Init( Adlib::MODE_DUALOPL2 );
break;
case OPL_opl3:
module.Init( Adlib::MODE_OPL3 );
break;
} else if (oplemu == "fast") {
handler = new DBOPL::Handler();
} else {
if ( oplmode == OPL_opl2 ) {
handler = new OPL2::Handler();
} else {
handler = new OPL3::Handler();
}
//0x388 range
WriteHandler[0].Install(0x388,OPL_Write,IO_MB, portRange );
ReadHandler[0].Install(0x388,OPL_Read,IO_MB, portRange - 1 );
//0x220 range
WriteHandler[1].Install(base,OPL_Write,IO_MB, portRange );
ReadHandler[1].Install(base,OPL_Read,IO_MB, portRange - 1 );
//0x228 range
WriteHandler[2].Install(base+8,OPL_Write,IO_MB,2);
ReadHandler[2].Install(base+8,OPL_Read,IO_MB,1);
MAPPER_AddHandler(OPL_SaveRawEvent,MK_f7,MMOD1|MMOD2,"caprawopl","Cap OPL");
}
~OPL() {
if ( module.capture )
delete module.capture;
old_OPL2::YM3812Shutdown();
old_OPL3::YMF262Shutdown();
handler->Init( rate );
Bit8u portRange = 4; //opl2 will set this to 2
switch ( oplmode ) {
case OPL_opl2:
portRange = 2;
Init( Adlib::MODE_OPL2 );
break;
case OPL_dualopl2:
Init( Adlib::MODE_DUALOPL2 );
break;
case OPL_opl3:
Init( Adlib::MODE_OPL3 );
break;
}
};
//0x388 range
WriteHandler[0].Install(0x388,OPL_Write,IO_MB, portRange );
ReadHandler[0].Install(0x388,OPL_Read,IO_MB, portRange - 1 );
//0x220 range
WriteHandler[1].Install(base,OPL_Write,IO_MB, portRange );
ReadHandler[1].Install(base,OPL_Read,IO_MB, portRange - 1 );
//0x228 range
WriteHandler[2].Install(base+8,OPL_Write,IO_MB,2);
ReadHandler[2].Install(base+8,OPL_Read,IO_MB,1);
static OPL* test;
MAPPER_AddHandler(OPL_SaveRawEvent,MK_f7,MMOD1|MMOD2,"caprawopl","Cap OPL");
}
Module::~Module() {
if ( capture ) {
delete capture;
}
if ( handler ) {
delete handler;
}
}
//Initialize static members
OPL_Mode OPL::oplmode=OPL_none;
OPL_Mode Module::oplmode=OPL_none;
}; //Adlib Namespace
void OPL_Init(Section* sec,OPL_Mode oplmode) {
OPL::oplmode = oplmode;
test = new OPL(sec);
Adlib::Module::oplmode = oplmode;
module = new Adlib::Module( sec );
}
void OPL_ShutDown(Section* sec){
delete test;
delete module;
module = 0;
}

View file

@ -16,14 +16,19 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* $Id: adlib.h,v 1.2 2009-04-06 11:23:21 qbix79 Exp $ */
/* $Id: adlib.h,v 1.3 2009-04-25 09:55:50 harekiet Exp $ */
#ifndef DOSBOX_ADLIB_H
#define DOSBOX_ADLIB_H
#include "dosbox.h"
#include "mixer.h"
#include "inout.h"
#include "mixer.h"
#include "setup.h"
#include "pic.h"
#include "hardware.h"
namespace Adlib {
@ -108,7 +113,11 @@ typedef Bit8u RegisterCache[512];
//Internal class used for dro capturing
class Capture;
class Module {
class Module: public Module_base {
IO_ReadHandleObject ReadHandler[3];
IO_WriteHandleObject WriteHandler[3];
MixerObject mixerObject;
//Mode we're running in
Mode mode;
//Last selected address in the chip for the different modes
@ -119,7 +128,8 @@ class Module {
void CacheWrite( Bit32u reg, Bit8u val );
void DualWrite( Bit8u index, Bit8u reg, Bit8u val );
public:
MixerChannel* chan;
static OPL_Mode oplmode;
MixerChannel* mixerChan;
Bit32u lastUsed; //Ticks when adlib was last used to turn of mixing after a few second
Handler* handler; //Handler that will generate the sound
@ -132,7 +142,8 @@ public:
Bitu PortRead( Bitu port, Bitu iolen );
void Init( Mode m );
Module();
Module( Section* configuration);
~Module();
};

1467
src/hardware/dbopl.cpp Normal file

File diff suppressed because it is too large Load diff

250
src/hardware/dbopl.h Normal file
View file

@ -0,0 +1,250 @@
/*
* Copyright (C) 2002-2009 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"
//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_HANDLER
//Enable vibrato in the output
#define DBOPL_VIBRATO
//Enable tremolo in the output
#define DBOPL_TREMOLO
namespace DBOPL {
struct Chip;
struct Operator;
struct Channel;
#if (DBOPL_WAVE == WAVE_HANDLER)
typedef Bits ( FASTCALL *WaveHandler) ( Bitu i, Bitu volume );
#endif
typedef Bits ( DBOPL::Operator::*VolumeHandler) ( );
typedef Channel* ( DBOPL::Channel::*SynthHandler) ( );
//Different synth modes that can generate blocks of data
typedef enum {
smNone,
sm2AM,
sm2FM,
sm2Rhytm,
sm3AM,
sm3FM,
sm3FMFM,
sm3AMFM,
sm3FMAM,
sm3AMAM,
sm3Rhytm,
} 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;
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; //totalLeve is added to every generated volume
Bit32s activeLevel; //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:
//is the operator silent?
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 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 rhytm 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 GenerateRhytm( Bit32s* output );
//Generate blocks of data in specific modes
template<SynthMode mode>
Channel* BlockTemplate( );
void BlockRhytm( );
Channel();
};
struct Chip {
//This is used as the base counter for vibrato and tremolo
Bit32u tremoloCounter;
Bit32u tremoloAdd;
Bit32u vibratoCounter;
Bit32u vibratoAdd;
//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 vibratoShift;
Bit8u tremoloShift;
//Mask for allowed wave forms
Bit8u waveFormMask;
//0 or -1 when enabled
Bit8s opl3Active;
Bit8u ForwardTremolo();
Bit8s ForwardVibrato();
void WriteBD( Bit8u val );
void WriteReg(Bit32u reg, Bit8u val );
Bit32u WriteAddr( Bit32u port, Bit8u val );
void GenerateBlock2( Bitu samples );
void GenerateBlock3( Bitu samples );
void Generate( Bit32u samples );
void Setup( Bit32u r );
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 );
};
}; //Namespace