xeij/YM2151.java
//========================================================================================
// YM2151.java
// en:YM2151
// ja:YM2151
// Copyright (C) 2003-2022 Makoto Kamada
//
// This file is part of the XEiJ (X68000 Emulator in Java).
// You can use, modify and redistribute the XEiJ if the conditions are met.
// Read the XEiJ License for more details.
// https://stdkmd.net/xeij/
//========================================================================================
//--------------------------------------------------------------------------------
// This program is based on ymfm developed by Aaron Giles.
// https://github.com/aaronsgiles/ymfm
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//ymfm License
//--------------------------------------------------------------------------------
// BSD 3-Clause License
//
// Copyright (c) 2021, Aaron Giles
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//--------------------------------------------------------------------------------
package xeij;
import java.io.*; //FileOutputStream
import java.nio.*; //ByteBuffer
import java.util.*; //Arrays
public class YM2151 {
public static int sint8 (int x) {
return (byte) x;
}
public static int sint16 (int x) {
return (short) x;
}
public static int uint8 (int x) {
return 0xff & x;
}
public static int uint16 (int x) {
return (char) x;
}
public static int umin32 (int x, int y) {
return Integer.compareUnsigned (x, y) < 0 ? x : y;
}
//-------------------------------------------------
// bitfield - extract a bitfield from the given
// value, starting at bit 'start' for a length of
// 'length' bits
//-------------------------------------------------
public static /*uint32*/ int bitfield (/*uint32*/ int value, int start) {
return (value >>> start) & 1;
}
public static /*uint32*/ int bitfield (/*uint32*/ int value, int start, int length) {
return (value >>> start) & ((1 << length) - 1);
}
//-------------------------------------------------
// clamp - clamp between the minimum and maximum
// values provided
//-------------------------------------------------
public static /*sint32*/ int clamp (/*sint32*/ int value, /*sint32*/ int minval, /*sint32*/ int maxval) {
//return Math.max (minval, Math.min (maxval, value));
if (value < minval) {
return minval;
}
if (value > maxval) {
return maxval;
}
return value;
}
//-------------------------------------------------
// count_leading_zeros - return the number of
// leading zeros in a 32-bit value; CPU-optimized
// versions for various architectures are included
// below
//-------------------------------------------------
public static /*uint8*/ int count_leading_zeros (/*uint32*/ int value) {
//return uint8 (Integer.numberOfLeadingZeros (value));
if (value == 0) {
return 32;
}
/*uint8*/ int count;
for (count = 0; /*sint32*/ value >= 0; count++) {
value <<= 1;
}
return count;
}
// Many of the Yamaha FM chips emit a floating-point value, which is sent to
// a DAC for processing. The exact format of this floating-point value is
// documented below. This description only makes sense if the "internal"
// format treats sign as 1=positive and 0=negative, so the helpers below
// presume that.
//
// Internal OPx data 16-bit signed data Exp Sign Mantissa
// ================= ================= === ==== ========
// 1 1xxxxxxxx------ -> 0 1xxxxxxxx------ -> 111 1 1xxxxxxx
// 1 01xxxxxxxx----- -> 0 01xxxxxxxx----- -> 110 1 1xxxxxxx
// 1 001xxxxxxxx---- -> 0 001xxxxxxxx---- -> 101 1 1xxxxxxx
// 1 0001xxxxxxxx--- -> 0 0001xxxxxxxx--- -> 100 1 1xxxxxxx
// 1 00001xxxxxxxx-- -> 0 00001xxxxxxxx-- -> 011 1 1xxxxxxx
// 1 000001xxxxxxxx- -> 0 000001xxxxxxxx- -> 010 1 1xxxxxxx
// 1 000000xxxxxxxxx -> 0 000000xxxxxxxxx -> 001 1 xxxxxxxx
// 0 111111xxxxxxxxx -> 1 111111xxxxxxxxx -> 001 0 xxxxxxxx
// 0 111110xxxxxxxx- -> 1 111110xxxxxxxx- -> 010 0 0xxxxxxx
// 0 11110xxxxxxxx-- -> 1 11110xxxxxxxx-- -> 011 0 0xxxxxxx
// 0 1110xxxxxxxx--- -> 1 1110xxxxxxxx--- -> 100 0 0xxxxxxx
// 0 110xxxxxxxx---- -> 1 110xxxxxxxx---- -> 101 0 0xxxxxxx
// 0 10xxxxxxxx----- -> 1 10xxxxxxxx----- -> 110 0 0xxxxxxx
// 0 0xxxxxxxx------ -> 1 0xxxxxxxx------ -> 111 0 0xxxxxxx
//-------------------------------------------------
// roundtrip_fp - compute the result of a round
// trip through the encode/decode process above
//-------------------------------------------------
public static /*sint16*/ int roundtrip_fp (/*sint32*/ int value) {
// handle overflows first
if (value < -32768) {
return sint16 (-32768);
}
if (value > 32767) {
return sint16 (32767);
}
// we need to count the number of leading sign bits after the sign
// we can use count_leading_zeros if we invert negative values
/*sint32*/ int scanvalue = value ^ (value >> 31);
// exponent is related to the number of leading bits starting from bit 14
int exponent = 7 - count_leading_zeros (scanvalue << 17);
// smallest exponent value allowed is 1
exponent = Math.max (exponent, 1);
// apply the shift back and forth to zero out bits that are lost
exponent -= 1;
return sint16 ((value >> exponent) << exponent);
}
// variants
// the YM2164 is almost 100% functionally identical to the YM2151, except
// it apparently has some mystery registers in the 00-07 range, and timer
// B's frequency is half that of the 2151
// constants
// the following constants need to be defined per family:
// uint OUTPUTS: The number of outputs exposed (1-4)
// uint CHANNELS: The number of channels on the chip
// uint ALL_CHANNELS: A bitmask of all channels
// uint OPERATORS: The number of operators on the chip
// uint WAVEFORMS: The number of waveforms offered
// uint REGISTERS: The number of 8-bit registers allocated
// uint DEFAULT_PRESCALE: The starting clock prescale
// uint EG_CLOCK_DIVIDER: The clock divider of the envelope generator
// uint CSM_TRIGGER_MASK: Mask of channels to trigger in CSM mode
// uint REG_MODE: The address of the "mode" register controlling timers
// uint8_t STATUS_TIMERA: Status bit to set when timer A fires
// uint8_t STATUS_TIMERB: Status bit to set when tiemr B fires
// uint8_t STATUS_BUSY: Status bit to set when the chip is busy
// uint8_t STATUS_IRQ: Status bit to set when an IRQ is signalled
public static final /*uint32*/ int OUTPUTS = 2;
public static final /*uint32*/ int CHANNELS = 8;
public static final /*uint32*/ int ALL_CHANNELS = (1 << CHANNELS) - 1;
public static final /*uint32*/ int OPERATORS = CHANNELS * 4;
public static final /*uint32*/ int WAVEFORMS = 1;
public static final /*uint32*/ int REGISTERS = 0x100;
public static final /*uint32*/ int DEFAULT_PRESCALE = 2;
public static final /*uint32*/ int EG_CLOCK_DIVIDER = 3;
public static final /*uint32*/ int CSM_TRIGGER_MASK = ALL_CHANNELS;
public static final /*uint32*/ int REG_MODE = 0x14;
public static final /*uint8*/ int STATUS_TIMERA = 0x01;
public static final /*uint8*/ int STATUS_TIMERB = 0x02;
public static final /*uint8*/ int STATUS_BUSY = 0x80;
public static final /*uint8*/ int STATUS_IRQ = 0;
// various envelope states
//envelope_state
public static final int EG_ATTACK = 1;
public static final int EG_DECAY = 2;
public static final int EG_SUSTAIN = 3;
public static final int EG_RELEASE = 4;
public static final int EG_STATES = 6;
// external I/O access classes
//access_class
// this value is returned from the write() function for rhythm channels
// this is the size of a full sin waveform
public static final /*uint32*/ int WAVEFORM_LENGTH = 0x400;
//struct opdata_cache
// set phase_step to this value to recalculate it each sample; needed
// in the case of PM LFO changes
public static final /*uint32*/ int PHASE_STEP_DYNAMIC = 1;
// "quiet" value, used to optimize when we can skip doing work
public static final /*uint32*/ int EG_QUIET = 0x380;
// 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
public static final /*uint16*/ int[] s_sin_table = {
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,
};
private static int X (int a) {
return (a | 0x400) << 2;
}
public static final /*uint16*/ int[] s_power_table = {
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),
};
public static final /*uint32*/ int[] s_increment_table = {
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)
};
public static final /*uint8*/ int[] s_detune_adjustment = {
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,
};
public static final /*uint32*/ int[] s_phase_step = {
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,
};
// 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
public static final /*uint8*/ int[] s_lfo_pm_shifts = {
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,
};
// LFO waveforms are 256 entries long
public static final /*uint32*/ int LFO_WAVEFORM_LENGTH = 256;
// helper to encode four operator numbers into a 32-bit value in the
// operator maps for each register class
//fm_registers_base::operator_list
private static /*uint32*/ int operator_list (/*uint8*/ int o1, /*uint8*/ int o2, /*uint8*/ int o3, /*uint8*/ int o4) {
return o1 | (o2 << 8) | (o3 << 16) | (o4 << 24);
}
// 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
//opm_registers::operator_map
public static final /*operator_mapping*/ int[] 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
};
//fm_channel::output_4op
private static int ALGORITHM (int op2in, int op3in, int op4in, int op1out, int op2out, int op3out) {
return op2in | (op3in << 1) | (op4in << 4) | (op1out << 7) | (op2out << 8) | (op3out << 9);
}
public static final /*uint16*/ int[] s_algorithm_ops = {
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]
};
public static final /*sint16*/ int[] s_detune2_delta = { 0, (600*64+50)/100, (781*64+50)/100, (950*64+50)/100 };
// three different keyon sources; actual keyon is an OR over all of these
//keyon_type
public static final int KEYON_NORMAL = 0;
public static final int KEYON_RHYTHM = 1;
public static final int KEYON_CSM = 2;
//-------------------------------------------------
// 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
//-------------------------------------------------
public static /*uint32*/ int abs_sin_attenuation (/*uint32*/ int input) {
// 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 (bitfield (input, 8) != 0) {
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
//-------------------------------------------------
public static /*uint32*/ int attenuation_to_volume (/*uint32*/ int 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
// 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)
//-------------------------------------------------
public static /*uint32*/ int attenuation_increment (/*uint32*/ int rate, /*uint32*/ int index) {
return bitfield (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
//-------------------------------------------------
public static /*sint32*/ int detune_adjustment (/*uint32*/ int detune, /*uint32*/ int keycode) {
/*sint32*/ int result = s_detune_adjustment[4 * keycode + (detune & 3)];
return bitfield (detune, 2) != 0 ? -result : result;
}
//-------------------------------------------------
// 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;
// this applies to OPM and OPZ, so it lives here
// in a central location
//-------------------------------------------------
public static /*uint32*/ int opm_key_code_to_phase_step (/*uint32*/ int block_freq, /*sint32*/ int 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.
// extract the block (octave) first
/*uint32*/ int block = bitfield (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
/*uint32*/ int adjusted_code = bitfield (block_freq, 6, 4) - bitfield (block_freq, 8, 2);
// now re-insert the 6-bit fraction
/*sint32*/ int eff_freq = (adjusted_code << 6) | bitfield (block_freq, 0, 6);
// now that the gaps are removed, add the delta
eff_freq += delta;
// handle over/underflow by adjusting the block:
if (Integer.compareUnsigned (eff_freq, 768) >= 0) {
// 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);
}
//-------------------------------------------------
// 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
//-------------------------------------------------
public static /*sint32*/ int opn_lfo_pm_phase_adjustment (/*uint32*/ int fnum_bits, /*uint32*/ int pm_sensitivity, /*sint32*/ int lfo_raw_pm) {
// look up the relevant shifts
/*sint32*/ int abs_pm = (lfo_raw_pm < 0) ? -lfo_raw_pm : lfo_raw_pm;
/*uint32*/ int shifts = s_lfo_pm_shifts[8 * pm_sensitivity + bitfield (abs_pm, 0, 3)];
// compute the adjustment
/*sint32*/ int adjust = (fnum_bits >>> bitfield (shifts, 0, 4)) + (fnum_bits >>> bitfield (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;
}
// this class holds data that is computed once at the start of clocking
// and remains static during subsequent sound generation
//struct opdata_cache
class opdata_cache {
/*uint16*/ int[] waveform; // base of sine table
/*uint32*/ int phase_step; // phase step, or PHASE_STEP_DYNAMIC if PM is active
/*uint32*/ int total_level; // total level * 8 + KSL
/*uint32*/ int block_freq; // raw block frequency value (used to compute phase_step)
/*sint32*/ int detune; // detuning value (used to compute phase_step)
/*uint32*/ int multiple; // multiple value (x.1, used to compute phase_step)
/*uint32*/ int eg_sustain; // sustain level, shifted up to envelope values
/*uint8*/ int[] eg_rate; // envelope rate, including KSR
/*uint8*/ int eg_shift; // envelope shift amount
public opdata_cache () {
eg_rate = new /*uint8*/ int[EG_STATES];
eg_shift = 0;
}
}
//class fm_registers_base
// helper to apply KSR to the raw ADSR rate, ignoring ksr if the
// raw value is 0, and clamping to 63
protected static /*uint32*/ int effective_rate (/*uint32*/ int rawrate, /*uint32*/ int ksr) {
return (rawrate == 0) ? 0 : umin32 (rawrate + ksr, 63);
}
// fm_operator represents an FM operator (or "slot" in FM parlance), which
// produces an output sine wave modulated by an envelope
class fm_operator {
// internal state
private /*uint32*/ int m_choffs; // channel offset in registers
private /*uint32*/ int m_opoffs; // operator offset in registers
private /*uint32*/ int m_phase; // current phase value (10.10 format)
public /*uint16*/ int m_env_attenuation; // computed envelope attenuation (4.6 format)
public /*envelope_state*/ int m_env_state; // current envelope state
private /*uint8*/ int m_key_state; // current key state: on or off (bit 0)
private /*uint8*/ int m_keyon_live; // live key on state (bit 0 = direct, bit 1 = rhythm, bit 2 = CSM)
private opdata_cache m_cache; // cached values for performance
// constructor
//-------------------------------------------------
// fm_operator - constructor
//-------------------------------------------------
public fm_operator (/*uint32*/ int opoffs) {
m_choffs = 0;
m_opoffs = opoffs;
m_phase = 0;
m_env_attenuation = uint16 (0x3ff);
m_env_state = EG_RELEASE;
m_key_state = uint8 (0);
m_keyon_live = uint8 (0);
m_cache = new opdata_cache ();
}
// reset the operator state
//-------------------------------------------------
// reset - reset the channel state
//-------------------------------------------------
public void reset () {
// reset our data
m_phase = 0;
m_env_attenuation = uint16 (0x3ff);
m_env_state = EG_RELEASE;
m_key_state = uint8 (0);
m_keyon_live = uint8 (0);
}
// set the current channel
public void set_choffs (/*uint32*/ int choffs) {
m_choffs = choffs;
}
// prepare prior to clocking
//-------------------------------------------------
// prepare - prepare for clocking
//-------------------------------------------------
public boolean prepare () {
// cache the data
cache_operator_data (m_choffs, m_opoffs, m_cache);
// clock the key state
clock_keystate (m_keyon_live != 0 ? 1 : 0);
//m_keyon_live &= ~(1 << KEYON_CSM);
m_keyon_live = uint8 (m_keyon_live & (~(1 << KEYON_CSM)));
// we're active until we're quiet after the release
return (m_env_state != EG_RELEASE || Integer.compareUnsigned (m_env_attenuation, EG_QUIET) < 0);
}
// master clocking function
//-------------------------------------------------
// clock - master clocking function
//-------------------------------------------------
public void clock (/*uint32*/ int env_counter, /*sint32*/ int lfo_raw_pm) {
// clock the envelope if on an envelope cycle; env_counter is a x.2 value
if (bitfield (env_counter, 0, 2) == 0) {
clock_envelope (env_counter >>> 2);
}
// clock the phase
//-------------------------------------------------
// clock_phase - clock the 10.10 phase value; the
// OPN version of the logic has been verified
// against the Nuked phase generator
//-------------------------------------------------
//fm_operator::clock_phase
// read from the cache, or recalculate if PM active
/*uint32*/ int phase_step = m_cache.phase_step;
if (phase_step == PHASE_STEP_DYNAMIC) {
phase_step = 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;
}
//fm_operator::phase
// return the current phase value
public /*uint32*/ int phase () {
return m_phase >>> 10;
}
// compute operator volume
//-------------------------------------------------
// compute_volume - compute the 14-bit signed
// volume of this operator, given a phase
// modulation and an AM LFO offset
//-------------------------------------------------
//fm_operator::compute_volume
public /*sint32*/ int compute_volume (/*uint32*/ int phase, /*uint32*/ int am_offset) {
// 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 (Integer.compareUnsigned (m_env_attenuation, EG_QUIET) > 0) {
return 0;
}
// get the absolute value of the sin, as attenuation, as a 4.8 fixed point value
/*uint32*/ int sin_attenuation = m_cache.waveform[phase & (WAVEFORM_LENGTH - 1)];
// get the attenuation from the evelope generator as a 4.6 value, shifted up to 4.8
/*uint32*/ int env_attenuation = envelope_attenuation (am_offset) << 2;
// combine into a 5.8 value, then convert from attenuation to 13-bit linear volume
/*sint32*/ int 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 bitfield (sin_attenuation, 15) != 0 ? -result : result;
}
// compute volume for the OPM noise channel
//-------------------------------------------------
// compute_noise_volume - compute the 14-bit
// signed noise volume of this operator, given a
// noise input value and an AM offset
//-------------------------------------------------
//fm_operator::compute_noise_volume
public int compute_noise_volume (/*uint32*/ int am_offset) {
// 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
/*sint32*/ int result = (envelope_attenuation (am_offset) ^ 0x3ff) << 1;
// QUESTION: is AM applied still?
// negate based on the noise state
return bitfield (noise_state (), 0) != 0 ? -result : result;
}
// key state control
//-------------------------------------------------
// keyonoff - signal a key on/off event
//-------------------------------------------------
//fm_operator::keyonoff
public void keyonoff (/*uint32*/ int on, /*keyon_type*/ int type) {
m_keyon_live = uint8 ((m_keyon_live & ~(1 << type)) | (bitfield (on, 0) << type));
}
// start the attack phase
//-------------------------------------------------
// start_attack - start the attack phase; called
// when a keyon happens or when an SSG-EG cycle
// is complete and restarts
//-------------------------------------------------
//fm_operator::start_attack
private void start_attack () {
start_attack (false);
}
private void start_attack (boolean is_restart) {
// don't change anything if already in attack state
if (m_env_state == EG_ATTACK) {
return;
}
m_env_state = EG_ATTACK;
// generally not inverted at start, except if SSG-EG is enabled and
// one of the inverted modes is specified; leave this alone on a
// restart, as it is managed by the clock_ssg_eg_state() code
// reset the phase when we start an attack due to a key on
// (but not when due to an SSG-EG restart except in certain cases
// managed directly by the SSG-EG code)
if (!is_restart) {
m_phase = 0;
}
// if the attack rate >= 62 then immediately go to max attenuation
if (Integer.compareUnsigned (m_cache.eg_rate[EG_ATTACK], 62) >= 0) {
m_env_attenuation = uint16 (0);
}
}
// start the release phase
//-------------------------------------------------
// start_release - start the release phase;
// called when a keyoff happens
//-------------------------------------------------
//fm_operator::start_release
private void start_release () {
// don't change anything if already in release state
if (m_env_state >= EG_RELEASE) {
return;
}
m_env_state = EG_RELEASE;
// if attenuation if inverted due to SSG-EG, snap the inverted attenuation
// as the starting point
}
// clock phases
//-------------------------------------------------
// clock_keystate - clock the keystate to match
// the incoming keystate
//-------------------------------------------------
//fm_operator::clock_keystate
private void clock_keystate (/*uint32*/ int keystate) {
// has the key changed?
if ((keystate ^ m_key_state) != 0) {
m_key_state = uint8 (keystate);
// if the key has turned on, start the attack
if (keystate != 0) {
// OPLL has a DP ("depress"?) state to bring the volume
// down before starting the attack
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
//-------------------------------------------------
//fm_operator::clock_ssg_eg_state
//-------------------------------------------------
// clock_envelope - clock the envelope state
// according to the given count
//-------------------------------------------------
//fm_operator::clock_envelope
private void clock_envelope (/*uint32*/ int env_counter) {
// handle attack->decay transitions
if (m_env_state == EG_ATTACK && m_env_attenuation == 0) {
m_env_state = EG_DECAY;
}
// handle decay->sustain transitions; it is important to do this immediately
// after the attack->decay transition above in the event that the sustain level
// is set to 0 (in which case we will skip right to sustain without doing any
// decay); as an example where this can be heard, check the cymbals sound
// in channel 0 of shinobi's test mode sound #5
if (m_env_state == EG_DECAY && Integer.compareUnsigned (m_env_attenuation, m_cache.eg_sustain) >= 0) {
m_env_state = EG_SUSTAIN;
}
// fetch the appropriate 6-bit rate value from the cache
/*uint32*/ int 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
/*uint32*/ int rate_shift = rate >>> 2;
env_counter <<= rate_shift;
// see if the fractional part is 0; if not, it's not time to clock
if (bitfield (env_counter, 0, 11) != 0) {
return;
}
// determine the increment based on the non-fractional part of env_counter
/*uint32*/ int relevant_bits = bitfield (env_counter, (rate_shift <= 11) ? 11 : rate_shift, 3);
/*uint32*/ int increment = attenuation_increment (rate, relevant_bits);
// attack is the only one that increases
if (m_env_state == EG_ATTACK) {
// glitch means that attack rates of 62/63 don't increment if
// changed after the initial key on (where they are handled
// specially); nukeykt confirms this happens on OPM, OPN, OPL/OPLL
// at least so assuming it is true for everyone
if (rate < 62) {
//m_env_attenuation += (~m_env_attenuation * increment) >>> 4;
m_env_attenuation = uint16 (m_env_attenuation + ((~m_env_attenuation * increment) >>> 4));
}
}
// all other cases are similar
else {
// non-SSG-EG cases just apply the increment
//m_env_attenuation += increment;
m_env_attenuation = uint16 (m_env_attenuation + increment);
// SSG-EG only applies if less than mid-point, and then at 4x
// clamp the final attenuation
if (Integer.compareUnsigned (m_env_attenuation, 0x400) >= 0) {
m_env_attenuation = uint16 (0x3ff);
}
// transition from depress to attack
// transition from release to reverb, should switch at -18dB
}
}
//fm_operator::clock_phase
// return effective attenuation of the envelope
//-------------------------------------------------
// envelope_attenuation - return the effective
// attenuation of the envelope
//-------------------------------------------------
//fm_operator::envelope_attenuation
private /*uint32*/ int envelope_attenuation (/*uint32*/ int am_offset) {
/*uint32*/ int result = m_env_attenuation >>> m_cache.eg_shift;
// invert if necessary due to SSG-EG
// add in LFO AM modulation
if (op_lfo_am_enable (m_opoffs) != 0) {
result += am_offset;
}
// add in total level and KSL from the cache
result += m_cache.total_level;
// clamp to max, apply shift, and return
return umin32 (result, 0x3ff);
}
} //class fm_operator
// fm_channel represents an FM channel which combines the output of 2 or 4
// operators into a final result
class fm_channel {
// internal state
private /*uint32*/ int m_choffs; // channel offset in registers
private /*sint16*/ int m_feedback_0, m_feedback_1; // feedback memory for operator 1
private /*sint16*/ int m_feedback_in; // next input value for op 1 feedback (set in output)
public fm_operator[] m_op; // up to 4 operators
// constructor
//-------------------------------------------------
// fm_channel - constructor
//-------------------------------------------------
//fm_channel::fm_channel
public fm_channel (/*uint32*/ int choffs) {
m_choffs = choffs;
m_feedback_0 = m_feedback_1 = sint16 (0);
m_feedback_in = sint16 (0);
m_op = new fm_operator[4];
}
// reset the channel state
//-------------------------------------------------
// reset - reset the channel state
//-------------------------------------------------
//fm_channel::reset
public void reset () {
// reset our data
m_feedback_0 = m_feedback_1 = sint16 (0);
m_feedback_in = sint16 (0);
}
//fm_channel::save_restore
// assign operators
public void assign (/*uint32*/ int index, fm_operator op) {
m_op[index] = op;
op.set_choffs (m_choffs);
}
// signal key on/off to our operators
//-------------------------------------------------
// keyonoff - signal key on/off to our operators
//-------------------------------------------------
//fm_channel::keyonoff
public void keyonoff (/*uint32*/ int states, /*keyon_type*/ int type, /*uint32*/ int chnum) {
for (/*uint32*/ int opnum = 0; opnum < 4; opnum++) {
m_op[opnum].keyonoff (bitfield (states, opnum), type);
}
}
// prepare prior to clocking
//-------------------------------------------------
// prepare - prepare for clocking
//-------------------------------------------------
//fm_channel::prepare
public boolean prepare () {
/*uint32*/ int active_mask = 0;
// prepare all operators and determine if they are active
for (/*uint32*/ int opnum = 0; opnum < 4; opnum++) {
if (m_op[opnum].prepare ()) {
active_mask |= 1 << opnum;
}
}
return (active_mask != 0);
}
// master clocking function
//-------------------------------------------------
// clock - master clock of all operators
//-------------------------------------------------
//fm_channel::clock
public void clock (/*uint32*/ int env_counter, /*sint32*/ int lfo_raw_pm) {
// clock the feedback through
m_feedback_0 = sint16 (m_feedback_1);
m_feedback_1 = sint16 (m_feedback_in);
for (/*uint32*/ int opnum = 0; opnum < 4; opnum++) {
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
//-------------------------------------------------
//fm_channel::output_2op
//-------------------------------------------------
// 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
//-------------------------------------------------
//fm_channel::output_4op
public void output_4op (/*uint32*/ int rshift, /*sint32*/ int clipmax) {
// all 4 operators should be populated
// AM amount is the same across all operators; compute it once
/*uint32*/ int am_offset = lfo_am_offset (m_choffs);
// operator 1 has optional self-feedback
/*sint32*/ int opmod = 0;
/*uint32*/ int feedback = 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
/*sint32*/ int op1value = m_feedback_in = sint16 (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 (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
/*uint32*/ int algorithm_ops = s_algorithm_ops[ch_algorithm (m_choffs)];
// populate the opout table
/*sint16*/ int[] opout = new int[8];
opout[0] = sint16 (0);
opout[1] = sint16 (op1value);
// compute the 14-bit volume/value of operator 2
opmod = opout[bitfield (algorithm_ops, 0, 1)] >> 1;
opout[2] = sint16 (m_op[1].compute_volume (m_op[1].phase () + opmod, am_offset));
opout[5] = sint16 (opout[1] + opout[2]);
// compute the 14-bit volume/value of operator 3
opmod = opout[bitfield (algorithm_ops, 1, 3)] >> 1;
opout[3] = sint16 (m_op[2].compute_volume (m_op[2].phase () + opmod, am_offset));
opout[6] = sint16 (opout[1] + opout[3]);
opout[7] = sint16 (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
/*sint32*/ int result;
if (noise_enable () != 0 && m_choffs == 7) {
result = m_op[3].compute_noise_volume (am_offset);
} else {
opmod = opout[bitfield (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
/*sint32*/ int clipmin = -clipmax - 1;
if (bitfield (algorithm_ops, 7) != 0) {
result = clamp (result + (opout[1] >> rshift), clipmin, clipmax);
}
if (bitfield (algorithm_ops, 8) != 0) {
result = clamp (result + (opout[2] >> rshift), clipmin, clipmax);
}
if (bitfield (algorithm_ops, 9) != 0) {
result = clamp (result + (opout[3] >> rshift), clipmin, clipmax);
}
// add to the output
if (ch_output_0 (m_choffs) != 0) {
buffer[pointer ] += result;
}
if (ch_output_1 (m_choffs) != 0) {
buffer[pointer + 1] += result;
}
}
} //class fm_channel
//ym2151
// internal state
private /*uint8*/ int m_address; // address register
// fm_engine_base represents a set of operators and channels which together
// form a Yamaha FM core; chips that implement other engines (ADPCM, wavetable,
// etc) take this output and combine it with the others externally
//fm_engine_base implements ymfm_engine_callbacks
//fm_engine_base
// internal state
//private ymfm_interface m_intf; // reference to the system interface
private /*uint32*/ int m_env_counter; // envelope counter; low 2 bits are sub-counter
private /*uint8*/ int m_status; // current status register
private /*uint8*/ int m_clock_prescale; // prescale factor (2/3/6)
private /*uint8*/ int m_irq_mask; // mask of which bits signal IRQs
private /*uint8*/ boolean m_irq_state; // current IRQ state
private /*uint8*/ boolean[] m_timer_running; // current timer running state
private /*uint8*/ int m_total_clocks; // low 8 bits of the total number of clocks processed
private /*uint32*/ int m_active_channels; // mask of active channels (computed by prepare)
private /*uint32*/ int m_modified_channels; // mask of channels that have been modified
private /*uint32*/ int m_prepare_count; // counter to do periodic prepare sweeps
public fm_channel[] m_channel = new fm_channel[CHANNELS]; // channel pointers
private fm_operator[] m_operator = new fm_operator[OPERATORS]; // operator pointers
//opm_registers
// OPM register map:
//
// System-wide registers:
// 01 xxxxxx-x Test register
// ------x- LFO reset
// 08 -x------ Key on/off operator 4
// --x----- Key on/off operator 3
// ---x---- Key on/off operator 2
// ----x--- Key on/off operator 1
// -----xxx Channel select
// 0F x------- Noise enable
// ---xxxxx Noise frequency
// 10 xxxxxxxx Timer A value (upper 8 bits)
// 11 ------xx Timer A value (lower 2 bits)
// 12 xxxxxxxx Timer B value
// 14 x------- CSM mode
// --x----- Reset timer B
// ---x---- Reset timer A
// ----x--- Enable timer B
// -----x-- Enable timer A
// ------x- Load timer B
// -------x Load timer A
// 18 xxxxxxxx LFO frequency
// 19 0xxxxxxx AM LFO depth
// 1xxxxxxx PM LFO depth
// 1B xx------ CT (2 output data lines)
// ------xx LFO waveform
//
// Per-channel registers (channel in address bits 0-2)
// 20-27 x------- Pan right
// -x------ Pan left
// --xxx--- Feedback level for operator 1 (0-7)
// -----xxx Operator connection algorithm (0-7)
// 28-2F -xxxxxxx Key code
// 30-37 xxxxxx-- Key fraction
// 38-3F -xxx---- LFO PM sensitivity
// ------xx LFO AM shift
//
// Per-operator registers (channel in address bits 0-2, operator in bits 3-4)
// 40-5F -xxx---- Detune value (0-7)
// ----xxxx Multiple value (0-15)
// 60-7F -xxxxxxx Total level (0-127)
// 80-9F xx------ Key scale rate (0-3)
// ---xxxxx Attack rate (0-31)
// A0-BF x------- LFO AM enable
// ---xxxxx Decay rate (0-31)
// C0-DF xx------ Detune 2 value (0-3)
// ---xxxxx Sustain rate (0-31)
// E0-FF xxxx---- Sustain level (0-15)
// ----xxxx Release rate (0-15)
//
// Internal (fake) registers:
// 1A -xxxxxxx PM depth
// internal state
protected /*uint32*/ int m_lfo_counter; // LFO counter
protected /*uint32*/ int m_noise_lfsr; // noise LFSR state
protected /*uint8*/ int m_noise_counter; // noise counter
protected /*uint8*/ int m_noise_state; // latched noise state
protected /*uint8*/ int m_noise_lfo; // latched LFO noise value
protected /*uint8*/ int m_lfo_am; // current LFO AM value
protected /*uint8*/ int[] m_regdata; // register data
protected /*sint16*/ int[] m_lfo_waveform; // LFO waveforms; AM in low 8, PM in upper 8
protected /*uint16*/ int[] m_waveform; // waveforms
public YM2151 () {
//-------------------------------------------------
// ym2151 - constructor
//-------------------------------------------------
m_address = uint8 (0);
//-------------------------------------------------
// fm_engine_base - constructor
//-------------------------------------------------
//m_intf = intf;
m_env_counter = 0;
m_status = uint8 (0);
m_clock_prescale = uint8 (DEFAULT_PRESCALE);
m_irq_mask = uint8 (STATUS_TIMERA | STATUS_TIMERB);
m_irq_state = false;
m_timer_running = new boolean[] { false, false };
m_active_channels = ALL_CHANNELS;
m_modified_channels = ALL_CHANNELS;
m_prepare_count = 0;
// inform the interface of their engine
//m_intf.m_engine = this;
// create the channels
for (/*uint32*/ int chnum = 0; chnum < CHANNELS; chnum++) {
m_channel[chnum] = new fm_channel (channel_offset (chnum));
}
// create the operators
for (/*uint32*/ int opnum = 0; opnum < OPERATORS; opnum++) {
m_operator[opnum] = new fm_operator (operator_offset (opnum));
}
// do the initial operator assignment
//-------------------------------------------------
// assign_operators - get the current mapping of
// operators to channels and assign them all
//-------------------------------------------------
//fm_engine_base::assign_operators
for (/*uint32*/ int chnum = 0; chnum < CHANNELS; chnum++) {
for (/*uint32*/ int index = 0; index < 4; index++) {
/*uint32*/ int opnum = bitfield (s_fixed_map[chnum], 8 * index, 8);
m_channel[chnum].assign (index, m_operator[opnum]);
}
}
//-------------------------------------------------
// opm_registers - constructor
//-------------------------------------------------
m_lfo_counter = 0;
m_noise_lfsr = 1;
m_noise_counter = uint8 (0);
m_noise_state = uint8 (0);
m_noise_lfo = uint8 (0);
m_lfo_am = uint8 (0);
m_regdata = new /*uint8*/ int[REGISTERS];
m_lfo_waveform = new /*sint16*/ int[LFO_WAVEFORM_LENGTH * 4];
m_waveform = new /*uint16*/ int[WAVEFORM_LENGTH * WAVEFORMS];
// create the waveforms
for (/*uint32*/ int index = 0; index < WAVEFORM_LENGTH; index++) {
m_waveform[WAVEFORM_LENGTH * 0 + index] = uint16 (abs_sin_attenuation (index) | (bitfield (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 (/*uint32*/ int index = 0; index < LFO_WAVEFORM_LENGTH; index++) {
// waveform 0 is a sawtooth
/*uint8*/ int am = uint8 (index ^ 0xff);
/*sint8*/ int pm = sint8 (index);
m_lfo_waveform[LFO_WAVEFORM_LENGTH * 0 + index] = sint16 (am | (pm << 8));
// waveform 1 is a square wave
am = uint8 (bitfield (index, 7) != 0 ? 0 : 0xff);
pm = sint8 (am ^ 0x80);
m_lfo_waveform[LFO_WAVEFORM_LENGTH * 1 + index] = sint16 (am | (pm << 8));
// waveform 2 is a triangle wave
am = uint8 (bitfield (index, 7) != 0 ? (index << 1) : ((index ^ 0xff) << 1));
pm = sint8 (bitfield (index, 6) != 0 ? am : ~am);
m_lfo_waveform[LFO_WAVEFORM_LENGTH * 2 + index] = sint16 (am | (pm << 8));
// waveform 3 is noise; it is filled in dynamically
m_lfo_waveform[LFO_WAVEFORM_LENGTH * 3 + index] = sint16 (0);
}
init2 ();
}
// reset
//-------------------------------------------------
// reset - reset the system
//-------------------------------------------------
// reset the overall state
//-------------------------------------------------
// reset - reset the overall state
//-------------------------------------------------
public void reset () {
// reset the engines
// reset all status bits
set_reset_status (0, 0xff);
// register type-specific initialization
// reset to initial state
//-------------------------------------------------
// reset - reset to initial state
//-------------------------------------------------
Arrays.fill (m_regdata, 0, REGISTERS, uint8 (0));
// enable output on both channels by default
m_regdata[0x20] = m_regdata[0x21] = m_regdata[0x22] = m_regdata[0x23] = uint8 (0xc0);
m_regdata[0x24] = m_regdata[0x25] = m_regdata[0x26] = m_regdata[0x27] = uint8 (0xc0);
// explicitly write to the mode register since it has side-effects
// QUESTION: old cores initialize this to 0x30 -- who is right?
writeAddress (REG_MODE);
writeData (0);
// reset the channels
for (fm_channel chan : m_channel) {
chan.reset ();
}
// reset the operators
for (fm_operator op : m_operator) {
op.reset ();
}
}
//-------------------------------------------------
// read_status - read the status register
//-------------------------------------------------
//public /*uint8*/ int read_status () {
public int readStatus () {
/*uint8*/ int result = uint8 (status ());
//if (m_intf.ymfm_is_busy ()) {
if (listener != null && listener.isBusy ()) {
//result |= STATUS_BUSY;
result = uint8 (result | STATUS_BUSY);
}
return uint8 (result);
}
//-------------------------------------------------
// writeAddress - handle a write to the address
// register
//-------------------------------------------------
public void writeAddress (int address) {
address &= 0xff;
// just set the address
m_address = address;
}
//-------------------------------------------------
// write - handle a write to the register
// interface
//-------------------------------------------------
public void writeData (int data) {
data &= 0xff;
if (listener != null) {
listener.written (pointer, m_address, data);
}
// write the FM register
// special case: writes to the mode register can impact IRQs;
// schedule these writes to ensure ordering with timers
if (m_address == REG_MODE) {
//m_intf.ymfm_sync_mode_write (data);
engine_mode_write (data);
return;
}
// for now just mark all channels as modified
m_modified_channels = ALL_CHANNELS;
// most writes are passive, consumed only when needed
regs_write (m_address, data);
// handle writes to the key on index
if (m_address == 0x08) {
/*uint32*/ int keyon_channel = bitfield (data, 0, 3);
/*uint32*/ int keyon_opmask = bitfield (data, 3, 4);
// handle writes to the keyon register(s)
if (keyon_channel < CHANNELS) {
// normal channel on/off
m_channel[keyon_channel].keyonoff (keyon_opmask, KEYON_NORMAL, keyon_channel);
}
}
// special cases
if (m_address == 0x1b) {
// writes to register 0x1B send the upper 2 bits to the output lines
//m_intf.ymfm_external_write (0, data >>> 6);
if (listener != null) {
listener.control ((data >>> 6) & 3);
}
}
// mark busy for a bit
//m_intf.ymfm_set_busy_end (32 * clock_prescale ());
listener.busy (32 * clock_prescale ());
}
// generate one sample of sound
//-------------------------------------------------
// generate - generate one sample of sound
//-------------------------------------------------
//ym2151::generate
public void generate (int limit) {
for (; pointer < limit; pointer += 2) {
// clock the system
//-------------------------------------------------
// clock - iterate over all channels, clocking
// them forward one step
//-------------------------------------------------
//fm_engine_base::clock
// update the clock counter
//m_total_clocks++;
m_total_clocks = uint8 (m_total_clocks + 1);
// if something was modified, prepare
// also prepare every 4k samples to catch ending notes
if (m_modified_channels != 0 || Integer.compareUnsigned (m_prepare_count++, 4096) >= 0) {
// call each channel to prepare
m_active_channels = 0;
for (/*uint32*/ int chnum = 0; chnum < CHANNELS; 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 (EG_CLOCK_DIVIDER == 1) {
m_env_counter += 4;
} else if (bitfield (++m_env_counter, 0, 2) == EG_CLOCK_DIVIDER) {
m_env_counter += 4 - EG_CLOCK_DIVIDER;
}
// clock the noise generator
/*sint32*/ int lfo_raw_pm = clock_noise_and_lfo ();
// now update the state of all the channels and operators
for (/*uint32*/ int chnum = 0; chnum < CHANNELS; chnum++) {
m_channel[chnum].clock (m_env_counter, lfo_raw_pm);
}
//ym2151::generate
// update the FM content; OPM is full 14-bit with no intermediate clipping
buffer[pointer ] = 0;
buffer[pointer + 1] = 0;
/*uint32*/ int chanmask = channelMask; //ALL_CHANNELS
//fm_engine_base::output
// mask out inactive channels
chanmask &= m_active_channels;
// sum over all the desired channels
for (/*uint32*/ int chnum = 0; chnum < CHANNELS; chnum++) {
if (bitfield (chanmask, chnum) != 0) {
m_channel[chnum].output_4op (0, 32767);
}
}
//ym2151::generate
// YM2151 uses an external DAC (YM3012) with mantissa/exponent format
// convert to 10.3 floating point value and back to simulate truncation
buffer[pointer ] = roundtrip_fp (buffer[pointer ]);
buffer[pointer + 1] = roundtrip_fp (buffer[pointer + 1]);
} //for pointer
}
//class fm_engine_base
// return the current status
//-------------------------------------------------
// status - return the current state of the
// status flags
//-------------------------------------------------
public /*uint8*/ int status () {
return uint8 (m_status & ~STATUS_BUSY);
}
// set/reset bits in the status register, updating the IRQ status
public /*uint8*/ int set_reset_status (/*uint8*/ int set, /*uint8*/ int reset) {
m_status = uint8 ((m_status | set) & ~(reset | STATUS_BUSY));
//m_intf.ymfm_sync_check_interrupts ();
engine_check_interrupts ();
return uint8 (m_status);
}
// set the IRQ mask
public void set_irq_mask (/*uint8*/ int mask) {
m_irq_mask = uint8 (mask);
//m_intf.ymfm_sync_check_interrupts ();
engine_check_interrupts ();
}
// return the current clock prescale
public /*uint32*/ int clock_prescale () {
return m_clock_prescale;
}
// set prescale factor (2/3/6)
public void set_clock_prescale (/*uint32*/ int prescale) {
m_clock_prescale = uint8 (prescale);
}
// timer callback; called by the interface when a timer fires
//-------------------------------------------------
// engine_timer_expired - timer has expired - signal
// status and possibly IRQs
//-------------------------------------------------
public void engine_timer_expired (/*uint32*/ int tnum) {
// update status
if (tnum == 0 && enable_timer_a () != 0) {
set_reset_status (STATUS_TIMERA, 0);
} else if (tnum == 1 && enable_timer_b () != 0) {
set_reset_status (STATUS_TIMERB, 0);
}
// if timer A fired in CSM mode, trigger CSM on all relevant channels
if (tnum == 0 && csm () != 0) {
for (/*uint32*/ int chnum = 0; chnum < CHANNELS; chnum++) {
if (bitfield (CSM_TRIGGER_MASK, chnum) != 0) {
m_channel[chnum].keyonoff (1, KEYON_CSM, chnum);
m_modified_channels |= 1 << chnum;
}
}
}
// reset
m_timer_running[tnum] = false;
update_timer (tnum, 1, 0);
}
// check interrupts; called by the interface after synchronization
//-------------------------------------------------
// check_interrupts - check the interrupt sources
// for interrupts
//-------------------------------------------------
public void engine_check_interrupts () {
// update the state
/*uint8*/ boolean old_state = m_irq_state;
m_irq_state = (m_status & m_irq_mask) != 0;
// set the IRQ status bit
if (m_irq_state) {
//m_status |= STATUS_IRQ;
m_status = uint8 (m_status | STATUS_IRQ);
} else {
//m_status &= ~STATUS_IRQ;
m_status = uint8 (m_status & (~STATUS_IRQ));
}
// if changed, signal the new state
if (old_state != m_irq_state) {
//m_intf.ymfm_update_irq (m_irq_state);
listener.irq (m_irq_state);
}
}
// mode register write; called by the interface after synchronization
//-------------------------------------------------
// engine_mode_write - handle a mode register write
// via timer callback
//-------------------------------------------------
public void engine_mode_write (/*uint8*/ int data) {
// mark all channels as modified
m_modified_channels = ALL_CHANNELS;
// actually write the mode register now
regs_write (REG_MODE, data);
// 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?
// reset timer status
/*uint8*/ int reset_mask = 0;
if (reset_timer_b () != 0) {
//reset_mask |= STATUS_TIMERB;
reset_mask = uint8 (reset_mask | STATUS_TIMERB);
}
if (reset_timer_a () != 0) {
//reset_mask |= STATUS_TIMERA;
reset_mask = uint8 (reset_mask | STATUS_TIMERA);
}
set_reset_status (0, reset_mask);
// load timers; note that timer B gets a small negative adjustment because
// the *16 multiplier is free-running, so the first tick of the clock
// is a bit shorter
updateTimerB (load_timer_b (), -(m_total_clocks & 15));
updateTimerA (load_timer_a (), 0);
}
protected void updateTimerA (int enable, int delta_clocks) {
update_timer (0, enable, delta_clocks);
}
protected void updateTimerB (int enable, int delta_clocks) {
update_timer (1, enable, delta_clocks);
}
// update the state of the given timer
//-------------------------------------------------
// update_timer - update the state of the given
// timer
//-------------------------------------------------
protected void update_timer (/*uint32*/ int tnum, /*uint32*/ int enable, /*sint32*/ int delta_clocks) {
// if the timer is live, but not currently enabled, set the timer
if (enable != 0 && !m_timer_running[tnum]) {
// period comes from the registers, and is different for each
/*uint32*/ int period = (tnum == 0) ? (1024 - timer_a_value ()) : 16 * (256 - timer_b_value ());
// caller can also specify a delta to account for other effects
period += delta_clocks;
// reset it
//m_intf.ymfm_set_timer (tnum, period * OPERATORS * m_clock_prescale);
if (tnum == 0) {
listener.timerA (period * OPERATORS * m_clock_prescale);
} else {
listener.timerB (period * OPERATORS * m_clock_prescale);
}
m_timer_running[tnum] = true;
}
// if the timer is not live, ensure it is not enabled
else if (enable == 0) {
//m_intf.ymfm_set_timer (tnum, -1);
if (tnum == 0) {
listener.timerA (-1);
} else {
listener.timerB (-1);
}
m_timer_running[tnum] = false;
}
}
//class opm_registers
// map channel number to register offset
public static /*uint32*/ int channel_offset (/*uint32*/ int chnum) {
return chnum;
}
// map operator number to register offset
public static /*uint32*/ int operator_offset (/*uint32*/ int opnum) {
return opnum;
}
// handle writes to the register array
//-------------------------------------------------
// write - handle writes to the register array
//-------------------------------------------------
public void regs_write (/*uint16*/ int index, /*uint8*/ int data) {
// 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 + bitfield (data, 7)] = uint8 (data);
} else if (index != 0x1a) {
m_regdata[index] = uint8 (data);
}
}
// clock the noise and LFO, if present, returning LFO PM value
//-------------------------------------------------
// clock_noise_and_lfo - clock the noise and LFO,
// handling clock division, depth, and waveform
// computations
//-------------------------------------------------
public int 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
/*uint32*/ int 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 |= bitfield (m_noise_lfsr, 17) ^ bitfield (m_noise_lfsr, 14) ^ 1;
// compare against the frequency and latch when we exceed it
//if (m_noise_counter++ >= freq) {
if (Integer.compareUnsigned ((m_noise_counter = uint8 (m_noise_counter + 1)), freq) >= 0) {
m_noise_counter = uint8 (0);
m_noise_state = uint8 (bitfield (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
/*uint32*/ int rate = lfo_rate ();
m_lfo_counter += (0x10 | bitfield (rate, 0, 4)) << bitfield (rate, 4, 4);
// bit 1 of the test register is officially undocumented but has been
// discovered to hold the LFO in reset while active
if (lfo_reset () != 0) {
m_lfo_counter = 0;
}
// now pull out the non-fractional LFO value
/*uint32*/ int lfo = bitfield (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
/*uint32*/ int lfo_noise = bitfield (m_noise_lfsr, 17, 8);
m_lfo_waveform[LFO_WAVEFORM_LENGTH * 3 + ((lfo + 1) & 0xff)] = sint16 (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
/*sint32*/ int ampm = m_lfo_waveform[LFO_WAVEFORM_LENGTH * lfo_waveform () + lfo];
// apply depth to the AM value and store for later
m_lfo_am = uint8 (((ampm & 0xff) * lfo_am_depth ()) >>> 7);
// apply depth to the PM value and return it
return ((ampm >> 8) * lfo_pm_depth ()) >> 7;
}
// return the AM offset from LFO for the given channel
//-------------------------------------------------
// lfo_am_offset - return the AM offset from LFO
// for the given channel
//-------------------------------------------------
public /*uint32*/ int lfo_am_offset (/*uint32*/ int choffs) {
// 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]
/*uint32*/ int 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);
}
// return the current noise state, gated by the noise clock
public /*uint32*/ int noise_state () {
return m_noise_state;
}
// caching helpers
//-------------------------------------------------
// cache_operator_data - fill the operator cache
// with prefetched data
//-------------------------------------------------
public void cache_operator_data (/*uint32*/ int choffs, /*uint32*/ int opoffs, opdata_cache cache) {
// set up the easy stuff
cache.waveform = m_waveform;
// get frequency from the channel
/*uint32*/ int 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)
/*uint32*/ int keycode = bitfield (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 = 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
/*uint32*/ int ksrval = keycode >>> (op_ksr (opoffs) ^ 3);
cache.eg_rate[EG_ATTACK] = uint8 (effective_rate (op_attack_rate (opoffs) * 2, ksrval));
cache.eg_rate[EG_DECAY] = uint8 (effective_rate (op_decay_rate (opoffs) * 2, ksrval));
cache.eg_rate[EG_SUSTAIN] = uint8 (effective_rate (op_sustain_rate (opoffs) * 2, ksrval));
cache.eg_rate[EG_RELEASE] = uint8 (effective_rate (op_release_rate (opoffs) * 4 + 2, ksrval));
}
// compute the phase step, given a PM value
//-------------------------------------------------
// compute_phase_step - compute the phase step
//-------------------------------------------------
public /*uint32*/ int compute_phase_step (/*uint32*/ int choffs, /*uint32*/ int opoffs, opdata_cache cache, /*sint32*/ int 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
/*sint32*/ int delta = s_detune2_delta[op_detune2 (opoffs)];
// add in the PM delta
/*uint32*/ int 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
/*uint32*/ int 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;
}
// return a bitfield extracted from a byte
private /*uint32*/ int regbyte (/*uint32*/ int offset, /*uint32*/ int start, /*uint32*/ int count) {
return bitfield (m_regdata[offset + 0], start, count);
}
private /*uint32*/ int regbyte (/*uint32*/ int offset, /*uint32*/ int start, /*uint32*/ int count, /*uint32*/ int extra_offset) {
return bitfield (m_regdata[offset + extra_offset], start, count);
}
// return a bitfield extracted from a pair of bytes, MSBs listed first
private /*uint32*/ int regword (/*uint32*/ int offset1, /*uint32*/ int start1, /*uint32*/ int count1, /*uint32*/ int offset2, /*uint32*/ int start2, /*uint32*/ int count2) {
return (regbyte (offset1, start1, count1, 0) << count2) | regbyte (offset2, start2, count2, 0);
}
private /*uint32*/ int regword (/*uint32*/ int offset1, /*uint32*/ int start1, /*uint32*/ int count1, /*uint32*/ int offset2, /*uint32*/ int start2, /*uint32*/ int count2, /*uint32*/ int extra_offset) {
return (regbyte (offset1, start1, count1, extra_offset) << count2) | regbyte (offset2, start2, count2, extra_offset);
}
// system-wide registers
public /*uint32*/ int test () {
return regbyte (0x01, 0, 8);
}
public /*uint32*/ int lfo_reset () {
return regbyte (0x01, 1, 1);
}
public /*uint32*/ int noise_frequency () {
return regbyte (0x0f, 0, 5) ^ 0x1f;
}
public /*uint32*/ int noise_enable () {
return regbyte (0x0f, 7, 1);
}
public /*uint32*/ int timer_a_value () {
return regword (0x10, 0, 8, 0x11, 0, 2);
}
public /*uint32*/ int timer_b_value () {
return regbyte (0x12, 0, 8);
}
public /*uint32*/ int csm () {
return regbyte (0x14, 7, 1);
}
public /*uint32*/ int reset_timer_b () {
return regbyte (0x14, 5, 1);
}
public /*uint32*/ int reset_timer_a () {
return regbyte (0x14, 4, 1);
}
public /*uint32*/ int enable_timer_b () {
return regbyte (0x14, 3, 1);
}
public /*uint32*/ int enable_timer_a () {
return regbyte (0x14, 2, 1);
}
public /*uint32*/ int load_timer_b () {
return regbyte (0x14, 1, 1);
}
public /*uint32*/ int load_timer_a () {
return regbyte (0x14, 0, 1);
}
public /*uint32*/ int lfo_rate () {
return regbyte (0x18, 0, 8);
}
public /*uint32*/ int lfo_am_depth () {
return regbyte (0x19, 0, 7);
}
public /*uint32*/ int lfo_pm_depth () {
return regbyte (0x1a, 0, 7);
}
public /*uint32*/ int output_bits () {
return regbyte (0x1b, 6, 2);
}
public /*uint32*/ int lfo_waveform () {
return regbyte (0x1b, 0, 2);
}
// per-channel registers
public /*uint32*/ int ch_output_any (/*uint32*/ int choffs) {
return regbyte (0x20, 6, 2, choffs);
}
public /*uint32*/ int ch_output_0 (/*uint32*/ int choffs) {
return regbyte (0x20, 6, 1, choffs);
}
public /*uint32*/ int ch_output_1 (/*uint32*/ int choffs) {
return regbyte (0x20, 7, 1, choffs);
}
public /*uint32*/ int ch_feedback (/*uint32*/ int choffs) {
return regbyte (0x20, 3, 3, choffs);
}
public /*uint32*/ int ch_algorithm (/*uint32*/ int choffs) {
return regbyte (0x20, 0, 3, choffs);
}
public /*uint32*/ int ch_block_freq (/*uint32*/ int choffs) {
return regword (0x28, 0, 7, 0x30, 2, 6, choffs);
}
public /*uint32*/ int ch_lfo_pm_sens (/*uint32*/ int choffs) {
return regbyte (0x38, 4, 3, choffs);
}
public /*uint32*/ int ch_lfo_am_sens (/*uint32*/ int choffs) {
return regbyte (0x38, 0, 2, choffs);
}
// per-operator registers
public /*uint32*/ int op_detune (/*uint32*/ int opoffs) {
return regbyte (0x40, 4, 3, opoffs);
}
public /*uint32*/ int op_multiple (/*uint32*/ int opoffs) {
return regbyte (0x40, 0, 4, opoffs);
}
public /*uint32*/ int op_total_level (/*uint32*/ int opoffs) {
return regbyte (0x60, 0, 7, opoffs);
}
public /*uint32*/ int op_ksr (/*uint32*/ int opoffs) {
return regbyte (0x80, 6, 2, opoffs);
}
public /*uint32*/ int op_attack_rate (/*uint32*/ int opoffs) {
return regbyte (0x80, 0, 5, opoffs);
}
public /*uint32*/ int op_lfo_am_enable (/*uint32*/ int opoffs) {
return regbyte (0xa0, 7, 1, opoffs);
}
public /*uint32*/ int op_decay_rate (/*uint32*/ int opoffs) {
return regbyte (0xa0, 0, 5, opoffs);
}
public /*uint32*/ int op_detune2 (/*uint32*/ int opoffs) {
return regbyte (0xc0, 6, 2, opoffs);
}
public /*uint32*/ int op_sustain_rate (/*uint32*/ int opoffs) {
return regbyte (0xc0, 0, 5, opoffs);
}
public /*uint32*/ int op_sustain_level (/*uint32*/ int opoffs) {
return regbyte (0xe0, 4, 4, opoffs);
}
public /*uint32*/ int op_release_rate (/*uint32*/ int opoffs) {
return regbyte (0xe0, 0, 4, opoffs);
}
// this class represents the interface between the fm_engine and the outside
// world; it provides hooks for timers, synchronization, and I/O
//class ymfm_interface
static interface Listener {
// the following functions must be implemented by any derived classes; the
// default implementations are sufficient for some minimal operation, but will
// likely need to be overridden to integrate with the outside world; they are
// all prefixed with ymfm_ to reduce the likelihood of namespace collisions
//
// timing and synchronizaton
//
// the chip implementation calls this when a write happens to the mode
// register, which could affect timers and interrupts; our responsibility
// is to ensure the system is up to date before calling the engine's
// engine_mode_write() method
//public void ymfm_sync_mode_write (/*uint8*/ int data);
// the chip implementation calls this when the chip's status has changed,
// which may affect the interrupt state; our responsibility is to ensure
// the system is up to date before calling the engine's
// engine_check_interrupts() method
//public void ymfm_sync_check_interrupts ();
// the chip implementation calls this when one of the two internal timers
// has changed state; our responsibility is to arrange to call the engine's
// engine_timer_expired() method after the provided number of clocks; if
// duration_in_clocks is negative, we should cancel any outstanding timers
//public void ymfm_set_timer (/*uint32*/ int tnum, int duration_in_clocks);
//timerA (clocks)
// タイマーAが始動または停止した
// clocks -1以外 始動。タイマーAがオーバーフローするまでの時間
// -1 停止
public void timerA (int clocks);
//timerB (clocks)
// タイマーBが始動または停止した
// clocks -1以外 始動。タイマーBがオーバーフローするまでの時間
// -1 停止
public void timerB (int clocks);
// the chip implementation calls this to indicate that the chip should be
// considered in a busy state until the given number of clocks has passed;
// our responsibility is to compute and remember the ending time based on
// the chip's clock for later checking
//public void ymfm_set_busy_end (/*uint32*/ int clocks);
//busy (clocks)
// BUSYがセットされた
// clocks BUSYがクリアされるまでの時間
public void busy (int clocks);
// the chip implementation calls this to see if the chip is still currently
// is a busy state, as specified by a previous call to ymfm_set_busy_end();
// our responsibility is to compare the current time against the previously
// noted busy end time and return true if we haven't yet passed it
//public boolean ymfm_is_busy ();
//busy = isBusy ()
// busy true BUSYがセットされている
// false BUSYがセットされていない
public boolean isBusy ();
//
// I/O functions
//
// the chip implementation calls this when the state of the IRQ signal has
// changed due to a status change; our responsibility is to respond as
// needed to the change in IRQ state, signaling any consumers
//public void ymfm_update_irq (boolean asserted);
//irq (asserted)
// IRQが変化した
// asserted false IRQがネゲートされた
// true IRQがアサートされた
public void irq (boolean asserted);
// the chip implementation calls this whenever data is read from outside
// of the chip; our responsibility is to provide the data requested
//public /*uint8*/ int ymfm_external_read (/*access_class*/ int type, /*uint32*/ int address);
// the chip implementation calls this whenever data is written outside
// of the chip; our responsibility is to pass the written data on to any consumers
//public void ymfm_external_write (/*uint32*/ int address, /*uint8*/ int data);
//control (data)
// コントロール
// data CT1<<1|CT2
public void control (int data);
//written (pointer, address, data)
// データレジスタへ書き込まれた
public void written (int pointer, int address, int data);
} //interface Listener
private Listener listener; //リスナー
private int[] buffer; //バッファ
private int pointer; //バッファのポインタ
private int channelMask; //チャンネルマスク
//init2 ()
private void init2 () {
listener = null;
buffer = new int[2 * 62500 * 5]; //5s
pointer = 0;
channelMask = ALL_CHANNELS;
}
//setListener (listener)
// リスナーを設定する
public void setListener (Listener listener) {
this.listener = listener;
}
//allocate (size)
// バッファを確保する
// バッファはクリアされる
// ポインタは先頭に戻る
public void allocate (int size) {
buffer = new int[size];
Arrays.fill (buffer, 0);
pointer = 0;
}
//clear ()
// バッファをクリアする
// ポインタは先頭に戻る
// チップは変化しない
public void clear () {
Arrays.fill (buffer, 0);
pointer = 0;
}
//buffer = getBuffer ()
// バッファを返す
public int[] getBuffer () {
return buffer;
}
//pointer = getPointer ()
// ポインタを返す
public int getPointer () {
return pointer;
}
//reset ()
// チップをリセットする
// バッファは変化しない
//public void reset () {
//}
//generate (limit)
// バッファを構築する
//public void generate (int limit) {
//}
//fill ()
// バッファを最後まで構築する
public void fill () {
generate (buffer.length);
}
//readStatus ()
// ステータスレジスタから読み出す
//public int readStatus () {
//}
//writeAddress (address)
// アドレスレジスタへ書き込む
//public void writeAddress (int address) {
//}
//writeData (data)
// データレジスタへ書き込む
//public void writeData (int data) {
//}
//setChannelMask (mask)
// チャンネルマスクを設定する
public void setChannelMask (int mask) {
channelMask = mask;
}
//timerAExpired ()
// タイマーAがオーバーフローした
public void timerAExpired () {
engine_timer_expired (0);
}
//timerBExpired ()
// タイマーBがオーバーフローした
public void timerBExpired () {
engine_timer_expired (1);
}
} //class YM2151