/**
* 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;
/**
* A 15 bit counter is used to implement the envelope rates, in effect dividing
* the clock to the envelope counter by the currently selected rate period.
* <P>
* In addition, another counter is used to implement the exponential envelope
* decay, in effect further dividing the clock to the envelope counter. The
* period of this counter is set to 1, 2, 4, 8, 16, 30 at the envelope counter
* values 255, 93, 54, 26, 14, 6, respectively.
*
* @author Ken Händel
*
*/
public class EnvelopeGenerator {
public enum State {
ATTACK, DECAY_SUSTAIN, RELEASE
};
protected int /* reg16 */rate_counter;
protected int /* reg16 */rate_period;
protected int /* reg8 */exponential_counter;
protected int /* reg8 */exponential_counter_period;
protected int /* reg8 */envelope_counter;
protected boolean hold_zero;
protected int /* reg4 */attack;
protected int /* reg4 */decay;
protected int /* reg4 */sustain;
protected int /* reg4 */release;
protected int /* reg8 */gate;
/**
* ATTACK/DECAY_SUSTAIN/RELEASE
*/
protected State state;
/**
* Lookup table to convert from attack, decay, or release value to rate
* counter period.
* <P>
* Rate counter periods are calculated from the Envelope Rates table in the
* Programmer's Reference Guide. The rate counter period is the number of
* cycles between each increment of the envelope counter. The rates have
* been verified by sampling ENV3.
* <P>
* The rate counter is a 16 bit register which is incremented each cycle.
* When the counter reaches a specific comparison value, the envelope
* counter is incremented (attack) or decremented (decay/release) and the
* counter is zeroed.
* <P>
* NB! Sampling ENV3 shows that the calculated values are not exact. It may
* seem like most calculated values have been rounded (.5 is rounded down)
* and 1 has beed added to the result. A possible explanation for this is
* that the SID designers have used the calculated values directly as rate
* counter comparison values, not considering a one cycle delay to zero the
* counter. This would yield an actual period of comparison value + 1.
* <P>
* The time of the first envelope count can not be exactly controlled,
* except possibly by resetting the chip. Because of this we cannot do cycle
* exact sampling and must devise another method to calculate the rate
* counter periods.
* <P>
* The exact rate counter periods can be determined e.g. by counting the
* number of cycles from envelope level 1 to envelope level 129, and
* dividing the number of cycles by 128. CIA1 timer A and B in linked mode
* can perform the cycle count. This is the method used to find the rates
* below.
* <P>
* To avoid the ADSR delay bug, sampling of ENV3 should be done using
* sustain = release = 0. This ensures that the attack state will not lower
* the current rate counter period.
* <P>
* The ENV3 sampling code below yields a maximum timing error of 14 cycles.
*
* <pre>
* lda #$01
* l1: cmp $d41c
* bne l1
* ...
* lda #$ff
* l2: cmp $d41c
* bne l2
* </pre>
*
* This yields a maximum error for the calculated rate period of 14/128
* cycles. The described method is thus sufficient for exact calculation of
* the rate periods.
*/
protected static int /* reg16 */rate_counter_period[] = {
9, // 2ms*1.0MHz/256 = 7.81
32, // 8ms*1.0MHz/256 = 31.25
63, // 16ms*1.0MHz/256 = 62.50
95, // 24ms*1.0MHz/256 = 93.75
149, // 38ms*1.0MHz/256 = 148.44
220, // 56ms*1.0MHz/256 = 218.75
267, // 68ms*1.0MHz/256 = 265.63
313, // 80ms*1.0MHz/256 = 312.50
392, // 100ms*1.0MHz/256 = 390.63
977, // 250ms*1.0MHz/256 = 976.56
1954, // 500ms*1.0MHz/256 = 1953.13
3126, // 800ms*1.0MHz/256 = 3125.00
3907, // 1 s*1.0MHz/256 = 3906.25
11720, // 3 s*1.0MHz/256 = 11718.75
19532, // 5 s*1.0MHz/256 = 19531.25
31251 // 8 s*1.0MHz/256 = 31250.00
};
/**
* The 16 selectable sustain levels.
* <P>
* For decay and release, the clock to the envelope counter is sequentially
* divided by 1, 2, 4, 8, 16, 30, 1 to create a piece-wise linear
* approximation of an exponential. The exponential counter period is loaded
* at the envelope counter values 255, 93, 54, 26, 14, 6, 0. The period can
* be different for the same envelope counter value, depending on whether
* the envelope has been rising (attack -> release) or sinking
* (decay/release).
* <P>
* Since it is not possible to reset the rate counter (the test bit has no
* influence on the envelope generator whatsoever) a method must be devised
* to do cycle exact sampling of ENV3 to do the investigation. This is
* possible with knowledge of the rate period for A=0, found above.
* <P>
* The CPU can be synchronized with ENV3 by first synchronizing with the
* rate counter by setting A=0 and wait in a carefully timed loop for the
* envelope counter _not_ to change for 9 cycles. We can then wait for a
* specific value of ENV3 with another timed loop to fully synchronize with
* ENV3.
* <P>
* At the first period when an exponential counter period larger than one is
* used (decay or relase), one extra cycle is spent before the envelope is
* decremented. The envelope output is then delayed one cycle until the
* state is changed to attack. Now one cycle less will be spent before the
* envelope is incremented, and the situation is normalized.
* <P>
* The delay is probably caused by the comparison with the exponential
* counter, and does not seem to affect the rate counter. This has been
* verified by timing 256 consecutive complete envelopes with A = D = R = 1,
* S = 0, using CIA1 timer A and B in linked mode. If the rate counter is
* not affected the period of each complete envelope is
* <P>
* (255 + 162*1 + 39*2 + 28*4 + 12*8 + 8*16 + 6*30)*32 = 756*32 = 32352
* <P>
* which corresponds exactly to the timed value divided by the number of
* complete envelopes.
* <P>
* NB! This one cycle delay is not modeled.
* <P>
* From the sustain levels it follows that both the low and high 4 bits of
* the envelope counter are compared to the 4-bit sustain value. This has
* been verified by sampling ENV3.
*/
protected static int /* reg8 */sustain_level[] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, };
// ----------------------------------------------------------------------------
// 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() {
// Check for ADSR delay bug.
// If the rate counter comparison value is set below the current value
// of the rate counter, the counter will continue counting up until it
// wraps
// around to zero at 2^15 = 0x8000, and then count rate_period - 1
// before the
// envelope can finally be stepped.
// This has been verified by sampling ENV3.
//
if ((++rate_counter & 0x8000) != 0) {
++rate_counter;
rate_counter &= 0x7fff;
}
if (rate_counter != rate_period) {
return;
}
rate_counter = 0;
// The first envelope step in the attack state also resets the
// exponential counter. This has been verified by sampling ENV3.
//
if (state == State.ATTACK
|| ++exponential_counter == exponential_counter_period) {
exponential_counter = 0;
// Check whether the envelope counter is frozen at zero.
if (hold_zero) {
return;
}
if (state == State.ATTACK) {
// The envelope counter can flip from 0xff to 0x00 by changing
// state to release, then to attack. The envelope counter is
// then frozen
// at zero; to unlock this situation the state must be changed
// to
// release, then to attack. This has been verified by sampling
// ENV3.
//
++envelope_counter;
envelope_counter &= 0xff;
if (envelope_counter == 0xff) {
state = State.DECAY_SUSTAIN;
rate_period = rate_counter_period[decay];
}
} else if (state == State.DECAY_SUSTAIN) {
if (envelope_counter != sustain_level[sustain]) {
--envelope_counter;
}
} else if (state == State.RELEASE) {
// The envelope counter can flip from 0x00 to 0xff by changing
// state to
// attack, then to release. The envelope counter will then
// continue
// counting down in the release state.
// This has been verified by sampling ENV3.
// NB! The operation below requires two's complement integer.
//
--envelope_counter;
envelope_counter &= 0xff;
}
// Check for change of exponential counter period.
switch (envelope_counter) {
case 0xff:
exponential_counter_period = 1;
break;
case 0x5d:
exponential_counter_period = 2;
break;
case 0x36:
exponential_counter_period = 4;
break;
case 0x1a:
exponential_counter_period = 8;
break;
case 0x0e:
exponential_counter_period = 16;
break;
case 0x06:
exponential_counter_period = 30;
break;
case 0x00:
exponential_counter_period = 1;
// When the envelope counter is changed to zero, it is frozen at
// zero.
// This has been verified by sampling ENV3.
hold_zero = true;
break;
}
}
}
/**
* SID clocking - delta_t cycles.
*/
public void clock(int /* cycle_count */delta_t) {
// Check for ADSR delay bug.
// If the rate counter comparison value is set below the current value
// of the
// rate counter, the counter will continue counting up until it wraps
// around
// to zero at 2^15 = 0x8000, and then count rate_period - 1 before the
// envelope can finally be stepped.
// This has been verified by sampling ENV3.
//
// NB! This requires two's complement integer.
int rate_step = rate_period - rate_counter;
if (rate_step <= 0) {
rate_step += 0x7fff;
}
while (delta_t != 0) {
if (delta_t < rate_step) {
rate_counter += delta_t;
if ((rate_counter & 0x8000) != 0) {
++rate_counter;
rate_counter &= 0x7fff;
}
return;
}
rate_counter = 0;
delta_t -= rate_step;
// The first envelope step in the attack state also resets the
// exponential
// counter. This has been verified by sampling ENV3.
//
if (state == State.ATTACK
|| ++exponential_counter == exponential_counter_period) {
exponential_counter = 0;
// Check whether the envelope counter is frozen at zero.
if (hold_zero) {
rate_step = rate_period;
continue;
}
if (state == State.ATTACK) {
// The envelope counter can flip from 0xff to 0x00 by
// changing state to
// release, then to attack. The envelope counter is then
// frozen at
// zero; to unlock this situation the state must be changed
// to release,
// then to attack. This has been verified by sampling ENV3.
//
++envelope_counter;
envelope_counter &= 0xff;
if (envelope_counter == 0xff) {
state = State.DECAY_SUSTAIN;
rate_period = rate_counter_period[decay];
}
} else if (state == State.DECAY_SUSTAIN) {
if (envelope_counter != sustain_level[sustain]) {
--envelope_counter;
}
} else if (state == State.RELEASE) {
// The envelope counter can flip from 0x00 to 0xff by
// changing state to
// attack, then to release. The envelope counter will then
// continue
// counting down in the release state.
// This has been verified by sampling ENV3.
// NB! The operation below requires two's complement
// integer.
//
--envelope_counter;
envelope_counter &= 0xff;
}
// Check for change of exponential counter period.
switch (envelope_counter) {
case 0xff:
exponential_counter_period = 1;
break;
case 0x5d:
exponential_counter_period = 2;
break;
case 0x36:
exponential_counter_period = 4;
break;
case 0x1a:
exponential_counter_period = 8;
break;
case 0x0e:
exponential_counter_period = 16;
break;
case 0x06:
exponential_counter_period = 30;
break;
case 0x00:
exponential_counter_period = 1;
// When the envelope counter is changed to zero, it is
// frozen at zero.
// This has been verified by sampling ENV3.
hold_zero = true;
break;
}
}
rate_step = rate_period;
}
}
/**
* 8-bit envelope output.
* <P>
* Read the envelope generator output.
*
* @return envelope_counter
*/
public int /* reg8 */output() {
return envelope_counter;
}
// ----------------------------------------------------------------------------
// END Inline functions.
// ----------------------------------------------------------------------------
/**
* Constructor.
*/
public EnvelopeGenerator() {
reset();
}
/**
* SID reset.
*/
public void reset() {
envelope_counter = 0;
attack = 0;
decay = 0;
sustain = 0;
release = 0;
gate = 0;
rate_counter = 0;
exponential_counter = 0;
exponential_counter_period = 1;
state = State.RELEASE;
rate_period = rate_counter_period[release];
hold_zero = true;
}
/**
* Register functions.
*
* @param control
* control register
*/
public void writeCONTROL_REG(int /* reg8 */control) {
int /* reg8 */gate_next = control & 0x01;
// The rate counter is never reset, thus there will be a delay before
// the
// envelope counter starts counting up (attack) or down (release).
// Gate bit on: Start attack, decay, sustain.
if ((gate == 0) && (gate_next != 0)) {
state = State.ATTACK;
rate_period = rate_counter_period[attack];
// Switching to attack state unlocks the zero freeze.
hold_zero = false;
}
// Gate bit off: Start release.
else if ((gate != 0) && (gate_next == 0)) {
state = State.RELEASE;
rate_period = rate_counter_period[release];
}
gate = gate_next;
}
/**
* @param attack_decay
* attack/decay value
*/
public void writeATTACK_DECAY(int /* reg8 */attack_decay) {
attack = (attack_decay >> 4) & 0x0f;
decay = attack_decay & 0x0f;
if (state == State.ATTACK) {
rate_period = rate_counter_period[attack];
} else if (state == State.DECAY_SUSTAIN) {
rate_period = rate_counter_period[decay];
}
}
/**
* @param sustain_release
* sustain/release value
*/
public void writeSUSTAIN_RELEASE(int /* reg8 */sustain_release) {
sustain = (sustain_release >> 4) & 0x0f;
release = sustain_release & 0x0f;
if (state == State.RELEASE) {
rate_period = rate_counter_period[release];
}
}
/**
* @return envelope counter
*/
public int /* reg8 */readENV() {
return output();
}
}