Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in - nap
CSDb User Forums


Forums > C64 Composing > Avoiding the ADSR bug in the decay phase.
2015-04-21 11:49
lft

Registered: Jul 2007
Posts: 369
Avoiding the ADSR bug in the decay phase.

Random insight of the day:

The ADSR bug is well known: When we switch from a slow to a fast envelope rate, the envelope generator sometimes gets stuck for about 33 ms (1.67 PAL frames). This tends to happen when we have a slow release, and then try to trigger a note with a fast attack. The attack gets delayed unpredictably.

Some playroutines provide a hard restart feature to work around this problem.

But here's the insight: The same thing can and does happen when we switch from a slow attack to a fast decay, or from a slow decay to a fast release. So, if we use an ADSR setting of, say, 10 aa, we get a fast attack, and then we switch to an even faster decay. This will actually trigger the bug! The volume level could remain at the maximum for up to 33 ms. Furthermore, if we try to release the note too soon (within 1-2 frames), the release could be delayed unpredictably.

To avoid this, we have to use a decay rate that is greater than or equal to the attack rate.

On the other hand, sometimes this phenomenon is useful. If we want a slow attack and a fast release, and we know that we want to hold the note for more than two frames beyond the attack period, then this is exactly what we want. For instance, if we use f0 f2, we get a slow attack, followed by the ADSR bug (random delay of up to 33 ms). Then, as soon as we release the gate, we get an immediate response, because we already have the bug behind us.

To summarise:

If you want to reach the sustain level in the same amount of time for every note, or if you want to reach it as quickly as possible, ensure that D >= A.

If you want the release to start immediately when you turn off the gate bit, ensure that R >= D.

Advanced technique:

Suppose you want to reach the sustain level as quickly as possible, but you also want the release to start immediately. And you want a slow attack and a fast release.

A > R, R >= D, D >= A, does not compute.

But you can use e.g. 77 84 when you start the note, and then, after the note has reached the sustain phase, switch to an instrument with a 70 84 envelope. Then wait two more frames to get past the bug. Then, the release will be predictable and immediate.
 
... 31 posts hidden. Click here to view all posts....
 
2015-04-23 17:44
ChristopherJam

Registered: Aug 2004
Posts: 1409
Ahaha, I'm an idiot. I was accidentally running my test code in an old copy of vice-2.2 I'd started writing a patch for. I'll investigate more thoroughly in the morning :D
2015-04-24 13:29
lft

Registered: Jul 2007
Posts: 369
Quoting ChristopherJam
Yes, I too would love to find a way to stabilise without letting it escape twice.


I spent some time thinking about this, until I had convinced myself that it was, in fact, impossible.

Then I figured out a way to do it anyway.

I believe this technique could be used to implement a new kind of hard-restart mechanism where you would get predictable ADSR bugs at the note level (i.e. each note with the same instrument, held for the same amount of frames, gets exactly the same envelope). For instance, you could toggle the gate bit any number of times from the wavetable, and the instrument would still sound exactly the same every time. However, this feature would eat up a lot of rastertime (at least 10 more lines) and would require parts of the playroutine to be cycle exact. But it could be useful for compo tunes.

In the immortal words of Knuth, beware of bugs in the code; I have only proved it correct, not tried it.

I'll take it from the beginning.

The first step is to perform an ordinary hard restart, i.e. selecting the shortest period (nine cycles) and waiting for the counter to wrap around. However, we add a twist, which is to perform the hard restart with the gate enabled and ADSR = 00ee. Naturally, we also select waveform 0 to avoid audible artefacts.

This will leave us in the sustain state, with the envelope counter at $ee, the exponential counter period at 1, and the rate counter somewhere in the range 0..8.

Now we do something quite similar to the code snippet provided by ChristopherJam. I took the liberty of optimising it, by using periods 9 and 32 instead, and distributing the phases 45 cycles apart instead of 63.

        ldx     #$ee
        lda     #$11
        ldy     #7
        jmp     entry
loop
        nop
        sta     $d405   ; 11
        nop
        nop
        sax     $d405   ; 00
        nop
        nop
        nop
        nop
        nop
entry  
        stx     $d405   ; ee
        nop
        nop
        sax     $d405   ; 00
        nop
        nop
        dey
        bne     loop

        bit     0
        sta     $d405   ; 11


Below is a table that shows what happens to the rate counter as we run the code. Starting with a given initial phase, run for N cycles at period P to obtain the phases on the next line.

Counter value (modulo 9 in brackets)                                       N      P
------------------------------------------------------------------------+------+ -------
0 (0)   1 (1)   2 (2)   3 (3)   4 (4)   5 (5)   6 (6)   7 (7)   8 (8)   |  8   |  19532
8 (8)   9 (0)   10 (1)  11 (2)  12 (3)  13 (4)  14 (5)  15 (6)  16 (7)  |  15  |  9
5 (5)   24 (6)  25 (7)  26 (8)  27 (0)  28 (1)  29 (2)  30 (3)  31 (4)  |  8   |  32
13 (4)  0 (0)   1 (1)   2 (2)   3 (3)   4 (4)   5 (5)   6 (6)   7 (7)   |  14  |  9
27 (0)  5 (5)   6 (6)   7 (7)   8 (8)   0 (0)   1 (1)   2 (2)   3 (3)   |  8   |  19532
35 (8)  13 (4)  14 (5)  15 (6)  16 (7)  8 (8)   9 (0)   10 (1)  11 (2)  |  15  |  9
50 (5)  28 (1)  29 (2)  30 (3)  31 (4)  5 (5)   24 (6)  25 (7)  26 (8)  |  8   |  32
58 (4)  4 (4)   5 (5)   6 (6)   7 (7)   13 (4)  0 (0)   1 (1)   2 (2)   |  14  |  9
72 (0)  0 (0)   1 (1)   2 (2)   3 (3)   27 (0)  5 (5)   6 (6)   7 (7)   |  8   |  19532
80 (8)  8 (8)   9 (0)   10 (1)  11 (2)  35 (8)  13 (4)  14 (5)  15 (6)  |  15  |  9
95 (5)  5 (5)   24 (6)  25 (7)  26 (8)  50 (5)  28 (1)  29 (2)  30 (3)  |  8   |  32
103 (4) 13 (4)  0 (0)   1 (1)   2 (2)   58 (4)  4 (4)   5 (5)   6 (6)   |  14  |  9
117 (0) 27 (0)  5 (5)   6 (6)   7 (7)   72 (0)  0 (0)   1 (1)   2 (2)   |  8   |  19532
125 (8) 35 (8)  13 (4)  14 (5)  15 (6)  80 (8)  8 (8)   9 (0)   10 (1)  |  15  |  9
140 (5) 50 (5)  28 (1)  29 (2)  30 (3)  95 (5)  5 (5)   24 (6)  25 (7)  |  8   |  32
148 (4) 58 (4)  4 (4)   5 (5)   6 (6)   103 (4) 13 (4)  0 (0)   1 (1)   |  14  |  9
162 (0) 72 (0)  0 (0)   1 (1)   2 (2)   117 (0) 27 (0)  5 (5)   6 (6)   |  8   |  19532
170 (8) 80 (8)  8 (8)   9 (0)   10 (1)  125 (8) 35 (8)  13 (4)  14 (5)  |  15  |  9
185 (5) 95 (5)  5 (5)   24 (6)  25 (7)  140 (5) 50 (5)  28 (1)  29 (2)  |  8   |  32
193 (4) 103 (4) 13 (4)  0 (0)   1 (1)   148 (4) 58 (4)  4 (4)   5 (5)   |  14  |  9
207 (0) 117 (0) 27 (0)  5 (5)   6 (6)   162 (0) 72 (0)  0 (0)   1 (1)   |  8   |  19532
215 (8) 125 (8) 35 (8)  13 (4)  14 (5)  170 (8) 80 (8)  8 (8)   9 (0)   |  15  |  9
230 (5) 140 (5) 50 (5)  28 (1)  29 (2)  185 (5) 95 (5)  5 (5)   24 (6)  |  8   |  32
238 (4) 148 (4) 58 (4)  4 (4)   5 (5)   193 (4) 103 (4) 13 (4)  0 (0)   |  14  |  9
252 (0) 162 (0) 72 (0)  0 (0)   1 (1)   207 (0) 117 (0) 27 (0)  5 (5)   |  8   |  19532
260 (8) 170 (8) 80 (8)  8 (8)   9 (0)   215 (8) 125 (8) 35 (8)  13 (4)  |  15  |  9
275 (5) 185 (5) 95 (5)  5 (5)   24 (6)  230 (5) 140 (5) 50 (5)  28 (1)  |  8   |  32
283 (4) 193 (4) 103 (4) 13 (4)  0 (0)   238 (4) 148 (4) 58 (4)  4 (4)   |  14  |  9
297 (0) 207 (0) 117 (0) 27 (0)  5 (5)   252 (0) 162 (0) 72 (0)  0 (0)   |  8   |  19532
305 (8) 215 (8) 125 (8) 35 (8)  13 (4)  260 (8) 170 (8) 80 (8)  8 (8)   |  15  |  9
320 (5) 230 (5) 140 (5) 50 (5)  28 (1)  275 (5) 185 (5) 95 (5)  5 (5)   |  4   |  32
324 (0) 234 (0) 144 (0) 54 (0)  0 (0)   279 (0) 189 (0) 99 (0)  9 (0)   |      |


At this point, the phases for the nine possible cases have been spread out so that they are equal modulo nine. The maximum value of the counter is 324.

Now for the spectacular finale where I take the error in my original post and turn it around to my advantage. We release the gate, set ADSR to 80ee, turn the gate on again, and wait for at least 392 * 17 cycles.

When we release the gate, nothing much happens (the period is reconfigured to 19532). But when we re-enable it, the state machine enters the attack state, and the envelope counter is incremented exactly 17 times, 392 cycles apart (rate #8). On the 17th time, the counter reaches $ff, and the rate counter is reconfigured for rate #0 (the decay rate), with a period of nine cycles. As was kindly pointed out by ChristopherJam, this transition happens synchronously, and doesn't trigger the bug. We don't know exactly when the transition occurs; it could happen at any of nine different moments. But these moments are equal modulo nine, so after the transition, the value of the rate counter is at a fixed offset relative to the time we turned on the gate, and thus relative to the remainder of the playroutine. This makes the ADSR bug behave deterministically.

We are now left with the the envelope counter at $ee when we want it at $00. A full decay takes 7k cycles. In fact, to implement a hard restart using the technique as described above, we would need to spread the routine over three frames. In a practical implementation, we should instead work with sustain level f, and take care to work around the envelope counter wraparound bugs. The entire procedure would then require 32758 cycles for the initial counter wrap, 2295 cycles to reach $ff, some 300 cycles for the code snippet above and 392 cycles to finally reach the decay stage, for a total of 35745 cycles (1.8 PAL frames). This would then be followed by some code to increment the envelope counter to $00, unfreeze it and release the gate.

To get an actual implementation up and running is left as an exercise for the reader.
2015-04-24 14:15
Mixer

Registered: Apr 2008
Posts: 452
Quoting lft


I spent some time thinking about this, until I had convinced myself that it was, in fact, impossible.

Then I figured out a way to do it anyway.



That is how to sum up the scene-attitude.
2015-04-24 17:51
ChristopherJam

Registered: Aug 2004
Posts: 1409
Oh that's bloody brilliant - nice work indeed. Perfect rate counter sync, and in about as much time as a normal hard restart. Going to have to have a go at trying this one out. At the very least, it should mean I can run my regression tests and measurements twice as fast :)
2015-04-27 15:21
chatGPZ

Registered: Dec 2001
Posts: 11386
gogogo! :)
2015-04-29 16:47
Agemixer

Registered: Dec 2002
Posts: 39
All right.. i haven't examined the ADSR bug(s) yet until now.. i should because i'm working on an editor which "almost requires"more exact handling of SID in general. I never did a "proper" hardrestart, but got to know there are plenty or "wrong" ways to do it, unlesss i'm mistaken?

Despite those sound flaws the tunes made even from the early days plays relatively perfectly (most of them) so that it's unlikely to heard bugs.

What exact transitions or SID programming sequences affect what, i have no idea. I only know the hard restart by musicroutines are made setting 2 frames before setting gate=1 to get a faster response for Attack cycle. But does it really have to be so?

I'm not familiar yet with all the current SID jargon, but i try to understand anyway :)

Are there any tools, test suites, code snippets, or whatsoever to demonstrate and minimize the problems? Do they summarize into just one ADSR counter having its own internal life and cannot be directly reset or programmed?

i can see most of you have been examining the ADSR bug for a while now.. The last time i was into that stuff was last millenium :)

Anyway, i just finished a little tool to examine ADSR:

http://skalaria.japo.fi/adsr-oscilloscope.zip

Also a source code available:

http://skalaria.japo.fi/adsr-oscilloscope.asm

Feel free to send patches and features for this. I already spent several hours doing that code.
2015-04-29 16:59
Agemixer

Registered: Dec 2002
Posts: 39
I'm not sure if that oscilloscope is a good one at all to examine this one, but atleast visualizes the SID. f.e. I read the R cycle is logarithmic but i didn't know it is THAT much. (refering to Bob Yannes there's some LUT tables to certain positions to halve the oscillator for D and R but A is a linear one).

About the program: The left side illustrates the gate is turned on, the right (grey) side when gate is turned off.

And i found some weird ADSR behaviors. One is here:
Start ADSR=$1132
Start gate=$41
Ending ADSR=$1132
Ending gate=$40
and, gate delay=9. (You can count the exact cycles out of this (SEI), see the code for reference to calculate it.)

Press return key several times. For some strange reason the ADSR is started sometimes in the middle of the screen. I thought the delay must be fraction of this, but the osc says there's a lot of cycles wasted before it actually starts, and starts always at same position (just using Vice, i haven't checked with real machines yet).

How is that possible, and why the Attack starts that late, in this situation?! Notice the small AD/R values, so exactly what might be causing this?
2015-04-29 19:43
Frantic

Registered: Mar 2003
Posts: 1648
I may miss something obvious but aren't you simply encountering the ADSR bug, which manifests itself precisely as a delay happening whenever that internal counter misses its target criterion and wraps around internally before eventually hitting the target criterion? At least that's my understanding.

Nice program btw. :)
2015-04-30 03:41
Agemixer

Registered: Dec 2002
Posts: 39
Thanks :)
Are all the bugs known gate transition influenced? Or register write?
2015-04-30 04:17
ChristopherJam

Registered: Aug 2004
Posts: 1409
Yup, that would be the ADSR bug manifesting.

To the best of my knowledge:
- it's only triggered by register writes
- it can happen any time a register write causes a transition from a slow speed to a faster one
- this happens either by changing the rate of the envelope phase that's currently running (eg changing attack from 4 to 3 during the attack time)
- or by setting or clearing the gate bit at a time there are 'dangerous' ADSR values set.

In your case, you're transitioning from a release of 2 to an attack of 1.

In general, setting gate when R>A, or clearing it when R<D (or <A if you do it during attack) will always risk locking up the envelope for a frame and a half.

There's also a slight risk setting gate when R=A, but only if D is different to them, and a clever music routine could work around this by temporarily setting D to the same as the other two (there's a single cycle bug that most emulators don't cover yet)

The usual work around is to use a hard-restart, that hides the lockup in a couple of frames of silence before the note starts. As LFT suggested above, in some instances it should be possible to hide the lockup in the sustain phase instead, but that would require more control than many players provide you with.
Previous - 1 | 2 | 3 | 4 | 5 - Next
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
Flashback
Shake/Role
HOL2001/Quantum
Steffan/BOOM!
diabolus
The Human Co../Maste..
Guests online: 112
Top Demos
1 Next Level  (9.7)
2 13:37  (9.7)
3 Mojo  (9.7)
4 Coma Light 13  (9.6)
5 Edge of Disgrace  (9.6)
6 What Is The Matrix 2  (9.6)
7 The Demo Coder  (9.6)
8 Uncensored  (9.6)
9 Comaland 100%  (9.6)
10 Wonderland XIV  (9.6)
Top onefile Demos
1 Layers  (9.6)
2 No Listen  (9.6)
3 Cubic Dream  (9.6)
4 Party Elk 2  (9.6)
5 Copper Booze  (9.6)
6 Rainbow Connection  (9.5)
7 Dawnfall V1.1  (9.5)
8 Onscreen 5k  (9.5)
9 Morph  (9.5)
10 Libertongo  (9.5)
Top Groups
1 Performers  (9.3)
2 Booze Design  (9.3)
3 Oxyron  (9.3)
4 Triad  (9.3)
5 Censor Design  (9.3)
Top NTSC-Fixers
1 Pudwerx  (10)
2 Booze  (9.7)
3 Stormbringer  (9.7)
4 Fungus  (9.6)
5 Grim Reaper  (9.3)

Home - Disclaimer
Copyright © No Name 2001-2024
Page generated in: 0.054 sec.