Merge pull request #669 from nukeykt/nuked-opl

opl: Nuked OPL emulator
This commit is contained in:
Simon Howard 2016-02-28 13:12:42 -05:00
commit a0ef4eda48
7 changed files with 1579 additions and 1876 deletions

View file

@ -158,10 +158,6 @@
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\opl\dbopl.c"
>
</File>
<File
RelativePath="..\opl\ioperm_sys.c"
>
@ -194,6 +190,10 @@
RelativePath="..\opl\opl_win32.c"
>
</File>
<File
RelativePath="..\opl\opl3.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
@ -224,6 +224,10 @@
RelativePath="..\opl\opl_timer.h"
>
</File>
<File
RelativePath="..\opl\opl3.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"

View file

@ -15,5 +15,5 @@ libopl_a_SOURCES = \
opl_timer.c opl_timer.h \
opl_win32.c \
ioperm_sys.c ioperm_sys.h \
dbopl.c dbopl.h
opl3.c opl3.h

File diff suppressed because it is too large Load diff

View file

@ -1,203 +0,0 @@
/*
* 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.
*/
#include <inttypes.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_TABLEMUL
typedef struct _Chip Chip;
typedef struct _Operator Operator;
typedef struct _Channel Channel;
typedef uintptr_t Bitu;
typedef intptr_t Bits;
typedef uint32_t Bit32u;
typedef int32_t Bit32s;
typedef uint16_t Bit16u;
typedef int16_t Bit16s;
typedef uint8_t Bit8u;
typedef int8_t Bit8s;
#if (DBOPL_WAVE == WAVE_HANDLER)
typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume );
#endif
#define DB_FASTCALL
typedef Bits (*VolumeHandler)(Operator *self);
typedef Channel* (*SynthHandler)(Channel *self, 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,
};
//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,
} OperatorState;
struct _Operator {
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;
};
struct _Channel {
Operator op[2];
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;
};
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;
};
/*
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 Chip__Setup(Chip *self, Bit32u rate );
void DBOPL_InitTables( void );
void Chip__Chip(Chip *self);
void Chip__WriteReg(Chip *self, Bit32u reg, Bit8u val );
void Chip__GenerateBlock2(Chip *self, Bitu total, Bit32s* output );
void Chip__GenerateBlock3(Chip *self, Bitu total, Bit32s* output );
// haleyjd 09/09/10: Not standard C.
#ifdef _MSC_VER
#define inline __inline
#endif

1430
opl/opl3.c Normal file

File diff suppressed because it is too large Load diff

135
opl/opl3.h Normal file
View file

@ -0,0 +1,135 @@
//
// Copyright (C) 2013-2016 Alexey Khokholov (Nuke.YKT)
//
// 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.
//
//
// Nuked OPL3 emulator.
// Thanks:
// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
// Feedback and Rhythm part calculation information.
// forums.submarine.org.uk(carbon14, opl3):
// Tremolo and phase generator calculation information.
// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
// OPL2 ROMs.
//
// version: 1.7
//
#ifndef OPL_OPL3_H
#define OPL_OPL3_H
#include <inttypes.h>
#define OPL_WRITEBUF_SIZE 1024
#define OPL_WRITEBUF_DELAY 2
typedef uintptr_t Bitu;
typedef intptr_t Bits;
typedef uint64_t Bit64u;
typedef int64_t Bit64s;
typedef uint32_t Bit32u;
typedef int32_t Bit32s;
typedef uint16_t Bit16u;
typedef int16_t Bit16s;
typedef uint8_t Bit8u;
typedef int8_t Bit8s;
typedef struct _opl3_slot opl3_slot;
typedef struct _opl3_channel opl3_channel;
typedef struct _opl3_chip opl3_chip;
struct _opl3_slot {
opl3_channel *channel;
opl3_chip *chip;
Bit16s out;
Bit16s fbmod;
Bit16s *mod;
Bit16s prout;
Bit16s eg_rout;
Bit16s eg_out;
Bit8u eg_inc;
Bit8u eg_gen;
Bit8u eg_rate;
Bit8u eg_ksl;
Bit8u *trem;
Bit8u reg_vib;
Bit8u reg_type;
Bit8u reg_ksr;
Bit8u reg_mult;
Bit8u reg_ksl;
Bit8u reg_tl;
Bit8u reg_ar;
Bit8u reg_dr;
Bit8u reg_sl;
Bit8u reg_rr;
Bit8u reg_wf;
Bit8u key;
Bit32u pg_phase;
Bit32u timer;
};
struct _opl3_channel {
opl3_slot *slots[2];
opl3_channel *pair;
opl3_chip *chip;
Bit16s *out[4];
Bit8u chtype;
Bit16u f_num;
Bit8u block;
Bit8u fb;
Bit8u con;
Bit8u alg;
Bit8u ksv;
Bit16u cha, chb;
};
typedef struct _opl3_writebuf {
Bit64u time;
Bit16u reg;
Bit8u data;
} opl3_writebuf;
struct _opl3_chip {
opl3_channel channel[18];
opl3_slot slot[36];
Bit16u timer;
Bit8u newm;
Bit8u nts;
Bit8u rhy;
Bit8u vibpos;
Bit8u vibshift;
Bit8u tremolo;
Bit8u tremolopos;
Bit8u tremoloshift;
Bit32u noise;
Bit16s zeromod;
Bit32s mixbuff[2];
//OPL3L
Bit32s rateratio;
Bit32s samplecnt;
Bit16s oldsamples[2];
Bit16s samples[2];
Bit64u writebuf_samplecnt;
Bit32u writebuf_cur;
Bit32u writebuf_last;
Bit64u writebuf_lasttime;
opl3_writebuf writebuf[OPL_WRITEBUF_SIZE];
};
void OPL3_Generate(opl3_chip *chip, Bit16s *buf);
void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf);
void OPL3_Reset(opl3_chip *chip, Bit32u samplerate);
void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v);
void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v);
void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples);
#endif

View file

@ -25,7 +25,7 @@
#include "SDL.h"
#include "SDL_mixer.h"
#include "dbopl.h"
#include "opl3.h"
#include "opl.h"
#include "opl_internal.h"
@ -70,7 +70,7 @@ static uint64_t pause_offset;
// OPL software emulator structure.
static Chip opl_chip;
static opl3_chip opl_chip;
static int opl_opl3mode;
// Temporary mixing buffer used by the mixing callback.
@ -165,30 +165,7 @@ static void FillBuffer(int16_t *buffer, unsigned int nsamples)
assert(nsamples < mixing_freq);
if (opl_opl3mode)
{
Chip__GenerateBlock3(&opl_chip, nsamples, mix_buffer);
// Mix into the destination buffer, doubling up into stereo.
for (i=0; i<nsamples; ++i)
{
buffer[i * 2] = (int16_t) mix_buffer[i * 2];
buffer[i * 2 + 1] = (int16_t) mix_buffer[i * 2 + 1];
}
}
else
{
Chip__GenerateBlock2(&opl_chip, nsamples, mix_buffer);
// Mix into the destination buffer, doubling up into stereo.
for (i=0; i<nsamples; ++i)
{
buffer[i * 2] = (int16_t) mix_buffer[i];
buffer[i * 2 + 1] = (int16_t) mix_buffer[i];
}
}
OPL3_GenerateStream(&opl_chip, buffer, nsamples);
}
// Callback function to fill a new sound buffer:
@ -371,9 +348,7 @@ static int OPL_SDL_Init(unsigned int port_base)
// Create the emulator structure:
DBOPL_InitTables();
Chip__Chip(&opl_chip);
Chip__Setup(&opl_chip, mixing_freq);
OPL3_Reset(&opl_chip, mixing_freq);
opl_opl3mode = 0;
callback_mutex = SDL_CreateMutex();
@ -465,7 +440,7 @@ static void WriteRegister(unsigned int reg_num, unsigned int value)
opl_opl3mode = value & 0x01;
default:
Chip__WriteReg(&opl_chip, reg_num, value);
OPL3_WriteRegBuffered(&opl_chip, reg_num, value);
break;
}
}