home *** CD-ROM | disk | FTP | other *** search
- // ---------------------------------------------------------------------------
- // 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
- // ---------------------------------------------------------------------------
-
- #define __ENVELOPE_CC__
- #include "envelope.h"
-
- // ----------------------------------------------------------------------------
- // Constructor.
- // ----------------------------------------------------------------------------
- EnvelopeGenerator::EnvelopeGenerator()
- {
- reset();
- }
-
- // ----------------------------------------------------------------------------
- // SID reset.
- // ----------------------------------------------------------------------------
- void EnvelopeGenerator::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 = RELEASE;
- rate_period = rate_counter_period[release];
- hold_zero = true;
- }
-
-
- // 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.
- //
- // 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.
- //
- // 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.
- //
- // 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.
- //
- // 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.
- //
- // 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.
- //
- // The ENV3 sampling code below yields a maximum timing error of 14 cycles.
- // lda #$01
- // l1: cmp $d41c
- // bne l1
- // ...
- // lda #$ff
- // l2: cmp $d41c
- // bne l2
- //
- // 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.
- //
- reg16 EnvelopeGenerator::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
- };
-
-
- // 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).
- //
- // 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.
- //
- // 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.
- //
- // 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.
- // 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
- // (255 + 162*1 + 39*2 + 28*4 + 12*8 + 8*16 + 6*30)*32 = 756*32 = 32352
- // which corresponds exactly to the timed value divided by the number of
- // complete envelopes.
- // NB! This one cycle delay is not modeled.
-
-
- // 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.
- //
- reg8 EnvelopeGenerator::sustain_level[] = {
- 0x00,
- 0x11,
- 0x22,
- 0x33,
- 0x44,
- 0x55,
- 0x66,
- 0x77,
- 0x88,
- 0x99,
- 0xaa,
- 0xbb,
- 0xcc,
- 0xdd,
- 0xee,
- 0xff,
- };
-
-
- // ----------------------------------------------------------------------------
- // Register functions.
- // ----------------------------------------------------------------------------
- void EnvelopeGenerator::writeCONTROL_REG(reg8 control)
- {
- 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 && gate_next) {
- 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 && !gate_next) {
- state = RELEASE;
- rate_period = rate_counter_period[release];
- }
-
- gate = gate_next;
- }
-
- void EnvelopeGenerator::writeATTACK_DECAY(reg8 attack_decay)
- {
- attack = (attack_decay >> 4) & 0x0f;
- decay = attack_decay & 0x0f;
- if (state == ATTACK) {
- rate_period = rate_counter_period[attack];
- }
- else if (state == DECAY_SUSTAIN) {
- rate_period = rate_counter_period[decay];
- }
- }
-
- void EnvelopeGenerator::writeSUSTAIN_RELEASE(reg8 sustain_release)
- {
- sustain = (sustain_release >> 4) & 0x0f;
- release = sustain_release & 0x0f;
- if (state == RELEASE) {
- rate_period = rate_counter_period[release];
- }
- }
-
- reg8 EnvelopeGenerator::readENV()
- {
- return output();
- }
-