Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
 Welcome to our latest new user maak ! (Registered 2024-04-18) You are not logged in - nap
CSDb User Forums


Forums > C64 Coding > Neat way to implement single/double hard-restart
2016-03-17 06:29
lft

Registered: Jul 2007
Posts: 369
Neat way to implement single/double hard-restart

In SID envelope rate counter phase alignment, Laurent6581 off-topicly wrote:

Quoting Laurent6581
I have seen many players that seemed to voluntarily triggered a second delay bug before attack restart.


Thanks a lot for this! I was unaware of the technique, but it is very useful. Here's how I implemented it in my current playroutine:

Two frames before a hard-restart instrument is about to be triggered, clear SR and Gate. On the target frame---again, only for hard-restart instruments---first write 0f to SR. The counter escapes from the 9-cycle bottle. Now do other stuff (including setting up AD), counting the CPU cycles. When the envelope counter is known to be in the range 33..61, set Gate. Finally write the correct SR.

In this way, hard-restart instruments with attack rate 0 or 1 will have the extra 30 ms delay, for snappy percussion sounds. Attack rate 2 or higher will behave normally. And the bug where the decay rate is used for one cycle is circumvented automatically.

The total attack rate becomes:

Rate   Normal   Extra   Total
0        2 ms   30 ms   32 ms
1        8 ms   30 ms   38 ms
2       16 ms           16 ms
3       24 ms           24 ms
4       38 ms           38 ms
...


So, for instance, instruments with attack rate 4 will line up with (hard-restart) instruments having attack rate 1.

Since the extra "delay" is just the envelope being stuck at zero, the first frame of wavetable/filtertable has to contain a dummy value. A corresponding delay of one frame could be programmed into the playroutine, or the dummy value could be hidden in the tracker UI.
 
... 8 posts hidden. Click here to view all posts....
 
2016-03-18 08:00
Jammer

Registered: Nov 2002
Posts: 1289
To add my three cents, I've practically stopped using Sustain/Release in instruments at 2x/4x speed if instrument is supposed to fade out at any time - I set SR to 0F and operate on AD entirely. It allowed me to use hardrestart time in Goat Tracker reduced from 8 player calls to 1 or 2 at 4x speed:

http://f.jammerstudio.pl/RealClap_4x.sid

Besides it's definitely more stable that my previous unstable Attack set to 1 that imposed earlier sound and I can use really quick retriggers ;)
2016-03-18 08:14
lft

Registered: Jul 2007
Posts: 369
Agemixer, I think there are two motivations for the traditional approach: Simplicity (and thus code size), and consistency of note starts. It's important to have precise control over the attack of notes, and that becomes difficult if the initial volume is varying.

When I want to do legato notes, I make some copies of the current instrument, disable hard-restart and fix the ADSR values to prevent the bug. Or I just change the pitch without retriggering the envelope.

But it's certainly possible to do what you suggest under the right circumstances, and I think that it overlaps with what ChristopherJam is attempting as well. If a note is currently being sustained (gate = on), we can do the hard-restart by writing 00 to AD two frames before the next note. To trigger the new note, we clear SR and the control register, set up the new AD, turn gate on, and finally set up SR. On the other hand, if no note is playing, we can do hard-restart the normal way. Or, like you suggest, we always stop notes by dropping S to 0 and leaving gate on.

The problem is when there's a note playing in the attack or decay phases. Clearing AD would produce an audible blip that would be out of time with the music. The only way to be safe would be to ensure, while composing, that there's enough time for every note to reach the sustain phase.
2016-03-18 15:46
ChristopherJam

Registered: Aug 2004
Posts: 1370
Quoting Agemixer
Does this all assume that sustain value should be dropped completely down to $00 before restart? Or by (level-1)..0?

Level (amplitude), not sustain.

Quote:
What if i wanted to leave at previous sustain level (read: reverb) until just the next tone Attack cycle starts?
..Without any delay, how would you deal with that?

Force a bug at start of second last frame of previous note, clear gate, and set S=R=0. This way the sustain continues until halfway through the last frame (as the envelope is frozen), then the level drops to zero in at most 6ms, leaving less than 10ms silence before the start of the next note.

Quote:
why not simulate the release with lowering Sustain level instead.

Internally, that's what I'll probably do, whenever there's a rest between that note and the next. But that's just an implementation detail; the editor should show a standard ADSR waveform.

Quote:
But how would you do a HR then, let's say when the remaining amplitude would be anything between $00..$ff? (And i don't mean the $d406 sustain setting)

See above - freeze env for 30ms, at the end of which it'll take at most 6ms to drop down from any amplitude. (edited now I read the question properly)
2016-03-18 20:24
lft

Registered: Jul 2007
Posts: 369
Quoting ChristopherJam
Force a bug at start of second last frame of previous note, clear gate, and set S=R=0. This way the sustain continues until halfway through the last frame (as the envelope is frozen), then the level drops to zero in at most 6ms, leaving less than 10ms silence before the start of the next note.


How would you force the bug at that precise moment unless you know the value of the counter? For long notes, you could rely on a hard-restart hidden in the sustain phase, but again, what if the new note is interrupting an ongoing attack or decay?
2016-03-18 20:33
lft

Registered: Jul 2007
Posts: 369
Quoting lft
Quoting cadaver
Requiring a semi-precise window of timing practically means you'll have to run the player in the border, otherwise the variable time of execution on other channels may lead the time-critical execution of e.g. the last channel to happen during a badline.


Correct!

For what it's worth, I believe that sprite DMA is safe. Nine cycles of phase uncertainty plus 0..19 stolen cycles, that's a jitter of 9 + 20 - 1 = 28 cycles, and we need to be within a 31-cycle range. So ghost sprites in the border shouldn't be a problem as long as the playroutine is tightly coded.


Some further thoughts: The worst that could happen is eight sprites, badline, eight sprites. That's going to push the counter beyond 63, but it's still well below 149. For the musician, this means that hard-restart instruments with attack rate 2 or 3 are unsafe (i.e. the note start could randomly be delayed by 30 ms) if the playroutine executes in the normal display area. Any other attack rate is going to behave properly. Rates 0 and 1 will always have the extra delay, and rates 4 and above will never have it. So this technique would still be usable in e.g. CIA-tempo tunes if you just avoid those two attack rates.
2016-03-18 22:13
ChristopherJam

Registered: Aug 2004
Posts: 1370
Quote: Quoting ChristopherJam
Force a bug at start of second last frame of previous note, clear gate, and set S=R=0. This way the sustain continues until halfway through the last frame (as the envelope is frozen), then the level drops to zero in at most 6ms, leaving less than 10ms silence before the start of the next note.


How would you force the bug at that precise moment unless you know the value of the counter? For long notes, you could rely on a hard-restart hidden in the sustain phase, but again, what if the new note is interrupting an ongoing attack or decay?


Editor should know what the rate limit is at that point, from the duration of the note. If the rate limit index is less than $f,then increase to $f for at least nine cycles, then drop rate limit index to $0

If rate limit index is equal to $f then it's a bit messier; easy way out would be to lower that for any notes short enough to be interrupted..

Of course, if it's a fairly fast attack or decay, then freezing the envelope level for 30ms might not be appropriate..
2016-03-19 20:24
lft

Registered: Jul 2007
Posts: 369
Quoting ChristopherJam
Editor should know what the rate limit is at that point, from the duration of the note. If the rate limit index is less than $f,then increase to $f for at least nine cycles, then drop rate limit index to $0


Suppose that rate $d is in use, perhaps during a note release. When it is time for hard-restart, the player switches to $f, then to $0. This will indeed trigger a wraparound. If the counter happened to be at a low value, you'll get the 30 ms delay, and "less than 10ms silence before the start of the next note". But if the counter was at 10000, you'll only get a 20 ms delay, and thus 20 ms of silence.
2016-03-20 03:55
ChristopherJam

Registered: Aug 2004
Posts: 1370
Quote: Quoting ChristopherJam
Editor should know what the rate limit is at that point, from the duration of the note. If the rate limit index is less than $f,then increase to $f for at least nine cycles, then drop rate limit index to $0


Suppose that rate $d is in use, perhaps during a note release. When it is time for hard-restart, the player switches to $f, then to $0. This will indeed trigger a wraparound. If the counter happened to be at a low value, you'll get the 30 ms delay, and "less than 10ms silence before the start of the next note". But if the counter was at 10000, you'll only get a 20 ms delay, and thus 20 ms of silence.


Good point. I guess anything from $d to $f would need dropping down to $c a frame or two in advance; if the decay is that slow then halting the fall for a few frames should be inaudible.
2016-03-20 03:57
ChristopherJam

Registered: Aug 2004
Posts: 1370
Jammer, those claps are excellent! I'm going to have to take a closer look at your register bashing..
2016-08-07 21:18
lft

Registered: Jul 2007
Posts: 369
Quoting lft
Quoting lft
Quoting cadaver
Requiring a semi-precise window of timing practically means you'll have to run the player in the border, otherwise the variable time of execution on other channels may lead the time-critical execution of e.g. the last channel to happen during a badline.


Correct!

For what it's worth, I believe that sprite DMA is safe. Nine cycles of phase uncertainty plus 0..19 stolen cycles, that's a jitter of 9 + 20 - 1 = 28 cycles, and we need to be within a 31-cycle range. So ghost sprites in the border shouldn't be a problem as long as the playroutine is tightly coded.


Some further thoughts: The worst that could happen is eight sprites, badline, eight sprites. That's going to push the counter beyond 63, but it's still well below 149. For the musician, this means that hard-restart instruments with attack rate 2 or 3 are unsafe (i.e. the note start could randomly be delayed by 30 ms) if the playroutine executes in the normal display area. Any other attack rate is going to behave properly. Rates 0 and 1 will always have the extra delay, and rates 4 and above will never have it. So this technique would still be usable in e.g. CIA-tempo tunes if you just avoid those two attack rates.


Based on a true story: If you use this technique, and you have sprite DMA interfering with the playroutine, then you should avoid decay rate 2 in double-hard-restart instruments (e.g. with attack 0 or 1).

Normally, my routine above will nicely avoid the bug where the decay rate is used for the first cycle of attack. However, at least in my current playroutine, if eight sprites are active and the envelope counter is at 8 when the bottle is opened, the counter will be at 62 just when the gate bit is set. Then the counter will wrap around to zero, preventing the second hard-restart and messing up the note attack. This only happens on real hardware, and it goes away if I change the decay rate to 1.
Previous - 1 | 2 - 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
dmantione
hedning/G★P
CreaMD/React
Mason/Unicess
jeroen1328
ΛΛdZ
lft
Guests online: 165
Top Demos
1 Next Level  (9.8)
2 Mojo  (9.7)
3 Coma Light 13  (9.7)
4 Edge of Disgrace  (9.6)
5 Comaland 100%  (9.6)
6 No Bounds  (9.6)
7 Uncensored  (9.6)
8 Wonderland XIV  (9.6)
9 The Ghost  (9.6)
10 Bromance  (9.6)
Top onefile Demos
1 It's More Fun to Com..  (9.9)
2 Party Elk 2  (9.7)
3 Cubic Dream  (9.6)
4 Copper Booze  (9.5)
5 Rainbow Connection  (9.5)
6 TRSAC, Gabber & Pebe..  (9.5)
7 Onscreen 5k  (9.5)
8 Dawnfall V1.1  (9.5)
9 Quadrants  (9.5)
10 Daah, Those Acid Pil..  (9.5)
Top Groups
1 Oxyron  (9.3)
2 Nostalgia  (9.3)
3 Booze Design  (9.3)
4 Censor Design  (9.3)
5 Crest  (9.3)
Top Organizers
1 Burglar  (9.9)
2 Sixx  (9.8)
3 hedning  (9.7)
4 Irata  (9.7)
5 MWS  (9.6)

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