/**
* encoding: UTF-8
* This file is part of reSID, a MOS6581 SID emulator engine.
* Copyright (C) 2004 Dag Lem <resid@nimrod.no>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* @author Ken Händel
*
*/
package resid;
import static resid.SID.ANTTI_LANKILA_PATCH;
import resid.ISIDDefs.chip_model;
/**
* A 24 bit accumulator is the basis for waveform generation. FREQ is added to
* the lower 16 bits of the accumulator each cycle. The accumulator is set to
* zero when TEST is set, and starts counting when TEST is cleared. The noise
* waveform is taken from intermediate bits of a 23 bit shift register. This
* register is clocked by bit 19 of the accumulator.
*
* @author Ken Händel
*
*/
public class WaveformGenerator implements IWave6581, IWave8580 {
protected WaveformGenerator sync_source = null;
protected WaveformGenerator sync_dest = null;
/**
* Tell whether the accumulator MSB was set high on this cycle.
*/
protected boolean msb_rising;
protected int /* reg24 */accumulator;
protected int /* reg24 */shift_register;
/**
* Fout = (Fn*Fclk/16777216)Hz
*/
protected int /* reg16 */freq;
/**
* PWout = (PWn/40.95)%
*/
protected int /* reg12 */pw;
/**
* The control register right-shifted 4 bits; used for output function table
* lookup.
*/
protected int /* reg8 */waveform;
/**
* The remaining control register bits.
*/
protected int /* reg8 */test;
/**
* The remaining control register bits.
*/
protected int /* reg8 */ring_mod;
/**
* The remaining control register bits.
*/
protected int /* reg8 */sync;
// The gate bit is handled by the EnvelopeGenerator
// Sample data for combinations of waveforms.
int /* reg8 */wave__ST[];
int /* reg8 */wave_P_T[];
int /* reg8 */wave_PS_[];
int /* reg8 */wave_PST[];
// The gate bit is handled by the EnvelopeGenerator.
/**
* Constructor.
*/
public WaveformGenerator() {
sync_source = this;
set_chip_model(chip_model.MOS6581);
reset();
}
/**
* Set sync source.
*
* @param source
* sync source
*/
public void set_sync_source(WaveformGenerator source) {
sync_source = source;
source.sync_dest = this;
}
/**
* Set chip model.
*
* @param model
* chip model
*/
public void set_chip_model(chip_model model) {
if (model == chip_model.MOS6581) {
wave__ST = wave6581__ST;
wave_P_T = wave6581_P_T;
wave_PS_ = wave6581_PS_;
wave_PST = wave6581_PST;
} else {
wave__ST = wave8580__ST;
wave_P_T = wave8580_P_T;
wave_PS_ = wave8580_PS_;
wave_PST = wave8580_PST;
}
}
/**
* Register functions.
*
* @param freq_lo
*/
public void writeFREQ_LO(int /* reg8 */freq_lo) {
freq = freq & 0xff00 | freq_lo & 0x00ff;
}
/**
* Register functions.
*
* @param freq_hi
*/
public void writeFREQ_HI(int /* reg8 */freq_hi) {
freq = (freq_hi << 8) & 0xff00 | freq & 0x00ff;
}
/**
* Register functions.
*
* @param pw_lo
*/
public void writePW_LO(int /* reg8 */pw_lo) {
pw = pw & 0xf00 | pw_lo & 0x0ff;
}
/**
* Register functions.
*
* @param pw_hi
*/
public void writePW_HI(int /* reg8 */pw_hi) {
pw = (pw_hi << 8) & 0xf00 | pw & 0x0ff;
}
/**
* Register functions.
*
* @param control
*/
public void writeCONTROL_REG(int /* reg8 */control) {
waveform = (control >> 4) & 0x0f;
ring_mod = control & 0x04;
sync = control & 0x02;
int /* reg8 */test_next = control & 0x08;
if (ANTTI_LANKILA_PATCH) {
/*
* SounDemoN found out that test bit can be used to control the
* noise register. Hear the result in Bojojoing.sid.
*/
// testbit set. invert bit 19 and write it to bit 1
if (test_next != 0 && test == 0) {
accumulator = 0;
int /* reg24 */bit19 = (shift_register >> 19) & 1;
shift_register = (shift_register & 0x7ffffd)
| ((bit19 ^ 1) << 1);
}
// Test bit cleared.
// The accumulator starts counting, and the shift register is reset
// to
// the value 0x7ffff8.
// NB! The shift register will not actually be set to this exact
// value
// if the
// shift register bits have not had time to fade to zero.
// This is not modeled.
else if (test_next == 0 && test > 0) {
int /* reg24 */bit0 = ((shift_register >> 22) ^ (shift_register >> 17)) & 0x1;
shift_register <<= 1;
shift_register &= 0x7fffff;
shift_register |= bit0;
}
// clear output bits of shift register if noise and other waveforms
// are selected simultaneously
if (waveform > 8) {
shift_register &= 0x7fffff ^ (1 << 22) ^ (1 << 20) ^ (1 << 16)
^ (1 << 13) ^ (1 << 11) ^ (1 << 7) ^ (1 << 4)
^ (1 << 2);
}
} else {
// Test bit set.
// The accumulator and the shift register are both cleared.
// NB! The shift register is not really cleared immediately. It
// seems
// like the individual bits in the shift register start to fade down
// towards zero when test is set. All bits reach zero within
// approximately $2000 - $4000 cycles.
// This is not modeled. There should fortunately be little audible
// output from this peculiar behavior.
if (test_next != 0) {
accumulator = 0;
shift_register = 0;
}
// Test bit cleared.
// The accumulator starts counting, and the shift register is reset
// to
// the value 0x7ffff8.
// NB! The shift register will not actually be set to this exact
// value
// if the
// shift register bits have not had time to fade to zero.
// This is not modeled.
else if (test != 0) {
shift_register = 0x7ffff8;
}
}
test = test_next;
// The gate bit is handled by the EnvelopeGenerator.
}
public int /* reg8 */readOSC() {
return output() >> 4;
}
/**
* SID reset.
*/
public void reset() {
accumulator = 0;
if (ANTTI_LANKILA_PATCH)
shift_register = 0x7ffffc;
else
shift_register = 0x7ffff8;
freq = 0;
pw = 0;
test = 0;
ring_mod = 0;
sync = 0;
msb_rising = false;
}
// ----------------------------------------------------------------------------
// Inline functions.
// The following functions are defined inline because they are called every
// time a sample is calculated.
// ----------------------------------------------------------------------------
/**
* SID clocking - 1 cycle.
*/
public void clock() {
// No operation if test bit is set.
if (test != 0) {
return;
}
int /* reg24 */accumulator_prev = accumulator;
// Calculate new accumulator value;
accumulator += freq;
accumulator &= 0xffffff;
// Check whether the MSB is set high. This is used for synchronization.
msb_rising = !((accumulator_prev & 0x800000) != 0)
&& ((accumulator & 0x800000) != 0);
// Shift noise register once for each time accumulator bit 19 is set
// high.
if (!((accumulator_prev & 0x080000) != 0)
&& ((accumulator & 0x080000) != 0)) {
int /* reg24 */bit0 = ((shift_register >> 22) ^ (shift_register >> 17)) & 0x1;
shift_register <<= 1;
shift_register &= 0x7fffff;
shift_register |= bit0;
}
}
/**
* SID clocking - delta_t cycles.
*/
public void clock(int/* cycle_count */delta_t) {
// No operation if test bit is set.
if (test != 0) {
return;
}
int /* reg24 */accumulator_prev = accumulator;
// Calculate new accumulator value;
int /* reg24 */delta_accumulator = delta_t * freq;
accumulator += delta_accumulator;
accumulator &= 0xffffff;
// Check whether the MSB is set high. This is used for synchronization.
msb_rising = !((accumulator_prev & 0x800000) != 0)
&& ((accumulator & 0x800000) != 0);
// Shift noise register once for each time accumulator bit 19 is set
// high.
// Bit 19 is set high each time 2^20 (0x100000) is added to the
// accumulator.
int /* reg24 */shift_period = 0x100000;
while (delta_accumulator != 0) {
if (delta_accumulator < shift_period) {
shift_period = delta_accumulator;
// Determine whether bit 19 is set on the last period.
// NB! Requires two's complement integer.
if (shift_period <= 0x080000) {
// Check for flip from 0 to 1.
if ((((accumulator - shift_period) & 0x080000) != 0)
|| !((accumulator & 0x080000) != 0)) {
break;
}
} else {
// Check for flip from 0 (to 1 or via 1 to 0) or from 1 via
// 0 to 1.
if ((((accumulator - shift_period) & 0x080000) != 0)
&& !((accumulator & 0x080000) != 0)) {
break;
}
}
}
// Shift the noise/random register.
// NB! The shift is actually delayed 2 cycles, this is not modeled.
int /* reg24 */bit0 = ((shift_register >> 22) ^ (shift_register >> 17)) & 0x1;
shift_register <<= 1;
shift_register &= 0x7fffff;
shift_register |= bit0;
delta_accumulator -= shift_period;
}
}
/**
* Synchronize oscillators. This must be done after all the oscillators have
* been clock()'ed since the oscillators operate in parallel. Note that the
* oscillators must be clocked exactly on the cycle when the MSB is set high
* for hard sync to operate correctly. See SID.clock().
*/
public void synchronize() {
// A special case occurs when a sync source is synced itself on the same
// cycle as when its MSB is set high. In this case the destination will
// not be synced. This has been verified by sampling OSC3.
if (msb_rising && (sync_dest.sync != 0)
&& !((sync != 0) && sync_source.msb_rising)) {
sync_dest.accumulator = 0;
}
}
// ----------------------------------------------------------------------------
// 16 possible combinations of waveforms.
// Output functions.
// NB! The output from SID 8580 is delayed one cycle compared to SID 6581,
// this is not modeled.
// ----------------------------------------------------------------------------
/**
* No waveform: Zero output.
*
* @return zero
*/
protected int /* reg12 */output____() {
return 0x000;
}
/**
* Triangle: The upper 12 bits of the accumulator are used. The MSB is used
* to create the falling edge of the triangle by inverting the lower 11
* bits. The MSB is thrown away and the lower 11 bits are left-shifted (half
* the resolution, full amplitude). Ring modulation substitutes the MSB with
* MSB EOR sync_source MSB.
*
* @return triangle
*/
protected int /* reg12 */output___T() {
int /* reg24 */msb = ((ring_mod != 0) ? accumulator
^ sync_source.accumulator : accumulator) & 0x800000;
return (((msb != 0) ? ~accumulator : accumulator) >> 11) & 0xfff;
}
/**
* Sawtooth: The output is identical to the upper 12 bits of the
* accumulator.
*
* @return sawtooth
*/
protected int /* reg12 */output__S_() {
return accumulator >> 12;
}
/**
* Pulse: The upper 12 bits of the accumulator are used. These bits are
* compared to the pulse width register by a 12 bit digital comparator;
* output is either all one or all zero bits.
* <P>
* NB! The output is actually delayed one cycle after the compare. This is
* not modeled.
* <P>
* The test bit, when set to one, holds the pulse waveform output at 0xfff
* regardless of the pulse width setting.
*
* @return
*/
protected int /* reg12 */output_P__() {
return ((test != 0) || (accumulator >> 12) >= pw) ? 0xfff : 0x000;
}
/**
* Noise: The noise output is taken from intermediate bits of a 23-bit shift
* register which is clocked by bit 19 of the accumulator. NB! The output is
* actually delayed 2 cycles after bit 19 is set high. This is not modeled.
* <P>
* Operation: Calculate EOR result, shift register, set bit 0 = result.
*
* <pre>
* ------------------------>--------------------
* | |
* ----EOR---- |
* | | |
* 2 2 2 1 1 1 1 1 1 1 1 1 1 |
* Register bits: 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 <---
* | | | | | | | |
* OSC3 bits : 7 6 5 4 3 2 1 0
* </pre>
*
* Since waveform output is 12 bits the output is left-shifted 4 times.
*/
protected int /* reg12 */outputN___() {
return ((shift_register & 0x400000) >> 11)
| ((shift_register & 0x100000) >> 10)
| ((shift_register & 0x010000) >> 7)
| ((shift_register & 0x002000) >> 5)
| ((shift_register & 0x000800) >> 4)
| ((shift_register & 0x000080) >> 1)
| ((shift_register & 0x000010) << 1)
| ((shift_register & 0x000004) << 2);
}
/**
* Combined waveforms: By combining waveforms, the bits of each waveform are
* effectively short circuited. A zero bit in one waveform will result in a
* zero output bit (thus the infamous claim that the waveforms are AND'ed).
* However, a zero bit in one waveform will also affect the neighboring bits
* in the output. The reason for this has not been determined.
* <P>
* Example:
*
* <pre>
*
* 1 1
* Bit # 1 0 9 8 7 6 5 4 3 2 1 0
* -----------------------
* Sawtooth 0 0 0 1 1 1 1 1 1 0 0 0
*
* Triangle 0 0 1 1 1 1 1 1 0 0 0 0
*
* AND 0 0 0 1 1 1 1 1 0 0 0 0
*
* Output 0 0 0 0 1 1 1 0 0 0 0 0
* </pre>
*
* This behavior would be quite difficult to model exactly, since the SID in
* this case does not act as a digital state machine. Tests show that minor
* (1 bit) differences can actually occur in the output from otherwise
* identical samples from OSC3 when waveforms are combined. To further
* complicate the situation the output changes slightly with time (more
* neighboring bits are successively set) when the 12-bit waveform registers
* are kept unchanged.
* <P>
* It is probably possible to come up with a valid model for the behavior,
* however this would be far too slow for practical use since it would have
* to be based on the mutual influence of individual bits.
* <P>
* The output is instead approximated by using the upper bits of the
* accumulator as an index to look up the combined output in a table
* containing actual combined waveform samples from OSC3. These samples are
* 8 bit, so 4 bits of waveform resolution is lost. All OSC3 samples are
* taken with FREQ=0x1000, adding a 1 to the upper 12 bits of the
* accumulator each cycle for a sample period of 4096 cycles.
* <P>
* Sawtooth+Triangle: The sawtooth output is used to look up an OSC3 sample.
* <P>
* Pulse+Triangle: The triangle output is right-shifted and used to look up
* an OSC3 sample. The sample is output if the pulse output is on. The
* reason for using the triangle output as the index is to handle ring
* modulation. Only the first half of the sample is used, which should be OK
* since the triangle waveform has half the resolution of the accumulator.
* <P>
* Pulse+Sawtooth: The sawtooth output is used to look up an OSC3 sample.
* The sample is output if the pulse output is on.
* <P>
* Pulse+Sawtooth+Triangle: The sawtooth output is used to look up an OSC3
* sample. The sample is output if the pulse output is on.
*/
protected int /* reg12 */output__ST() {
return wave__ST[output__S_()] << 4;
}
/**
* Combined waveforms: By combining waveforms, the bits of each waveform are
* effectively short circuited. A zero bit in one waveform will result in a
* zero output bit (thus the infamous claim that the waveforms are AND'ed).
* However, a zero bit in one waveform will also affect the neighboring bits
* in the output. The reason for this has not been determined.
* <P>
* Example:
*
* <pre>
*
* 1 1
* Bit # 1 0 9 8 7 6 5 4 3 2 1 0
* -----------------------
* Sawtooth 0 0 0 1 1 1 1 1 1 0 0 0
*
* Triangle 0 0 1 1 1 1 1 1 0 0 0 0
*
* AND 0 0 0 1 1 1 1 1 0 0 0 0
*
* Output 0 0 0 0 1 1 1 0 0 0 0 0
* </pre>
*
* This behavior would be quite difficult to model exactly, since the SID in
* this case does not act as a digital state machine. Tests show that minor
* (1 bit) differences can actually occur in the output from otherwise
* identical samples from OSC3 when waveforms are combined. To further
* complicate the situation the output changes slightly with time (more
* neighboring bits are successively set) when the 12-bit waveform registers
* are kept unchanged.
* <P>
* It is probably possible to come up with a valid model for the behavior,
* however this would be far too slow for practical use since it would have
* to be based on the mutual influence of individual bits.
* <P>
* The output is instead approximated by using the upper bits of the
* accumulator as an index to look up the combined output in a table
* containing actual combined waveform samples from OSC3. These samples are
* 8 bit, so 4 bits of waveform resolution is lost. All OSC3 samples are
* taken with FREQ=0x1000, adding a 1 to the upper 12 bits of the
* accumulator each cycle for a sample period of 4096 cycles.
* <P>
* Sawtooth+Triangle: The sawtooth output is used to look up an OSC3 sample.
* <P>
* Pulse+Triangle: The triangle output is right-shifted and used to look up
* an OSC3 sample. The sample is output if the pulse output is on. The
* reason for using the triangle output as the index is to handle ring
* modulation. Only the first half of the sample is used, which should be OK
* since the triangle waveform has half the resolution of the accumulator.
* <P>
* Pulse+Sawtooth: The sawtooth output is used to look up an OSC3 sample.
* The sample is output if the pulse output is on.
* <P>
* Pulse+Sawtooth+Triangle: The sawtooth output is used to look up an OSC3
* sample. The sample is output if the pulse output is on.
*/
protected int /* reg12 */output_P_T() {
return (wave_P_T[output___T() >> 1] << 4) & output_P__();
}
/**
* Combined waveforms: By combining waveforms, the bits of each waveform are
* effectively short circuited. A zero bit in one waveform will result in a
* zero output bit (thus the infamous claim that the waveforms are AND'ed).
* However, a zero bit in one waveform will also affect the neighboring bits
* in the output. The reason for this has not been determined.
* <P>
* Example:
*
* <pre>
*
* 1 1
* Bit # 1 0 9 8 7 6 5 4 3 2 1 0
* -----------------------
* Sawtooth 0 0 0 1 1 1 1 1 1 0 0 0
*
* Triangle 0 0 1 1 1 1 1 1 0 0 0 0
*
* AND 0 0 0 1 1 1 1 1 0 0 0 0
*
* Output 0 0 0 0 1 1 1 0 0 0 0 0
* </pre>
*
* This behavior would be quite difficult to model exactly, since the SID in
* this case does not act as a digital state machine. Tests show that minor
* (1 bit) differences can actually occur in the output from otherwise
* identical samples from OSC3 when waveforms are combined. To further
* complicate the situation the output changes slightly with time (more
* neighboring bits are successively set) when the 12-bit waveform registers
* are kept unchanged.
* <P>
* It is probably possible to come up with a valid model for the behavior,
* however this would be far too slow for practical use since it would have
* to be based on the mutual influence of individual bits.
* <P>
* The output is instead approximated by using the upper bits of the
* accumulator as an index to look up the combined output in a table
* containing actual combined waveform samples from OSC3. These samples are
* 8 bit, so 4 bits of waveform resolution is lost. All OSC3 samples are
* taken with FREQ=0x1000, adding a 1 to the upper 12 bits of the
* accumulator each cycle for a sample period of 4096 cycles.
* <P>
* Sawtooth+Triangle: The sawtooth output is used to look up an OSC3 sample.
* <P>
* Pulse+Triangle: The triangle output is right-shifted and used to look up
* an OSC3 sample. The sample is output if the pulse output is on. The
* reason for using the triangle output as the index is to handle ring
* modulation. Only the first half of the sample is used, which should be OK
* since the triangle waveform has half the resolution of the accumulator.
* <P>
* Pulse+Sawtooth: The sawtooth output is used to look up an OSC3 sample.
* The sample is output if the pulse output is on.
* <P>
* Pulse+Sawtooth+Triangle: The sawtooth output is used to look up an OSC3
* sample. The sample is output if the pulse output is on.
*/
protected int /* reg12 */output_PS_() {
return (wave_PS_[output__S_()] << 4) & output_P__();
}
/**
* Combined waveforms: By combining waveforms, the bits of each waveform are
* effectively short circuited. A zero bit in one waveform will result in a
* zero output bit (thus the infamous claim that the waveforms are AND'ed).
* However, a zero bit in one waveform will also affect the neighboring bits
* in the output. The reason for this has not been determined.
* <P>
* Example:
*
* <pre>
*
* 1 1
* Bit # 1 0 9 8 7 6 5 4 3 2 1 0
* -----------------------
* Sawtooth 0 0 0 1 1 1 1 1 1 0 0 0
*
* Triangle 0 0 1 1 1 1 1 1 0 0 0 0
*
* AND 0 0 0 1 1 1 1 1 0 0 0 0
*
* Output 0 0 0 0 1 1 1 0 0 0 0 0
* </pre>
*
* This behavior would be quite difficult to model exactly, since the SID in
* this case does not act as a digital state machine. Tests show that minor
* (1 bit) differences can actually occur in the output from otherwise
* identical samples from OSC3 when waveforms are combined. To further
* complicate the situation the output changes slightly with time (more
* neighboring bits are successively set) when the 12-bit waveform registers
* are kept unchanged.
* <P>
* It is probably possible to come up with a valid model for the behavior,
* however this would be far too slow for practical use since it would have
* to be based on the mutual influence of individual bits.
* <P>
* The output is instead approximated by using the upper bits of the
* accumulator as an index to look up the combined output in a table
* containing actual combined waveform samples from OSC3. These samples are
* 8 bit, so 4 bits of waveform resolution is lost. All OSC3 samples are
* taken with FREQ=0x1000, adding a 1 to the upper 12 bits of the
* accumulator each cycle for a sample period of 4096 cycles.
* <P>
* Sawtooth+Triangle: The sawtooth output is used to look up an OSC3 sample.
* <P>
* Pulse+Triangle: The triangle output is right-shifted and used to look up
* an OSC3 sample. The sample is output if the pulse output is on. The
* reason for using the triangle output as the index is to handle ring
* modulation. Only the first half of the sample is used, which should be OK
* since the triangle waveform has half the resolution of the accumulator.
* <P>
* Pulse+Sawtooth: The sawtooth output is used to look up an OSC3 sample.
* The sample is output if the pulse output is on.
* <P>
* Pulse+Sawtooth+Triangle: The sawtooth output is used to look up an OSC3
* sample. The sample is output if the pulse output is on.
*/
protected int /* reg12 */output_PST() {
return (wave_PST[output__S_()] << 4) & output_P__();
}
/**
* Combined waveforms including noise: All waveform combinations including
* noise output zero after a few cycles.
* <P>
* NB! The effects of such combinations are not fully explored. It is
* claimed that the shift register may be filled with zeroes and locked up,
* which seems to be true.
* <P>
* We have not attempted to model this behavior, suffice to say that there
* is very little audible output from waveform combinations including noise.
* We hope that nobody is actually using it.
*/
protected int /* reg12 */outputN__T() {
return 0;
}
/**
* Combined waveforms including noise: All waveform combinations including
* noise output zero after a few cycles.
* <P>
* NB! The effects of such combinations are not fully explored. It is
* claimed that the shift register may be filled with zeroes and locked up,
* which seems to be true.
* <P>
* We have not attempted to model this behavior, suffice to say that there
* is very little audible output from waveform combinations including noise.
* We hope that nobody is actually using it.
*/
protected int /* reg12 */outputN_S_() {
return 0;
}
/**
* Combined waveforms including noise: All waveform combinations including
* noise output zero after a few cycles.
* <P>
* NB! The effects of such combinations are not fully explored. It is
* claimed that the shift register may be filled with zeroes and locked up,
* which seems to be true.
* <P>
* We have not attempted to model this behavior, suffice to say that there
* is very little audible output from waveform combinations including noise.
* We hope that nobody is actually using it.
*/
protected int /* reg12 */outputN_ST() {
return 0;
}
/**
* Combined waveforms including noise: All waveform combinations including
* noise output zero after a few cycles.
* <P>
* NB! The effects of such combinations are not fully explored. It is
* claimed that the shift register may be filled with zeroes and locked up,
* which seems to be true.
* <P>
* We have not attempted to model this behavior, suffice to say that there
* is very little audible output from waveform combinations including noise.
* We hope that nobody is actually using it.
*/
protected int /* reg12 */outputNP__() {
return 0;
}
/**
* Combined waveforms including noise: All waveform combinations including
* noise output zero after a few cycles.
* <P>
* NB! The effects of such combinations are not fully explored. It is
* claimed that the shift register may be filled with zeroes and locked up,
* which seems to be true.
* <P>
* We have not attempted to model this behavior, suffice to say that there
* is very little audible output from waveform combinations including noise.
* We hope that nobody is actually using it.
*/
protected int /* reg12 */outputNP_T() {
return 0;
}
/**
* Combined waveforms including noise: All waveform combinations including
* noise output zero after a few cycles.
* <P>
* NB! The effects of such combinations are not fully explored. It is
* claimed that the shift register may be filled with zeroes and locked up,
* which seems to be true.
* <P>
* We have not attempted to model this behavior, suffice to say that there
* is very little audible output from waveform combinations including noise.
* We hope that nobody is actually using it.
*/
protected int /* reg12 */outputNPS_() {
return 0;
}
/**
* Combined waveforms including noise: All waveform combinations including
* noise output zero after a few cycles.
* <P>
* NB! The effects of such combinations are not fully explored. It is
* claimed that the shift register may be filled with zeroes and locked up,
* which seems to be true.
* <P>
* We have not attempted to model this behavior, suffice to say that there
* is very little audible output from waveform combinations including noise.
* We hope that nobody is actually using it.
*/
protected int /* reg12 */outputNPST() {
return 0;
}
/**
* 12-bit waveform output. Select one of 16 possible combinations of
* waveforms.
*
* @return
*/
public int /* reg12 */output() {
// It may seem cleaner to use an array of member functions to return
// waveform output; however a switch with inline functions is faster.
switch (waveform) {
default:
case 0x0:
return output____();
case 0x1:
return output___T();
case 0x2:
return output__S_();
case 0x3:
return output__ST();
case 0x4:
return output_P__();
case 0x5:
return output_P_T();
case 0x6:
return output_PS_();
case 0x7:
return output_PST();
case 0x8:
return outputN___();
case 0x9:
return outputN__T();
case 0xa:
return outputN_S_();
case 0xb:
return outputN_ST();
case 0xc:
return outputNP__();
case 0xd:
return outputNP_T();
case 0xe:
return outputNPS_();
case 0xf:
return outputNPST();
}
}
// ----------------------------------------------------------------------------
// END Inline functions.
// ----------------------------------------------------------------------------
}