Kenji's K5000 Message Board Digest - Overview | K5000 Resources - Overview |

The Eat at Joe's Kawai K5000 Message Board Digest Converting Rates to Time Values ------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ Re: Rate/Time Formula Tuesday, 24-Mar-98 08:44:07 130.67.65.6 writes: First of all, you said something about sending a letter to Kawai. I hope that will solve the matter. As already stated, level adjustment is an accelerated type of motion, and the acceleration is greater for low levels than for high ones. The general solution should therefore be some sine or exponential function, depending. Just what that formula is and how to fit it to the constants in our case eludes me at present, but I might succeed if I keep working on it. In any case, the simplest solution may be to use a table derived from systematic experiments. I will probably make such a table for my own uses as soon as I have a satisfactory FFT for harmonic analysis, in which case I will publish the table here. As noted by several posters here, the SoundDiver import routine does not work satisfactorily, and the reason might be that they have used some simplistic and/or erroneous formula for the Rate/Time/Level relationships. Kawai should realize that this is bad publicity and help us get it right. Tore tl001@online.no ------------------------------------------------------------------------------------------ Re: Re: Rate/Time Formula Tuesday, 24-Mar-98 13:18:11 192.86.155.91 writes: Wouldn't a table be a problem since the rate seems to be dependant not only on the relative values between the beginning and end points, but also the absolute values? It seems like you would need either a three dimensional table, or a large and cumbersome set of tables. *QUOTE FROM TORE* One thing that is certain about the time needed to change a level is that this movement is accelerated. And it appears that the acceleration is greater for low levels than for higher ones. Going from level 0 to 10 in the Harmonics Envelopes takes around 10 secs at a rate of 42, going from 50 to 60 takes 16 secs. *UNQUOTE* -Kenji ------------------------------------------------------------------------------------------ Re: Re: Re: Rate/Time Formula Tuesday, 24-Mar-98 17:52:39 130.67.65.101 writes: QUOTE It seems like you would need either a three dimensional table, or a large and cumbersome set of tables. UNQUOTE Yes, in some cases one would need a 3-D table, and it would be a real hassle if we had to do it by hand. However, you talk about a computer program, and that simplifies matters. When we have to compute times from start level, end level and rate, a 2-D table would be enough, it seems. Let us call the matrix D() for Delay in order to let T mean the physical time. Supposing that the table of delays has been recorded at a rate of 40, we would have: T = D(L1, L2) * 2^(-R/8) * 32 L1 is the start level, L2 the end level, R is the rate, 32 is 2^(40/8). Actually, the times thus obtained are not 100% linear if you use VERY slow rates. I hope they are linear with the fast rates that are normally used. For finding the start or end level, one would have to search the matrix D(). This is clumsy, but no match for a computer - and it's the only option unless we find a formula. Another thing, Kenji. Could you find if there is a way to make tabs or blank spaces in this font? Spaces and tabs are both ignored, so it's hard to make tidy arrangements of time tables, etc. Tore tl001@online.no ------------------------------------------------------------------------------------------ The Formula - or very nearly so... Friday, 27-Mar-98 14:42:24 130.67.0.147 writes: I have made a formula that relates the levels, the rates and the time it takes to effect changes in level. This formula applies to Level and Rate in the Harmonics Envelopes page. The key element is a factor that I call Delay which is defined as follows: D = (ln(LH - LL) - (80 - LL) * 0.1 + 13.4) LH is here the higher of the two levels, LL the lower. This formula is derived from an exponential function of the simplest type, namely Ce^(kt). In fact, this function may be a bit too simplistic, but it seems to be good enough for our purposes. Level adjustments are accelerated, and the acceleration seems to be inversely proportional to the level. The solution of the corresponding differential equation gives us the exponential function mentioned above. The formula for D says that zero acceleration occurs at Level 80 - which is beyond the maximum value of 63. Thus the acceleration does not begin at 0 when the adjustment starts, even if we start at 63, which is one reason why I fumbled a good deal before I found a workable formula. The number 80 is not necessarily correct, and the same holds for the other constants, but they appear to be close to the real values. The time it takes to effect a level change is proportional to 2^(-Rate/8) and to Delay. The Time in seconds can therefore be computed as: T = 46 * D * 2^(-R/8) where 46 is a proportionality factor. In most situtations, as I see it, what we shall want to know is the Rate, since this is a purely internal parameter. The Rate is given as: R = 8 * log2(46 * D / T) And if we need to adjust a level while keeping the time constant, we shall have to compute the new rate R2 from the old one R1 as follows: R2 = R1 + 8 * log2(D2 / D1) where D2 and D1 are the new and old D, respectively. Such calculations are hardly practicable unless you use a computer or programmable calculator. If we calculate LL - the lower level - we shall get the exponential function that I departed from in making the formula for D. Calculating LH is worse. We get an equation of the type ln a + a = constant, which may have to be solved by some sort of approximation. If you know a better way, I would like to hear about that. As noted before by Jens (I think), two consecutive levels will lead to one stage being skipped, no matter what the rate is. For keeping the amplitude "level" across two stages one therefore has to let the levels differ. This is one case where the formulas above may prove very helpful in deciding how to set the rate in order to obtain a specific delay. * When I test these formulas, I find that they are not quite exact, although they are reasonably close most of the time. I hope that you will test them too and suggest improvements. Tore tl001@online.no ------------------------------------------------------------------------------------------ Re: The Formula - or very nearly so... Monday, 30-Mar-98 04:52:34 130.67.2.140 writes: For some reason I left a proportionality factor of 46 in these formulas. We should of course bake it into the Delay expression as follows: D = (ln(LH - LL) - (80 - LL) * 0.1 + 13.4) * 46 It is possible to arrange this formula with fewer terms, but I don't think readibility is enhanced that way. We then get the Time in seconds as: T = D * 2^(-R / 8) And the Rate as: R = 8 * log2(D / T) * I forgot to say that these formulas are not exact for extremely slow rates. Such rates are largely uninteresting for musical purposes, so this is no big deal. The question is whether they hold for very short time intervals of the sort that occur in onset transients. I have looked for ways to test this, using beats etc., but I have not yet found a workable scheme. Maybe someone else has ideas here? * And I said that the acceleration is inversely proportional to the level. It is of course proportional to (80 - Level), which is something else. Tore tl001@online.no ------------------------------------------------------------------------------------------ Re: Re: The Formula - or very nearly so... Monday, 30-Mar-98 10:38:39 194.172.230.108 writes: Hi Tore, hi all! When I programmed my 'ADDpeggio' patch, I used the envelope loop function, the built-in echo effect and my ears to find multiples of a given delay time. You can hear quite well whether a looped attack coincides with its echo or they drift apart. This is how I found the regularities that we might call the 'constant levels formula': "Reducing the rate by 8 means doubling the time". I observed as well some time quantization effects: Using envelope loops, I found a maximum loop frequency of about 43.5 Hertz. This gives 11.5 milliseconds as shortest possible time unit. We should possibly take time quantization into account when the times are very short. I expect a sort of 'level change quantization', too. This should have effects on very long times and very small level differences and may also have to do with the 'no flat' rule (for all stages except the sustain). How did you measure the times in order to develop your formula, Tore? And what do you mean by 'acceleration'? The nonlinearity in the delay/level relation that you measured, or did you really observe a curved level slope? Could it perhaps be explained with a linear slope on an amplitude scale (which is non-logarithmic)?... I would like to have a model of the envelope algorithm rather than a formula. What about a kind of 'increment and compare' algorithm? Or, couldn't we make the MORF calculator do the work for us? Or Kawai? ;-) So many questions... Jens Groh ------------------------------------------------------------------------------------------ Re: Re: Re: The Formula - or very nearly so... Monday, 30-Mar-98 14:10:04 130.67.66.152 writes: Hi Jens - QUOTE When I programmed my 'ADDpeggio' patch, I used the envelope loop function, the built-in echo effect and my ears to find multiples of a given delay time. You can hear quite well whether a looped attack coincides with its echo or they drift apart. UNQUOTE Thanks, I'll try that. QUOTE How did you measure the times in order to develop your formula, Tore? UNQUOTE I just measured it with my wrist watch. Changing levels at rate 40, times range from about 6 secs to 22 secs. QUOTE And what do you mean by 'acceleration'? UNQUOTE I mean level change per second per second. Going downward from level 60 at rate 40, it takes 16 secs to reach level 59, 20 secs to reach 50, 21.5 secs to reach levels 30-10. Hence, the speed - level change per second - is increasing during this movement. QUOTE Could it perhaps be explained with a linear slope on an amplitude scale (which is non-logarithmic)?... UNQUOTE I guess you mean to say that if we have an expression of the type log(exp(Amp)), this reduces to Amp or maybe Amp times a constant. I hoped for the same thing, but it looks like we have log(log(Amp)) or, conversely, exp(exp(Level)), unfortunately. QUOTE I would like to have a model of the envelope algorithm rather than a formula. What about a kind of 'increment and compare' algorithm? UNQUOTE I am not sure what you mean by an "increment and compare" algorithm. When we move from a high level to a low level, we can express the level as a function of the time as follows: s LL = LH - exp(T * 2^(R / 8) / 46 + (80 - LH) * 0.1 - 13.4) which is a "normal" exponential function. I guess this is what you mean by an "envelope algorithm". Going from a low level to a higher one, however, is worse. We ought to get a function of the type (1 - cos kt), since the acceleration now decrease with increasing level, but I have not been able to find it yet. Anyway, the time it takes to change a level appears to be the same whether we go upward or downward. Maybe some of you math gurus can use that bit of information to find a solution? QUOTE Or, couldn't we make the MORF calculator do the work for us? Or Kawai? ;-) So many questions... UNQUOTE Yes, I am also trying to find better approaches. We'll see... Tore tl001@online.no ------------------------------------------------------------------------------------------ Re: Re: Re: Re: The Formula - or very nearly so... Tuesday, 31-Mar-98 06:46:34 194.172.230.108 writes: Hi, Tore! (Other contributors very welcome, too!) You wrote: QUOTE I guess you mean to say that if we have an expression of the type log(exp(Amp)), this reduces to Amp or maybe Amp times a constant. I hoped for the same thing, but it looks like we have log(log(Amp)) or, conversely, exp(exp(Level)), unfortunately. [...] I am not sure what you mean by an "increment and compare" algorithm. UNQUOTE I understand 'amplitude' as the peak value of a wave, and 'level' as its logarithm. In the K5000 envelope settings, we have levels. But somewhere inside the synthesis process, they must be transformed into the amplitude factor that the sine wave is to be multiplied with. This exponent function can be realized with a look-up table. Keep in mind that the K5000 must calculate up to 2048 envelopes (32 sources * 64 harmonics) at the same time! Thus, the algorithm that generates the envelopes must be very, very simple. A possible solution to generate an envelope slope would be the following: Increment (or decrement) either the current level or the current amplitude by a constant value and repeat this step in intervals of, say, 11.5 milliseconds. The increment/decrement value can be taken from a look-up table, again. Now, if they took the amplitude and not the level, an acceleration of a falling slope can be explained: Equal amplitude steps become increasing level steps. Conversely, for a rising slope with constant amplitude increments you get a retardation on the level scale. The slope ends when the target amplitude (or level) is reached - that's the 'compare' part. In the special case that the levels are equal, the increment value is zero. Then, the algorithm can only take either no time or infinite time, depending on how the comparison is done. The programmers decided for 'no time', of course. That explains the 'no flat' restriction. Do you think you can fit your measured times to that model, Tore? Jens Groh ------------------------------------------------------------------------------------------ Re: Re: Re: Re: Re: The Formula - or very nearly so... Tuesday, 31-Mar-98 15:14:45 130.67.2.100 writes: Jens wrote: Keep in mind that the K5000 must calculate up to 2048 envelopes (32 sources * 64 harmonics) at the same time! Thus, the algorithm that generates the envelopes must be very, very simple. This is where I wonder: is it really done digitally? The formula that fits the data looks like a typical analog event, with its exponential rise and decay. Though, it would be very strange if an analog signal appears before the DCF/DCA, so I suppose it is really digital, but it certainly looks analog from the formula. Equal amplitude steps become increasing level steps. Conversely, for a rising slope with constant amplitude increments you get a retardation on the level scale. Yes, that is right, but I am afraid you have missed the point. There is no retardation. The level adjustment is always accelerated, even if the acceleration is less in the higher levels. This means that if we go from level 0 to 60, the derivative of the acceleration is negative, but the acceleration itself remains positive. I am sorry to demolish the scheme you put forward, because it would have been much simpler, but it just does not fit the data. I have tried to figure out how an exponential function could be broken down into some sort of "increment and compare" algorithm, but I don't see any simple way of doing it so far. * About data and fitting, let's see how my formulas fit. If we go from Level 0 upward at Rate 40 and take down pairs of (Level, Time) we shall get something like this: (1, 7.5), (2, 9), (5, 11), (10, 12), (20, 14), (30, 16), etc. Applying the formulas instead gives us these pairs: (1, 7.9), (2, 9.0), (5, 10.8), (10, 12.5), (20, 14.9), (30, 17.0), etc. The fit is fairly good, and it gets better for faster rates. My conclusion is that we have an exponential function, but I don't know how to program it in a fast and digital way. Tore tl001@online.no ------------------------------------------------------------------------------------------ Re: Re: Re: Re: Re: Re: The Formula - or very nearly so... Wednesday, 01-Apr-98 03:38:06 194.172.230.108 writes: Tore wrote: I am sorry to demolish the scheme you put forward, because it would have been much simpler, but it just does not fit the data. What a pity! ...was my first thought. But then I noticed a slight difference between how you measured falling slopes and rising slopes. For falling slopes, you varied the smaller level, for rising slopes, you varied the greater one. That's not wrong. But, what if only the greater level determined the amplitude increment value? Then, you would have measured falling slopes with equal decrements, but rising slopes with different increments. This could lead to the impression that there is an acceleration there, too. Could this be our last hope for a simple explanation? Jens Groh ------------------------------------------------------------------------------------------ Re * 7: The Formula - or very nearly so... Wednesday, 01-Apr-98 06:22:58 130.67.65.182 writes: QUOTE For falling slopes, you varied the smaller level, for rising slopes, you varied the greater one. UNQUOTE I am not quite sure what you mean here. In any case, I think Jens may have a good point when he talks about whole-number algorithms that must be fast. There are several ways that the behavior of such algorithms could resemble acceleration. What I wonder about is the actual format of the signal as it leaves the "oscillator" (i.e. DHL/DHE). Is it comparable to a sampled waveform, or is it in some other format that is converted to actual waves after the DCF/DCA? It is very difficult to think about these matters without knowing more about those details. Let's hope that the reply to Kenji's letter will bring us some answers. Tore tl001@online.no ------------------------------------------------------------------------------------------ Re * 8: The Formula - or very nearly so... Thursday, 02-Apr-98 05:58:23 194.172.230.108 writes: Hi Tore! You are not sure what I mean? Well, perhaps I should have said 'lower' and 'higher' level - sorry if my bad English was the reason. I assume that the increment value (resp. the amplitude gradient) is a function of the higher level and the rate only, but not a function of the lower level. And I assume that the slopes are amplitude-linear, not level-linear. Well - it's only a hypothesis. Let me try to sketch a few formulae: start_ampl = 2^(start_level/8) end_ampl = 2^(end_level/8) ampl_gradient = incr_val / time_unit higher_level = max(start_level,end_level) lower_level = min(start_level,end_level) My hypothesis: time_diff = (end_ampl - start_ampl) / ampl_gradient abs(ampl_gradient) = some_factor * 2^(rate/8) * 2^(higher_level/8) For a rising slope follows: higher_level = end_level lower_level = start_level ampl_gradient = some_factor * 2^(rate/8) * 2^(end_level/8) => time_diff = (2^(end_level/8) - 2^(start_level/8)) / (some_factor * 2^(rate/8) * 2^(end_level/8)) For a falling slope follows: higher_level = start_level lower_level = end_level ampl_gradient = -some_factor * 2^(rate/8) * 2^(start_level/8) => time_diff = (2^(end_level/8) - 2^(start_level/8)) / (-some_factor * 2^(rate/8) * 2^(start_level/8)) Wow - this IS a time/rate formula! I didn't realize that before I wrote it down (and made some refinements). Theoretically, it should be sufficient to make one exact measurement to determine the unknown 'some_factor'. I think you have a lot of data, Tore, which the formula can be verified with. But I'd like to test it myself, too. Two things are for sure: The 'constant levels rule' applies for the formula, and a rising slope takes the same time as a falling slope with the same levels and rate. Is this what we were looking for??? If yes, I hope we'll make really cool sounds of it! Jens Groh ------------------------------------------------------------------------------------------ Re * 9: The Formula - or very nearly so... Thursday, 02-Apr-98 09:17:35 130.67.65.197 writes: Thanks for your ideas. I have to mull them over for a while. Just want to say that I have tried to use your ideas about the need for a fast algorithm to make a model that looks very promising. It can be implemented with three 32-bit registers where you do some adding and shifting. The resulting ramp is neither amplitude-linear nor level-linear, but it fits the data almost EXACTLY. It is probably too good to be true, so I will check it carefully before I publish it... Tore tl001@online.no ------------------------------------------------------------------------------------------ An answer Monday, 06-Apr-98 03:39:34 194.172.230.108 writes: After having made my own measurements, I have to tell the readers that the answer to my 'big question' is: "No." Although the formula had some promising properties, it produces values that do not reflect what the K5000 does. Well, in science, even such a negative answer is considered useful. This may serve as a consolation for all who may be disappointed now, me included. Jens Groh ------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ An Increment and Compare Algorithm Saturday, 04-Apr-98 07:58:26 130.67.1.248 writes: I have been trying to use Jens' idea about an increment and compare algorithm to devise a program that fits the data rather well. Consider this correspondence between end levels and the time it takes to reach them when we start from level 0: Start level 0, end level: 10 20 30 40 50 60 Times at rate 40 in secs: 11.9 14.2 16.0 17.7 19.3 20.9 Increments : 2.3 1.8 1.7 1.6 1.6 In other words, we have a function that tends toward an arithmetic progression in the higher levels. If what is actually increased is the amplitude, as suggested by Jens, the amplitude will have to to increase geometrically in order to give the arithmetic progression above. So I thought, what if we make a function that is starts out as an arithmetic progression and ends as a geometric one? This could be done by means of a 32-bit register that is shifted 8-bits and then added to itself. We could emulate that in C as follows: sum = 256; time = 0; while (amp < end_amp) { sum += sum / 256; amp += sum; time++; } This loop is supposed to be executed at equal time intervals. Now, if sum is an integer, division by 256 will yield 1 as long as 256 <= sum < 512. Hence, we will have an arithmetic progression. When sum gets large, however, adding 1 / 256 of its value will be almost equivalent to multiplying by (1 + 1 / 256), and we will have a geometric progression. I have made a C program that does these calculations (attached below). Running it produces this set of values at rate 40: 0 10 20 30 40 50 60 From/To 0.0 11.9 14.2 16.0 17.7 19.3 20.9 0 11.9 0.0 13.5 15.8 17.6 19.2 20.9 10 14.2 13.5 0.0 15.1 17.4 19.2 20.8 20 16.0 15.8 15.1 0.0 16.7 18.9 20.8 30 17.7 17.6 17.4 16.7 0.0 18.3 20.5 40 19.3 19.2 19.2 18.9 18.3 0.0 19.9 50 20.9 20.9 20.8 20.8 20.5 19.9 0.0 60 This fits the observed values very well. Modifying the parameters a bit we can get this set of values: 0 1 2 3 4 5 From/To 0.0 6.9 8.3 9.1 9.7 10.2 0 6.9 0.0 7.0 8.4 9.3 9.9 1 8.3 7.0 0.0 7.2 8.6 9.4 2 9.1 8.4 7.2 0.0 7.4 8.7 3 9.7 9.3 8.6 7.4 0.0 7.5 4 10.2 9.9 9.4 8.7 7.5 0.0 5 Or this one: 55 56 57 58 59 60 From/To 0.0 15.7 17.0 17.9 18.5 19.0 55 15.7 0.0 15.8 17.2 18.0 18.6 56 17.0 15.8 0.0 16.0 17.4 18.2 57 17.9 17.2 16.0 0.0 16.2 17.5 58 18.5 18.0 17.4 16.2 0.0 16.3 59 19.0 18.6 18.2 17.5 16.3 0.0 60 The match is not perfect, but it is very close. At least, this is a purely digital and very fast way to obtain those values that looked to me like an exponential or logarithmic function (which also fits the data rather well). The deep question is why Kawai should want to do it this way. They could simply have added or subtracted 1 / 256 of the amplitude to the amplitude itself rather than using the auxiliary sum variable. And this procedure would have given us the level as a linear function of the time. However, that algorithm does not fit the data, so they did not do it that way, for whatever reason. What is not explained by this program is the behavior of the rates, but this could be implemented in a number of ways. We agree that the time is proportional to 2^(-Rate / 8), but it looks like this formula is not quite exact - raising the rate by 8 makes the time drop to slightly less than one half, it seems, and that makes me wonder how it is actually done. Finally, here is the program: #include #include #define MAXAMP 0xffffffffL void main(void) { unsigned long sum, time, amp, end_amp; float level, end_level; for (level = 0; level <= 60; level += 10) printf("%5.0f ", level); printf("From/To\n\n"); for (end_level = 0; end_level <= 60; end_level += 10) { for (level = 0; level <= 60; level += 10) { amp = MAXAMP * pow(2, (level - 63) / 8); end_amp = MAXAMP * pow(2, (end_level - 63) / 8); sum = 256; time = 0; if (amp < end_amp) while (amp < end_amp) { sum += sum / 256; amp += sum; time++; } else while (amp > end_amp) { sum += sum / 256; amp -= sum; time++; } printf("%5.1f ", time / 140.0); } printf(" %2.0f\n", end_level); } } Tore tl001@online.no ------------------------------------------------------------------------------------------ Re: An Increment and Compare Algorithm Saturday, 04-Apr-98 08:02:01 130.67.1.248 writes: Well, the PRE tag kept the tables tidy, but the board still removed the empty lines. The intelligent reader will understand that the #include files in the C program are STDIO.H and MATH.H - which disappeared because they were written within angle brackets. Tore tl001@online.no ------------------------------------------------------------------------------------------ Re: An Increment and Compare Algorithm Monday, 06-Apr-98 15:11:35 192.86.155.91 writes: That is some excellent work you've done. How would one calculate values for rates other than 40 using this formula. I would help out more myself, but my K5000 is *STILL BEING REPAIRED* so I can't test anything out! !!@#&@!?$#* Can you believe Kawai shipped the replacement parts that were under warranty to the authorized repair center COD??? They are supposed to *pay* the repair center for labor, not charge them for parts! Anyway, is it a matter of changing the constant in this line??? printf("%5.1f ", time / 140.0); Or is it more tricky than that? I'll put your algorithm into a little rate calculator applet for everyone to use. I guess I just need this last little thing though. -Kenji ------------------------------------------------------------------------------------------ Re: Re: An Increment and Compare Algorithm Monday, 06-Apr-98 17:57:26 130.67.65.114 writes: QUOTE How would one calculate values for rates other than 40 using this formula. UNQUOTE The time is proportional to 2^(-rate/8), so you in order to get the time for other rates than 40 you have to divide the time by 2^(-40/8), i.e. 1/32, and then you multiply with the new factor, which would be something like pow(2, -rate/8) in C. QUOTE I'll put your algorithm into a little rate calculator applet for everyone to use. I guess I just need this last little thing though. UNQUOTE Well, I don't think it is quite exact, but it is probably good enough. For that matter, so is this formula: time = log(level - end_level) + level * 0.1 + 5.4) * 46 * pow(2, - rate/8.0; If I trim this formula a bit, the results get very close to the tables as published. I think we can still get better approximations, especially if we get some help from Kawai. What I would like to know is why they chose to use such a nonlinear function for the envelope. Tore tl001@online.no ------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ Attack and Release Times Saturday, 23-Jan-99 12:42:24 199.199.157.24 writes: Some info for the archive: I tried setting attack and release to 0 and looked at the .wav, and it looks like the minimum attack time is about 0.2 ms. An attack setting of 2 is about 1 ms and 3 is about 5 ms. The minimum release time is pretty long, about 20 ms. In some places the waveform seems to try to start at a peak instead of a zero, or maybe it's starting a few ticks into the waveform, but that must account for that pop you get at short attack settings. leiter ------------------------------------------------------------------------------------------ Re: Attack and Release Times Saturday, 23-Jan-99 17:02:54 128.8.201.10 writes: Interesting. Is this a common problem among synthesizers? It seemed like the synth was never *EXACTLY* precise. Maybe those times are what give it that feeling. Ivan. ------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------