summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/ymfm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/ymfm.cpp')
-rw-r--r--src/devices/sound/ymfm.cpp3276
1 files changed, 0 insertions, 3276 deletions
diff --git a/src/devices/sound/ymfm.cpp b/src/devices/sound/ymfm.cpp
deleted file mode 100644
index 44a869bc1fd..00000000000
--- a/src/devices/sound/ymfm.cpp
+++ /dev/null
@@ -1,3276 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-
-#include "emu.h"
-#include "ymfm.h"
-
-//#define VERBOSE 1
-#define LOG_OUTPUT_FUNC osd_printf_verbose
-#include "logmacro.h"
-
-//
-// ONE FM CORE TO RULE THEM ALL
-//
-// This emulator is written from the ground-up using the analysis and deduction
-// by Nemesis as a starting point, particularly in this thread:
-//
-// https://gendev.spritesmind.net/forum/viewtopic.php?f=24&t=386
-//
-// The core assumption is that these details apply to all FM variants unless
-// otherwise proven incorrect.
-//
-// The fine details of this implementation have also been cross-checked against
-// Nemesis' implementation in his Exodus emulator, as well as Alexey Khokholov's
-// "Nuked" implementations based off die shots.
-//
-// Operator and channel summing/mixing code is largely based off of research
-// done by David Viens and Hubert Lamontagne.
-//
-// Search for QUESTION to find areas where I am unsure.
-//
-//
-// FAMILIES
-//
-// The Yamaha FM chips can be broadly categoried into families:
-//
-// OPM (YM2151)
-// OPN (YM2203)
-// OPNA/OPNB/OPN2 (YM2608, YM2610, YM2610B, YM2612, YM3438, YMF276, YMF288)
-// OPL (YM3526)
-// OPL2 (YM3812)
-// OPLL (YM2413, YM2423, YMF281, DS1001, and others)
-// OPL3 (YMF262, YMF278)
-//
-// All of these families are very closely related, and the ymfm engine
-// implemented below is designed to be universal to work across all of
-// these families.
-//
-// Of course, each variant has its own register maps, features, and
-// implementation details which need to be sorted out. Thus, each
-// significant variant listed above is represented by a register class. The
-// register class contains:
-//
-// * constants describing core parameters and features
-// * mappers between operators and channels
-// * generic fetchers that return normalized values across families
-// * family-specific helper functions
-//
-//
-// FAMILY HISTORY
-//
-// OPM started it all off, featuring:
-// - 8 FM channels, 4 operators each
-// - LFO and noise support
-// - Stereo output
-//
-// OPM -> OPN changes:
-// - Reduced to 3 FM channels, 4 operators each
-// - Removed LFO and noise support
-// - Mono output
-// - Integrated AY-8910 compatible PSG
-// - Added SSG-EG envelope mode
-// - Added multi-frequency mode: ch. 3 operators can have separate frequencies
-// - Software controlled clock divider
-//
-// OPN -> OPNA changes:
-// - Increased to 6 FM channels, 4 operators each
-// - Added back (a cut-down) LFO
-// - Stereo output again
-// - Removed software controlled divider on later versions (OPNB/OPN2)
-// - Removed PSG on OPN2 models
-//
-// OPNA -> OPL changes:
-// - Increased to 9 FM channels, but only 2 operators each
-// - Even more simplified LFO
-// - Mono output
-// - Removed PSG
-// - Removed SSG-EG envelope modes
-// - Removed multi-frequency modes
-// - Fixed clock divider
-// - Built-in ryhthm generation
-//
-// OPL -> OPL2 changes:
-// - Added 4 selectable waveforms
-//
-// OPL2 -> OPLL changes:
-// - Vastly simplified register map
-// - 15 built-in instruments, plus built-in rhythm instruments
-// - 1 user-controlled instrument
-//
-// OPL2 -> OPL3 changes:
-// - Increased to 18 FM channels, 2 operators each
-// - 4 output channels
-// - Increased to 8 selectable waveforms
-// - 6 channels can be configured to use 4 operators
-//
-//
-// CHANNELS AND OPERATORS
-//
-// The polyphony of a given chip is determined by the number of channels
-// it supports. This number ranges from as low as 3 to as high as 18.
-// Each channel has either 2 or 4 operators that can be combined in a
-// myriad of ways. On most chips the number of operators per channel is
-// fixed; however, some later OPL chips allow this to be toggled between
-// 2 and 4 at runtime.
-//
-// The base ymfm engine class maintains an array of channels and operators,
-// while the relationship between the two is described by the register
-// class.
-//
-//
-// REGISTERS
-//
-// Registers on the Yamaha chips are generally write-only, and can be divided
-// into three distinct categories:
-//
-// * system-wide registers
-// * channel-specific registers
-// * operator-specific registers
-//
-// For maximum flexibility, most parameters can be configured at the operator
-// level, with channel-level registers controlling details such as how to
-// combine the operators into the final output. System-wide registers are
-// used to control chip-wide modes and manage onboard timer functions.
-//
-// Note that since registers are write-only, some implementations will use
-// "holes" in the register space to store additional values that may be
-// needed.
-//
-//
-// STATUS AND TIMERS
-//
-// Generically, all chips (except OPLL) support two timers that can be
-// programmed to fire and signal IRQs. These timers also set bits in the
-// status register. The behavior of these bits is shared across all
-// implementations, even if the exact bit positions shift (this is controlled
-// by constants in the registers class).
-//
-// In addition, several chips incorporate ADPCM decoders which also may set
-// bits in the same status register. For this reason, it is possible to
-// control various bits in the status register via the set_reset_status()
-// function directly. Any active bits that are set and which are not masked
-// (mask is controlled by set_irq_mask()), lead to an IRQ being signalled.
-//
-// Thus, it is possible for the chip-specific implementations to set the
-// mask and control the status register bits such that IRQs are signalled
-// via the same mechanism as timer signals.
-//
-// In addition, the OPM and OPN families have a "busy" flag, which is set
-// after each write, indicating that another write should not be performed.
-// Historically, the duration of this flag was constant and had nothing to
-// do with the internals of the chip. However, since the details can
-// potentially vary chip-to-chip, it is the chip's responsibility after any
-// operation to call set_busy_end() with the attotime of when the busy
-// signal should be released.
-//
-//
-// CLOCKING
-//
-// Each of the Yamaha chips works by cycling through all operators one at
-// a time. Thus, the effective output rate of the chips is related to the
-// input clock divided by the number of operators. In addition, the input
-// clock is prescaled by an amount. Generally, this is a fixed value, though
-// some early OPN chips allow this to be selected at runtime from a small
-// number of values.
-//
-//
-// CHANNEL FREQUENCIES
-//
-// One major difference between OPM and later families is in how frequencies
-// are specified. OPM specifies frequency via a 3-bit 'block' (aka octave),
-// combined with a 4-bit 'key code' (note number) and a 6-bit 'key fraction'.
-// The key code and fraction are converted on the chip into an x.11 fixed-
-// point value and then shifted by the block to produce the final step value
-// for the phase.
-//
-// Later families, on the other hand, specify frequencies via a 3-bit 'block'
-// just as on OPM, but combined with a 9, 10, or 11-bit 'frequency number'
-// or 'fnum', which is directly shifted by the block to produce the step
-// value. So essentially, later chips make the user do the conversion from
-// note value to phase increment, while OPM is programmed in a more 'musical'
-// way, specifying notes and cents.
-//
-// Interally, this is abstracted away into a 'block_freq' value, which is a
-// 16-bit value containing the block and frequency info concatenated together
-// as follows:
-//
-// OPM: [3-bit block]:[4-bit keycode]:[6-bit fraction] = 13 bits total
-//
-// OPN: [3-bit block]:[11-bit fnum] = 14 bits total
-// OPL: [3-bit block]:[10-bit fnum]:0 = 14 bits total
-// OPLL: [3-bit block]:[ 9-bit fnum]:00 = 14 bits total
-//
-// Template specialization in functions that interpret the 'block_freq' value
-// is used to deconstruct it appropriately (specifically, see clock_phase).
-//
-//
-// LOW FREQUENCY OSCILLATOR (LFO)
-//
-// The LFO engines are different in several key ways. The OPM LFO engine is
-// fairly intricate. It has a 4.4 floating-point rate which allows for a huge
-// range of frequencies, and can select between four different waveforms
-// (sawtooth, square, triangle, or noise). Separate 7-bit depth controls for
-// AM and PM control the amount of modulation applied in each case. This
-// global LFO value is then further controlled at the channel level by a 2-bit
-// AM sensitivity and a 3-bit PM sensitivity, and each operator has a 1-bit AM
-// on/off switch.
-//
-// For OPN the LFO engine was removed entirely, but a limited version was put
-// back in OPNA and later chips. This stripped-down version offered only a
-// 3-bit rate setting (versus the 4.4 floating-point rate in OPN), and no
-// depth control. It did bring back the channel-level sensitivity controls and
-// the operator-level on/off control.
-//
-// For OPL, the LFO is simplified again, with AM and PM running at fixed
-// frequencies, and simple enable flags at the operator level for each
-// controlling their application.
-//
-//
-// DIFFERENCES BETWEEN FAMILIES
-//
-// The table below provides some high level functional differences between the
-// differnet families:
-//
-// +--------++-----------------++-----------------------------------+
-// family: | OPM || OPN || OPL |
-// +--------++--------+--------++--------+--------+--------+--------+
-// subfamily: | OPM || OPN | OPNA || OPL | OPL2 | OPLL | OPL3 |
-// +--------++--------+--------++--------+--------+--------+--------+
-// outputs: | 2 || 1 | 2 || 1 | 1 | 1 | 4 |
-// channels: | 8 || 3 | 6 || 9 | 9 | 9 | 18 |
-// operators: | 32 || 12 | 24 || 18 | 18 | 18 | 36 |
-// waveforms: | 1 || 1 | 1 || 1 | 4 | 2 | 8 |
-// instruments: | no || no | no || yes | yes | yes | yes |
-// ryhthm: | no || no | no || no | no | yes | no |
-// dynamic ops: | no || no | no || no | no | no | yes |
-// prescale: | 2 || 2/3/6 | 2/3/6 || 4 | 4 | 4 | 8 |
-// EG divider: | 3 || 3 | 3 || 1 | 1 | 1 | 1 |
-// EG DP: | no || no | no || no | no | yes | no |
-// EG SSG: | no || yes | yes || no | no | no | no |
-// mod delay: | no || no | no || yes | yes | yes? | no |
-// CSM: | yes || ch 2 | ch 2 || yes | yes | yes | no |
-// LFO: | yes || no | yes || yes | yes | yes | yes |
-// noise: | yes || no | no || no | no | no | no |
-// +--------++--------+--------++--------+--------+--------+--------+
-//
-// Outputs represents the number of output channels: 1=mono, 2=stereo, 4=stereo+.
-// Channels represents the number of independent FM channels.
-// Operators represents the number of operators, or "slots" which are assembled
-// into the channels.
-// Waveforms represents the number of different sine-derived waveforms available.
-// Instruments indicates whether the family has built-in instruments.
-// Rhythm indicates whether the family has a built-in rhythm
-// Dynamic ops indicates whether it is possible to switch between 2-operator and
-// 4-operator modes dynamically.
-// Prescale specifies the default clock divider; some chips allow this to be
-// controlled via register writes.
-// EG divider represents the divider applied to the envelope generator clock.
-// EG DP indicates whether the envelope generator includes a DP (depress?) phase
-// at the beginning of each key on.
-// SSG EG indicates whether the envelope generator has SSG-style support.
-// Mod delay indicates whether the connection to the first modulator's input is
-// delayed by 1 sample.
-// CSM indicates whether CSM mode is supported, triggered by timer A.
-// LFO indicates whether LFO is supported.
-// Noise indicates whether one of the operators can be replaced with a noise source.
-//
-//
-// CHIP SPECIFICS
-//
-// While OPM is its own thing, the OPN and OPL families have quite a few specific
-// implementations, with many differing details beyond the core FM parts. Here are
-// some details on the OPN family:
-//
-// +--------++--------+--------++--------+---------++--------+--------+--------+
-// chip ID: | YM2203 || YM2608 | YMF288 || YM2610 | YM2610B || YM2612 | YM3438 | YMF276 |
-// +--------++--------+--------++--------+---------++--------+--------+--------+
-// aka: | OPN || OPNA | OPN3 || OPNB | OPNB2 || OPN2 | OPN2C | OPN2L |
-// FM: | 3 || 6 | 6 || 4 | 6 || 6 | 6 | 6 |
-// AY-8910: | 3 || 3 | 3 || 3 | 3 || - | - | - |
-// ADPCM-A: | - || 6 int | 6 int || 6 ext | 6 ext || - | - | - |
-// ADPCM-B: | - || 1 ext | - || 1 ext | 1 ext || - | - | - |
-// DAC: | no || no | no || no | no || yes | yes | yes |
-// output: | 10.3fp || 16-bit | 16-bit || 16-bit | 16-bit || 9-bit | 9-bit | 16-bit |
-// summing: | adder || adder | adder || adder | adder || muxer | muxer | adder |
-// +--------++--------+--------++--------+---------++--------+--------+--------+
-//
-// FM represents the number of FM channels available.
-// AY-8910 represents the number of AY-8910-compatible channels that are built in.
-// ADPCM-A represents the number of internal/external ADPCM-A channels present.
-// ADPCM-B represents the number of internal/external ADPCM-B channels present.
-// DAC indicates if a directly-accessible DAC output exists, replacing one channel.
-// Output indicates the output format to the final DAC.
-// Summing indicates whether channels are added or time divided in the output.
-//
-// OPL has a similar trove of chip variants:
-//
-// +--------+---------++--------++--------++--------++---------+
-// chip ID: | YM3526 | Y8950 || YM3812 || YM2413 || YMF262 || YMF278B |
-// +--------+---------++--------++--------++--------++---------+
-// aka: | OPL |MSX-AUDIO|| OPL2 || OPLL || OPL3 || OPL4 |
-// FM: | 9 | 9 || 9 || 9 || 18 || 18 |
-// ADPCM-B: | - | 1 ext || - || - || - || - |
-// wavetable: | - | - || - || - || - || 24 |
-// instruments: | no | no || no || yes || no || no |
-// output: | 10.3fp | 10.3fp || 10.3fp || 9-bit || 16-bit || 16-bit |
-// summing: | adder | adder || adder || muxer || adder || adder |
-// +--------+---------++--------++--------++--------++---------+
-//
-// FM represents the number of FM channels available.
-// ADPCM-B represents the number of external ADPCM-B channels present.
-// Wavetable indicates the number of wavetable channels present.
-// Instruments indicates that the chip has built-in instrument selection.
-// Output indicates the output format to the final DAC.
-// Summing indicates whether channels are added or time divided in the output.
-//
-// There are several close variants of the YM2413 with different sets of built-
-// in instruments. These include the YM2423, YMF281, and DS1001 (aka Konami VRC7).
-//
-// ===================================================================================
-//
-// OPN Test Bit Functions (YM2612)
-// $21:0: Select which of two unknown signals is read as bit 14 of the test read output.
-// $21:1: Some LFO control, unknown function.
-// $21:2: Timers increment once every internal clock rather than once every sample. (Untested by me)
-// $21:3: Freezes PG. Presumably disables writebacks to the phase register.
-// $21:4: Ugly bit. Inverts MSB of operators.
-// $21:5: Freezes EG. Presumably disables writebacks to the envelope counter register.
-// Unknown whether this affects the other EG state bits.
-// $21:6: Enable reading test data from OPN2 rather than status flags.
-// $21:7: Select LSB (1) or MSB (0) of read test data. (Yes, it's backwards.)
-// $2C:2 downto 0: Ignored by OPN2, confirmed by die shot.
-// $2C:3: Bit 0 of Channel 6 DAC value
-// $2C:4: Read 9-bit channel output (1) instead of 14-bit operator output (0)
-// $2C:5: Play DAC output over all channels (possibly except for Channel 5--in my testing
-// the DAC is the only thing you hear and it's much louder, you do not get any output
-// from Channel 5; but someone else supposedly found that the pan flags for Channel 5
-// don't affect the panning of this sound, which is only possible if it's not being
-// output during that time slot for some reason. I don't have any other reason to
-// believe this is true though).
-// $2C:6: Select function of TEST pin input--both unknown functions.
-// $2C:7: Set the TEST pin to be an output (1) instead of input (0).
-//
-
-
-//*********************************************************
-// GLOBAL TABLE LOOKUPS
-//*********************************************************
-
-//-------------------------------------------------
-// abs_sin_attenuation - given a sin (phase) input
-// where the range 0-2*PI is mapped onto 10 bits,
-// return the absolute value of sin(input),
-// logarithmically-adjusted and treated as an
-// attenuation value, in 4.8 fixed point format
-//-------------------------------------------------
-
-inline u32 abs_sin_attenuation(u32 input)
-{
- // the values here are stored as 4.8 logarithmic values for 1/4 phase
- // this matches the internal format of the OPN chip, extracted from the die
- static u16 const s_sin_table[256] =
- {
- 0x859,0x6c3,0x607,0x58b,0x52e,0x4e4,0x4a6,0x471,0x443,0x41a,0x3f5,0x3d3,0x3b5,0x398,0x37e,0x365,
- 0x34e,0x339,0x324,0x311,0x2ff,0x2ed,0x2dc,0x2cd,0x2bd,0x2af,0x2a0,0x293,0x286,0x279,0x26d,0x261,
- 0x256,0x24b,0x240,0x236,0x22c,0x222,0x218,0x20f,0x206,0x1fd,0x1f5,0x1ec,0x1e4,0x1dc,0x1d4,0x1cd,
- 0x1c5,0x1be,0x1b7,0x1b0,0x1a9,0x1a2,0x19b,0x195,0x18f,0x188,0x182,0x17c,0x177,0x171,0x16b,0x166,
- 0x160,0x15b,0x155,0x150,0x14b,0x146,0x141,0x13c,0x137,0x133,0x12e,0x129,0x125,0x121,0x11c,0x118,
- 0x114,0x10f,0x10b,0x107,0x103,0x0ff,0x0fb,0x0f8,0x0f4,0x0f0,0x0ec,0x0e9,0x0e5,0x0e2,0x0de,0x0db,
- 0x0d7,0x0d4,0x0d1,0x0cd,0x0ca,0x0c7,0x0c4,0x0c1,0x0be,0x0bb,0x0b8,0x0b5,0x0b2,0x0af,0x0ac,0x0a9,
- 0x0a7,0x0a4,0x0a1,0x09f,0x09c,0x099,0x097,0x094,0x092,0x08f,0x08d,0x08a,0x088,0x086,0x083,0x081,
- 0x07f,0x07d,0x07a,0x078,0x076,0x074,0x072,0x070,0x06e,0x06c,0x06a,0x068,0x066,0x064,0x062,0x060,
- 0x05e,0x05c,0x05b,0x059,0x057,0x055,0x053,0x052,0x050,0x04e,0x04d,0x04b,0x04a,0x048,0x046,0x045,
- 0x043,0x042,0x040,0x03f,0x03e,0x03c,0x03b,0x039,0x038,0x037,0x035,0x034,0x033,0x031,0x030,0x02f,
- 0x02e,0x02d,0x02b,0x02a,0x029,0x028,0x027,0x026,0x025,0x024,0x023,0x022,0x021,0x020,0x01f,0x01e,
- 0x01d,0x01c,0x01b,0x01a,0x019,0x018,0x017,0x017,0x016,0x015,0x014,0x014,0x013,0x012,0x011,0x011,
- 0x010,0x00f,0x00f,0x00e,0x00d,0x00d,0x00c,0x00c,0x00b,0x00a,0x00a,0x009,0x009,0x008,0x008,0x007,
- 0x007,0x007,0x006,0x006,0x005,0x005,0x005,0x004,0x004,0x004,0x003,0x003,0x003,0x002,0x002,0x002,
- 0x002,0x001,0x001,0x001,0x001,0x001,0x001,0x001,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000
- };
-
- // if the top bit is set, we're in the second half of the curve
- // which is a mirror image, so invert the index
- if (BIT(input, 8))
- input = ~input;
-
- // return the value from the table
- return s_sin_table[input & 0xff];
-}
-
-
-//-------------------------------------------------
-// attenuation_to_volume - given a 5.8 fixed point
-// logarithmic attenuation value, return a 13-bit
-// linear volume
-//-------------------------------------------------
-
-inline u32 attenuation_to_volume(u32 input)
-{
- // the values here are 10-bit mantissas with an implied leading bit
- // this matches the internal format of the OPN chip, extracted from the die
-
- // as a nod to performance, the implicit 0x400 bit is pre-incorporated, and
- // the values are left-shifted by 2 so that a simple right shift is all that
- // is needed; also the order is reversed to save a NOT on the input
-#define X(a) ((a | 0x400) << 2)
- static u16 const s_power_table[256] =
- {
- X(0x3fa),X(0x3f5),X(0x3ef),X(0x3ea),X(0x3e4),X(0x3df),X(0x3da),X(0x3d4),
- X(0x3cf),X(0x3c9),X(0x3c4),X(0x3bf),X(0x3b9),X(0x3b4),X(0x3ae),X(0x3a9),
- X(0x3a4),X(0x39f),X(0x399),X(0x394),X(0x38f),X(0x38a),X(0x384),X(0x37f),
- X(0x37a),X(0x375),X(0x370),X(0x36a),X(0x365),X(0x360),X(0x35b),X(0x356),
- X(0x351),X(0x34c),X(0x347),X(0x342),X(0x33d),X(0x338),X(0x333),X(0x32e),
- X(0x329),X(0x324),X(0x31f),X(0x31a),X(0x315),X(0x310),X(0x30b),X(0x306),
- X(0x302),X(0x2fd),X(0x2f8),X(0x2f3),X(0x2ee),X(0x2e9),X(0x2e5),X(0x2e0),
- X(0x2db),X(0x2d6),X(0x2d2),X(0x2cd),X(0x2c8),X(0x2c4),X(0x2bf),X(0x2ba),
- X(0x2b5),X(0x2b1),X(0x2ac),X(0x2a8),X(0x2a3),X(0x29e),X(0x29a),X(0x295),
- X(0x291),X(0x28c),X(0x288),X(0x283),X(0x27f),X(0x27a),X(0x276),X(0x271),
- X(0x26d),X(0x268),X(0x264),X(0x25f),X(0x25b),X(0x257),X(0x252),X(0x24e),
- X(0x249),X(0x245),X(0x241),X(0x23c),X(0x238),X(0x234),X(0x230),X(0x22b),
- X(0x227),X(0x223),X(0x21e),X(0x21a),X(0x216),X(0x212),X(0x20e),X(0x209),
- X(0x205),X(0x201),X(0x1fd),X(0x1f9),X(0x1f5),X(0x1f0),X(0x1ec),X(0x1e8),
- X(0x1e4),X(0x1e0),X(0x1dc),X(0x1d8),X(0x1d4),X(0x1d0),X(0x1cc),X(0x1c8),
- X(0x1c4),X(0x1c0),X(0x1bc),X(0x1b8),X(0x1b4),X(0x1b0),X(0x1ac),X(0x1a8),
- X(0x1a4),X(0x1a0),X(0x19c),X(0x199),X(0x195),X(0x191),X(0x18d),X(0x189),
- X(0x185),X(0x181),X(0x17e),X(0x17a),X(0x176),X(0x172),X(0x16f),X(0x16b),
- X(0x167),X(0x163),X(0x160),X(0x15c),X(0x158),X(0x154),X(0x151),X(0x14d),
- X(0x149),X(0x146),X(0x142),X(0x13e),X(0x13b),X(0x137),X(0x134),X(0x130),
- X(0x12c),X(0x129),X(0x125),X(0x122),X(0x11e),X(0x11b),X(0x117),X(0x114),
- X(0x110),X(0x10c),X(0x109),X(0x106),X(0x102),X(0x0ff),X(0x0fb),X(0x0f8),
- X(0x0f4),X(0x0f1),X(0x0ed),X(0x0ea),X(0x0e7),X(0x0e3),X(0x0e0),X(0x0dc),
- X(0x0d9),X(0x0d6),X(0x0d2),X(0x0cf),X(0x0cc),X(0x0c8),X(0x0c5),X(0x0c2),
- X(0x0be),X(0x0bb),X(0x0b8),X(0x0b5),X(0x0b1),X(0x0ae),X(0x0ab),X(0x0a8),
- X(0x0a4),X(0x0a1),X(0x09e),X(0x09b),X(0x098),X(0x094),X(0x091),X(0x08e),
- X(0x08b),X(0x088),X(0x085),X(0x082),X(0x07e),X(0x07b),X(0x078),X(0x075),
- X(0x072),X(0x06f),X(0x06c),X(0x069),X(0x066),X(0x063),X(0x060),X(0x05d),
- X(0x05a),X(0x057),X(0x054),X(0x051),X(0x04e),X(0x04b),X(0x048),X(0x045),
- X(0x042),X(0x03f),X(0x03c),X(0x039),X(0x036),X(0x033),X(0x030),X(0x02d),
- X(0x02a),X(0x028),X(0x025),X(0x022),X(0x01f),X(0x01c),X(0x019),X(0x016),
- X(0x014),X(0x011),X(0x00e),X(0x00b),X(0x008),X(0x006),X(0x003),X(0x000)
- };
-#undef X
-
- // look up the fractional part, then shift by the whole
- return s_power_table[input & 0xff] >> (input >> 8);
-}
-
-
-//-------------------------------------------------
-// attenuation_increment - given a 6-bit ADSR
-// rate value and a 3-bit stepping index,
-// return a 4-bit increment to the attenutaion
-// for this step (or for the attack case, the
-// fractional scale factor to decrease by)
-//-------------------------------------------------
-
-inline u32 attenuation_increment(u32 rate, u32 index)
-{
- static u32 const s_increment_table[64] =
- {
- 0x00000000, 0x00000000, 0x10101010, 0x10101010, // 0-3 (0x00-0x03)
- 0x10101010, 0x10101010, 0x11101110, 0x11101110, // 4-7 (0x04-0x07)
- 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 8-11 (0x08-0x0B)
- 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 12-15 (0x0C-0x0F)
- 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 16-19 (0x10-0x13)
- 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 20-23 (0x14-0x17)
- 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 24-27 (0x18-0x1B)
- 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 28-31 (0x1C-0x1F)
- 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 32-35 (0x20-0x23)
- 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 36-39 (0x24-0x27)
- 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 40-43 (0x28-0x2B)
- 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 44-47 (0x2C-0x2F)
- 0x11111111, 0x21112111, 0x21212121, 0x22212221, // 48-51 (0x30-0x33)
- 0x22222222, 0x42224222, 0x42424242, 0x44424442, // 52-55 (0x34-0x37)
- 0x44444444, 0x84448444, 0x84848484, 0x88848884, // 56-59 (0x38-0x3B)
- 0x88888888, 0x88888888, 0x88888888, 0x88888888 // 60-63 (0x3C-0x3F)
- };
- return BIT(s_increment_table[rate], 4*index, 4);
-}
-
-
-//-------------------------------------------------
-// detune_adjustment - given a 5-bit key code
-// value and a 3-bit detune parameter, return a
-// 6-bit signed phase displacement; this table
-// has been verified against Nuked's equations,
-// but the equations are rather complicated, so
-// we'll keep the simplicity of the table
-//-------------------------------------------------
-
-inline s32 detune_adjustment(u32 detune, u32 keycode)
-{
- static u8 const s_detune_adjustment[32][4] =
- {
- { 0, 0, 1, 2 }, { 0, 0, 1, 2 }, { 0, 0, 1, 2 }, { 0, 0, 1, 2 },
- { 0, 1, 2, 2 }, { 0, 1, 2, 3 }, { 0, 1, 2, 3 }, { 0, 1, 2, 3 },
- { 0, 1, 2, 4 }, { 0, 1, 3, 4 }, { 0, 1, 3, 4 }, { 0, 1, 3, 5 },
- { 0, 2, 4, 5 }, { 0, 2, 4, 6 }, { 0, 2, 4, 6 }, { 0, 2, 5, 7 },
- { 0, 2, 5, 8 }, { 0, 3, 6, 8 }, { 0, 3, 6, 9 }, { 0, 3, 7, 10 },
- { 0, 4, 8, 11 }, { 0, 4, 8, 12 }, { 0, 4, 9, 13 }, { 0, 5, 10, 14 },
- { 0, 5, 11, 16 }, { 0, 6, 12, 17 }, { 0, 6, 13, 19 }, { 0, 7, 14, 20 },
- { 0, 8, 16, 22 }, { 0, 8, 16, 22 }, { 0, 8, 16, 22 }, { 0, 8, 16, 22 }
- };
- s32 result = s_detune_adjustment[keycode][detune & 3];
- return BIT(detune, 2) ? -result : result;
-}
-
-
-//-------------------------------------------------
-// opn_lfo_pm_phase_adjustment - given the 7 most
-// significant frequency number bits, plus a 3-bit
-// PM depth value and a signed 5-bit raw PM value,
-// return a signed PM adjustment to the frequency;
-// algorithm written to match Nuked behavior
-//-------------------------------------------------
-
-inline s32 opn_lfo_pm_phase_adjustment(u32 fnum_bits, u32 pm_sensitivity, s32 lfo_raw_pm)
-{
- // this table encodes 2 shift values to apply to the top 7 bits
- // of fnum; it is effectively a cheap multiply by a constant
- // value containing 0-2 bits
- static u8 const s_lfo_pm_shifts[8][8] =
- {
- { 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77 },
- { 0x77, 0x77, 0x77, 0x77, 0x72, 0x72, 0x72, 0x72 },
- { 0x77, 0x77, 0x77, 0x72, 0x72, 0x72, 0x17, 0x17 },
- { 0x77, 0x77, 0x72, 0x72, 0x17, 0x17, 0x12, 0x12 },
- { 0x77, 0x77, 0x72, 0x17, 0x17, 0x17, 0x12, 0x07 },
- { 0x77, 0x77, 0x17, 0x12, 0x07, 0x07, 0x02, 0x01 },
- { 0x77, 0x77, 0x17, 0x12, 0x07, 0x07, 0x02, 0x01 },
- { 0x77, 0x77, 0x17, 0x12, 0x07, 0x07, 0x02, 0x01 }
- };
-
- // look up the relevant shifts
- s32 abs_pm = (lfo_raw_pm < 0) ? -lfo_raw_pm : lfo_raw_pm;
- u32 const shifts = s_lfo_pm_shifts[pm_sensitivity][BIT(abs_pm, 0, 3)];
-
- // compute the adjustment
- s32 adjust = (fnum_bits >> BIT(shifts, 0, 4)) + (fnum_bits >> BIT(shifts, 4, 4));
- if (pm_sensitivity > 5)
- adjust <<= pm_sensitivity - 5;
- adjust >>= 2;
-
- // every 16 cycles it inverts sign
- return (lfo_raw_pm < 0) ? -adjust : adjust;
-}
-
-
-//-------------------------------------------------
-// opm_key_code_to_phase_step - converts an
-// OPM concatenated block (3 bits), keycode
-// (4 bits) and key fraction (6 bits) to a 0.10
-// phase step, after applying the given delta
-//-------------------------------------------------
-
-inline u32 opm_key_code_to_phase_step(u32 block_freq, s32 delta)
-{
- // The phase step is essentially the fnum in OPN-speak. To compute this table,
- // we used the standard formula for computing the frequency of a note, and
- // then converted that frequency to fnum using the formula documented in the
- // YM2608 manual.
- //
- // However, the YM2608 manual describes everything in terms of a nominal 8MHz
- // clock, which produces an FM clock of:
- //
- // 8000000 / 24(operators) / 6(prescale) = 55555Hz FM clock
- //
- // Whereas the descriptions for the YM2151 use a nominal 3.579545MHz clock:
- //
- // 3579545 / 32(operators) / 2(prescale) = 55930Hz FM clock
- //
- // To correct for this, the YM2608 formula was adjusted to use a clock of
- // 8053920Hz, giving this equation for the fnum:
- //
- // fnum = (double(144) * freq * (1 << 20)) / double(8053920) / 4;
- //
- // Unfortunately, the computed table differs in a few spots from the data
- // verified from an actual chip. The table below comes from David Viens'
- // analysis, used with his permission.
- static const u32 s_phase_step[12*64] =
- {
- 41568,41600,41632,41664,41696,41728,41760,41792,41856,41888,41920,41952,42016,42048,42080,42112,
- 42176,42208,42240,42272,42304,42336,42368,42400,42464,42496,42528,42560,42624,42656,42688,42720,
- 42784,42816,42848,42880,42912,42944,42976,43008,43072,43104,43136,43168,43232,43264,43296,43328,
- 43392,43424,43456,43488,43552,43584,43616,43648,43712,43744,43776,43808,43872,43904,43936,43968,
- 44032,44064,44096,44128,44192,44224,44256,44288,44352,44384,44416,44448,44512,44544,44576,44608,
- 44672,44704,44736,44768,44832,44864,44896,44928,44992,45024,45056,45088,45152,45184,45216,45248,
- 45312,45344,45376,45408,45472,45504,45536,45568,45632,45664,45728,45760,45792,45824,45888,45920,
- 45984,46016,46048,46080,46144,46176,46208,46240,46304,46336,46368,46400,46464,46496,46528,46560,
- 46656,46688,46720,46752,46816,46848,46880,46912,46976,47008,47072,47104,47136,47168,47232,47264,
- 47328,47360,47392,47424,47488,47520,47552,47584,47648,47680,47744,47776,47808,47840,47904,47936,
- 48032,48064,48096,48128,48192,48224,48288,48320,48384,48416,48448,48480,48544,48576,48640,48672,
- 48736,48768,48800,48832,48896,48928,48992,49024,49088,49120,49152,49184,49248,49280,49344,49376,
- 49440,49472,49504,49536,49600,49632,49696,49728,49792,49824,49856,49888,49952,49984,50048,50080,
- 50144,50176,50208,50240,50304,50336,50400,50432,50496,50528,50560,50592,50656,50688,50752,50784,
- 50880,50912,50944,50976,51040,51072,51136,51168,51232,51264,51328,51360,51424,51456,51488,51520,
- 51616,51648,51680,51712,51776,51808,51872,51904,51968,52000,52064,52096,52160,52192,52224,52256,
- 52384,52416,52448,52480,52544,52576,52640,52672,52736,52768,52832,52864,52928,52960,52992,53024,
- 53120,53152,53216,53248,53312,53344,53408,53440,53504,53536,53600,53632,53696,53728,53792,53824,
- 53920,53952,54016,54048,54112,54144,54208,54240,54304,54336,54400,54432,54496,54528,54592,54624,
- 54688,54720,54784,54816,54880,54912,54976,55008,55072,55104,55168,55200,55264,55296,55360,55392,
- 55488,55520,55584,55616,55680,55712,55776,55808,55872,55936,55968,56032,56064,56128,56160,56224,
- 56288,56320,56384,56416,56480,56512,56576,56608,56672,56736,56768,56832,56864,56928,56960,57024,
- 57120,57152,57216,57248,57312,57376,57408,57472,57536,57568,57632,57664,57728,57792,57824,57888,
- 57952,57984,58048,58080,58144,58208,58240,58304,58368,58400,58464,58496,58560,58624,58656,58720,
- 58784,58816,58880,58912,58976,59040,59072,59136,59200,59232,59296,59328,59392,59456,59488,59552,
- 59648,59680,59744,59776,59840,59904,59936,60000,60064,60128,60160,60224,60288,60320,60384,60416,
- 60512,60544,60608,60640,60704,60768,60800,60864,60928,60992,61024,61088,61152,61184,61248,61280,
- 61376,61408,61472,61536,61600,61632,61696,61760,61824,61856,61920,61984,62048,62080,62144,62208,
- 62272,62304,62368,62432,62496,62528,62592,62656,62720,62752,62816,62880,62944,62976,63040,63104,
- 63200,63232,63296,63360,63424,63456,63520,63584,63648,63680,63744,63808,63872,63904,63968,64032,
- 64096,64128,64192,64256,64320,64352,64416,64480,64544,64608,64672,64704,64768,64832,64896,64928,
- 65024,65056,65120,65184,65248,65312,65376,65408,65504,65536,65600,65664,65728,65792,65856,65888,
- 65984,66016,66080,66144,66208,66272,66336,66368,66464,66496,66560,66624,66688,66752,66816,66848,
- 66944,66976,67040,67104,67168,67232,67296,67328,67424,67456,67520,67584,67648,67712,67776,67808,
- 67904,67936,68000,68064,68128,68192,68256,68288,68384,68448,68512,68544,68640,68672,68736,68800,
- 68896,68928,68992,69056,69120,69184,69248,69280,69376,69440,69504,69536,69632,69664,69728,69792,
- 69920,69952,70016,70080,70144,70208,70272,70304,70400,70464,70528,70560,70656,70688,70752,70816,
- 70912,70976,71040,71104,71136,71232,71264,71360,71424,71488,71552,71616,71648,71744,71776,71872,
- 71968,72032,72096,72160,72192,72288,72320,72416,72480,72544,72608,72672,72704,72800,72832,72928,
- 72992,73056,73120,73184,73216,73312,73344,73440,73504,73568,73632,73696,73728,73824,73856,73952,
- 74080,74144,74208,74272,74304,74400,74432,74528,74592,74656,74720,74784,74816,74912,74944,75040,
- 75136,75200,75264,75328,75360,75456,75488,75584,75648,75712,75776,75840,75872,75968,76000,76096,
- 76224,76288,76352,76416,76448,76544,76576,76672,76736,76800,76864,76928,77024,77120,77152,77248,
- 77344,77408,77472,77536,77568,77664,77696,77792,77856,77920,77984,78048,78144,78240,78272,78368,
- 78464,78528,78592,78656,78688,78784,78816,78912,78976,79040,79104,79168,79264,79360,79392,79488,
- 79616,79680,79744,79808,79840,79936,79968,80064,80128,80192,80256,80320,80416,80512,80544,80640,
- 80768,80832,80896,80960,80992,81088,81120,81216,81280,81344,81408,81472,81568,81664,81696,81792,
- 81952,82016,82080,82144,82176,82272,82304,82400,82464,82528,82592,82656,82752,82848,82880,82976
- };
-
- // extract the block (octave) first
- u32 block = BIT(block_freq, 10, 3);
-
- // the keycode (bits 6-9) is "gappy", mapping 12 values over 16 in each
- // octave; to correct for this, we multiply the 4-bit value by 3/4 (or
- // rather subtract 1/4); note that a (invalid) value of 15 will bleed into
- // the next octave -- this is confirmed
- u32 adjusted_code = BIT(block_freq, 6, 4) - BIT(block_freq, 8, 2);
-
- // now re-insert the 6-bit fraction
- s32 eff_freq = (adjusted_code << 6) | BIT(block_freq, 0, 6);
-
- // now that the gaps are removed, add the delta
- eff_freq += delta;
-
- // handle over/underflow by adjusting the block:
- if (u32(eff_freq) >= 768)
- {
- // minimum delta is -512 (PM), so we can only underflow by 1 octave
- if (eff_freq < 0)
- {
- eff_freq += 768;
- if (block-- == 0)
- return s_phase_step[0] >> 7;
- }
-
- // maximum delta is +512+608 (PM+detune), so we can overflow by up to 2 octaves
- else
- {
- eff_freq -= 768;
- if (eff_freq >= 768)
- block++, eff_freq -= 768;
- if (block++ >= 7)
- return s_phase_step[767];
- }
- }
-
- // look up the phase shift for the key code, then shift by octave
- return s_phase_step[eff_freq] >> (block ^ 7);
-}
-
-
-//-------------------------------------------------
-// opl_key_scale_atten - converts an
-// OPL concatenated block (3 bits) and fnum
-// (10 bits) into an attenuation offset; values
-// here are for 6dB/octave, in 0.75dB units
-// (matching total level LSB)
-//-------------------------------------------------
-
-inline u32 opl_key_scale_atten(u32 block, u32 fnum_4msb)
-{
- // this table uses the top 4 bits of FNUM and are the maximal values
- // (for when block == 7). Values for other blocks can be computed by
- // subtracting 8 for each block below 7.
- static u8 const fnum_to_atten[16] = { 0,24,32,37,40,43,45,47,48,50,51,52,53,54,55,56 };
- s32 result = fnum_to_atten[fnum_4msb] - 8 * (block ^ 7);
- return std::max<s32>(0, result);
-}
-
-
-
-//*********************************************************
-// OPM SPECIFICS
-//*********************************************************
-
-//-------------------------------------------------
-// ymopm_registers - constructor
-//-------------------------------------------------
-
-ymopm_registers::ymopm_registers() :
- m_lfo_counter(0),
- m_noise_lfsr(1),
- m_noise_counter(0),
- m_noise_state(0),
- m_noise_lfo(0),
- m_lfo_am(0)
-{
- // create the waveforms
- for (int index = 0; index < WAVEFORM_LENGTH; index++)
- m_waveform[0][index] = abs_sin_attenuation(index) | (BIT(index, 9) << 15);
-
- // create the LFO waveforms; AM in the low 8 bits, PM in the upper 8
- // waveforms are adjusted to match the pictures in the application manual
- for (int index = 0; index < LFO_WAVEFORM_LENGTH; index++)
- {
- // waveform 0 is a sawtooth
- u8 am = index ^ 0xff;
- s8 pm = s8(index);
- m_lfo_waveform[0][index] = am | (pm << 8);
-
- // waveform 1 is a square wave
- am = BIT(index, 7) ? 0 : 0xff;
- pm = s8(am ^ 0x80);
- m_lfo_waveform[1][index] = am | (pm << 8);
-
- // waveform 2 is a triangle wave
- am = BIT(index, 7) ? (index << 1) : ((index ^ 0xff) << 1);
- pm = s8(BIT(index, 6) ? am : ~am);
- m_lfo_waveform[2][index] = am | (pm << 8);
-
- // waveform 3 is noise; it is filled in dynamically
- }
-}
-
-
-//-------------------------------------------------
-// save - register for save states
-//-------------------------------------------------
-
-void ymopm_registers::save(device_t &device)
-{
- device.save_item(YMFM_NAME(m_lfo_counter));
- device.save_item(YMFM_NAME(m_lfo_am));
- device.save_item(YMFM_NAME(m_noise_lfsr));
- device.save_item(YMFM_NAME(m_noise_counter));
- device.save_item(YMFM_NAME(m_noise_state));
- device.save_item(YMFM_NAME(m_noise_lfo));
- device.save_item(YMFM_NAME(m_regdata));
-}
-
-
-//-------------------------------------------------
-// reset - reset to initial state
-//-------------------------------------------------
-
-void ymopm_registers::reset()
-{
- std::fill_n(&m_regdata[0], REGISTERS, 0);
-
- // enable output on both channels by default
- m_regdata[0x20] = m_regdata[0x21] = m_regdata[0x22] = m_regdata[0x23] = 0xc0;
- m_regdata[0x24] = m_regdata[0x25] = m_regdata[0x26] = m_regdata[0x27] = 0xc0;
-}
-
-
-//-------------------------------------------------
-// operator_map - return an array of operator
-// indices for each channel; for OPM this is fixed
-//-------------------------------------------------
-
-void ymopm_registers::operator_map(operator_mapping &dest) const
-{
- // Note that the channel index order is 0,2,1,3, so we bitswap the index.
- //
- // This is because the order in the map is:
- // carrier 1, carrier 2, modulator 1, modulator 2
- //
- // But when wiring up the connections, the more natural order is:
- // carrier 1, modulator 1, carrier 2, modulator 2
- static const operator_mapping s_fixed_map =
- { {
- operator_list( 0, 16, 8, 24 ), // Channel 0 operators
- operator_list( 1, 17, 9, 25 ), // Channel 1 operators
- operator_list( 2, 18, 10, 26 ), // Channel 2 operators
- operator_list( 3, 19, 11, 27 ), // Channel 3 operators
- operator_list( 4, 20, 12, 28 ), // Channel 4 operators
- operator_list( 5, 21, 13, 29 ), // Channel 5 operators
- operator_list( 6, 22, 14, 30 ), // Channel 6 operators
- operator_list( 7, 23, 15, 31 ), // Channel 7 operators
- } };
- dest = s_fixed_map;
-}
-
-
-//-------------------------------------------------
-// write - handle writes to the register array
-//-------------------------------------------------
-
-bool ymopm_registers::write(u16 index, u8 data, u32 &channel, u32 &opmask)
-{
- assert(index < REGISTERS);
-
- // LFO AM/PM depth are written to the same register (0x19);
- // redirect the PM depth to an unused neighbor (0x1a)
- if (index == 0x19)
- m_regdata[index + BIT(data, 7)] = data;
- else if (index != 0x1a)
- m_regdata[index] = data;
-
- // handle writes to the key on index
- if (index == 0x08)
- {
- channel = BIT(data, 0, 3);
- opmask = BIT(data, 3, 4);
- return true;
- }
- return false;
-}
-
-
-//-------------------------------------------------
-// clock_noise_and_lfo - clock the noise and LFO,
-// handling clock division, depth, and waveform
-// computations
-//-------------------------------------------------
-
-s32 ymopm_registers::clock_noise_and_lfo()
-{
- // base noise frequency is measured at 2x 1/2 FM frequency; this
- // means each tick counts as two steps against the noise counter
- u32 freq = noise_frequency();
- for (int rep = 0; rep < 2; rep++)
- {
- // evidence seems to suggest the LFSR is clocked continually and just
- // sampled at the noise frequency for output purposes; note that the
- // low 8 bits are the most recent 8 bits of history while bits 8-24
- // contain the 17 bit LFSR state
- m_noise_lfsr <<= 1;
- m_noise_lfsr |= BIT(m_noise_lfsr, 17) ^ BIT(m_noise_lfsr, 14) ^ 1;
-
- // compare against the frequency and latch when we exceed it
- if (m_noise_counter++ >= freq)
- {
- m_noise_counter = 0;
- m_noise_state = BIT(m_noise_lfsr, 17);
- }
- }
-
- // treat the rate as a 4.4 floating-point step value with implied
- // leading 1; this matches exactly the frequencies in the application
- // manual, though it might not be implemented exactly this way on chip
- u32 rate = lfo_rate();
- m_lfo_counter += (0x10 | BIT(rate, 0, 4)) << BIT(rate, 4, 4);
- u32 lfo = BIT(m_lfo_counter, 22, 8);
-
- // fill in the noise entry 1 ahead of our current position; this
- // ensures the current value remains stable for a full LFO clock
- // and effectively latches the running value when the LFO advances
- u32 lfo_noise = BIT(m_noise_lfsr, 17, 8);
- m_lfo_waveform[3][(lfo + 1) & 0xff] = lfo_noise | (lfo_noise << 8);
-
- // fetch the AM/PM values based on the waveform; AM is unsigned and
- // encoded in the low 8 bits, while PM signed and encoded in the upper
- // 8 bits
- s32 ampm = m_lfo_waveform[lfo_waveform()][lfo];
-
- // apply depth to the AM value and store for later
- m_lfo_am = ((ampm & 0xff) * lfo_am_depth()) >> 7;
-
- // apply depth to the PM value and return it
- return ((ampm >> 8) * s32(lfo_pm_depth())) >> 7;
-}
-
-
-//-------------------------------------------------
-// lfo_am_offset - return the AM offset from LFO
-// for the given channel
-//-------------------------------------------------
-
-u32 ymopm_registers::lfo_am_offset(u32 choffs) const
-{
- // OPM maps AM quite differently from OPN
-
- // shift value for AM sensitivity is [*, 0, 1, 2],
- // mapping to values of [0, 23.9, 47.8, and 95.6dB]
- u32 am_sensitivity = ch_lfo_am_sens(choffs);
- if (am_sensitivity == 0)
- return 0;
-
- // QUESTION: see OPN note below for the dB range mapping; it applies
- // here as well
-
- // raw LFO AM value on OPM is 0-FF, which is already a factor of 2
- // larger than the OPN below, putting our staring point at 2x theirs;
- // this works out since our minimum is 2x their maximum
- return m_lfo_am << (am_sensitivity - 1);
-}
-
-
-//-------------------------------------------------
-// cache_operator_data - fill the operator cache
-// with prefetched data
-//-------------------------------------------------
-
-void ymopm_registers::cache_operator_data(u32 choffs, u32 opoffs, ymfm_opdata_cache &cache)
-{
- // set up the easy stuff
- cache.waveform = &m_waveform[0][0];
-
- // get frequency from the channel
- u32 block_freq = cache.block_freq = ch_block_freq(choffs);
-
- // compute the keycode: block_freq is:
- //
- // BBBCCCCFFFFFF
- // ^^^^^
- //
- // the 5-bit keycode is just the top 5 bits (block + top 2 bits
- // of the key code)
- u32 keycode = BIT(block_freq, 8, 5);
-
- // detune adjustment
- cache.detune = detune_adjustment(op_detune(opoffs), keycode);
-
- // multiple value, as an x.1 value (0 means 0.5)
- cache.multiple = op_multiple(opoffs) * 2;
- if (cache.multiple == 0)
- cache.multiple = 1;
-
- // phase step, or PHASE_STEP_DYNAMIC if PM is active; this depends on
- // block_freq, detune, and multiple, so compute it after we've done those
- if (lfo_pm_depth() == 0 || ch_lfo_pm_sens(choffs) == 0)
- cache.phase_step = compute_phase_step(choffs, opoffs, cache, 0);
- else
- cache.phase_step = ymfm_opdata_cache::PHASE_STEP_DYNAMIC;
-
- // total level, scaled by 8
- cache.total_level = op_total_level(opoffs) << 3;
-
- // 4-bit sustain level, but 15 means 31 so effectively 5 bits
- cache.eg_sustain = op_sustain_level(opoffs);
- cache.eg_sustain |= (cache.eg_sustain + 1) & 0x10;
- cache.eg_sustain <<= 5;
-
- // determine KSR adjustment for enevlope rates
- u32 ksrval = keycode >> (op_ksr(opoffs) ^ 3);
- cache.eg_rate[YMFM_ENV_ATTACK] = effective_rate(op_attack_rate(opoffs) * 2, ksrval);
- cache.eg_rate[YMFM_ENV_DECAY] = effective_rate(op_decay_rate(opoffs) * 2, ksrval);
- cache.eg_rate[YMFM_ENV_SUSTAIN] = effective_rate(op_sustain_rate(opoffs) * 2, ksrval);
- cache.eg_rate[YMFM_ENV_RELEASE] = effective_rate(op_release_rate(opoffs) * 4 + 2, ksrval);
- cache.eg_rate[YMFM_ENV_DEPRESS] = 0x3f;
-}
-
-
-//-------------------------------------------------
-// compute_phase_step - compute the phase step
-//-------------------------------------------------
-
-u32 ymopm_registers::compute_phase_step(u32 choffs, u32 opoffs, ymfm_opdata_cache const &cache, s32 lfo_raw_pm)
-{
- // OPM logic is rather unique here, due to extra detune
- // and the use of key codes (not to be confused with keycode)
-
- // start with coarse detune delta; table uses cents value from
- // manual, converted into 1/64ths
- static const s16 s_detune2_delta[4] = { 0, (600*64+50)/100, (781*64+50)/100, (950*64+50)/100 };
- s32 delta = s_detune2_delta[op_detune2(opoffs)];
-
- // add in the PM delta
- u32 pm_sensitivity = ch_lfo_pm_sens(choffs);
- if (pm_sensitivity != 0)
- {
- // raw PM value is -127..128 which is +/- 200 cents
- // manual gives these magnitudes in cents:
- // 0, +/-5, +/-10, +/-20, +/-50, +/-100, +/-400, +/-700
- // this roughly corresponds to shifting the 200-cent value:
- // 0 >> 5, >> 4, >> 3, >> 2, >> 1, << 1, << 2
- if (pm_sensitivity < 6)
- delta += lfo_raw_pm >> (6 - pm_sensitivity);
- else
- delta += lfo_raw_pm << (pm_sensitivity - 5);
- }
-
- // apply delta and convert to a frequency number
- u32 phase_step = opm_key_code_to_phase_step(cache.block_freq, delta);
-
- // apply detune based on the keycode
- phase_step += cache.detune;
-
- // apply frequency multiplier (which is cached as an x.1 value)
- return (phase_step * cache.multiple) >> 1;
-}
-
-
-//-------------------------------------------------
-// log_keyon - log a key-on event
-//-------------------------------------------------
-
-void ymopm_registers::log_keyon(u32 choffs, u32 opoffs)
-{
- u32 chnum = choffs;
- u32 opnum = opoffs;
-
- LOG("%d.%02d freq=%04X dt2=%d dt=%d fb=%d alg=%X mul=%X tl=%02X ksr=%d adsr=%02X/%02X/%02X/%X sl=%X out=%c%c",
- chnum, opnum,
- ch_block_freq(choffs),
- op_detune2(opoffs),
- op_detune(opoffs),
- ch_feedback(choffs),
- ch_algorithm(choffs),
- op_multiple(opoffs),
- op_total_level(opoffs),
- op_ksr(opoffs),
- op_attack_rate(opoffs),
- op_decay_rate(opoffs),
- op_sustain_rate(opoffs),
- op_release_rate(opoffs),
- op_sustain_level(opoffs),
- ch_output_0(choffs) ? 'L' : '-',
- ch_output_1(choffs) ? 'R' : '-');
-
- bool am = (lfo_am_depth() != 0 && ch_lfo_am_sens(choffs) != 0 && op_lfo_am_enable(opoffs) != 0);
- if (am)
- LOG(" am=%d/%02X", ch_lfo_am_sens(choffs), lfo_am_depth());
- bool pm = (lfo_pm_depth() != 0 && ch_lfo_pm_sens(choffs) != 0);
- if (pm)
- LOG(" pm=%d/%02X", ch_lfo_pm_sens(choffs), lfo_pm_depth());
- if (am || pm)
- LOG(" lfo=%02X/%c", lfo_rate(), "WQTN"[lfo_waveform()]);
- if (noise_enable() && opoffs == 31)
- LOG(" noise=1");
-}
-
-
-//*********************************************************
-// OPN/OPNA SPECIFICS
-//*********************************************************
-
-//-------------------------------------------------
-// ymopn_registers_base - constructor
-//-------------------------------------------------
-
-template<bool IsOpnA>
-ymopn_registers_base<IsOpnA>::ymopn_registers_base() :
- m_lfo_counter(0),
- m_lfo_am(0)
-{
- // create the waveforms
- for (int index = 0; index < WAVEFORM_LENGTH; index++)
- m_waveform[0][index] = abs_sin_attenuation(index) | (BIT(index, 9) << 15);
-}
-
-
-//-------------------------------------------------
-// save - register for save states
-//-------------------------------------------------
-
-template<bool IsOpnA>
-void ymopn_registers_base<IsOpnA>::save(device_t &device)
-{
- if (IsOpnA)
- {
- device.save_item(YMFM_NAME(m_lfo_counter));
- device.save_item(YMFM_NAME(m_lfo_am));
- }
- device.save_item(YMFM_NAME(m_regdata));
-}
-
-
-//-------------------------------------------------
-// reset - reset to initial state
-//-------------------------------------------------
-
-template<bool IsOpnA>
-void ymopn_registers_base<IsOpnA>::reset()
-{
- std::fill_n(&m_regdata[0], REGISTERS, 0);
- if (IsOpnA)
- {
- // enable output on both channels by default
- m_regdata[0xb4] = m_regdata[0xb5] = m_regdata[0xb6] = 0xc0;
- m_regdata[0x1b4] = m_regdata[0x1b5] = m_regdata[0x1b6] = 0xc0;
- }
-}
-
-
-//-------------------------------------------------
-// operator_map - return an array of operator
-// indices for each channel; for OPN this is fixed
-//-------------------------------------------------
-
-template<>
-void ymopn_registers_base<false>::operator_map(operator_mapping &dest) const
-{
- // Note that the channel index order is 0,2,1,3, so we bitswap the index.
- //
- // This is because the order in the map is:
- // carrier 1, carrier 2, modulator 1, modulator 2
- //
- // But when wiring up the connections, the more natural order is:
- // carrier 1, modulator 1, carrier 2, modulator 2
- static const operator_mapping s_fixed_map =
- { {
- operator_list( 0, 6, 3, 9 ), // Channel 0 operators
- operator_list( 1, 7, 4, 10 ), // Channel 1 operators
- operator_list( 2, 8, 5, 11 ), // Channel 2 operators
- } };
- dest = s_fixed_map;
-}
-
-template<>
-void ymopn_registers_base<true>::operator_map(operator_mapping &dest) const
-{
- // Note that the channel index order is 0,2,1,3, so we bitswap the index.
- //
- // This is because the order in the map is:
- // carrier 1, carrier 2, modulator 1, modulator 2
- //
- // But when wiring up the connections, the more natural order is:
- // carrier 1, modulator 1, carrier 2, modulator 2
- static const operator_mapping s_fixed_map =
- { {
- operator_list( 0, 6, 3, 9 ), // Channel 0 operators
- operator_list( 1, 7, 4, 10 ), // Channel 1 operators
- operator_list( 2, 8, 5, 11 ), // Channel 2 operators
- operator_list( 12, 18, 15, 21 ), // Channel 3 operators
- operator_list( 13, 19, 16, 22 ), // Channel 4 operators
- operator_list( 14, 20, 17, 23 ), // Channel 5 operators
- } };
- dest = s_fixed_map;
-}
-
-
-//-------------------------------------------------
-// write - handle writes to the register array
-//-------------------------------------------------
-
-template<bool IsOpnA>
-bool ymopn_registers_base<IsOpnA>::write(u16 index, u8 data, u32 &channel, u32 &opmask)
-{
- assert(index < REGISTERS);
-
- // writes in the 0xa0-af/0x1a0-af region are handled as latched pairs
- // borrow unused registers 0xb8-bf/0x1b8-bf as temporary holding locations
- if ((index & 0xf0) == 0xa0)
- {
- u32 latchindex = 0xb8 | (BIT(index, 3) << 2) | BIT(index, 0, 2);
- if (IsOpnA)
- latchindex |= index & 0x100;
-
- // writes to the upper half just latch (only low 6 bits matter)
- if (BIT(index, 2))
- m_regdata[latchindex] = data | 0x80;
-
- // writes to the lower half only commit if the latch is there
- else if (BIT(m_regdata[latchindex], 7))
- {
- m_regdata[index | 4] = m_regdata[latchindex] & 0x3f;
- m_regdata[latchindex] = 0;
- }
- }
-
- // everything else is normal
- m_regdata[index] = data;
-
- // handle writes to the key on index
- if (index == 0x28)
- {
- channel = BIT(data, 0, 2);
- if (channel == 3)
- return false;
- if (IsOpnA)
- channel += BIT(data, 2, 1) * 3;
- opmask = BIT(data, 4, 4);
- return true;
- }
- return false;
-}
-
-
-//-------------------------------------------------
-// clock_noise_and_lfo - clock the noise and LFO,
-// handling clock division, depth, and waveform
-// computations
-//-------------------------------------------------
-
-template<bool IsOpnA>
-s32 ymopn_registers_base<IsOpnA>::clock_noise_and_lfo()
-{
- // OPN has no noise generation
-
- // if LFO not enabled (not present on OPN), quick exit with 0s
- if (!IsOpnA || !lfo_enable())
- {
- m_lfo_counter = 0;
- m_lfo_am = 0;
- return 0;
- }
-
- // this table is based on converting the frequencies in the applications
- // manual to clock dividers, based on the assumption of a 7-bit LFO value
- static u8 const lfo_max_count[8] = { 109, 78, 72, 68, 63, 45, 9, 6 };
- u32 subcount = u8(m_lfo_counter++);
-
- // when we cross the divider count, add enough to zero it and cause an
- // increment at bit 8; the 7-bit value lives from bits 8-14
- if (subcount >= lfo_max_count[lfo_rate()])
- m_lfo_counter += subcount ^ 0xff;
-
- // AM value is 7 bits, staring at bit 8; grab the low 6 directly
- m_lfo_am = BIT(m_lfo_counter, 8, 6);
-
- // first half of the AM period (bit 6 == 0) is inverted
- if (BIT(m_lfo_counter, 8+6) == 0)
- m_lfo_am ^= 0x3f;
-
- // PM value is 5 bits, starting at bit 10; grab the low 3 directly
- s32 pm = BIT(m_lfo_counter, 10, 3);
-
- // PM is reflected based on bit 3
- if (BIT(m_lfo_counter, 10+3))
- pm ^= 7;
-
- // PM is negated based on bit 4
- return BIT(m_lfo_counter, 10+4) ? -pm : pm;
-}
-
-
-//-------------------------------------------------
-// lfo_am_offset - return the AM offset from LFO
-// for the given channel
-//-------------------------------------------------
-
-template<bool IsOpnA>
-u32 ymopn_registers_base<IsOpnA>::lfo_am_offset(u32 choffs) const
-{
- // shift value for AM sensitivity is [7, 3, 1, 0],
- // mapping to values of [0, 1.4, 5.9, and 11.8dB]
- u32 am_shift = (1 << (ch_lfo_am_sens(choffs) ^ 3)) - 1;
-
- // QUESTION: max sensitivity should give 11.8dB range, but this value
- // is directly added to an x.8 attenuation value, which will only give
- // 126/256 or ~4.9dB range -- what am I missing? The calculation below
- // matches several other emulators, including the Nuked implemenation.
-
- // raw LFO AM value on OPN is 0-3F, scale that up by a factor of 2
- // (giving 7 bits) before applying the final shift
- return (m_lfo_am << 1) >> am_shift;
-}
-
-
-//-------------------------------------------------
-// cache_operator_data - fill the operator cache
-// with prefetched data
-//-------------------------------------------------
-
-template<bool IsOpnA>
-void ymopn_registers_base<IsOpnA>::cache_operator_data(u32 choffs, u32 opoffs, ymfm_opdata_cache &cache)
-{
- // set up the easy stuff
- cache.waveform = &m_waveform[0][0];
-
- // get frequency from the channel
- u32 block_freq = cache.block_freq = ch_block_freq(choffs);
-
- // if multi-frequency mode is enabled and this is channel 2,
- // fetch one of the special frequencies
- if (multi_freq() && choffs == 2)
- {
- if (opoffs == 2)
- block_freq = cache.block_freq = multi_block_freq(1);
- else if (opoffs == 10)
- block_freq = cache.block_freq = multi_block_freq(2);
- else if (opoffs == 6)
- block_freq = cache.block_freq = multi_block_freq(0);
- }
-
- // compute the keycode: block_freq is:
- //
- // BBBFFFFFFFFFFF
- // ^^^^???
- //
- // the 5-bit keycode uses the top 4 bits plus a magic formula
- // for the final bit
- u32 keycode = BIT(block_freq, 10, 4) << 1;
-
- // lowest bit is determined by a mix of next lower FNUM bits
- // according to this equation from the YM2608 manual:
- //
- // (F11 & (F10 | F9 | F8)) | (!F11 & F10 & F9 & F8)
- //
- // for speed, we just look it up in a 16-bit constant
- keycode |= BIT(0xfe80, BIT(block_freq, 7, 4));
-
- // detune adjustment
- cache.detune = detune_adjustment(op_detune(opoffs), keycode);
-
- // multiple value, as an x.1 value (0 means 0.5)
- cache.multiple = op_multiple(opoffs) * 2;
- if (cache.multiple == 0)
- cache.multiple = 1;
-
- // phase step, or PHASE_STEP_DYNAMIC if PM is active; this depends on
- // block_freq, detune, and multiple, so compute it after we've done those
- if (!IsOpnA || lfo_enable() == 0 || ch_lfo_pm_sens(choffs) == 0)
- cache.phase_step = compute_phase_step(choffs, opoffs, cache, 0);
- else
- cache.phase_step = ymfm_opdata_cache::PHASE_STEP_DYNAMIC;
-
- // total level, scaled by 8
- cache.total_level = op_total_level(opoffs) << 3;
-
- // 4-bit sustain level, but 15 means 31 so effectively 5 bits
- cache.eg_sustain = op_sustain_level(opoffs);
- cache.eg_sustain |= (cache.eg_sustain + 1) & 0x10;
- cache.eg_sustain <<= 5;
-
- // determine KSR adjustment for enevlope rates
- u32 ksrval = keycode >> (op_ksr(opoffs) ^ 3);
- cache.eg_rate[YMFM_ENV_ATTACK] = effective_rate(op_attack_rate(opoffs) * 2, ksrval);
- cache.eg_rate[YMFM_ENV_DECAY] = effective_rate(op_decay_rate(opoffs) * 2, ksrval);
- cache.eg_rate[YMFM_ENV_SUSTAIN] = effective_rate(op_sustain_rate(opoffs) * 2, ksrval);
- cache.eg_rate[YMFM_ENV_RELEASE] = effective_rate(op_release_rate(opoffs) * 4 + 2, ksrval);
- cache.eg_rate[YMFM_ENV_DEPRESS] = 0x3f;
-}
-
-
-//-------------------------------------------------
-// compute_phase_step - compute the phase step
-//-------------------------------------------------
-
-template<bool IsOpnA>
-u32 ymopn_registers_base<IsOpnA>::compute_phase_step(u32 choffs, u32 opoffs, ymfm_opdata_cache const &cache, s32 lfo_raw_pm)
-{
- // OPN phase calculation has only a single detune parameter
- // and uses FNUMs instead of keycodes
-
- // extract frequency number (low 11 bits of block_freq)
- u32 fnum = BIT(cache.block_freq, 0, 11) << 1;
-
- // if there's a non-zero PM sensitivity, compute the adjustment
- u32 pm_sensitivity = ch_lfo_pm_sens(choffs);
- if (pm_sensitivity != 0)
- {
- // apply the phase adjustment based on the upper 7 bits
- // of FNUM and the PM depth parameters
- fnum += opn_lfo_pm_phase_adjustment(BIT(cache.block_freq, 4, 7), pm_sensitivity, lfo_raw_pm);
-
- // keep fnum to 12 bits
- fnum &= 0xfff;
- }
-
- // apply block shift to compute phase step
- u32 block = BIT(cache.block_freq, 11, 3);
- u32 phase_step = (fnum << block) >> 2;
-
- // apply detune based on the keycode
- phase_step += cache.detune;
-
- // clamp to 17 bits in case detune overflows
- // QUESTION: is this specific to the YM2612/3438?
- phase_step &= 0x1ffff;
-
- // apply frequency multiplier (which is cached as an x.1 value)
- return (phase_step * cache.multiple) >> 1;
-}
-
-
-//-------------------------------------------------
-// log_keyon - log a key-on event
-//-------------------------------------------------
-
-template<bool IsOpnA>
-void ymopn_registers_base<IsOpnA>::log_keyon(u32 choffs, u32 opoffs)
-{
- u32 chnum = (choffs & 3) + 3 * BIT(choffs, 8);
- u32 opnum = (opoffs & 15) - ((opoffs & 15) / 4) + 12 * BIT(opoffs, 8);
-
- u32 block_freq = ch_block_freq(choffs);
- if (multi_freq() && choffs == 2)
- {
- if (opoffs == 2)
- block_freq = multi_block_freq(1);
- else if (opoffs == 10)
- block_freq = multi_block_freq(2);
- else if (opoffs == 6)
- block_freq = multi_block_freq(0);
- }
-
- LOG("%d.%02d freq=%04X dt=%d fb=%d alg=%X mul=%X tl=%02X ksr=%d adsr=%02X/%02X/%02X/%X sl=%X",
- chnum, opnum,
- block_freq,
- op_detune(opoffs),
- ch_feedback(choffs),
- ch_algorithm(choffs),
- op_multiple(opoffs),
- op_total_level(opoffs),
- op_ksr(opoffs),
- op_attack_rate(opoffs),
- op_decay_rate(opoffs),
- op_sustain_rate(opoffs),
- op_release_rate(opoffs),
- op_sustain_level(opoffs));
-
- if (OUTPUTS > 1)
- LOG(" out=%c%c",
- ch_output_0(choffs) ? 'L' : '-',
- ch_output_1(choffs) ? 'R' : '-');
- if (op_ssg_eg_enable(opoffs))
- LOG(" ssg=%X", op_ssg_eg_mode(opoffs));
- bool am = (lfo_enable() && op_lfo_am_enable(opoffs) && ch_lfo_am_sens(choffs) != 0);
- if (am)
- LOG(" am=%d", ch_lfo_am_sens(choffs));
- bool pm = (lfo_enable() && ch_lfo_pm_sens(choffs) != 0);
- if (pm)
- LOG(" pm=%d", ch_lfo_pm_sens(choffs));
- if (am || pm)
- LOG(" lfo=%02X", lfo_rate());
- if (multi_freq() && choffs == 2)
- LOG(" multi=1");
-}
-
-
-//*********************************************************
-// OPL SPECIFICS
-//*********************************************************
-
-//-------------------------------------------------
-// ymopl_registers_base - constructor
-//-------------------------------------------------
-
-template<int Revision>
-ymopl_registers_base<Revision>::ymopl_registers_base() :
- m_lfo_am_counter(0),
- m_lfo_pm_counter(0),
- m_noise_lfsr(1),
- m_lfo_am(0)
-{
- // create the waveforms
- for (int index = 0; index < WAVEFORM_LENGTH; index++)
- m_waveform[0][index] = abs_sin_attenuation(index) | (BIT(index, 9) << 15);
-
- if (WAVEFORMS >= 4)
- {
- u16 zeroval = m_waveform[0][0];
- for (int index = 0; index < WAVEFORM_LENGTH; index++)
- {
- m_waveform[1][index] = BIT(index, 9) ? zeroval : m_waveform[0][index];
- m_waveform[2][index] = m_waveform[0][index] & 0x7fff;
- m_waveform[3][index] = BIT(index, 8) ? zeroval : (m_waveform[0][index] & 0x7fff);
- if (WAVEFORMS >= 8)
- {
- m_waveform[4][index] = BIT(index, 9) ? zeroval : m_waveform[0][index * 2];
- m_waveform[5][index] = BIT(index, 9) ? zeroval : m_waveform[0][(index * 2) & 0x1ff];
- m_waveform[6][index] = BIT(index, 9) << 15;
- m_waveform[7][index] = (zeroval - m_waveform[0][(index / 2)]) | (BIT(index, 9) << 15);
- }
- }
- }
-}
-
-
-//-------------------------------------------------
-// save - register for save states
-//-------------------------------------------------
-
-template<int Revision>
-void ymopl_registers_base<Revision>::save(device_t &device)
-{
- device.save_item(YMFM_NAME(m_lfo_am_counter));
- device.save_item(YMFM_NAME(m_lfo_pm_counter));
- device.save_item(YMFM_NAME(m_lfo_am));
- device.save_item(YMFM_NAME(m_noise_lfsr));
- device.save_item(YMFM_NAME(m_regdata));
-}
-
-
-//-------------------------------------------------
-// reset - reset to initial state
-//-------------------------------------------------
-
-template<int Revision>
-void ymopl_registers_base<Revision>::reset()
-{
- std::fill_n(&m_regdata[0], REGISTERS, 0);
-}
-
-
-//-------------------------------------------------
-// operator_map - return an array of operator
-// indices for each channel; for OPL this is fixed
-//-------------------------------------------------
-
-template<int Revision>
-void ymopl_registers_base<Revision>::operator_map(operator_mapping &dest) const
-{
- if (Revision <= 2)
- {
- // OPL/OPL2 has a fixed map, all 2 operators
- static const operator_mapping s_fixed_map =
- { {
- operator_list( 0, 3 ), // Channel 0 operators
- operator_list( 1, 4 ), // Channel 1 operators
- operator_list( 2, 5 ), // Channel 2 operators
- operator_list( 6, 9 ), // Channel 3 operators
- operator_list( 7, 10 ), // Channel 4 operators
- operator_list( 8, 11 ), // Channel 5 operators
- operator_list( 12, 15 ), // Channel 6 operators
- operator_list( 13, 16 ), // Channel 7 operators
- operator_list( 14, 17 ), // Channel 8 operators
- } };
- dest = s_fixed_map;
- }
- else
- {
- // OPL3/OPL4 can be configured for 2 or 4 operators
- u32 fourop = fourop_enable();
-
- dest.chan[ 0] = BIT(fourop, 0) ? operator_list( 0, 3, 6, 9 ) : operator_list( 0, 3 );
- dest.chan[ 1] = BIT(fourop, 1) ? operator_list( 1, 4, 7, 10 ) : operator_list( 1, 4 );
- dest.chan[ 2] = BIT(fourop, 2) ? operator_list( 2, 5, 8, 11 ) : operator_list( 2, 5 );
- dest.chan[ 3] = BIT(fourop, 0) ? operator_list() : operator_list( 6, 9 );
- dest.chan[ 4] = BIT(fourop, 1) ? operator_list() : operator_list( 7, 10 );
- dest.chan[ 5] = BIT(fourop, 2) ? operator_list() : operator_list( 8, 11 );
- dest.chan[ 6] = operator_list( 12, 15 );
- dest.chan[ 7] = operator_list( 13, 16 );
- dest.chan[ 8] = operator_list( 14, 17 );
-
- dest.chan[ 9] = BIT(fourop, 3) ? operator_list( 18, 21, 24, 27 ) : operator_list( 18, 21 );
- dest.chan[10] = BIT(fourop, 4) ? operator_list( 19, 22, 25, 28 ) : operator_list( 19, 22 );
- dest.chan[11] = BIT(fourop, 5) ? operator_list( 20, 23, 26, 29 ) : operator_list( 20, 23 );
- dest.chan[12] = BIT(fourop, 3) ? operator_list() : operator_list( 24, 27 );
- dest.chan[13] = BIT(fourop, 4) ? operator_list() : operator_list( 25, 28 );
- dest.chan[14] = BIT(fourop, 5) ? operator_list() : operator_list( 26, 29 );
- dest.chan[15] = operator_list( 30, 33 );
- dest.chan[16] = operator_list( 31, 34 );
- dest.chan[17] = operator_list( 32, 35 );
- }
-}
-
-
-//-------------------------------------------------
-// write - handle writes to the register array
-//-------------------------------------------------
-
-template<int Revision>
-bool ymopl_registers_base<Revision>::write(u16 index, u8 data, u32 &channel, u32 &opmask)
-{
- assert(index < REGISTERS);
-
- // writes to the mode register with high bit set ignore the low bits
- if (index == REG_MODE && BIT(data, 7) != 0)
- m_regdata[index] |= 0x80;
- else
- m_regdata[index] = data;
-
- // handle writes to the rhythm keyons
- if (index == 0xbd)
- {
- channel = YMFM_RHYTHM_CHANNEL;
- opmask = BIT(data, 5) ? BIT(data, 0, 5) : 0;
- return true;
- }
-
- // handle writes to the channel keyons
- if ((index & 0xf0) == 0xb0)
- {
- channel = index & 0x0f;
- if (channel < 9)
- {
- if (IsOpl3Plus)
- channel += 9 * BIT(index, 8);
- opmask = BIT(data, 5) ? 15 : 0;
- return true;
- }
- }
- return false;
-}
-
-
-//-------------------------------------------------
-// clock_noise_and_lfo - clock the noise and LFO,
-// handling clock division, depth, and waveform
-// computations
-//-------------------------------------------------
-
-static s32 opl_clock_noise_and_lfo(u32 &noise_lfsr, u16 &lfo_am_counter, u16 &lfo_pm_counter, u8 &lfo_am, u32 am_depth, u32 pm_depth)
-{
- // OPL has a 23-bit noise generator for the rhythm section, running at
- // a constant rate, used only for percussion input
- noise_lfsr <<= 1;
- noise_lfsr |= BIT(noise_lfsr, 23) ^ BIT(noise_lfsr, 9) ^ BIT(noise_lfsr, 8) ^ BIT(noise_lfsr, 1);
-
- // OPL has two fixed-frequency LFOs, one for AM, one for PM
-
- // the AM LFO has 210*64 steps; at a nominal 50kHz output,
- // this equates to a period of 50000/(210*64) = 3.72Hz
- u32 am_counter = lfo_am_counter++;
- if (am_counter >= 210*64 - 1)
- lfo_am_counter = 0;
-
- // low 8 bits are fractional; depth 0 is divided by 2, while depth 1 is times 2
- int shift = 9 - 2 * am_depth;
-
- // AM value is the upper bits of the value, inverted across the midpoint
- // to produce a triangle
- lfo_am = ((am_counter < 105*64) ? am_counter : (210*64+63 - am_counter)) >> shift;
-
- // the PM LFO has 8192 steps, or a nominal period of 6.1Hz
- u32 pm_counter = lfo_pm_counter++;
-
- // PM LFO is broken into 8 chunks, each lasting 1024 steps; the PM value
- // depends on the upper bits of FNUM, so this value is a fraction and
- // sign to apply to that value, as a 1.3 value
- static s8 const pm_scale[8] = { 8, 4, 0, -4, -8, -4, 0, 4 };
- return pm_scale[BIT(pm_counter, 10, 3)] >> (pm_depth ^ 1);
-}
-
-template<int Revision>
-s32 ymopl_registers_base<Revision>::clock_noise_and_lfo()
-{
- return opl_clock_noise_and_lfo(m_noise_lfsr, m_lfo_am_counter, m_lfo_pm_counter, m_lfo_am, lfo_am_depth(), lfo_pm_depth());
-}
-
-
-//-------------------------------------------------
-// cache_operator_data - fill the operator cache
-// with prefetched data; note that this code is
-// also used by ymopna_registers, so it must
-// handle upper channels cleanly
-//-------------------------------------------------
-
-template<int Revision>
-void ymopl_registers_base<Revision>::cache_operator_data(u32 choffs, u32 opoffs, ymfm_opdata_cache &cache)
-{
- // set up the easy stuff
- cache.waveform = &m_waveform[op_waveform(opoffs) % WAVEFORMS][0];
-
- // get frequency from the channel
- u32 block_freq = cache.block_freq = ch_block_freq(choffs);
-
- // compute the keycode: block_freq is:
- //
- // 111 |
- // 21098|76543210
- // BBBFF|FFFFFFFF
- // ^^^??
- //
- // the 4-bit keycode uses the top 3 bits plus one of the next two bits
- u32 keycode = BIT(block_freq, 10, 3) << 1;
-
- // lowest bit is determined by note_select(); note that it is
- // actually reversed from what the manual says, however
- keycode |= BIT(block_freq, 9 - note_select(), 1);
-
- // no detune adjustment on OPL
- cache.detune = 0;
-
- // multiple value, as an x.1 value (0 means 0.5)
- // replace the low bit with a table lookup to give 0,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15
- u32 multiple = op_multiple(opoffs);
- cache.multiple = ((multiple & 0xe) | BIT(0xc2aa, multiple)) * 2;
- if (cache.multiple == 0)
- cache.multiple = 1;
-
- // phase step, or PHASE_STEP_DYNAMIC if PM is active; this depends on block_freq, detune,
- // and multiple, so compute it after we've done those
- if (op_lfo_pm_enable(opoffs) == 0)
- cache.phase_step = compute_phase_step(choffs, opoffs, cache, 0);
- else
- cache.phase_step = ymfm_opdata_cache::PHASE_STEP_DYNAMIC;
-
- // total level, scaled by 8
- cache.total_level = op_total_level(opoffs) << 3;
-
- // pre-add key scale level
- u32 ksl = op_ksl(opoffs);
- if (ksl != 0)
- cache.total_level += opl_key_scale_atten(BIT(block_freq, 10, 3), BIT(block_freq, 6, 4)) << ksl;
-
- // 4-bit sustain level, but 15 means 31 so effectively 5 bits
- cache.eg_sustain = op_sustain_level(opoffs);
- cache.eg_sustain |= (cache.eg_sustain + 1) & 0x10;
- cache.eg_sustain <<= 5;
-
- // determine KSR adjustment for enevlope rates
- u32 ksrval = keycode >> (2 * (op_ksr(opoffs) ^ 1));
- cache.eg_rate[YMFM_ENV_ATTACK] = effective_rate(op_attack_rate(opoffs) * 4, ksrval);
- cache.eg_rate[YMFM_ENV_DECAY] = effective_rate(op_decay_rate(opoffs) * 4, ksrval);
- cache.eg_rate[YMFM_ENV_SUSTAIN] = op_eg_sustain(opoffs) ? 0 : effective_rate(op_release_rate(opoffs) * 4, ksrval);
- cache.eg_rate[YMFM_ENV_RELEASE] = effective_rate(op_release_rate(opoffs) * 4, ksrval);
- cache.eg_rate[YMFM_ENV_DEPRESS] = 0x3f;
-}
-
-
-//-------------------------------------------------
-// compute_phase_step - compute the phase step
-//-------------------------------------------------
-
-static u32 opl_compute_phase_step(u32 block_freq, u32 multiple, s32 lfo_raw_pm)
-{
- // OPL phase calculation has no detuning, but uses FNUMs like
- // the OPN version, and computes PM a bit differently
-
- // extract frequency number as a 12-bit fraction
- u32 fnum = BIT(block_freq, 0, 10) << 2;
-
- // apply the phase adjustment based on the upper 3 bits
- // of FNUM and the PM depth parameters
- fnum += (lfo_raw_pm * BIT(block_freq, 7, 3)) >> 1;
-
- // keep fnum to 12 bits
- fnum &= 0xfff;
-
- // apply block shift to compute phase step
- u32 block = BIT(block_freq, 10, 3);
- u32 phase_step = (fnum << block) >> 2;
-
- // apply frequency multiplier (which is cached as an x.1 value)
- return (phase_step * multiple) >> 1;
-}
-
-template<int Revision>
-u32 ymopl_registers_base<Revision>::compute_phase_step(u32 choffs, u32 opoffs, ymfm_opdata_cache const &cache, s32 lfo_raw_pm)
-{
- return opl_compute_phase_step(cache.block_freq, cache.multiple, op_lfo_pm_enable(opoffs) ? lfo_raw_pm : 0);
-}
-
-
-//-------------------------------------------------
-// log_keyon - log a key-on event
-//-------------------------------------------------
-
-template<int Revision>
-void ymopl_registers_base<Revision>::log_keyon(u32 choffs, u32 opoffs)
-{
- u32 chnum = (choffs & 15) + 9 * BIT(choffs, 8);
- u32 opnum = (opoffs & 31) - 2 * ((opoffs & 31) / 8) + 18 * BIT(opoffs, 8);
-
- LOG("%2d.%02d freq=%04X fb=%d alg=%X mul=%X tl=%02X ksr=%d ns=%d ksl=%d adr=%X/%X/%X sl=%X sus=%d",
- chnum, opnum,
- ch_block_freq(choffs),
- ch_feedback(choffs),
- ch_algorithm(choffs),
- op_multiple(opoffs),
- op_total_level(opoffs),
- op_ksr(opoffs),
- note_select(),
- op_ksl(opoffs),
- op_attack_rate(opoffs),
- op_decay_rate(opoffs),
- op_release_rate(opoffs),
- op_sustain_level(opoffs),
- op_eg_sustain(opoffs));
-
- if (OUTPUTS > 1)
- LOG(" out=%c%c%c%c",
- ch_output_0(choffs) ? 'L' : '-',
- ch_output_1(choffs) ? 'R' : '-',
- ch_output_2(choffs) ? '0' : '-',
- ch_output_3(choffs) ? '1' : '-');
- if (op_lfo_am_enable(opoffs) != 0)
- LOG(" am=%d", lfo_am_depth());
- if (op_lfo_pm_enable(opoffs) != 0)
- LOG(" pm=%d", lfo_pm_depth());
- if (waveform_enable() && op_waveform(opoffs) != 0)
- LOG(" wf=%d", op_waveform(opoffs));
- if (is_rhythm(choffs))
- LOG(" rhy=1");
- if (DYNAMIC_OPS)
- {
- operator_mapping map;
- operator_map(map);
- if (BIT(map.chan[chnum], 16, 8) != 0xff)
- LOG(" 4op");
- }
-}
-
-
-//*********************************************************
-// OPLL SPECIFICS
-//*********************************************************
-
-//-------------------------------------------------
-// ymopll_registers - constructor
-//-------------------------------------------------
-
-ymopll_registers::ymopll_registers() :
- m_lfo_am_counter(0),
- m_lfo_pm_counter(0),
- m_noise_lfsr(1),
- m_lfo_am(0)
-{
- // create the waveforms
- for (int index = 0; index < WAVEFORM_LENGTH; index++)
- m_waveform[0][index] = abs_sin_attenuation(index) | (BIT(index, 9) << 15);
-
- u16 zeroval = m_waveform[0][0];
- for (int index = 0; index < WAVEFORM_LENGTH; index++)
- m_waveform[1][index] = BIT(index, 9) ? zeroval : m_waveform[0][index];
-
- // initialize the instruments to something sane
- for (int choffs = 0; choffs < CHANNELS; choffs++)
- m_chinst[choffs] = &m_regdata[0];
- for (int opoffs = 0; opoffs < OPERATORS; opoffs++)
- m_opinst[opoffs] = &m_regdata[BIT(opoffs, 0)];
-}
-
-
-//-------------------------------------------------
-// save - register for save states
-//-------------------------------------------------
-
-void ymopll_registers::save(device_t &device)
-{
- device.save_item(YMFM_NAME(m_lfo_am_counter));
- device.save_item(YMFM_NAME(m_lfo_pm_counter));
- device.save_item(YMFM_NAME(m_lfo_am));
- device.save_item(YMFM_NAME(m_noise_lfsr));
- device.save_item(YMFM_NAME(m_regdata));
-}
-
-
-//-------------------------------------------------
-// reset - reset to initial state
-//-------------------------------------------------
-
-void ymopll_registers::reset()
-{
- std::fill_n(&m_regdata[0], REGISTERS, 0);
-}
-
-
-//-------------------------------------------------
-// operator_map - return an array of operator
-// indices for each channel; for OPLL this is fixed
-//-------------------------------------------------
-
-void ymopll_registers::operator_map(operator_mapping &dest) const
-{
- static const operator_mapping s_fixed_map =
- { {
- operator_list( 0, 1 ), // Channel 0 operators
- operator_list( 2, 3 ), // Channel 1 operators
- operator_list( 4, 5 ), // Channel 2 operators
- operator_list( 6, 7 ), // Channel 3 operators
- operator_list( 8, 9 ), // Channel 4 operators
- operator_list( 10, 11 ), // Channel 5 operators
- operator_list( 12, 13 ), // Channel 6 operators
- operator_list( 14, 15 ), // Channel 7 operators
- operator_list( 16, 17 ), // Channel 8 operators
- } };
- dest = s_fixed_map;
-}
-
-
-//-------------------------------------------------
-// write - handle writes to the register array;
-// note that this code is also used by
-// ymopl3_registers, so it must handle upper
-// channels cleanly
-//-------------------------------------------------
-
-bool ymopll_registers::write(u16 index, u8 data, u32 &channel, u32 &opmask)
-{
- // unclear the address is masked down to 6 bits or if writes above
- // the register top are ignored; assuming the latter for now
- if (index >= REGISTERS)
- {
- LOG("ymopll write above register area; ignoring: %02X=%02X\n", index, data);
- return false;
- }
-
- // write the new data
- m_regdata[index] = data;
-
- // handle writes to the rhythm keyons
- if (index == 0x0e)
- {
- channel = YMFM_RHYTHM_CHANNEL;
- opmask = BIT(data, 5) ? BIT(data, 0, 5) : 0;
- return true;
- }
-
- // handle writes to the channel keyons
- if ((index & 0xf0) == 0x20)
- {
- channel = index & 0x0f;
- if (channel < CHANNELS)
- {
- opmask = BIT(data, 4) ? 3 : 0;
- return true;
- }
- }
- return false;
-}
-
-
-//-------------------------------------------------
-// clock_noise_and_lfo - clock the noise and LFO,
-// handling clock division, depth, and waveform
-// computations
-//-------------------------------------------------
-
-s32 ymopll_registers::clock_noise_and_lfo()
-{
- // implementation is the same as OPL with fixed depths
- return opl_clock_noise_and_lfo(m_noise_lfsr, m_lfo_am_counter, m_lfo_pm_counter, m_lfo_am, 1, 1);
-}
-
-
-//-------------------------------------------------
-// cache_operator_data - fill the operator cache
-// with prefetched data; note that this code is
-// also used by ymopna_registers, so it must
-// handle upper channels cleanly
-//-------------------------------------------------
-
-void ymopll_registers::cache_operator_data(u32 choffs, u32 opoffs, ymfm_opdata_cache &cache)
-{
- // first set up the instrument data
- u32 instrument = ch_instrument(choffs);
- if (rhythm_enable() && choffs >= 6)
- m_chinst[choffs] = &m_instdata[8 * (15 + (choffs - 6))];
- else
- m_chinst[choffs] = (instrument == 0) ? &m_regdata[0] : &m_instdata[8 * (instrument - 1)];
- m_opinst[opoffs] = m_chinst[choffs] + BIT(opoffs, 0);
-
- // set up the easy stuff
- cache.waveform = &m_waveform[op_waveform(opoffs) % WAVEFORMS][0];
-
- // get frequency from the channel
- u32 block_freq = cache.block_freq = ch_block_freq(choffs);
-
- // compute the keycode: block_freq is:
- //
- // 11 |
- // 1098|76543210
- // BBBF|FFFFFFFF
- // ^^^^
- //
- // the 4-bit keycode uses the top 4 bits
- u32 keycode = BIT(block_freq, 8, 4);
-
- // no detune adjustment on OPLL
- cache.detune = 0;
-
- // multiple value, as an x.1 value (0 means 0.5)
- // replace the low bit with a table lookup to give 0,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15
- u32 multiple = op_multiple(opoffs);
- cache.multiple = ((multiple & 0xe) | BIT(0xc2aa, multiple)) * 2;
- if (cache.multiple == 0)
- cache.multiple = 1;
-
- // phase step, or PHASE_STEP_DYNAMIC if PM is active; this depends on
- // block_freq, detune, and multiple, so compute it after we've done those
- if (op_lfo_pm_enable(opoffs) == 0)
- cache.phase_step = compute_phase_step(choffs, opoffs, cache, 0);
- else
- cache.phase_step = ymfm_opdata_cache::PHASE_STEP_DYNAMIC;
-
- // total level, scaled by 8; for non-rhythm operator 0, this is the total
- // level from the instrument data; for other operators it is 4*volume
- if (BIT(opoffs, 0) == 1 || (rhythm_enable() && choffs >= 7))
- cache.total_level = op_volume(opoffs) * 4;
- else
- cache.total_level = ch_total_level(choffs);
- cache.total_level <<= 3;
-
- // pre-add key scale level
- u32 ksl = op_ksl(opoffs);
- if (ksl != 0)
- cache.total_level += opl_key_scale_atten(BIT(block_freq, 9, 3), BIT(block_freq, 5, 4)) << ksl;
-
- // 4-bit sustain level, but 15 means 31 so effectively 5 bits
- cache.eg_sustain = op_sustain_level(opoffs);
- cache.eg_sustain |= (cache.eg_sustain + 1) & 0x10;
- cache.eg_sustain <<= 5;
-
- // The envelope diagram in the YM2413 datasheet gives values for these
- // in ms from 0->48dB. The attack/decay tables give values in ms from
- // 0->96dB, so to pick an equivalent decay rate, we want to find the
- // closest match that is 2x the 0->48dB value:
- //
- // DP = 10ms (0->48db) -> 20ms (0->96db); decay of 12 gives 19.20ms
- // RR = 310ms (0->48db) -> 620ms (0->96db); decay of 7 gives 613.76ms
- // RS = 1200ms (0->48db) -> 2400ms (0->96db); decay of 5 gives 2455.04ms
- //
- // The envelope diagram for percussive sounds (eg_sustain() == 0) also uses
- // "RR" to mean both the constant RR above and the Release Rate specified in
- // the instrument data. In this case, Relief Pitcher's credit sound bears out
- // that the Release Rate is used during sustain, and that the constant RR
- // (or RS) is used during the release phase.
- constexpr u8 DP = 12 * 4;
- constexpr u8 RR = 7 * 4;
- constexpr u8 RS = 5 * 4;
-
- // determine KSR adjustment for envelope rates
- u32 ksrval = keycode >> (2 * (op_ksr(opoffs) ^ 1));
- cache.eg_rate[YMFM_ENV_DEPRESS] = DP;
- cache.eg_rate[YMFM_ENV_ATTACK] = effective_rate(op_attack_rate(opoffs) * 4, ksrval);
- cache.eg_rate[YMFM_ENV_DECAY] = effective_rate(op_decay_rate(opoffs) * 4, ksrval);
- if (op_eg_sustain(opoffs))
- {
- cache.eg_rate[YMFM_ENV_SUSTAIN] = 0;
- cache.eg_rate[YMFM_ENV_RELEASE] = ch_sustain(choffs) ? RS : effective_rate(op_release_rate(opoffs) * 4, ksrval);
- }
- else
- {
- cache.eg_rate[YMFM_ENV_SUSTAIN] = effective_rate(op_release_rate(opoffs) * 4, ksrval);
- cache.eg_rate[YMFM_ENV_RELEASE] = ch_sustain(choffs) ? RS : RR;
- }
-}
-
-
-//-------------------------------------------------
-// compute_phase_step - compute the phase step
-//-------------------------------------------------
-
-u32 ymopll_registers::compute_phase_step(u32 choffs, u32 opoffs, ymfm_opdata_cache const &cache, s32 lfo_raw_pm)
-{
- // phase step computation is the same as OPL but the block_freq has one
- // more bit, which we shift in
- return opl_compute_phase_step(cache.block_freq << 1, cache.multiple, op_lfo_pm_enable(opoffs) ? lfo_raw_pm : 0);
-}
-
-
-//-------------------------------------------------
-// log_keyon - log a key-on event
-//-------------------------------------------------
-
-void ymopll_registers::log_keyon(u32 choffs, u32 opoffs)
-{
- u32 chnum = choffs;
- u32 opnum = opoffs;
-
- LOG("%d.%02d freq=%04X inst=%X fb=%d mul=%X",
- chnum, opnum,
- ch_block_freq(choffs),
- ch_instrument(choffs),
- ch_feedback(choffs),
- op_multiple(opoffs));
-
- if (BIT(opoffs, 0) == 1 || (is_rhythm(choffs) && choffs >= 6))
- LOG(" vol=%X", op_volume(opoffs));
- else
- LOG(" tl=%02X", ch_total_level(choffs));
-
- LOG(" ksr=%d ksl=%d adr=%X/%X/%X sl=%X sus=%d/%d",
- op_ksr(opoffs),
- op_ksl(opoffs),
- op_attack_rate(opoffs),
- op_decay_rate(opoffs),
- op_release_rate(opoffs),
- op_sustain_level(opoffs),
- op_eg_sustain(opoffs),
- ch_sustain(choffs));
-
- if (op_lfo_am_enable(opoffs))
- LOG(" am=1");
- if (op_lfo_pm_enable(opoffs))
- LOG(" pm=1");
- if (op_waveform(opoffs) != 0)
- LOG(" wf=1");
- if (is_rhythm(choffs))
- LOG(" rhy=1");
-}
-
-
-//*********************************************************
-// YMFM OPERATOR
-//*********************************************************
-
-//-------------------------------------------------
-// ymfm_operator - constructor
-//-------------------------------------------------
-
-template<class RegisterType>
-ymfm_operator<RegisterType>::ymfm_operator(ymfm_engine_base<RegisterType> &owner, u32 opoffs) :
- m_choffs(0),
- m_opoffs(opoffs),
- m_phase(0),
- m_env_attenuation(0x3ff),
- m_env_state(YMFM_ENV_RELEASE),
- m_ssg_inverted(false),
- m_key_state(0),
- m_keyon_live(0),
- m_regs(owner.regs()),
- m_owner(owner)
-{
-}
-
-
-//-------------------------------------------------
-// save - register for save states
-//-------------------------------------------------
-
-ALLOW_SAVE_TYPE(ymfm_envelope_state);
-
-template<class RegisterType>
-void ymfm_operator<RegisterType>::save(device_t &device, u32 index)
-{
- // save our data
- device.save_item(YMFM_NAME(m_phase), index);
- device.save_item(YMFM_NAME(m_env_attenuation), index);
- device.save_item(YMFM_NAME(m_env_state), index);
- device.save_item(YMFM_NAME(m_ssg_inverted), index);
- device.save_item(YMFM_NAME(m_key_state), index);
- device.save_item(YMFM_NAME(m_keyon_live), index);
-}
-
-
-//-------------------------------------------------
-// reset - reset the channel state
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_operator<RegisterType>::reset()
-{
- // reset our data
- m_phase = 0;
- m_env_attenuation = 0x3ff;
- m_env_state = YMFM_ENV_RELEASE;
- m_ssg_inverted = 0;
- m_key_state = 0;
- m_keyon_live = 0;
-}
-
-
-//-------------------------------------------------
-// prepare - prepare for clocking
-//-------------------------------------------------
-
-template<class RegisterType>
-bool ymfm_operator<RegisterType>::prepare()
-{
- // cache the data
- m_regs.cache_operator_data(m_choffs, m_opoffs, m_cache);
-
- // clock the key state
- clock_keystate(u32(m_keyon_live != 0));
- m_keyon_live &= ~(1 << YMFM_KEYON_CSM);
-
- // we're active until we're quiet after the release
- return (m_env_state != YMFM_ENV_RELEASE || m_env_attenuation < ENV_QUIET);
-}
-
-
-//-------------------------------------------------
-// clock - master clocking function
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_operator<RegisterType>::clock(u32 env_counter, s32 lfo_raw_pm)
-{
- // clock the SSG-EG state (OPN/OPNA)
- if (m_regs.op_ssg_eg_enable(m_opoffs))
- clock_ssg_eg_state();
-
- // clock the envelope if on an envelope cycle; env_counter is a x.2 value
- if (BIT(env_counter, 0, 2) == 0)
- clock_envelope(env_counter >> 2);
-
- // clock the phase
- clock_phase(lfo_raw_pm);
-}
-
-
-//-------------------------------------------------
-// compute_volume - compute the 14-bit signed
-// volume of this operator, given a phase
-// modulation and an AM LFO offset
-//-------------------------------------------------
-
-template<class RegisterType>
-s32 ymfm_operator<RegisterType>::compute_volume(u32 phase, u32 am_offset) const
-{
- // the low 10 bits of phase represents a full 2*PI period over
- // the full sin wave
-
- // early out if the envelope is effectively off
- if (m_env_attenuation > ENV_QUIET)
- return 0;
-
- // get the absolute value of the sin, as attenuation, as a 4.8 fixed point value
- u32 sin_attenuation = m_cache.waveform[phase & (RegisterType::WAVEFORM_LENGTH - 1)];
-
- // get the attenuation from the evelope generator as a 4.6 value, shifted up to 4.8
- u32 env_attenuation = envelope_attenuation(am_offset) << 2;
-
- // combine into a 5.8 value, then convert from attenuation to 13-bit linear volume
- s32 result = attenuation_to_volume((sin_attenuation & 0x7fff) + env_attenuation);
-
- // negate if in the negative part of the sin wave (sign bit gives 14 bits)
- return BIT(sin_attenuation, 15) ? -result : result;
-}
-
-
-//-------------------------------------------------
-// compute_noise_volume - compute the 14-bit
-// signed noise volume of this operator, given a
-// noise input value and an AM offset
-//-------------------------------------------------
-
-template<class RegisterType>
-s32 ymfm_operator<RegisterType>::compute_noise_volume(u32 am_offset) const
-{
- // application manual says the logarithmic transform is not applied here, so we
- // just use the raw envelope attenuation, inverted (since 0 attenuation should be
- // maximum), and shift it up from a 10-bit value to an 11-bit value
- u32 result = (envelope_attenuation(am_offset) ^ 0x3ff) << 1;
-
- // QUESTION: is AM applied still?
-
- // negate based on the noise state
- return BIT(m_regs.noise_state(), 0) ? -result : result;
-}
-
-
-//-------------------------------------------------
-// keyonoff - signal a key on/off event
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_operator<RegisterType>::keyonoff(u32 on, ymfm_keyon_type type)
-{
- m_keyon_live = (m_keyon_live & ~(1 << int(type))) | (BIT(on, 0) << int(type));
-}
-
-
-//-------------------------------------------------
-// start_attack - start the attack phase; called
-// when a keyon happens or when an SSG-EG cycle
-// is complete and restarts
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_operator<RegisterType>::start_attack()
-{
- // don't change anything if already in attack state
- if (m_env_state == YMFM_ENV_ATTACK)
- return;
- m_env_state = YMFM_ENV_ATTACK;
-
- // generally not inverted at start, except if SSG-EG is
- // enabled and one of the inverted modes is specified
- if (RegisterType::EG_HAS_SSG)
- m_ssg_inverted = m_regs.op_ssg_eg_enable(m_opoffs) & BIT(m_regs.op_ssg_eg_mode(m_opoffs), 2);
-
- // reset the phase when we start an attack
- m_phase = 0;
-
- // if the attack rate >= 62 then immediately go to max attenuation
- if (m_cache.eg_rate[YMFM_ENV_ATTACK] >= 62)
- m_env_attenuation = 0;
-}
-
-
-//-------------------------------------------------
-// start_release - start the release phase;
-// called when a keyoff happens
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_operator<RegisterType>::start_release()
-{
- // don't change anything if already in release state
- if (m_env_state == YMFM_ENV_RELEASE)
- return;
- m_env_state = YMFM_ENV_RELEASE;
-
- // adjust attenuation if inverted due to SSG-EG
- if (RegisterType::EG_HAS_SSG && m_ssg_inverted)
- m_env_attenuation = 0x200 - m_env_attenuation;
-}
-
-
-//-------------------------------------------------
-// clock_keystate - clock the keystate to match
-// the incoming keystate
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_operator<RegisterType>::clock_keystate(u32 keystate)
-{
- assert(keystate == 0 || keystate == 1);
-
- // has the key changed?
- if ((keystate ^ m_key_state) != 0)
- {
- m_key_state = keystate;
-
- // if the key has turned on, start the attack
- if (keystate != 0)
- {
- // log key on events under certain conditions
- // if (m_regs.lfo_waveform() == 3 && m_regs.lfo_enable() && ((m_regs.lfo_am_enable() && m_regs.lfo_am_sensitivity() != 0) || m_regs.lfo_pm_sensitivity() != 0))
- // if ((m_regs.rhythm_enable() && m_regs.chnum() >= 6) ||
- // (m_regs.waveform_enable() && m_regs.waveform() != 0))
- {
- LOG("%s: ", m_owner.device().tag(), m_opoffs);
- m_regs.log_keyon(m_choffs, m_opoffs);
- LOG("\n");
- }
-
- // OPLL has a DP ("depress"?) state to bring the volume
- // down before starting the attack
- if (RegisterType::EG_HAS_DEPRESS && m_env_attenuation < 0x200)
- m_env_state = YMFM_ENV_DEPRESS;
- else
- start_attack();
- }
-
- // otherwise, start the release
- else
- start_release();
- }
-}
-
-
-//-------------------------------------------------
-// clock_ssg_eg_state - clock the SSG-EG state;
-// should only be called if SSG-EG is enabled
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_operator<RegisterType>::clock_ssg_eg_state()
-{
- // work only happens once the attenuation crosses above 0x200
- if (!BIT(m_env_attenuation, 9))
- return;
-
- // 8 SSG-EG modes:
- // 000: repeat normally
- // 001: run once, hold low
- // 010: repeat, alternating between inverted/non-inverted
- // 011: run once, hold high
- // 100: inverted repeat normally
- // 101: inverted run once, hold low
- // 110: inverted repeat, alternating between inverted/non-inverted
- // 111: inverted run once, hold high
- u32 mode = m_regs.op_ssg_eg_mode(m_opoffs);
-
- // hold modes (1/3/5/7)
- if (BIT(mode, 0))
- {
- // set the inverted flag to the end state (0 for modes 1/7, 1 for modes 3/5)
- m_ssg_inverted = BIT(mode, 2) ^ BIT(mode, 1);
-
- // if holding low (modes 1/5), force the attenuation to maximum
- // once we're past the attack phase
- if (m_env_state != YMFM_ENV_ATTACK && BIT(mode, 1) == 0)
- m_env_attenuation = 0x3ff;
- }
-
- // continuous modes (0/2/4/6)
- else
- {
- // toggle invert in alternating mode (even in attack state)
- m_ssg_inverted ^= BIT(mode, 1);
-
- // restart attack if in decay/sustain states
- if (m_env_state == YMFM_ENV_DECAY || m_env_state == YMFM_ENV_SUSTAIN)
- start_attack();
-
- // phase is reset to 0 regardless in modes 0/4
- if (BIT(mode, 1) == 0)
- m_phase = 0;
- }
-
- // in all modes, once we hit release state, attenuation is forced to maximum
- if (m_env_state == YMFM_ENV_RELEASE)
- m_env_attenuation = 0x3ff;
-}
-
-
-//-------------------------------------------------
-// clock_envelope - clock the envelope state
-// according to the given count
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_operator<RegisterType>::clock_envelope(u32 env_counter)
-{
- // handle attack->decay and decay->sustain transitions
- if (m_env_state == YMFM_ENV_ATTACK && m_env_attenuation == 0)
- m_env_state = YMFM_ENV_DECAY;
- else if (m_env_state == YMFM_ENV_DECAY && m_env_attenuation >= m_cache.eg_sustain)
- m_env_state = YMFM_ENV_SUSTAIN;
-
- // fetch the appropriate 6-bit rate value from the cache
- u32 rate = m_cache.eg_rate[m_env_state];
-
- // compute the rate shift value; this is the shift needed to
- // apply to the env_counter such that it becomes a 5.11 fixed
- // point number
- u32 rate_shift = rate >> 2;
- env_counter <<= rate_shift;
-
- // see if the fractional part is 0; if not, it's not time to clock
- if (BIT(env_counter, 0, 11) != 0)
- return;
-
- // determine the increment based on the non-fractional part of env_counter
- u32 increment = attenuation_increment(rate, BIT(env_counter, 11, 3));
-
- // attack is the only one that increases
- if (m_env_state == YMFM_ENV_ATTACK)
- {
- // glitch means that attack rates of 62/63 don't increment if
- // changed after the initial key on (where they are handled
- // specially)
-
- // QUESTION: this check affects one of the operators on the gng credit sound
- // is it correct?
- // QUESTION: does this apply only to YM2612?
- if (rate < 62)
- m_env_attenuation += (~m_env_attenuation * increment) >> 4;
- }
-
- // all other cases are similar
- else
- {
- // non-SSG-EG cases just apply the increment
- if (!m_regs.op_ssg_eg_enable(m_opoffs))
- m_env_attenuation += increment;
-
- // SSG-EG only applies if less than mid-point, and then at 4x
- else if (m_env_attenuation < 0x200)
- m_env_attenuation += 4 * increment;
-
- // clamp the final attenuation
- if (m_env_attenuation >= 0x400)
- m_env_attenuation = 0x3ff;
-
- // transition from depress to attack
- if (RegisterType::EG_HAS_DEPRESS && m_env_state == YMFM_ENV_DEPRESS && m_env_attenuation >= 0x200)
- start_attack();
- }
-}
-
-
-//-------------------------------------------------
-// clock_phase - clock the 10.10 phase value; the
-// OPN version of the logic has been verified
-// against the Nuked phase generator
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_operator<RegisterType>::clock_phase(s32 lfo_raw_pm)
-{
- // read from the cache, or recalculate if PM active
- u32 phase_step = m_cache.phase_step;
- if (phase_step == ymfm_opdata_cache::PHASE_STEP_DYNAMIC)
- phase_step = m_regs.compute_phase_step(m_choffs, m_opoffs, m_cache, lfo_raw_pm);
-
- // finally apply the step to the current phase value
- m_phase += phase_step;
-}
-
-
-//-------------------------------------------------
-// envelope_attenuation - return the effective
-// attenuation of the envelope
-//-------------------------------------------------
-
-template<class RegisterType>
-u32 ymfm_operator<RegisterType>::envelope_attenuation(u32 am_offset) const
-{
- u32 result = m_env_attenuation;
-
- // invert if necessary due to SSG-EG
- if (RegisterType::EG_HAS_SSG && m_ssg_inverted)
- result = (0x200 - result) & 0x3ff;
-
- // add in LFO AM modulation
- if (m_regs.op_lfo_am_enable(m_opoffs))
- result += am_offset;
-
- // add in total level and KSL from the cache
- result += m_cache.total_level;
-
- // clamp to max and return
- return (result < 0x400) ? result : 0x3ff;
-}
-
-
-
-//*********************************************************
-// YMFM_CHANNEL
-//*********************************************************
-
-//-------------------------------------------------
-// ymfm_channel - constructor
-//-------------------------------------------------
-
-template<class RegisterType>
-ymfm_channel<RegisterType>::ymfm_channel(ymfm_engine_base<RegisterType> &owner, u32 choffs) :
- m_choffs(choffs),
- m_feedback{ 0, 0 },
- m_feedback_in(0),
- m_op{ nullptr, nullptr, nullptr, nullptr },
- m_regs(owner.regs()),
- m_owner(owner)
-{
-}
-
-
-//-------------------------------------------------
-// save - register for save states
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_channel<RegisterType>::save(device_t &device, u32 index)
-{
- // save our data
- device.save_item(YMFM_NAME(m_feedback), index);
- device.save_item(YMFM_NAME(m_feedback_in), index);
-}
-
-
-//-------------------------------------------------
-// reset - reset the channel state
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_channel<RegisterType>::reset()
-{
- // reset our data
- m_feedback[0] = m_feedback[1] = 0;
- m_feedback_in = 0;
-}
-
-
-//-------------------------------------------------
-// keyonoff - signal key on/off to our operators
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_channel<RegisterType>::keyonoff(u32 states, ymfm_keyon_type type)
-{
- for (int opnum = 0; opnum < std::size(m_op); opnum++)
- if (m_op[opnum] != nullptr)
- m_op[opnum]->keyonoff(BIT(states, opnum), type);
-}
-
-
-//-------------------------------------------------
-// prepare - prepare for clocking
-//-------------------------------------------------
-
-template<class RegisterType>
-bool ymfm_channel<RegisterType>::prepare()
-{
- u32 active_mask = 0;
-
- // prepare all operators and determine if they are active
- for (int opnum = 0; opnum < std::size(m_op); opnum++)
- if (m_op[opnum] != nullptr)
- if (m_op[opnum]->prepare())
- active_mask |= 1 << opnum;
-
- return (active_mask != 0);
-}
-
-
-//-------------------------------------------------
-// clock - master clock of all operators
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_channel<RegisterType>::clock(u32 env_counter, s32 lfo_raw_pm)
-{
- // clock the feedback through
- m_feedback[0] = m_feedback[1];
- m_feedback[1] = m_feedback_in;
-
- for (int opnum = 0; opnum < std::size(m_op); opnum++)
- if (m_op[opnum] != nullptr)
- m_op[opnum]->clock(env_counter, lfo_raw_pm);
-}
-
-
-//-------------------------------------------------
-// output_2op - combine 4 operators according to
-// the specified algorithm, returning a sum
-// according to the rshift and clipmax parameters,
-// which vary between different implementations
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_channel<RegisterType>::output_2op(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const
-{
- // The first 2 operators should be populated
- assert(m_op[0] != nullptr);
- assert(m_op[1] != nullptr);
-
- // AM amount is the same across all operators; compute it once
- u32 am_offset = m_regs.lfo_am_offset(m_choffs);
-
- // operator 1 has optional self-feedback
- s32 opmod = 0;
- u32 feedback = m_regs.ch_feedback(m_choffs);
- if (feedback != 0)
- opmod = (m_feedback[0] + m_feedback[1]) >> (10 - feedback);
-
- // compute the 14-bit volume/value of operator 1 and update the feedback
- s32 op1value = m_feedback_in = m_op[0]->compute_volume(m_op[0]->phase() + opmod, am_offset);
-
- // now that the feedback has been computed, skip the rest if all volumes
- // are clear; no need to do all this work for nothing
- if (m_regs.ch_output_any(m_choffs) == 0)
- return;
-
- // Algorithms for two-operator case:
- // 0: O1 -> O2 -> out
- // 1: (O1 + O2) -> out
- s32 result;
- if (BIT(m_regs.ch_algorithm(m_choffs), 0) == 0)
- {
- // some OPL chips use the previous sample for modulation instead of
- // the current sample
- opmod = (RegisterType::MODULATOR_DELAY ? m_feedback[1] : op1value) >> 1;
- result = m_op[1]->compute_volume(m_op[1]->phase() + opmod, am_offset) >> rshift;
- }
- else
- {
- result = op1value + (m_op[1]->compute_volume(m_op[1]->phase(), am_offset) >> rshift);
- s32 clipmin = -clipmax - 1;
- result = std::clamp(result, clipmin, clipmax);
- }
-
- // add to the output
- add_to_output(m_choffs, outputs, result);
-}
-
-
-//-------------------------------------------------
-// output_4op - combine 4 operators according to
-// the specified algorithm, returning a sum
-// according to the rshift and clipmax parameters,
-// which vary between different implementations
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_channel<RegisterType>::output_4op(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const
-{
- // all 4 operators should be populated
- assert(m_op[0] != nullptr);
- assert(m_op[1] != nullptr);
- assert(m_op[2] != nullptr);
- assert(m_op[3] != nullptr);
-
- // AM amount is the same across all operators; compute it once
- u32 am_offset = m_regs.lfo_am_offset(m_choffs);
-
- // operator 1 has optional self-feedback
- s32 opmod = 0;
- u32 feedback = m_regs.ch_feedback(m_choffs);
- if (feedback != 0)
- opmod = (m_feedback[0] + m_feedback[1]) >> (10 - feedback);
-
- // compute the 14-bit volume/value of operator 1 and update the feedback
- s32 op1value = m_feedback_in = m_op[0]->compute_volume(m_op[0]->phase() + opmod, am_offset);
-
- // now that the feedback has been computed, skip the rest if all volumes
- // are clear; no need to do all this work for nothing
- if (m_regs.ch_output_any(m_choffs) == 0)
- return;
-
- // OPM/OPN offer 8 different connection algorithms for 4 operators,
- // and OPL3 offers 4 more, which we designate here as 8-11.
- //
- // The operators are computed in order, with the inputs pulled from
- // an array of values (opout) that is populated as we go:
- // 0 = 0
- // 1 = O1
- // 2 = O2
- // 3 = O3
- // 4 = (O4)
- // 5 = O1+O2
- // 6 = O1+O3
- // 7 = O2+O3
- //
- // The s_algorithm_ops table describes the inputs and outputs of each
- // algorithm as follows:
- //
- // ---------x use opout[x] as operator 2 input
- // ------xxx- use opout[x] as operator 3 input
- // ---xxx---- use opout[x] as operator 4 input
- // --x------- include opout[1] in final sum
- // -x-------- include opout[2] in final sum
- // x--------- include opout[3] in final sum
- #define ALGORITHM(op2in, op3in, op4in, op1out, op2out, op3out) \
- (op2in | (op3in << 1) | (op4in << 4) | (op1out << 7) | (op2out << 8) | (op3out << 9))
- static u16 const s_algorithm_ops[8+4] =
- {
- ALGORITHM(1,2,3, 0,0,0), // 0: O1 -> O2 -> O3 -> O4 -> out (O4)
- ALGORITHM(0,5,3, 0,0,0), // 1: (O1 + O2) -> O3 -> O4 -> out (O4)
- ALGORITHM(0,2,6, 0,0,0), // 2: (O1 + (O2 -> O3)) -> O4 -> out (O4)
- ALGORITHM(1,0,7, 0,0,0), // 3: ((O1 -> O2) + O3) -> O4 -> out (O4)
- ALGORITHM(1,0,3, 0,1,0), // 4: ((O1 -> O2) + (O3 -> O4)) -> out (O2+O4)
- ALGORITHM(1,1,1, 0,1,1), // 5: ((O1 -> O2) + (O1 -> O3) + (O1 -> O4)) -> out (O2+O3+O4)
- ALGORITHM(1,0,0, 0,1,1), // 6: ((O1 -> O2) + O3 + O4) -> out (O2+O3+O4)
- ALGORITHM(0,0,0, 1,1,1), // 7: (O1 + O2 + O3 + O4) -> out (O1+O2+O3+O4)
- ALGORITHM(1,2,3, 0,0,0), // 8: O1 -> O2 -> O3 -> O4 -> out (O4) [same as 0]
- ALGORITHM(0,2,3, 1,0,0), // 9: (O1 + (O2 -> O3 -> O4)) -> out (O1+O4) [unique]
- ALGORITHM(1,0,3, 0,1,0), // 10: ((O1 -> O2) + (O3 -> O4)) -> out (O2+O4) [same as 4]
- ALGORITHM(0,2,0, 1,0,1) // 11: (O1 + (O2 -> O3) + O4) -> out (O1+O3+O4) [unique]
- };
- u32 algorithm_ops = s_algorithm_ops[m_regs.ch_algorithm(m_choffs)];
-
- // populate the opout table
- s16 opout[8];
- opout[0] = 0;
- opout[1] = op1value;
-
- // compute the 14-bit volume/value of operator 2
- opmod = opout[BIT(algorithm_ops, 0, 1)] >> 1;
- opout[2] = m_op[1]->compute_volume(m_op[1]->phase() + opmod, am_offset);
- opout[5] = opout[1] + opout[2];
-
- // compute the 14-bit volume/value of operator 3
- opmod = opout[BIT(algorithm_ops, 1, 3)] >> 1;
- opout[3] = m_op[2]->compute_volume(m_op[2]->phase() + opmod, am_offset);
- opout[6] = opout[1] + opout[3];
- opout[7] = opout[2] + opout[3];
-
- // compute the 14-bit volume/value of operator 4; this could be a noise
- // value on the OPM; all algorithms consume OP4 output at a minimum
- s32 result;
- if (m_regs.noise_enable() && m_choffs == 7)
- result = m_op[3]->compute_noise_volume(am_offset);
- else
- {
- opmod = opout[BIT(algorithm_ops, 4, 3)] >> 1;
- result = m_op[3]->compute_volume(m_op[3]->phase() + opmod, am_offset);
- }
- result >>= rshift;
-
- // optionally add OP1, OP2, OP3
- s32 clipmin = -clipmax - 1;
- if (BIT(algorithm_ops, 7) != 0)
- result = std::clamp(result + (opout[1] >> rshift), clipmin, clipmax);
- if (BIT(algorithm_ops, 8) != 0)
- result = std::clamp(result + (opout[2] >> rshift), clipmin, clipmax);
- if (BIT(algorithm_ops, 9) != 0)
- result = std::clamp(result + (opout[3] >> rshift), clipmin, clipmax);
-
- // add to the output
- add_to_output(m_choffs, outputs, result);
-}
-
-
-//-------------------------------------------------
-// output_rhythm_ch6 - special case output
-// computation for OPL channel 6 in rhythm mode,
-// which outputs a Bass Drum instrument
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_channel<RegisterType>::output_rhythm_ch6(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const
-{
- // AM amount is the same across all operators; compute it once
- u32 am_offset = m_regs.lfo_am_offset(m_choffs);
-
- // Bass Drum: this uses operators 12 and 15 (i.e., channel 6)
- // in an almost-normal way, except that if the algorithm is 1,
- // the first operator is ignored instead of added in
-
- // operator 1 has optional self-feedback
- s32 opmod = 0;
- u32 feedback = m_regs.ch_feedback(m_choffs);
- if (feedback != 0)
- opmod = (m_feedback[0] + m_feedback[1]) >> (10 - feedback);
-
- // compute the 14-bit volume/value of operator 1 and update the feedback
- s32 opout1 = m_feedback_in = m_op[0]->compute_volume(m_op[0]->phase() + opmod, am_offset);
-
- // compute the 14-bit volume/value of operator 2, which is the result
- opmod = BIT(m_regs.ch_algorithm(m_choffs), 0) ? 0 : (opout1 >> 1);
- s32 result = m_op[1]->compute_volume(m_op[1]->phase() + opmod, am_offset) >> rshift;
-
- // add to the output
- add_to_output(m_choffs, outputs, result * 2);
-}
-
-
-//-------------------------------------------------
-// output_rhythm_ch7 - special case output
-// computation for OPL channel 7 in rhythm mode,
-// which outputs High Hat and Snare Drum
-// instruments
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_channel<RegisterType>::output_rhythm_ch7(u32 phase_select, s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const
-{
- // AM amount is the same across all operators; compute it once
- u32 am_offset = m_regs.lfo_am_offset(m_choffs);
- u32 noise_state = BIT(m_regs.noise_state(), 0);
-
- // High Hat: this uses the envelope from operator 13 (channel 7),
- // and a combination of noise and the operator 13/17 phase select
- // to compute the phase
- u32 phase = (phase_select << 9) | (0xd0 >> (2 * (noise_state ^ phase_select)));
- s32 result = m_op[0]->compute_volume(phase, am_offset) >> rshift;
-
- // Snare Drum: this uses the envelope from operator 16 (channel 7),
- // and a combination of noise and operator 13 phase to pick a phase
- u32 op13phase = m_op[0]->phase();
- phase = (0x100 << BIT(op13phase, 8)) ^ (noise_state << 8);
- result += m_op[1]->compute_volume(phase, am_offset) >> rshift;
- result = std::clamp<s32>(result, -clipmax - 1, clipmax);
-
- // add to the output
- add_to_output(m_choffs, outputs, result * 2);
-}
-
-
-//-------------------------------------------------
-// output_rhythm_ch8 - special case output
-// computation for OPL channel 8 in rhythm mode,
-// which outputs Tom Tom and Top Cymbal instruments
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_channel<RegisterType>::output_rhythm_ch8(u32 phase_select, s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const
-{
- // AM amount is the same across all operators; compute it once
- u32 am_offset = m_regs.lfo_am_offset(m_choffs);
-
- // Tom Tom: this is just a single operator processed normally
- s32 result = m_op[0]->compute_volume(m_op[0]->phase(), am_offset) >> rshift;
-
- // Top Cymbal: this uses the envelope from operator 17 (channel 8),
- // and the operator 13/17 phase select to compute the phase
- u32 phase = 0x100 | (phase_select << 9);
- result += m_op[1]->compute_volume(phase, am_offset) >> rshift;
- result = std::clamp<s32>(result, -clipmax - 1, clipmax);
-
- // add to the output
- add_to_output(m_choffs, outputs, result * 2);
-}
-
-
-
-//*********************************************************
-// YMFM ENGINE BASE
-//*********************************************************
-
-//-------------------------------------------------
-// ymfm_engine_base - constructor
-//-------------------------------------------------
-
-template<class RegisterType>
-ymfm_engine_base<RegisterType>::ymfm_engine_base(device_t &device) :
- m_device(device),
- m_env_counter(0),
- m_status(0),
- m_clock_prescale(RegisterType::DEFAULT_PRESCALE),
- m_irq_mask(STATUS_TIMERA | STATUS_TIMERB),
- m_irq_state(0),
- m_active_channels(ALL_CHANNELS),
- m_modified_channels(ALL_CHANNELS),
- m_prepare_count(0),
- m_busy_end(attotime::zero),
- m_timer{ nullptr, nullptr },
- m_irq_handler(device)
-{
- // create the channels
- for (int chnum = 0; chnum < CHANNELS; chnum++)
- m_channel[chnum] = std::make_unique<ymfm_channel<RegisterType>>(*this, RegisterType::channel_offset(chnum));
-
- // create the operators
- for (int opnum = 0; opnum < OPERATORS; opnum++)
- m_operator[opnum] = std::make_unique<ymfm_operator<RegisterType>>(*this, RegisterType::operator_offset(opnum));
-
- // do the initial operator assignment
- assign_operators();
-}
-
-
-//-------------------------------------------------
-// save - register for save states
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_engine_base<RegisterType>::save(device_t &device)
-{
- // allocate our timers
- for (int tnum = 0; tnum < 2; tnum++)
- m_timer[tnum] = device.machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ymfm_engine_base::timer_handler), this));
-
- // resolve the IRQ handler while we're here
- m_irq_handler.resolve();
-
- // save our data
- device.save_item(YMFM_NAME(m_env_counter));
- device.save_item(YMFM_NAME(m_status));
- device.save_item(YMFM_NAME(m_clock_prescale));
- device.save_item(YMFM_NAME(m_irq_mask));
- device.save_item(YMFM_NAME(m_irq_state));
- device.save_item(YMFM_NAME(m_busy_end));
-
- // save the register/family data
- m_regs.save(device);
-
- // save channel data
- for (int chnum = 0; chnum < CHANNELS; chnum++)
- m_channel[chnum]->save(device, chnum);
-
- // save operator data
- for (int opnum = 0; opnum < OPERATORS; opnum++)
- m_operator[opnum]->save(device, opnum);
-}
-
-
-//-------------------------------------------------
-// reset - reset the overall state
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_engine_base<RegisterType>::reset()
-{
- // reset all status bits
- set_reset_status(0, 0xff);
-
- // register type-specific initialization
- m_regs.reset();
-
- // explicitly write to the mode register since it has side-effects
- // QUESTION: old cores initialize this to 0x30 -- who is right?
- write(RegisterType::REG_MODE, 0);
-
- // reset the channels
- for (auto &chan : m_channel)
- chan->reset();
-
- // reset the operators
- for (auto &op : m_operator)
- op->reset();
-}
-
-
-//-------------------------------------------------
-// clock - iterate over all channels, clocking
-// them forward one step
-//-------------------------------------------------
-
-template<class RegisterType>
-u32 ymfm_engine_base<RegisterType>::clock(u32 chanmask)
-{
- // if something was modified, prepare
- // also prepare every 4k samples to catch ending notes
- if (m_modified_channels != 0 || m_prepare_count++ >= 4096)
- {
- // reassign operators to channels if dynamic
- if (RegisterType::DYNAMIC_OPS)
- assign_operators();
-
- // call each channel to prepare
- m_active_channels = 0;
- for (int chnum = 0; chnum < CHANNELS; chnum++)
- if (BIT(chanmask, chnum))
- if (m_channel[chnum]->prepare())
- m_active_channels |= 1 << chnum;
-
- // reset the modified channels and prepare count
- m_modified_channels = m_prepare_count = 0;
- }
-
- // if the envelope clock divider is 1, just increment by 4;
- // otherwise, increment by 1 and manually wrap when we reach the divide count
- if (RegisterType::EG_CLOCK_DIVIDER == 1)
- m_env_counter += 4;
- else if (BIT(++m_env_counter, 0, 2) == RegisterType::EG_CLOCK_DIVIDER)
- m_env_counter += 4 - RegisterType::EG_CLOCK_DIVIDER;
-
- // clock the noise generator
- s32 lfo_raw_pm = m_regs.clock_noise_and_lfo();
-
- // now update the state of all the channels and operators
- for (int chnum = 0; chnum < CHANNELS; chnum++)
- if (BIT(chanmask, chnum))
- m_channel[chnum]->clock(m_env_counter, lfo_raw_pm);
-
- // return the envelope counter as it is used to clock ADPCM-A
- return m_env_counter;
-}
-
-
-//-------------------------------------------------
-// output - compute a sum over the relevant
-// channels
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_engine_base<RegisterType>::output(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax, u32 chanmask) const
-{
- // mask out inactive channels
- chanmask &= m_active_channels;
-
- // handle the rhythm case, where some of the operators are dedicated
- // to percussion (this is an OPL-specific feature)
- if (m_regs.rhythm_enable())
- {
- // we don't support the OPM noise channel here; ensure it is off
- assert(m_regs.noise_enable() == 0);
-
- // precompute the operator 13+17 phase selection value
- u32 op13phase = m_operator[13]->phase();
- u32 op17phase = m_operator[17]->phase();
- u32 phase_select = (BIT(op13phase, 2) ^ BIT(op13phase, 7)) | BIT(op13phase, 3) | (BIT(op17phase, 5) ^ BIT(op17phase, 3));
-
- // sum over all the desired channels
- for (int chnum = 0; chnum < CHANNELS; chnum++)
- if (BIT(chanmask, chnum))
- {
- if (chnum == 6)
- m_channel[chnum]->output_rhythm_ch6(outputs, rshift, clipmax);
- else if (chnum == 7)
- m_channel[chnum]->output_rhythm_ch7(phase_select, outputs, rshift, clipmax);
- else if (chnum == 8)
- m_channel[chnum]->output_rhythm_ch8(phase_select, outputs, rshift, clipmax);
- else if (m_channel[chnum]->is4op())
- m_channel[chnum]->output_4op(outputs, rshift, clipmax);
- else
- m_channel[chnum]->output_2op(outputs, rshift, clipmax);
- }
- }
- else
- {
- // sum over all the desired channels
- for (int chnum = 0; chnum < CHANNELS; chnum++)
- if (BIT(chanmask, chnum))
- {
- if (m_channel[chnum]->is4op())
- m_channel[chnum]->output_4op(outputs, rshift, clipmax);
- else
- m_channel[chnum]->output_2op(outputs, rshift, clipmax);
- }
- }
-}
-
-
-//-------------------------------------------------
-// write - handle writes to the OPN registers
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_engine_base<RegisterType>::write(u16 regnum, u8 data)
-{
- // special case: writes to the mode register can impact IRQs;
- // schedule these writes to ensure ordering with timers
- if (regnum == RegisterType::REG_MODE)
- {
- m_device.machine().scheduler().synchronize(timer_expired_delegate(FUNC(ymfm_engine_base<RegisterType>::synced_mode_w), this), data);
- return;
- }
-
- // for now just mark all channels as modified
- m_modified_channels = ALL_CHANNELS;
-
- // most writes are passive, consumed only when needed
- u32 keyon_channel;
- u32 keyon_opmask;
- if (m_regs.write(regnum, data, keyon_channel, keyon_opmask))
- {
- // handle writes to the keyon register(s)
- if (keyon_channel < CHANNELS)
- {
- // normal channel on/off
- m_channel[keyon_channel]->keyonoff(keyon_opmask, YMFM_KEYON_NORMAL);
- }
- else if (CHANNELS >= 9 && keyon_channel == RegisterType::YMFM_RHYTHM_CHANNEL)
- {
- // special case for the OPL rhythm channels
- m_channel[6]->keyonoff(BIT(keyon_opmask, 4) ? 3 : 0, YMFM_KEYON_RHYTHM);
- m_channel[7]->keyonoff(BIT(keyon_opmask, 0) | (BIT(keyon_opmask, 3) << 1), YMFM_KEYON_RHYTHM);
- m_channel[8]->keyonoff(BIT(keyon_opmask, 2) | (BIT(keyon_opmask, 1) << 1), YMFM_KEYON_RHYTHM);
- }
- }
-}
-
-
-//-------------------------------------------------
-// status - return the current state of the
-// status flags
-//-------------------------------------------------
-
-template<class RegisterType>
-u8 ymfm_engine_base<RegisterType>::status() const
-{
- u8 result = m_status & ~STATUS_BUSY & ~m_regs.status_mask();
- if (m_device.machine().time() < m_busy_end)
- result |= STATUS_BUSY;
- return result;
-}
-
-
-//-------------------------------------------------
-// assign_operators - get the current mapping of
-// operators to channels and assign them all
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_engine_base<RegisterType>::assign_operators()
-{
- typename RegisterType::operator_mapping map;
- m_regs.operator_map(map);
-
- for (int chnum = 0; chnum < CHANNELS; chnum++)
- for (int index = 0; index < 4; index++)
- {
- u32 opnum = BIT(map.chan[chnum], 8 * index, 8);
- m_channel[chnum]->assign(index, (opnum == 0xff) ? nullptr : m_operator[opnum].get());
- }
-}
-
-
-//-------------------------------------------------
-// update_timer - update the state of the given
-// timer
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_engine_base<RegisterType>::update_timer(u32 tnum, u32 enable)
-{
- // if the timer is live, but not currently enabled, set the timer
- if (enable && !m_timer[tnum]->enable())
- {
- // each timer clock is n operators * prescale factor (2/3/6)
- u32 clockscale = OPERATORS * m_clock_prescale;
-
- // period comes from the registers, and is different for each
- u32 period = (tnum == 0) ? (1024 - m_regs.timer_a_value()) : 16 * (256 - m_regs.timer_b_value());
-
- // reset it
- m_timer[tnum]->adjust(attotime::from_hz(m_device.clock()) * (period * clockscale), tnum);
- }
-
- // if the timer is not live, ensure it is not enabled
- else if (!enable)
- m_timer[tnum]->enable(false);
-}
-
-
-//-------------------------------------------------
-// timer_handler - timer has expired - signal
-// status and possibly IRQs
-//-------------------------------------------------
-
-template<class RegisterType>
-TIMER_CALLBACK_MEMBER(ymfm_engine_base<RegisterType>::timer_handler)
-{
- // update status
- if (param == 0 && m_regs.enable_timer_a())
- set_reset_status(STATUS_TIMERA, 0);
- else if (param == 1 && m_regs.enable_timer_b())
- set_reset_status(STATUS_TIMERB, 0);
-
- // if timer A fired in CSM mode, trigger CSM on all relevant channels
- if (param == 0 && m_regs.csm())
- for (int chnum = 0; chnum < CHANNELS; chnum++)
- if (BIT(RegisterType::CSM_TRIGGER_MASK, chnum))
- m_channel[chnum]->keyonoff(1, YMFM_KEYON_CSM);
-
- // reset
- update_timer(param, 1);
-}
-
-
-//-------------------------------------------------
-// schedule_check_interrupts - schedule an
-// interrupt check via timer
-//-------------------------------------------------
-
-template<class RegisterType>
-void ymfm_engine_base<RegisterType>::schedule_check_interrupts()
-{
- // if we're currently executing a CPU, schedule the interrupt check;
- // otherwise, do it directly
- auto &scheduler = m_device.machine().scheduler();
- if (scheduler.currently_executing())
- scheduler.synchronize(timer_expired_delegate(FUNC(ymfm_engine_base<RegisterType>::check_interrupts), this), 0);
- else
- check_interrupts(nullptr, 0);
-}
-
-
-//-------------------------------------------------
-// check_interrupts - check the interrupt sources
-// for interrupts
-//-------------------------------------------------
-
-template<class RegisterType>
-TIMER_CALLBACK_MEMBER(ymfm_engine_base<RegisterType>::check_interrupts)
-{
- // update the state
- u8 old_state = m_irq_state;
- m_irq_state = ((m_status & m_irq_mask & ~m_regs.status_mask()) != 0);
-
- // set the IRQ status bit
- if (m_irq_state)
- m_status |= STATUS_IRQ;
- else
- m_status &= ~STATUS_IRQ;
-
- // if changed, signal the new state
- if (old_state != m_irq_state && !m_irq_handler.isnull())
- m_irq_handler(m_irq_state ? ASSERT_LINE : CLEAR_LINE);
-}
-
-
-//-------------------------------------------------
-// synced_mode_w - handle a mode register write
-// via timer callback
-//-------------------------------------------------
-
-template<class RegisterType>
-TIMER_CALLBACK_MEMBER(ymfm_engine_base<RegisterType>::synced_mode_w)
-{
- // mark all channels as modified
- m_modified_channels = ALL_CHANNELS;
-
- // actually write the mode register now
- u32 dummy1, dummy2;
- m_regs.write(RegisterType::REG_MODE, param, dummy1, dummy2);
-
- // reset IRQ status -- when written, all other bits are ignored
- // QUESTION: should this maybe just reset the IRQ bit and not all the bits?
- // That is, check_interrupts would only set, this would only clear?
- if (m_regs.irq_reset())
- set_reset_status(0, 0x78);
- else
- {
- // reset timer status
- u8 reset_mask = 0;
- if (m_regs.reset_timer_b())
- reset_mask |= RegisterType::STATUS_TIMERB;
- if (m_regs.reset_timer_a())
- reset_mask |= RegisterType::STATUS_TIMERA;
- set_reset_status(0, reset_mask);
-
- // load timers
- update_timer(1, m_regs.load_timer_b());
- update_timer(0, m_regs.load_timer_a());
- }
-}
-
-
-
-//*********************************************************
-// EXPLICIT TEMPLATE INSTANTIATION
-//*********************************************************
-
-template class ymfm_engine_base<ymopm_registers>;
-template class ymfm_engine_base<ymopn_registers>;
-template class ymfm_engine_base<ymopna_registers>;
-template class ymfm_engine_base<ymopl_registers>;
-template class ymfm_engine_base<ymopl2_registers>;
-template class ymfm_engine_base<ymopll_registers>;
-template class ymfm_engine_base<ymopl3_registers>;
-template class ymfm_engine_base<ymopl4_registers>;