// 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(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 } } //------------------------------------------------- // register_save - register for save states //------------------------------------------------- void ymopm_registers::register_save(save_registrar &save) { save.reg(NAME(m_lfo_counter)) .reg(NAME(m_lfo_am)) .reg(NAME(m_noise_lfsr)) .reg(NAME(m_noise_counter)) .reg(NAME(m_noise_state)) .reg(NAME(m_noise_lfo)) .reg(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 ymopn_registers_base::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); } //------------------------------------------------- // register_save - register for save states //------------------------------------------------- template void ymopn_registers_base::register_save(save_registrar &save) { if (IsOpnA) { save.reg(NAME(m_lfo_counter)) .reg(NAME(m_lfo_am)); } save.reg(NAME(m_regdata)); } //------------------------------------------------- // reset - reset to initial state //------------------------------------------------- template void ymopn_registers_base::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::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::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 ymopn_registers_base::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 s32 ymopn_registers_base::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 u32 ymopn_registers_base::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 void ymopn_registers_base::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 u32 ymopn_registers_base::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 void ymopn_registers_base::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 ymopl_registers_base::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); } } } } //------------------------------------------------- // register_save - register for save states //------------------------------------------------- template void ymopl_registers_base::register_save(save_registrar &save) { save.reg(NAME(m_lfo_am_counter)) .reg(NAME(m_lfo_pm_counter)) .reg(NAME(m_lfo_am)) .reg(NAME(m_noise_lfsr)) .reg(NAME(m_regdata)); } //------------------------------------------------- // reset - reset to initial state //------------------------------------------------- template void ymopl_registers_base::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 void ymopl_registers_base::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 bool ymopl_registers_base::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 s32 ymopl_registers_base::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 void ymopl_registers_base::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 u32 ymopl_registers_base::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 void ymopl_registers_base::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)]; } //------------------------------------------------- // register_save - register for save states //------------------------------------------------- void ymopll_registers::register_save(save_registrar &save) { save.reg(NAME(m_lfo_am_counter)) .reg(NAME(m_lfo_pm_counter)) .reg(NAME(m_lfo_am)) .reg(NAME(m_noise_lfsr)) .reg(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 ymfm_operator::ymfm_operator(ymfm_engine_base &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) { } //------------------------------------------------- // register_save - register for save states //------------------------------------------------- template void ymfm_operator::register_save(save_registrar &save) { // save our data save.reg(NAME(m_phase)) .reg(NAME(m_env_attenuation)) .reg(NAME(m_env_state)) .reg(NAME(m_ssg_inverted)) .reg(NAME(m_key_state)) .reg(NAME(m_keyon_live)); } //------------------------------------------------- // reset - reset the channel state //------------------------------------------------- template void ymfm_operator::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 bool ymfm_operator::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 void ymfm_operator::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 s32 ymfm_operator::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 s32 ymfm_operator::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 void ymfm_operator::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 void ymfm_operator::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 void ymfm_operator::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 void ymfm_operator::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 void ymfm_operator::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 void ymfm_operator::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 void ymfm_operator::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 u32 ymfm_operator::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 ymfm_channel::ymfm_channel(ymfm_engine_base &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) { } //------------------------------------------------- // register_save - register for save states //------------------------------------------------- template void ymfm_channel::register_save(save_registrar &save) { // save our data save.reg(NAME(m_feedback)) .reg(NAME(m_feedback_in)); } //------------------------------------------------- // reset - reset the channel state //------------------------------------------------- template void ymfm_channel::reset() { // reset our data m_feedback[0] = m_feedback[1] = 0; m_feedback_in = 0; } //------------------------------------------------- // keyonoff - signal key on/off to our operators //------------------------------------------------- template void ymfm_channel::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 bool ymfm_channel::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 void ymfm_channel::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 void ymfm_channel::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 void ymfm_channel::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 void ymfm_channel::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 void ymfm_channel::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(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 void ymfm_channel::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(result, -clipmax - 1, clipmax); // add to the output add_to_output(m_choffs, outputs, result * 2); } //********************************************************* // YMFM ENGINE BASE //********************************************************* //------------------------------------------------- // ymfm_engine_base - constructor //------------------------------------------------- template ymfm_engine_base::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>(*this, RegisterType::channel_offset(chnum)); // create the operators for (int opnum = 0; opnum < OPERATORS; opnum++) m_operator[opnum] = std::make_unique>(*this, RegisterType::operator_offset(opnum)); // do the initial operator assignment assign_operators(); } //------------------------------------------------- // init - initialize our state //------------------------------------------------- template void ymfm_engine_base::init() { // allocate our timers for (int tnum = 0; tnum < 2; tnum++) m_timer[tnum] = m_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(); } //------------------------------------------------- // register_save - register for save states //------------------------------------------------- template void ymfm_engine_base::register_save(save_registrar &save) { // save our data save.reg(NAME(m_env_counter)) .reg(NAME(m_status)) .reg(NAME(m_clock_prescale)) .reg(NAME(m_irq_mask)) .reg(NAME(m_irq_state)) .reg(NAME(m_busy_end)) .reg(NAME(m_channel)) .reg(NAME(m_operator)) .reg(NAME(m_regs)); } //------------------------------------------------- // reset - reset the overall state //------------------------------------------------- template void ymfm_engine_base::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 u32 ymfm_engine_base::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 void ymfm_engine_base::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 void ymfm_engine_base::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::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 u8 ymfm_engine_base::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 void ymfm_engine_base::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 void ymfm_engine_base::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 TIMER_CALLBACK_MEMBER(ymfm_engine_base::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 void ymfm_engine_base::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::check_interrupts), this), 0); else check_interrupts(nullptr, 0); } //------------------------------------------------- // check_interrupts - check the interrupt sources // for interrupts //------------------------------------------------- template TIMER_CALLBACK_MEMBER(ymfm_engine_base::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 TIMER_CALLBACK_MEMBER(ymfm_engine_base::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; template class ymfm_engine_base; template class ymfm_engine_base; template class ymfm_engine_base; template class ymfm_engine_base; template class ymfm_engine_base; template class ymfm_engine_base; template class ymfm_engine_base;