by andete. Original documents available at: https://github.com/andete/ym2413/tree/master/results

<< YM2413 Reverse Engineering Notes 2015-03-20 | YM2413 Reverse Engineering Notes | YM2413 Reverse Engineering Notes 2015-04-09 >>

Last post we looked at the YM2413 decay rates. Now it's time for the attack rates. Unfortunately I wasn't yet able to figure it out completely. But I'll already post what I've got now. Maybe one of you can help fill in some details.

Attack-rate table from the YM2413 datasheet

Let's start with the 0%-100% attack-rate table from the YM2413 datasheet. The first table below is copy/pasted from the datasheet (but rearranged in 4 columns). The second table is calculated using the C-program listed below.

RATE+0+1+2+3
0infinfinfinf
41730.151400.601153.43988.66
8865.08700.30576.72494.33
12432.54350.15288.36247.16
16216.27175.07144.18123.58
20108.1387.5472.0961.79
2454.0743.7736.0430.90
2827.0321.8818.0215.45
3213.5210.949.017.72
366.765.474.513.86
403.382.742.251.93
441.691.371.130.97
480.840.700.600.54
520.500.420.340.30
560.280.220.180.14
600.000.000.000.00
RATE+0+1+2+3
0infinfinfinf
41730.151400.61153.43988.657
8865.075700.299576.717494.329
12432.538350.15288.358247.164
16216.269175.075144.179123.582
20108.13487.537472.089661.7911
2454.067243.768736.044830.8955
2827.033621.884318.022415.4478
3213.516810.94229.01127.72389
366.75845.471094.50563.86194
403.37922.735542.25281.93097
441.68961.367771.12640.965486
480.84480.6838860.56320.482743
520.42240.3419430.28160.241371
560.2011430.1609140.14080.120686
600000
    double dur = 72.0 / 3579545.0 * 1000; // duration of 1 sample in ms
    for (int i = 4; i < 60; ++i) {
        int s[4] = {21, 17, 14, 12};
        int cycles = (i < 56)
                   ? (1 << (13 - (i / 4))) * s[i & 3]
                   : s[i & 3] / 2;
        cout << cycles * dur << endl;    
    }

Attack rates 0..3 take infinitely long (envelope doesn't change). Rates 60..63 are instantaneous.

Similar to the decay-rate tables, each row is half the row above, and there's also a fixed ratio between the values in the columns (factors are "21 17 14 12"). Though for the higher rates (48 and above) this isn't 100% correct anymore.

When expressed in YM2413 samples (49716Hz) instead of milliseconds, and rounded to the nearest integer, the values listed in the datasheet match exactly with the predicted values. At least up-to rate=48, for higher rates the values start to deviate.

Though it's not clear what the predictions in the above table actually mean. E.g. where do these column-ratios "21 17 14 12" come from? And how does the envelope actually change over that time period?

Attack rate measurements

Let's first look at some pictures:

  +0+1+2+3
4
8
12
16
20
24
28
32
36
40
44

These measurements are similar to the ones in the previous post: I played a sine wave but now varied channel.block and car.AR (instead of car.DR) to measure the different attack-rates (remember the effective rate is a combination of the selected AR parameter and the frequency of the channel). Here are the details of the settings I've used:

OperatorAMPMEGKRMLKLTLWFFBARDRSLRR
modulator0010000630015150015
carrier0010**0 0 **001515
reg#0x20 = 0x00key-off
reg#0x10 = 0x**fnum-low
reg#0x30 = 0x00max volume / custom instrument
reg#0x20 = 0x1*key-on / block=* / fnum=*

I varied car.AR from 0 to 15 and block between 1, 3, 5 and 7 (this gives effective rates 0..63). I mostly used fnum=256, but near the end I switched to fnum=511. I started with car.ML=0, but gradually ramped it up to car.ML=15.

Some observations:

- In column +0 all steps (except for the first and last) take equally long.
- In column +1 there are 3 long steps followed by 2 short steps.
- In column +2 the repeating pattern is 1 x long, 2 x short.
- And in column +3 the pattern is 6 x short, 1 x long.
- These patterns are exactly the same as we saw for decay, see previous post for details.
- Note that this pattern doesn't always start in the same relative position in the envelope. This can again be explained by the global counter.

Attack timing

Justified by the above measurements/observations we can now use almost exactly the same algorithm as we used for decay to explain the attack rate timing:

0.. 3: never advance to the next EG level (same as decay)
60..63: instantaneously go to the max level (different from decay)
eg_shift = 13 - (rate / 4)
eg_select = rate & 3
{0,1,0,1,0,1,0,1} // 4 out of 8
{0,1,0,1,1,1,0,1} // 5 out of 8
{0,1,1,1,0,1,1,1} // 6 out of 8
{0,1,1,1,1,1,1,1} // 7 out of 8

As mentioned above this algorithm likely doesn't apply for rates 52..59. It probably needs similar changes as were done for the decay-rate, though I don't have data yet to verify this.

To obtain data for these very high rates we cannot use the same measurement methodology (look at amplitude peaks). Instead I'm thinking about numerically matching all the sampled values with predictions from an emulation model. Though for this to work we first need to figure out the exact content of the internal sine and exponential table. That's something I'd like to do in one of the following posts.

Attack levels

We now know the timing of the attack-envelope transitions, but we do not yet know to what level we must go at each transition. (In case of decay it was simple: always add 1 (or 2) to the 7-bit EG counter).

In the above table we saw that (almost) all graphs used the same 12 amplitude levels. If we match those with levels of the decay envelope we get this:

attack-stepamplitudeEG-level
11112-127
2491-95
31171-72
42553
54739
67528
710720
814513
91729
102055
112441
122550

So for each of the 12 attack-rate levels (1st column) I measured the amplitude of the peaks (2nd column). Then I looked up the corresponding decay-EG level with the same amplitude (3rd column). Note that for low amplitudes there are multiple EG-levels that correspond with the same amplitude. So for the first few attack-steps I could only match a range of possible levels (I hope to also refine this measurement in the future).

I couldn't see any pattern in this sequence (3rd column), so I looked at earlier OPL3 reverse engineering work by 'carbon14' and 'opl3' for inspiration: http://forums.submarine.org.uk/phpBB/viewtopic.php?f=9&t=16

OPL3 has 512 EG steps (instead of 128 for YM2413). The formula for the OPL3 attack envelope levels is:

start with: x = 511;
advance: x += ~x >> 3; // Note: complement(~) instead of negate(-)

I tried to modify this for YM2413. The following comes close, but doesn't match exactly:

start with: x = 127;
advance: x += ~x >> 2;
predicted:1279571533929211511853210
actual:(127)(95)(71)53392820139510

So initially it matches pretty well, but near the end it goes too slow. I haven't been able yet to find a better formula.

Above I mentioned that 'almost' all rates used these same 12 levels. But rate=4 is different (visible in the pictures if you look closely). Instead for rate=4 I got this sequence:

112-127, 96-102, 73-74, 55, 41, 29, 21, 14, 10, 6, 2, 0

So also 12 steps, but slightly different levels.

But when I repeated the measurement for rate=4 I got the same sequence as for all the other measurements. So likely there's nothing special about rate=4. The special thing is that it's the very first measurement I took.

When I start another measurement, I do not fully restart the YM2413 hardware, instead I briefly set the channel to key-off and then to key-on again. Because car.DR=0 and car.RR=15 this very quickly goes from EG-level=0 to EG=127 before starting the attack-phase. I don't remember what I was doing before the very first attack-measurement but possibly the EG-level was in a different state at that time.

So next I started experimenting with different settings for car.SL, car.DR, car.RR, ... I tried to get into a different EG-level before starting the attack-measurement. Only very occasionally I could trigger an alternative attack sequence. (Only) once I could reproduce the sequence

112-127, 96-102, 73-74, 55, 41, 29, 21, 14, 10, 6, 2, 0

A few more times I got

112-127, 96-102, 75-77, 57, 42, 30, 22, 14, 10, 6, 2, 0

But, by far, in the majority of the cases I got

112-127, 91- 95, 71-72, 53, 39, 28, 20, 13, 9, 5, 1, 0

I'm not sure yet what determines which sequence the attack-envelope follows. My best guess is that for some reason the initial EG level is not 127 but another value, and because of this the formula generates a different sequence. But I don't know yet why the initial value is different and I also don't know yet what the exact formula is that generates the sequence.

In this and in the previous post we've looked at the attack and decay (and release) states in isolation. We should still investigate in more detail what happens on the transition between the different states. But that's also something for later.

Next post

Above I already mentioned possible improvements to the attack-rate measurements: instead of looking for peak-amplitude, try to numerically match the measured values with predicted values. This will allow to also measure rates 44..59 and distinguish between levels with the same amplitude.

I also mentioned that to be able to construct an emulation model to make predictions we first need to know the content of the internal sine and exponential tables. My plan is to investigate that in one of the next posts.

However I can already give a program that correctly predicts the maximum amplitudes for all 128 EG levels. This program is based on earlier OPL3 reverse engineering work done by Matthew Gambrell and Olli Niemitalo: https://docs.google.com/document/d/18IGx18NQY_Q1PJVZ-bHywao9bhsDoAqoIn1rIm42nwo

I'll explain in more detail in a later post.

This is the program:

    int expTable[256];

    int lookupExp(int val)
    {
        return (expTable[val & 0xFF] << 1) >> (val >> 8);
    }

    int main()
    {
        for (int i = 0; i < 256; ++i) {
            expTable[i ^ 255] = round(pow(2.0, i / 256.0) * 1024.0);
        }
        for (int i = 0; i < 128; ++i) {
            cout << i << 't' << lookupExp(16 * i) / 16 << endl;
        }
    }

And below is the output it produces. This matches 100% with the measured amplitude of all 128 EG levels, including the same level-ranges that share the same maximum amplitude.

EG-levelmax-amplitude
0255
1244
2234
3224
4214
5205
6196
7188
8180
9172
10165
11158
12151
13145
14139
15133
16127
17122
18117
19112
20107
21102
2298
2394
2490
2586
2682
2779
2875
2972
3069
3166
3263
3361
3458
3556
3653
3751
3849
3947
4045
4143
4241
4339
4437
4536
4634
4733
4831
4930
5029
5128
5226
5325
5424
5523
5622
5721
5820
5919
6018
6118
6217
6316
6415
6515
6614
6714
6813
6912
7012
7111
7211
7310
7410
759
769
779
788
798
807
817
827
837
846
856
866
875
885
895
905
914
924
934
944
954
963
973
983
993
1003
1013
1023
1032
1042
1052
1062
1072
1082
1092
1102
1112
1121
1131
1141
1151
1161
1171
1181
1191
1201
1211
1221
1231
1241
1251
1261
1271

<< YM2413 Reverse Engineering Notes 2015-03-20 | YM2413 Reverse Engineering Notes | YM2413 Reverse Engineering Notes 2015-04-09 >>




Return to top
0.268s