Mod Archive Forums

Music Production => MilkyTracker => Tracking => MilkyTracker Support => Topic started by: LokiClock on October 05, 2011, 05:23:19

Title: Envelope & fadeout meaning
Post by: LokiClock on October 05, 2011, 05:23:19
I'm translating envelopes and have some questions.
Can you export or read off the numerical values of envelope points? I built something for this since posting, but it didn't work for all my modules.
What are the lengths of each sample distance in the envelope, i.e. the width of each square in seconds?
How do fadeout settings translate into seconds?

A for sample distance:
amp=65536((e_1.amp-e_2.amp)(e_2.amp-tickspassed)/distance(e_1,e_2)+e_2.amp)>>16
Amplitude is a function of ticks passed, & the distance b-n points is more an expression of how many ticks it takes to shift the weight of interpolation from one envelope point e_1 to the next e_2.

A for fadeout:
amp(tick)=65536-fadeout*tick.
Has points (0, 65536) & (65536/fadeout, 0).
When fadeout=0, the 0 is at never (infinity) & the amplitude is constantly 65536.
Title: Re: Envelope & fadeout meaning
Post by: raina on October 05, 2011, 11:50:25
You can exchange envelope data between XI and PAT instruments. The tiny buttons above the envelope window are for storing and restoring envelopes. To store an envelope, first click the Store button, then one of the number buttons. The envelope is now saved on that # slot. You can then switch instruments and by clicking the # button, the stored envelope is applied to the current instrument. That's pretty much it for what you can do inside MilkyTracker, at least for now. The envelopes are saved in XI files, which could be processed outside milky though.

The smallest x-increment in the envelope editor is one tracker tick. The song Spd value controls how many ticks there are per pattern row. The BPM value sets the rate of the ticks. In other words the envelope speed is not fixed to time.

Shoot, I had the fadeout formula written down somewhere straight from the hors.. pailes' mouth. I can't find it right now but I'm fairly sure the fadeout speed is also related to ticks, not seconds. 0 never fades out, max fades out instantly. Trial and error is what I always say but I can try looking for the exact thing. In the meantime, it can be found somewhere in the source code. :)
Title: Re: Envelope & fadeout meaning
Post by: LokiClock on October 05, 2011, 14:09:21
The envelopes are saved in XI files, which could be processed outside milky though.

This is more what I mean. Clarified.

Quote
The smallest x-increment in the envelope editor is one tracker tick. The song Spd value controls how many ticks there are per pattern row. The BPM value sets the rate of the ticks. In other words the envelope speed is not fixed to time.

Okay, but if I use a fixed BPM & speed, how do I turn a tick into real time?

Quote
Trial and error is what I always say but I can try looking for the exact thing. In the meantime, it can be found somewhere in the source code. :)

Trial and error isn't an option, because I have no way of measuring the time precisely. :( If I get any spare time I'll go through the source, it can't be too hard to find.
Title: Re: Envelope & fadeout meaning
Post by: LokiClock on October 07, 2011, 17:48:29
I just found something strange to me, which is that sample points have 5- and 6-bit precision for each coordinate, but take up two bytes. Why on Earth?

EDIT: Nevermind, I can see the time values going beyond, I wasn't thinking straight and read the block precision for the numerical precision.
Title: Re: Envelope & fadeout meaning
Post by: LokiClock on October 13, 2011, 05:52:58
Partially answered for fadeout, going on milkyplay/PlayerSTD.cpp. Every tick, it lowers the amplitude by the sample fadeout value/65536. However, I don't know when that starts - When does keyOn become false? - or that the sample fadeout is exactly the same as the instrument's.

Code
------

Initial values:

Code: [Select]
void PlayerSTD::triggerInstrumentFX(TModuleChannel* chnInf)
{...
chnInf->fadevolstart = 65536;
chnInf->fadevolstep = module->smp[chnInf->smp].volfade;
...}

Values lowered:

Code: [Select]
void PlayerSTD::update()
{
mp_sint32 c;
#ifdef MILKYTRACKER
for (c=0;c<initialNumChannels;c++)
#else
for (c=0;c<numChannels;c++)
#endif
{...
if (!chnInf->keyon)
{
chnInf->fadevolstart-=chnInf->fadevolstep;
if (chnInf->fadevolstart<0) chnInf->fadevolstart=0;
}
...}

Which is called at the end of void PlayerSTD::tickhandler().
---

I may have the result for the envelope -> amplitude formula between these two pieces of code:

Code: [Select]
mp_sint32 PlayerSTD::getenvval(mp_sint32 c,TPrEnv *env,mp_sint32 n)
{
if (env->envstruc==NULL) return n;

if ((env->envstruc->type&1))
{

mp_sint32 dx = (env->envstruc->env[env->b][0]-env->envstruc->env[env->a][0]);
if (dx==0) dx=1;
mp_sint32 t = (env->envstruc->env[env->b][0]-env->step)*65536/dx;
mp_sint32 y0 = env->envstruc->env[env->a][1];
mp_sint32 y1 = env->envstruc->env[env->b][1];

mp_sint32 y = (y0*t)+(y1*(65536-t));

return y>>16;

}

else return n;
}

where env->b is the point after env->a. So far I know that if t is 0 then the result is y1, & if t is 65536 then it's y0.

Code: [Select]
mp_sint32 getvolume(mp_sint32 c,mp_sint32 nv)
{
mp_sint32 vol = (nv*getenvval(c,&chninfo[c].venv,256))>>7;
vol = (vol*chninfo[c].fadevolstart)>>16;
vol = (vol*chninfo[c].masterVol)>>8;
vol = (vol*mainVolume)>>8;
return vol;
}

I assume the mainVolume & masterVol parts are separate from the curve application, & that I can discard them. >>16 cancels the maximum value for fadevolstart, which is to be expected, since 65536 is the reference amplitude.
Title: Re: Envelope & fadeout meaning
Post by: LokiClock on October 13, 2011, 09:20:20
EDIT: Nevermind --

I found chnInf->step set to 0 & iterated in PlayerSTD::triggerEnvelope & PlayerSTD::prenvelope(), though under different names.

So the whole thing executes from triggerInstrumentFX, which is not, as I feared, only an effects envelope. noteOff is set before effects are called.

triggerInstrumentFX, besides from effects commands, is called by progressRow() in tickhandler(). I assume that runs once per tick, therefore prenvelope() can, so step is the number of ticks since the note started.

While getenvval() is interpolating the envelope points, this number is subtracted from the 2nd point of the pair's amplitude, & the result is multiplied by 65536 divided by the time difference dx between the two envelope points to get t.

I'll take 65536/dx to be a conversion of units from ticks as a portion of dx to portions of the reference amplitude 65536. When that portion is close to 100%, y0 has more weight, & when it's close to 0% y1 has more weight. Since the reference amplitude isn't normalized, the result needs to be divided by the maximum possible, 65536.

amp=65536((e_1.amp-e_2.amp)(e_2.amp-tickspassed)/distance(e_1,e_2)+e_2.amp)>>16