// 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. #include "ymfm_opl.h" #include "ymfm_fm.ipp" namespace ymfm { //------------------------------------------------- // 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 uint32_t opl_key_scale_atten(uint32_t block, uint32_t 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 uint8_t const fnum_to_atten[16] = { 0,24,32,37,40,43,45,47,48,50,51,52,53,54,55,56 }; int32_t result = fnum_to_atten[fnum_4msb] - 8 * (block ^ 7); return std::max(0, result); } //********************************************************* // OPL REGISTERS //********************************************************* //------------------------------------------------- // opl_registers_base - constructor //------------------------------------------------- template opl_registers_base::opl_registers_base() : m_lfo_am_counter(0), m_lfo_pm_counter(0), m_noise_lfsr(1), m_lfo_am(0) { // create these pointers to appease overzealous compilers checking array // bounds in unreachable code (looking at you, clang) uint16_t *wf0 = &m_waveform[0][0]; uint16_t *wf1 = &m_waveform[1 % WAVEFORMS][0]; uint16_t *wf2 = &m_waveform[2 % WAVEFORMS][0]; uint16_t *wf3 = &m_waveform[3 % WAVEFORMS][0]; uint16_t *wf4 = &m_waveform[4 % WAVEFORMS][0]; uint16_t *wf5 = &m_waveform[5 % WAVEFORMS][0]; uint16_t *wf6 = &m_waveform[6 % WAVEFORMS][0]; uint16_t *wf7 = &m_waveform[7 % WAVEFORMS][0]; // create the waveforms for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) wf0[index] = abs_sin_attenuation(index) | (bitfield(index, 9) << 15); if (WAVEFORMS >= 4) { uint16_t zeroval = wf0[0]; for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) { wf1[index] = bitfield(index, 9) ? zeroval : wf0[index]; wf2[index] = wf0[index] & 0x7fff; wf3[index] = bitfield(index, 8) ? zeroval : (wf0[index] & 0x7fff); if (WAVEFORMS >= 8) { wf4[index] = bitfield(index, 9) ? zeroval : wf0[index * 2]; wf5[index] = bitfield(index, 9) ? zeroval : wf0[(index * 2) & 0x1ff]; wf6[index] = bitfield(index, 9) << 15; wf7[index] = (bitfield(index, 9) ? (index ^ 0x13ff) : index) << 3; } } } // OPL3/OPL4 have dynamic operators, so initialize the fourop_enable value here // since operator_map() is called right away, prior to reset() if (Revision > 2) m_regdata[0x104 % REGISTERS] = 0; } //------------------------------------------------- // reset - reset to initial state //------------------------------------------------- template void opl_registers_base::reset() { std::fill_n(&m_regdata[0], REGISTERS, 0); } //------------------------------------------------- // save_restore - save or restore the data //------------------------------------------------- template void opl_registers_base::save_restore(ymfm_saved_state &state) { state.save_restore(m_lfo_am_counter); state.save_restore(m_lfo_pm_counter); state.save_restore(m_lfo_am); state.save_restore(m_noise_lfsr); state.save_restore(m_regdata); } //------------------------------------------------- // operator_map - return an array of operator // indices for each channel; for OPL this is fixed //------------------------------------------------- template void opl_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 uint32_t fourop = fourop_enable(); dest.chan[ 0] = bitfield(fourop, 0) ? operator_list( 0, 3, 6, 9 ) : operator_list( 0, 3 ); dest.chan[ 1] = bitfield(fourop, 1) ? operator_list( 1, 4, 7, 10 ) : operator_list( 1, 4 ); dest.chan[ 2] = bitfield(fourop, 2) ? operator_list( 2, 5, 8, 11 ) : operator_list( 2, 5 ); dest.chan[ 3] = bitfield(fourop, 0) ? operator_list() : operator_list( 6, 9 ); dest.chan[ 4] = bitfield(fourop, 1) ? operator_list() : operator_list( 7, 10 ); dest.chan[ 5] = bitfield(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] = bitfield(fourop, 3) ? operator_list( 18, 21, 24, 27 ) : operator_list( 18, 21 ); dest.chan[10] = bitfield(fourop, 4) ? operator_list( 19, 22, 25, 28 ) : operator_list( 19, 22 ); dest.chan[11] = bitfield(fourop, 5) ? operator_list( 20, 23, 26, 29 ) : operator_list( 20, 23 ); dest.chan[12] = bitfield(fourop, 3) ? operator_list() : operator_list( 24, 27 ); dest.chan[13] = bitfield(fourop, 4) ? operator_list() : operator_list( 25, 28 ); dest.chan[14] = bitfield(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 opl_registers_base::write(uint16_t index, uint8_t data, uint32_t &channel, uint32_t &opmask) { assert(index < REGISTERS); // writes to the mode register with high bit set ignore the low bits if (index == REG_MODE && bitfield(data, 7) != 0) m_regdata[index] |= 0x80; else m_regdata[index] = data; // handle writes to the rhythm keyons if (index == 0xbd) { channel = RHYTHM_CHANNEL; opmask = bitfield(data, 5) ? bitfield(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 * bitfield(index, 8); opmask = bitfield(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 int32_t opl_clock_noise_and_lfo(uint32_t &noise_lfsr, uint16_t &lfo_am_counter, uint16_t &lfo_pm_counter, uint8_t &lfo_am, uint32_t am_depth, uint32_t 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 |= bitfield(noise_lfsr, 23) ^ bitfield(noise_lfsr, 9) ^ bitfield(noise_lfsr, 8) ^ bitfield(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 uint32_t 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 uint32_t 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 int8_t const pm_scale[8] = { 8, 4, 0, -4, -8, -4, 0, 4 }; return pm_scale[bitfield(pm_counter, 10, 3)] >> (pm_depth ^ 1); } template int32_t opl_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 opl_registers_base::cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache) { // set up the easy stuff cache.waveform = &m_waveform[op_waveform(opoffs) % WAVEFORMS][0]; // get frequency from the channel uint32_t 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 uint32_t keycode = bitfield(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 |= bitfield(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 uint32_t multiple = op_multiple(opoffs); cache.multiple = ((multiple & 0xe) | bitfield(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 = opdata_cache::PHASE_STEP_DYNAMIC; // total level, scaled by 8 cache.total_level = op_total_level(opoffs) << 3; // pre-add key scale level uint32_t ksl = op_ksl(opoffs); if (ksl != 0) cache.total_level += opl_key_scale_atten(bitfield(block_freq, 10, 3), bitfield(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 uint32_t ksrval = keycode >> (2 * (op_ksr(opoffs) ^ 1)); cache.eg_rate[EG_ATTACK] = effective_rate(op_attack_rate(opoffs) * 4, ksrval); cache.eg_rate[EG_DECAY] = effective_rate(op_decay_rate(opoffs) * 4, ksrval); cache.eg_rate[EG_SUSTAIN] = op_eg_sustain(opoffs) ? 0 : effective_rate(op_release_rate(opoffs) * 4, ksrval); cache.eg_rate[EG_RELEASE] = effective_rate(op_release_rate(opoffs) * 4, ksrval); cache.eg_rate[EG_DEPRESS] = 0x3f; } //------------------------------------------------- // compute_phase_step - compute the phase step //------------------------------------------------- static uint32_t opl_compute_phase_step(uint32_t block_freq, uint32_t multiple, int32_t 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 uint32_t fnum = bitfield(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 * bitfield(block_freq, 7, 3)) >> 1; // keep fnum to 12 bits fnum &= 0xfff; // apply block shift to compute phase step uint32_t block = bitfield(block_freq, 10, 3); uint32_t phase_step = (fnum << block) >> 2; // apply frequency multiplier (which is cached as an x.1 value) return (phase_step * multiple) >> 1; } template uint32_t opl_registers_base::compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t 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 std::string opl_registers_base::log_keyon(uint32_t choffs, uint32_t opoffs) { uint32_t chnum = (choffs & 15) + 9 * bitfield(choffs, 8); uint32_t opnum = (opoffs & 31) - 2 * ((opoffs & 31) / 8) + 18 * bitfield(opoffs, 8); char buffer[256]; char *end = &buffer[0]; end += sprintf(end, "%2u.%02u freq=%04X fb=%u alg=%X mul=%X tl=%02X ksr=%u ns=%u ksl=%u adr=%X/%X/%X sl=%X sus=%u", 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) end += sprintf(end, " 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) end += sprintf(end, " am=%u", lfo_am_depth()); if (op_lfo_pm_enable(opoffs) != 0) end += sprintf(end, " pm=%u", lfo_pm_depth()); if (waveform_enable() && op_waveform(opoffs) != 0) end += sprintf(end, " wf=%u", op_waveform(opoffs)); if (is_rhythm(choffs)) end += sprintf(end, " rhy=1"); if (DYNAMIC_OPS) { operator_mapping map; operator_map(map); if (bitfield(map.chan[chnum], 16, 8) != 0xff) end += sprintf(end, " 4op"); } return buffer; } //********************************************************* // OPLL SPECIFICS //********************************************************* //------------------------------------------------- // opll_registers - constructor //------------------------------------------------- opll_registers::opll_registers() : m_lfo_am_counter(0), m_lfo_pm_counter(0), m_noise_lfsr(1), m_lfo_am(0) { // create the waveforms for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) m_waveform[0][index] = abs_sin_attenuation(index) | (bitfield(index, 9) << 15); uint16_t zeroval = m_waveform[0][0]; for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) m_waveform[1][index] = bitfield(index, 9) ? zeroval : m_waveform[0][index]; // initialize the instruments to something sane for (uint32_t choffs = 0; choffs < CHANNELS; choffs++) m_chinst[choffs] = &m_regdata[0]; for (uint32_t opoffs = 0; opoffs < OPERATORS; opoffs++) m_opinst[opoffs] = &m_regdata[bitfield(opoffs, 0)]; } //------------------------------------------------- // reset - reset to initial state //------------------------------------------------- void opll_registers::reset() { std::fill_n(&m_regdata[0], REGISTERS, 0); } //------------------------------------------------- // save_restore - save or restore the data //------------------------------------------------- void opll_registers::save_restore(ymfm_saved_state &state) { state.save_restore(m_lfo_am_counter); state.save_restore(m_lfo_pm_counter); state.save_restore(m_lfo_am); state.save_restore(m_noise_lfsr); state.save_restore(m_regdata); } //------------------------------------------------- // operator_map - return an array of operator // indices for each channel; for OPLL this is fixed //------------------------------------------------- void opll_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 opll_registers::write(uint16_t index, uint8_t data, uint32_t &channel, uint32_t &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) return false; // write the new data m_regdata[index] = data; // handle writes to the rhythm keyons if (index == 0x0e) { channel = RHYTHM_CHANNEL; opmask = bitfield(data, 5) ? bitfield(data, 0, 5) : 0; return true; } // handle writes to the channel keyons if ((index & 0xf0) == 0x20) { channel = index & 0x0f; if (channel < CHANNELS) { opmask = bitfield(data, 4) ? 3 : 0; return true; } } return false; } //------------------------------------------------- // clock_noise_and_lfo - clock the noise and LFO, // handling clock division, depth, and waveform // computations //------------------------------------------------- int32_t opll_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 opll_registers::cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache) { // first set up the instrument data uint32_t 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] + bitfield(opoffs, 0); // set up the easy stuff cache.waveform = &m_waveform[op_waveform(opoffs) % WAVEFORMS][0]; // get frequency from the channel uint32_t 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 uint32_t keycode = bitfield(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 uint32_t multiple = op_multiple(opoffs); cache.multiple = ((multiple & 0xe) | bitfield(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 = 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 (bitfield(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 uint32_t ksl = op_ksl(opoffs); if (ksl != 0) cache.total_level += opl_key_scale_atten(bitfield(block_freq, 9, 3), bitfield(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 uint8_t DP = 12 * 4; constexpr uint8_t RR = 7 * 4; constexpr uint8_t RS = 5 * 4; // determine KSR adjustment for envelope rates uint32_t ksrval = keycode >> (2 * (op_ksr(opoffs) ^ 1)); cache.eg_rate[EG_DEPRESS] = DP; cache.eg_rate[EG_ATTACK] = effective_rate(op_attack_rate(opoffs) * 4, ksrval); cache.eg_rate[EG_DECAY] = effective_rate(op_decay_rate(opoffs) * 4, ksrval); if (op_eg_sustain(opoffs)) { cache.eg_rate[EG_SUSTAIN] = 0; cache.eg_rate[EG_RELEASE] = ch_sustain(choffs) ? RS : effective_rate(op_release_rate(opoffs) * 4, ksrval); } else { cache.eg_rate[EG_SUSTAIN] = effective_rate(op_release_rate(opoffs) * 4, ksrval); cache.eg_rate[EG_RELEASE] = ch_sustain(choffs) ? RS : RR; } } //------------------------------------------------- // compute_phase_step - compute the phase step //------------------------------------------------- uint32_t opll_registers::compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t 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 //------------------------------------------------- std::string opll_registers::log_keyon(uint32_t choffs, uint32_t opoffs) { uint32_t chnum = choffs; uint32_t opnum = opoffs; char buffer[256]; char *end = &buffer[0]; end += sprintf(end, "%u.%02u freq=%04X inst=%X fb=%u mul=%X", chnum, opnum, ch_block_freq(choffs), ch_instrument(choffs), ch_feedback(choffs), op_multiple(opoffs)); if (bitfield(opoffs, 0) == 1 || (is_rhythm(choffs) && choffs >= 6)) end += sprintf(end, " vol=%X", op_volume(opoffs)); else end += sprintf(end, " tl=%02X", ch_total_level(choffs)); end += sprintf(end, " ksr=%u ksl=%u adr=%X/%X/%X sl=%X sus=%u/%u", 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)) end += sprintf(end, " am=1"); if (op_lfo_pm_enable(opoffs)) end += sprintf(end, " pm=1"); if (op_waveform(opoffs) != 0) end += sprintf(end, " wf=1"); if (is_rhythm(choffs)) end += sprintf(end, " rhy=1"); return buffer; } //********************************************************* // YM3526 //********************************************************* //------------------------------------------------- // ym3526 - constructor //------------------------------------------------- ym3526::ym3526(ymfm_interface &intf) : m_address(0), m_fm(intf) { } //------------------------------------------------- // reset - reset the system //------------------------------------------------- void ym3526::reset() { // reset the engines m_fm.reset(); } //------------------------------------------------- // save_restore - save or restore the data //------------------------------------------------- void ym3526::save_restore(ymfm_saved_state &state) { state.save_restore(m_address); m_fm.save_restore(state); } //------------------------------------------------- // read_status - read the status register //------------------------------------------------- uint8_t ym3526::read_status() { return m_fm.status() | 0x06; } //------------------------------------------------- // read - handle a read from the device //------------------------------------------------- uint8_t ym3526::read(uint32_t offset) { uint8_t result = 0xff; switch (offset & 1) { case 0: // status port result = read_status(); break; case 1: // when A0=1 datasheet says "the data on the bus are not guaranteed" break; } return result; } //------------------------------------------------- // write_address - handle a write to the address // register //------------------------------------------------- void ym3526::write_address(uint8_t data) { // YM3526 doesn't expose a busy signal, and the datasheets don't indicate // delays, but all other OPL chips need 12 cycles for address writes m_fm.intf().ymfm_set_busy_end(12 * m_fm.clock_prescale()); // just set the address m_address = data; } //------------------------------------------------- // write - handle a write to the register // interface //------------------------------------------------- void ym3526::write_data(uint8_t data) { // YM3526 doesn't expose a busy signal, and the datasheets don't indicate // delays, but all other OPL chips need 84 cycles for data writes m_fm.intf().ymfm_set_busy_end(84 * m_fm.clock_prescale()); // write to FM m_fm.write(m_address, data); } //------------------------------------------------- // write - handle a write to the register // interface //------------------------------------------------- void ym3526::write(uint32_t offset, uint8_t data) { switch (offset & 1) { case 0: // address port write_address(data); break; case 1: // data port write_data(data); break; } } //------------------------------------------------- // generate - generate samples of sound //------------------------------------------------- void ym3526::generate(output_data *output, uint32_t numsamples) { for (uint32_t samp = 0; samp < numsamples; samp++, output++) { // clock the system m_fm.clock(fm_engine::ALL_CHANNELS); // update the FM content; mixing details for YM3526 need verification m_fm.output(output->clear(), 1, 32767, fm_engine::ALL_CHANNELS); // YM3526 uses an external DAC (YM3014) with mantissa/exponent format // convert to 10.3 floating point value and back to simulate truncation output->roundtrip_fp(); } } //********************************************************* // Y8950 //********************************************************* //------------------------------------------------- // y8950 - constructor //------------------------------------------------- y8950::y8950(ymfm_interface &intf) : m_address(0), m_io_ddr(0), m_fm(intf), m_adpcm_b(intf) { } //------------------------------------------------- // reset - reset the system //------------------------------------------------- void y8950::reset() { // reset the engines m_fm.reset(); m_adpcm_b.reset(); } //------------------------------------------------- // save_restore - save or restore the data //------------------------------------------------- void y8950::save_restore(ymfm_saved_state &state) { state.save_restore(m_address); state.save_restore(m_io_ddr); m_fm.save_restore(state); } //------------------------------------------------- // read_status - read the status register //------------------------------------------------- uint8_t y8950::read_status() { // start with current FM status, masking out bits we might set uint8_t status = m_fm.status() & ~(STATUS_ADPCM_B_EOS | STATUS_ADPCM_B_BRDY | STATUS_ADPCM_B_PLAYING); // insert the live ADPCM status bits uint8_t adpcm_status = m_adpcm_b.status(); if ((adpcm_status & adpcm_b_channel::STATUS_EOS) != 0) status |= STATUS_ADPCM_B_EOS; if ((adpcm_status & adpcm_b_channel::STATUS_BRDY) != 0) status |= STATUS_ADPCM_B_BRDY; if ((adpcm_status & adpcm_b_channel::STATUS_PLAYING) != 0) status |= STATUS_ADPCM_B_PLAYING; // run it through the FM engine to handle interrupts for us return m_fm.set_reset_status(status, ~status); } //------------------------------------------------- // read_data - read the data port //------------------------------------------------- uint8_t y8950::read_data() { uint8_t result = 0xff; switch (m_address) { case 0x05: // keyboard in result = m_fm.intf().ymfm_external_read(ACCESS_IO, 1); break; case 0x09: // ADPCM data case 0x1a: result = m_adpcm_b.read(m_address - 0x07); break; case 0x19: // I/O data result = m_fm.intf().ymfm_external_read(ACCESS_IO, 0); break; default: debug::log_unexpected_read_write("Unexpected read from Y8950 data port %02X\n", m_address); break; } return result; } //------------------------------------------------- // read - handle a read from the device //------------------------------------------------- uint8_t y8950::read(uint32_t offset) { uint8_t result = 0xff; switch (offset & 1) { case 0: // status port result = read_status(); break; case 1: // when A0=1 datasheet says "the data on the bus are not guaranteed" result = read_data(); break; } return result; } //------------------------------------------------- // write_address - handle a write to the address // register //------------------------------------------------- void y8950::write_address(uint8_t data) { // Y8950 doesn't expose a busy signal, but it does indicate that // address writes should be no faster than every 12 clocks m_fm.intf().ymfm_set_busy_end(12 * m_fm.clock_prescale()); // just set the address m_address = data; } //------------------------------------------------- // write - handle a write to the register // interface //------------------------------------------------- void y8950::write_data(uint8_t data) { // Y8950 doesn't expose a busy signal, but it does indicate that // data writes should be no faster than every 12 clocks for // registers 00-1A, or every 84 clocks for other registers m_fm.intf().ymfm_set_busy_end(((m_address <= 0x1a) ? 12 : 84) * m_fm.clock_prescale()); // handle special addresses switch (m_address) { case 0x04: // IRQ control m_fm.write(m_address, data); read_status(); break; case 0x06: // keyboard out m_fm.intf().ymfm_external_write(ACCESS_IO, 1, data); break; case 0x08: // split FM/ADPCM-B m_adpcm_b.write(m_address - 0x07, (data & 0x0f) | 0x80); m_fm.write(m_address, data & 0xc0); break; case 0x07: // ADPCM-B registers case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10: case 0x11: case 0x12: case 0x15: case 0x16: case 0x17: m_adpcm_b.write(m_address - 0x07, data); break; case 0x18: // I/O direction m_io_ddr = data & 0x0f; break; case 0x19: // I/O data m_fm.intf().ymfm_external_write(ACCESS_IO, 0, data & m_io_ddr); break; default: // everything else to FM m_fm.write(m_address, data); break; } } //------------------------------------------------- // write - handle a write to the register // interface //------------------------------------------------- void y8950::write(uint32_t offset, uint8_t data) { switch (offset & 1) { case 0: // address port write_address(data); break; case 1: // data port write_data(data); break; } } //------------------------------------------------- // generate - generate samples of sound //------------------------------------------------- void y8950::generate(output_data *output, uint32_t numsamples) { for (uint32_t samp = 0; samp < numsamples; samp++, output++) { // clock the system m_fm.clock(fm_engine::ALL_CHANNELS); m_adpcm_b.clock(); // update the FM content; clipping need verification m_fm.output(output->clear(), 1, 32767, fm_engine::ALL_CHANNELS); // mix in the ADPCM; ADPCM-B is stereo, but only one channel // not sure how it's wired up internally m_adpcm_b.output(*output, 3); // Y8950 uses an external DAC (YM3014) with mantissa/exponent format // convert to 10.3 floating point value and back to simulate truncation output->roundtrip_fp(); } } //********************************************************* // YM3812 //********************************************************* //------------------------------------------------- // ym3812 - constructor //------------------------------------------------- ym3812::ym3812(ymfm_interface &intf) : m_address(0), m_fm(intf) { } //------------------------------------------------- // reset - reset the system //------------------------------------------------- void ym3812::reset() { // reset the engines m_fm.reset(); } //------------------------------------------------- // save_restore - save or restore the data //------------------------------------------------- void ym3812::save_restore(ymfm_saved_state &state) { state.save_restore(m_address); m_fm.save_restore(state); } //------------------------------------------------- // read_status - read the status register //------------------------------------------------- uint8_t ym3812::read_status() { return m_fm.status() | 0x06; } //------------------------------------------------- // read - handle a read from the device //------------------------------------------------- uint8_t ym3812::read(uint32_t offset) { uint8_t result = 0xff; switch (offset & 1) { case 0: // status port result = read_status(); break; case 1: // "inhibit" according to datasheet break; } return result; } //------------------------------------------------- // write_address - handle a write to the address // register //------------------------------------------------- void ym3812::write_address(uint8_t data) { // YM3812 doesn't expose a busy signal, but it does indicate that // address writes should be no faster than every 12 clocks m_fm.intf().ymfm_set_busy_end(12 * m_fm.clock_prescale()); // just set the address m_address = data; } //------------------------------------------------- // write - handle a write to the register // interface //------------------------------------------------- void ym3812::write_data(uint8_t data) { // YM3812 doesn't expose a busy signal, but it does indicate that // data writes should be no faster than every 84 clocks m_fm.intf().ymfm_set_busy_end(84 * m_fm.clock_prescale()); // write to FM m_fm.write(m_address, data); } //------------------------------------------------- // write - handle a write to the register // interface //------------------------------------------------- void ym3812::write(uint32_t offset, uint8_t data) { switch (offset & 1) { case 0: // address port write_address(data); break; case 1: // data port write_data(data); break; } } //------------------------------------------------- // generate - generate samples of sound //------------------------------------------------- void ym3812::generate(output_data *output, uint32_t numsamples) { for (uint32_t samp = 0; samp < numsamples; samp++, output++) { // clock the system m_fm.clock(fm_engine::ALL_CHANNELS); // update the FM content; mixing details for YM3812 need verification m_fm.output(output->clear(), 1, 32767, fm_engine::ALL_CHANNELS); // YM3812 uses an external DAC (YM3014) with mantissa/exponent format // convert to 10.3 floating point value and back to simulate truncation output->roundtrip_fp(); } } //********************************************************* // YMF262 //********************************************************* //------------------------------------------------- // ymf262 - constructor //------------------------------------------------- ymf262::ymf262(ymfm_interface &intf) : m_address(0), m_fm(intf) { } //------------------------------------------------- // reset - reset the system //------------------------------------------------- void ymf262::reset() { // reset the engines m_fm.reset(); } //------------------------------------------------- // save_restore - save or restore the data //------------------------------------------------- void ymf262::save_restore(ymfm_saved_state &state) { state.save_restore(m_address); m_fm.save_restore(state); } //------------------------------------------------- // read_status - read the status register //------------------------------------------------- uint8_t ymf262::read_status() { return m_fm.status(); } //------------------------------------------------- // read - handle a read from the device //------------------------------------------------- uint8_t ymf262::read(uint32_t offset) { uint8_t result = 0xff; switch (offset & 3) { case 0: // status port result = read_status(); break; case 1: case 2: case 3: debug::log_unexpected_read_write("Unexpected read from YMF262 offset %d\n", offset & 3); break; } return result; } //------------------------------------------------- // write_address - handle a write to the address // register //------------------------------------------------- void ymf262::write_address(uint8_t data) { // YMF262 doesn't expose a busy signal, but it does indicate that // address writes should be no faster than every 32 clocks m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); // just set the address m_address = data; } //------------------------------------------------- // write_data - handle a write to the data // register //------------------------------------------------- void ymf262::write_data(uint8_t data) { // YMF262 doesn't expose a busy signal, but it does indicate that // data writes should be no faster than every 32 clocks m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); // write to FM m_fm.write(m_address, data); } //------------------------------------------------- // write_address_hi - handle a write to the upper // address register //------------------------------------------------- void ymf262::write_address_hi(uint8_t data) { // YMF262 doesn't expose a busy signal, but it does indicate that // address writes should be no faster than every 32 clocks m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); // just set the address m_address = data | 0x100; // tests reveal that in compatibility mode, upper bit is masked // except for register 0x105 if (m_fm.regs().newflag() == 0 && m_address != 0x105) m_address &= 0xff; } //------------------------------------------------- // write - handle a write to the register // interface //------------------------------------------------- void ymf262::write(uint32_t offset, uint8_t data) { switch (offset & 3) { case 0: // address port write_address(data); break; case 1: // data port write_data(data); break; case 2: // address port write_address_hi(data); break; case 3: // data port write_data(data); break; } } //------------------------------------------------- // generate - generate samples of sound //------------------------------------------------- void ymf262::generate(output_data *output, uint32_t numsamples) { for (uint32_t samp = 0; samp < numsamples; samp++, output++) { // clock the system m_fm.clock(fm_engine::ALL_CHANNELS); // update the FM content; mixing details for YMF262 need verification m_fm.output(output->clear(), 0, 32767, fm_engine::ALL_CHANNELS); // YMF262 output is 16-bit offset serial via YAC512 DAC output->clamp16(); } } //********************************************************* // YMF289B //********************************************************* // YMF289B is a YMF262 with the following changes: // * "Power down" mode added // * Bulk register clear added // * Busy flag added to the status register // * Shorter busy times // * All registers can be read // * Only 2 outputs exposed //------------------------------------------------- // ymf289b - constructor //------------------------------------------------- ymf289b::ymf289b(ymfm_interface &intf) : m_address(0), m_fm(intf) { } //------------------------------------------------- // reset - reset the system //------------------------------------------------- void ymf289b::reset() { // reset the engines m_fm.reset(); } //------------------------------------------------- // save_restore - save or restore the data //------------------------------------------------- void ymf289b::save_restore(ymfm_saved_state &state) { state.save_restore(m_address); m_fm.save_restore(state); } //------------------------------------------------- // read_status - read the status register //------------------------------------------------- uint8_t ymf289b::read_status() { uint8_t result = m_fm.status(); // YMF289B adds a busy flag if (ymf289b_mode() && m_fm.intf().ymfm_is_busy()) result |= STATUS_BUSY_FLAGS; return result; } //------------------------------------------------- // read_data - read the data register //------------------------------------------------- uint8_t ymf289b::read_data() { uint8_t result = 0xff; // YMF289B can read register data back if (ymf289b_mode()) result = m_fm.regs().read(m_address); return result; } //------------------------------------------------- // read - handle a read from the device //------------------------------------------------- uint8_t ymf289b::read(uint32_t offset) { uint8_t result = 0xff; switch (offset & 3) { case 0: // status port result = read_status(); break; case 1: // data port result = read_data(); break; case 2: case 3: debug::log_unexpected_read_write("Unexpected read from YMF289B offset %d\n", offset & 3); break; } return result; } //------------------------------------------------- // write_address - handle a write to the address // register //------------------------------------------------- void ymf289b::write_address(uint8_t data) { m_address = data; // count busy time m_fm.intf().ymfm_set_busy_end(56); } //------------------------------------------------- // write_data - handle a write to the data // register //------------------------------------------------- void ymf289b::write_data(uint8_t data) { // write to FM m_fm.write(m_address, data); // writes to 0x108 with the CLR flag set clear the registers if (m_address == 0x108 && bitfield(data, 2) != 0) m_fm.regs().reset(); // count busy time m_fm.intf().ymfm_set_busy_end(56); } //------------------------------------------------- // write_address_hi - handle a write to the upper // address register //------------------------------------------------- void ymf289b::write_address_hi(uint8_t data) { // just set the address m_address = data | 0x100; // tests reveal that in compatibility mode, upper bit is masked // except for register 0x105 if (m_fm.regs().newflag() == 0 && m_address != 0x105) m_address &= 0xff; // count busy time m_fm.intf().ymfm_set_busy_end(56); } //------------------------------------------------- // write - handle a write to the register // interface //------------------------------------------------- void ymf289b::write(uint32_t offset, uint8_t data) { switch (offset & 3) { case 0: // address port write_address(data); break; case 1: // data port write_data(data); break; case 2: // address port write_address_hi(data); break; case 3: // data port write_data(data); break; } } //------------------------------------------------- // generate - generate samples of sound //------------------------------------------------- void ymf289b::generate(output_data *output, uint32_t numsamples) { for (uint32_t samp = 0; samp < numsamples; samp++, output++) { // clock the system m_fm.clock(fm_engine::ALL_CHANNELS); // update the FM content; mixing details for YMF262 need verification fm_engine::output_data full; m_fm.output(full.clear(), 0, 32767, fm_engine::ALL_CHANNELS); // YMF278B output is 16-bit offset serial via YAC512 DAC, but // only 2 of the 4 outputs are exposed output->data[0] = full.data[0]; output->data[1] = full.data[1]; output->clamp16(); } } //********************************************************* // YMF278B //********************************************************* //------------------------------------------------- // ymf278b - constructor //------------------------------------------------- ymf278b::ymf278b(ymfm_interface &intf) : m_address(0), m_fm_pos(0), m_load_remaining(0), m_next_status_id(false), m_fm(intf), m_pcm(intf) { } //------------------------------------------------- // reset - reset the system //------------------------------------------------- void ymf278b::reset() { // reset the engines m_fm.reset(); m_pcm.reset(); // next status read will return ID m_next_status_id = true; } //------------------------------------------------- // save_restore - save or restore the data //------------------------------------------------- void ymf278b::save_restore(ymfm_saved_state &state) { state.save_restore(m_address); state.save_restore(m_fm_pos); state.save_restore(m_load_remaining); state.save_restore(m_next_status_id); m_fm.save_restore(state); m_pcm.save_restore(state); } //------------------------------------------------- // read_status - read the status register //------------------------------------------------- uint8_t ymf278b::read_status() { uint8_t result; // first status read after initialization returns a chip ID, which // varies based on the "new" flags, indicating the mode if (m_next_status_id) { if (m_fm.regs().new2flag()) result = 0x02; else if (m_fm.regs().newflag()) result = 0x00; else result = 0x06; m_next_status_id = false; } else { result = m_fm.status(); if (m_fm.intf().ymfm_is_busy()) result |= STATUS_BUSY; if (m_load_remaining != 0) result |= STATUS_LD; // if new2 flag is not set, we're in OPL2 or OPL3 mode if (!m_fm.regs().new2flag()) result &= ~(STATUS_BUSY | STATUS_LD); } return result; } //------------------------------------------------- // write_data_pcm - handle a write to the PCM data // register //------------------------------------------------- uint8_t ymf278b::read_data_pcm() { // read from PCM if (bitfield(m_address, 9) != 0) { uint8_t result = m_pcm.read(m_address & 0xff); if ((m_address & 0xff) == 0x02) result |= 0x20; return result; } return 0; } //------------------------------------------------- // read - handle a read from the device //------------------------------------------------- uint8_t ymf278b::read(uint32_t offset) { uint8_t result = 0xff; switch (offset & 7) { case 0: // status port result = read_status(); break; case 5: // PCM data port result = read_data_pcm(); break; default: debug::log_unexpected_read_write("Unexpected read from ymf278b offset %d\n", offset & 3); break; } return result; } //------------------------------------------------- // write_address - handle a write to the address // register //------------------------------------------------- void ymf278b::write_address(uint8_t data) { // just set the address m_address = data; } //------------------------------------------------- // write_data - handle a write to the data // register //------------------------------------------------- void ymf278b::write_data(uint8_t data) { // write to FM if (bitfield(m_address, 9) == 0) { uint8_t old = m_fm.regs().new2flag(); m_fm.write(m_address, data); // changing NEW2 from 0->1 causes the next status read to // return the chip ID if (old == 0 && m_fm.regs().new2flag() != 0) m_next_status_id = true; } // BUSY goes for 56 clocks on FM writes m_fm.intf().ymfm_set_busy_end(56); } //------------------------------------------------- // write_address_hi - handle a write to the upper // address register //------------------------------------------------- void ymf278b::write_address_hi(uint8_t data) { // just set the address m_address = data | 0x100; // YMF262, in compatibility mode, treats the upper bit as masked // except for register 0x105; assuming YMF278B works the same way? if (m_fm.regs().newflag() == 0 && m_address != 0x105) m_address &= 0xff; } //------------------------------------------------- // write_address_pcm - handle a write to the upper // address register //------------------------------------------------- void ymf278b::write_address_pcm(uint8_t data) { // just set the address m_address = data | 0x200; } //------------------------------------------------- // write_data_pcm - handle a write to the PCM data // register //------------------------------------------------- void ymf278b::write_data_pcm(uint8_t data) { // ignore data writes if new2 is not yet set if (m_fm.regs().new2flag() == 0) return; // write to FM if (bitfield(m_address, 9) != 0) { uint8_t addr = m_address & 0xff; m_pcm.write(addr, data); // writes to the waveform number cause loads to happen for "about 300usec" // which is ~13 samples at the nominal output frequency of 44.1kHz if (addr >= 0x08 && addr <= 0x1f) m_load_remaining = 13; } // BUSY goes for 88 clocks on PCM writes m_fm.intf().ymfm_set_busy_end(88); } //------------------------------------------------- // write - handle a write to the register // interface //------------------------------------------------- void ymf278b::write(uint32_t offset, uint8_t data) { switch (offset & 7) { case 0: // address port write_address(data); break; case 1: // data port write_data(data); break; case 2: // address port write_address_hi(data); break; case 3: // data port write_data(data); break; case 4: // PCM address port write_address_pcm(data); break; case 5: // PCM address port write_data_pcm(data); break; default: debug::log_unexpected_read_write("Unexpected write to ymf278b offset %d\n", offset & 7); break; } } //------------------------------------------------- // generate - generate one sample of sound //------------------------------------------------- void ymf278b::generate(output_data *output, uint32_t numsamples) { static const int16_t s_mix_scale[8] = { 0x7fa, 0x5a4, 0x3fd, 0x2d2, 0x1fe, 0x169, 0xff, 0 }; int32_t const pcm_l = s_mix_scale[m_pcm.regs().mix_pcm_l()]; int32_t const pcm_r = s_mix_scale[m_pcm.regs().mix_pcm_r()]; int32_t const fm_l = s_mix_scale[m_pcm.regs().mix_fm_l()]; int32_t const fm_r = s_mix_scale[m_pcm.regs().mix_fm_r()]; for (uint32_t samp = 0; samp < numsamples; samp++, output++) { // clock the system m_fm_pos += FM_EXTRA_SAMPLE_STEP; if (m_fm_pos >= FM_EXTRA_SAMPLE_THRESH) { m_fm.clock(fm_engine::ALL_CHANNELS); m_fm_pos -= FM_EXTRA_SAMPLE_THRESH; } m_fm.clock(fm_engine::ALL_CHANNELS); m_pcm.clock(pcm_engine::ALL_CHANNELS); // update the FM content; mixing details for YMF278B need verification fm_engine::output_data fmout; m_fm.output(fmout.clear(), 0, 32767, fm_engine::ALL_CHANNELS); // update the PCM content pcm_engine::output_data pcmout; m_pcm.output(pcmout.clear(), pcm_engine::ALL_CHANNELS); // DO0 output: FM channels 2+3 only output->data[0] = fmout.data[2]; output->data[1] = fmout.data[3]; // DO1 output: wavetable channels 2+3 only output->data[2] = pcmout.data[2]; output->data[3] = pcmout.data[3]; // DO2 output: mixed FM channels 0+1 and wavetable channels 0+1 output->data[4] = (fmout.data[0] * fm_l + pcmout.data[0] * pcm_l) >> 11; output->data[5] = (fmout.data[1] * fm_r + pcmout.data[1] * pcm_r) >> 11; // YMF278B output is 16-bit 2s complement serial output->clamp16(); } // decrement the load waiting count if (m_load_remaining > 0) m_load_remaining -= std::min(m_load_remaining, numsamples); } //********************************************************* // OPLL BASE //********************************************************* //------------------------------------------------- // opll_base - constructor //------------------------------------------------- opll_base::opll_base(ymfm_interface &intf, uint8_t const *instrument_data) : m_address(0), m_fm(intf) { m_fm.regs().set_instrument_data(instrument_data); } //------------------------------------------------- // reset - reset the system //------------------------------------------------- void opll_base::reset() { // reset the engines m_fm.reset(); } //------------------------------------------------- // save_restore - save or restore the data //------------------------------------------------- void opll_base::save_restore(ymfm_saved_state &state) { state.save_restore(m_address); m_fm.save_restore(state); } //------------------------------------------------- // write_address - handle a write to the address // register //------------------------------------------------- void opll_base::write_address(uint8_t data) { // OPLL doesn't expose a busy signal, but datasheets are pretty consistent // in indicating that address writes should be no faster than every 12 clocks m_fm.intf().ymfm_set_busy_end(12); // just set the address m_address = data; } //------------------------------------------------- // write - handle a write to the register // interface //------------------------------------------------- void opll_base::write_data(uint8_t data) { // OPLL doesn't expose a busy signal, but datasheets are pretty consistent // in indicating that address writes should be no faster than every 84 clocks m_fm.intf().ymfm_set_busy_end(84); // write to FM m_fm.write(m_address, data); } //------------------------------------------------- // write - handle a write to the register // interface //------------------------------------------------- void opll_base::write(uint32_t offset, uint8_t data) { switch (offset & 1) { case 0: // address port write_address(data); break; case 1: // data port write_data(data); break; } } //------------------------------------------------- // generate - generate one sample of sound //------------------------------------------------- void opll_base::generate(output_data *output, uint32_t numsamples) { for (uint32_t samp = 0; samp < numsamples; samp++, output++) { // clock the system m_fm.clock(fm_engine::ALL_CHANNELS); // update the FM content; OPLL has a built-in 9-bit DAC m_fm.output(output->clear(), 5, 256, fm_engine::ALL_CHANNELS); // final output is multiplexed; we don't simulate that here except // to average over everything output->data[0] = (output->data[0] * 128) / 9; output->data[1] = (output->data[1] * 128) / 9; } } //********************************************************* // YM2413 //********************************************************* //------------------------------------------------- // ym2413 - constructor //------------------------------------------------- ym2413::ym2413(ymfm_interface &intf, uint8_t const *instrument_data) : opll_base(intf, (instrument_data != nullptr) ? instrument_data : s_default_instruments) { }; // table below taken from https://github.com/plgDavid/misc/wiki/Copyright-free-OPLL(x)-ROM-patches uint8_t const ym2413::s_default_instruments[] = { //April 2015 David Viens, tweaked May 19-21th 2015 Hubert Lamontagne 0x71, 0x61, 0x1E, 0x17, 0xEF, 0x7F, 0x00, 0x17, //Violin 0x13, 0x41, 0x1A, 0x0D, 0xF8, 0xF7, 0x23, 0x13, //Guitar 0x13, 0x01, 0x99, 0x00, 0xF2, 0xC4, 0x11, 0x23, //Piano 0x31, 0x61, 0x0E, 0x07, 0x98, 0x64, 0x70, 0x27, //Flute 0x22, 0x21, 0x1E, 0x06, 0xBF, 0x76, 0x00, 0x28, //Clarinet 0x31, 0x22, 0x16, 0x05, 0xE0, 0x71, 0x0F, 0x18, //Oboe 0x21, 0x61, 0x1D, 0x07, 0x82, 0x8F, 0x10, 0x07, //Trumpet 0x23, 0x21, 0x2D, 0x14, 0xFF, 0x7F, 0x00, 0x07, //Organ 0x41, 0x61, 0x1B, 0x06, 0x64, 0x65, 0x10, 0x17, //Horn 0x61, 0x61, 0x0B, 0x18, 0x85, 0xFF, 0x81, 0x07, //Synthesizer 0x13, 0x01, 0x83, 0x11, 0xFA, 0xE4, 0x10, 0x04, //Harpsichord 0x17, 0x81, 0x23, 0x07, 0xF8, 0xF8, 0x22, 0x12, //Vibraphone 0x61, 0x50, 0x0C, 0x05, 0xF2, 0xF5, 0x29, 0x42, //Synthesizer Bass 0x01, 0x01, 0x54, 0x03, 0xC3, 0x92, 0x03, 0x02, //Acoustic Bass 0x41, 0x41, 0x89, 0x03, 0xF1, 0xE5, 0x11, 0x13, //Electric Guitar 0x01, 0x01, 0x18, 0x0F, 0xDF, 0xF8, 0x6A, 0x6D, //rhythm 1 0x01, 0x01, 0x00, 0x00, 0xC8, 0xD8, 0xA7, 0x48, //rhythm 2 0x05, 0x01, 0x00, 0x00, 0xF8, 0xAA, 0x59, 0x55 //rhythm 3 }; //********************************************************* // YM2423 //********************************************************* //------------------------------------------------- // ym2423 - constructor //------------------------------------------------- ym2423::ym2423(ymfm_interface &intf, uint8_t const *instrument_data) : opll_base(intf, (instrument_data != nullptr) ? instrument_data : s_default_instruments) { }; // table below taken from https://github.com/plgDavid/misc/wiki/Copyright-free-OPLL(x)-ROM-patches uint8_t const ym2423::s_default_instruments[] = { // May 4-6 2016 Hubert Lamontagne // Doesn't seem to have any diff between opllx-x and opllx-y // Drums seem identical to regular opll 0x61, 0x61, 0x1B, 0x07, 0x94, 0x5F, 0x10, 0x06, //1 Strings Saw wave with vibrato Violin 0x93, 0xB1, 0x51, 0x04, 0xF3, 0xF2, 0x70, 0xFB, //2 Guitar Jazz GuitarPiano 0x41, 0x21, 0x11, 0x85, 0xF2, 0xF2, 0x70, 0x75, //3 Electric Guitar Same as OPLL No.15 Synth 0x93, 0xB2, 0x28, 0x07, 0xF3, 0xF2, 0x70, 0xB4, //4 Electric Piano 2 Slow attack, tremoloDing-a-ling 0x72, 0x31, 0x97, 0x05, 0x51, 0x6F, 0x60, 0x09, //5 Flute Same as OPLL No.4Clarinet 0x13, 0x30, 0x18, 0x06, 0xF7, 0xF4, 0x50, 0x85, //6 Marimba Also be used as steel drumXyophone 0x51, 0x31, 0x1C, 0x07, 0x51, 0x71, 0x20, 0x26, //7 Trumpet Same as OPLL No.7Trumpet 0x41, 0xF4, 0x1B, 0x07, 0x74, 0x34, 0x00, 0x06, //8 Harmonica Harmonica synth 0x50, 0x30, 0x4D, 0x03, 0x42, 0x65, 0x20, 0x06, //9 Tuba Tuba 0x40, 0x20, 0x10, 0x85, 0xF3, 0xF5, 0x20, 0x04, //10 Synth Brass 2 Synth sweep 0x61, 0x61, 0x1B, 0x07, 0xC5, 0x96, 0xF3, 0xF6, //11 Short Saw Saw wave with short envelopeSynth hit 0xF9, 0xF1, 0xDC, 0x00, 0xF5, 0xF3, 0x77, 0xF2, //12 Vibraphone Bright vibraphoneVibes 0x60, 0xA2, 0x91, 0x03, 0x94, 0xC1, 0xF7, 0xF7, //13 Electric Guitar 2 Clean guitar with feedbackHarmonic bass 0x30, 0x30, 0x17, 0x06, 0xF3, 0xF1, 0xB7, 0xFC, //14 Synth Bass 2Snappy bass 0x31, 0x36, 0x0D, 0x05, 0xF2, 0xF4, 0x27, 0x9C, //15 Sitar Also be used as ShamisenBanjo 0x01, 0x01, 0x18, 0x0F, 0xDF, 0xF8, 0x6A, 0x6D, //rhythm 1 0x01, 0x01, 0x00, 0x00, 0xC8, 0xD8, 0xA7, 0x48, //rhythm 2 0x05, 0x01, 0x00, 0x00, 0xF8, 0xAA, 0x59, 0x55 //rhythm 3 }; //********************************************************* // YMF281 //********************************************************* //------------------------------------------------- // ymf281 - constructor //------------------------------------------------- ymf281::ymf281(ymfm_interface &intf, uint8_t const *instrument_data) : opll_base(intf, (instrument_data != nullptr) ? instrument_data : s_default_instruments) { }; // table below taken from https://github.com/plgDavid/misc/wiki/Copyright-free-OPLL(x)-ROM-patches uint8_t const ymf281::s_default_instruments[] = { // May 14th 2015 Hubert Lamontagne 0x72, 0x21, 0x1A, 0x07, 0xF6, 0x64, 0x01, 0x16, // Clarinet ~~ Electric String Square wave with vibrato 0x00, 0x10, 0x45, 0x00, 0xF6, 0x83, 0x73, 0x63, // Synth Bass ~~ Bow wow Triangular wave 0x13, 0x01, 0x96, 0x00, 0xF1, 0xF4, 0x31, 0x23, // Piano ~~ Electric Guitar Despite of its name, same as Piano of YM2413. 0x71, 0x21, 0x0B, 0x0F, 0xF9, 0x64, 0x70, 0x17, // Flute ~~ Organ Sine wave 0x02, 0x21, 0x1E, 0x06, 0xF9, 0x76, 0x00, 0x28, // Square Wave ~~ Clarinet Same as ones of YM2413. 0x00, 0x61, 0x82, 0x0E, 0xF9, 0x61, 0x20, 0x27, // Space Oboe ~~ Saxophone Saw wave with vibrato 0x21, 0x61, 0x1B, 0x07, 0x84, 0x8F, 0x10, 0x07, // Trumpet ~~ Trumpet Same as ones of YM2413. 0x37, 0x32, 0xCA, 0x02, 0x66, 0x64, 0x47, 0x29, // Wow Bell ~~ Street Organ Calliope 0x41, 0x41, 0x07, 0x03, 0xF5, 0x70, 0x51, 0xF5, // Electric Guitar ~~ Synth Brass Same as Synthesizer of YM2413. 0x36, 0x01, 0x5E, 0x07, 0xF2, 0xF3, 0xF7, 0xF7, // Vibes ~~ Electric Piano Simulate of Rhodes Piano 0x00, 0x00, 0x18, 0x06, 0xC5, 0xF3, 0x20, 0xF2, // Bass ~~ Bass Electric bass 0x17, 0x81, 0x25, 0x07, 0xF7, 0xF3, 0x21, 0xF7, // Vibraphone ~~ Vibraphone Same as ones of YM2413. 0x35, 0x64, 0x00, 0x00, 0xFF, 0xF3, 0x77, 0xF5, // Vibrato Bell ~~ Chime Bell 0x11, 0x31, 0x00, 0x07, 0xDD, 0xF3, 0xFF, 0xFB, // Click Sine ~~ Tom Tom II Tom 0x3A, 0x21, 0x00, 0x07, 0x95, 0x84, 0x0F, 0xF5, // Noise and Tone ~~ Noise for S.E. 0x01, 0x01, 0x18, 0x0F, 0xDF, 0xF8, 0x6A, 0x6D, //rhythm 1 0x01, 0x01, 0x00, 0x00, 0xC8, 0xD8, 0xA7, 0x48, //rhythm 2 0x05, 0x01, 0x00, 0x00, 0xF8, 0xAA, 0x59, 0x55 //rhythm 3 }; //********************************************************* // DS1001 //********************************************************* //------------------------------------------------- // ds1001 - constructor //------------------------------------------------- ds1001::ds1001(ymfm_interface &intf, uint8_t const *instrument_data) : opll_base(intf, (instrument_data != nullptr) ? instrument_data : s_default_instruments) { }; // table below taken from https://github.com/plgDavid/misc/wiki/Copyright-free-OPLL(x)-ROM-patches uint8_t const ds1001::s_default_instruments[] = { // May 15th 2015 Hubert Lamontagne & David Viens 0x03, 0x21, 0x05, 0x06, 0xC8, 0x81, 0x42, 0x27, // Buzzy Bell 0x13, 0x41, 0x14, 0x0D, 0xF8, 0xF7, 0x23, 0x12, // Guitar 0x31, 0x11, 0x08, 0x08, 0xFA, 0xC2, 0x28, 0x22, // Wurly 0x31, 0x61, 0x0C, 0x07, 0xF8, 0x64, 0x60, 0x27, // Flute 0x22, 0x21, 0x1E, 0x06, 0xFF, 0x76, 0x00, 0x28, // Clarinet 0x02, 0x01, 0x05, 0x00, 0xAC, 0xF2, 0x03, 0x02, // Synth 0x21, 0x61, 0x1D, 0x07, 0x82, 0x8F, 0x10, 0x07, // Trumpet 0x23, 0x21, 0x22, 0x17, 0xFF, 0x73, 0x00, 0x17, // Organ 0x15, 0x11, 0x25, 0x00, 0x41, 0x71, 0x00, 0xF1, // Bells 0x95, 0x01, 0x10, 0x0F, 0xB8, 0xAA, 0x50, 0x02, // Vibes 0x17, 0xC1, 0x5E, 0x07, 0xFA, 0xF8, 0x22, 0x12, // Vibraphone 0x71, 0x23, 0x11, 0x06, 0x65, 0x74, 0x10, 0x16, // Tutti 0x01, 0x02, 0xD3, 0x05, 0xF3, 0x92, 0x83, 0xF2, // Fretless 0x61, 0x63, 0x0C, 0x00, 0xA4, 0xFF, 0x30, 0x06, // Synth Bass 0x21, 0x62, 0x0D, 0x00, 0xA1, 0xFF, 0x50, 0x08, // Sweep 0x01, 0x01, 0x18, 0x0F, 0xDF, 0xF8, 0x6A, 0x6D, //rhythm 1 0x01, 0x01, 0x00, 0x00, 0xC8, 0xD8, 0xA7, 0x48, //rhythm 2 0x05, 0x01, 0x00, 0x00, 0xF8, 0xAA, 0x59, 0x55 //rhythm 3 }; //********************************************************* // EXPLICIT INSTANTIATION //********************************************************* template class opl_registers_base<4>; template class fm_engine_base>; }