2 ********************************************************************
4 Otiginally a unit to extend the VST SDK with some useful functions.
5 expanded with generic audioprocessing utilities by Thaddy de Koning
7 Based upon Frederic Vanmol's DVstUtils.pas, but with some
8 extensions by Tobybear and Thaddy.
9 You can easily use this instead
10 of the original DVstUtils.pas
12 I have also translated some of TobyBear's functions to assembler as well
13 as making this KOL compatible,
15 Note that most assembler functions would run more efficient if
16 written in external assembler. (Because of superfluous stack allocations,
17 result allocation and register pushing by the compiler)
18 I have incluede remarks to that extend where appropiate.
21 ********************************************************************
33 top
, left
, bottom
, right
: smallint
;
36 // Frederic's functions:
38 function FourCharToLong(C1
, C2
, C3
, C4
: char): longint;
39 // Converts four chars to a longint in the format required
40 // by Cubase VST for the identifier of the effect.
42 function FMod(d1
, d2
: double): double;
43 // Gets the remainder after the floating point division of d1 and d2.
46 procedure dB2string(Value
: single; Text: PChar
);
47 // Converts value to a null terminated string representation in decibels.
49 procedure dB2stringRound(Value
: single; Text: PChar
);
50 // Converts value to a null terminated string representation in decibels
51 // after having rounded it.
53 procedure float2string(const Value
: single; Text: PChar
);
54 // Converts the floating point variable value to a null terminated string
57 procedure long2string(Value
: longint; Text: PChar
);
58 // Converts the integer variable value to a null terminated string
61 procedure float2stringAsLong(Value
: single; Text: PChar
);
62 // Converts the floating point variable value to a null terminated string
63 // representation with nothing after the decimal point.
65 procedure Hz2string(samples
, sampleRate
: single; Text: PChar
);
66 // Converts samples in combination with sampleRate to Hz.
68 procedure ms2string(samples
, sampleRate
: single; Text: PChar
);
69 // Converts samples in combination with sampleRate to milliseconds.
71 function gapSmallValue(Value
, MaxValue
: double): double;
72 // Converts value (between 0 and 1) to an unevenly spread representation
73 // between 0 and maxValue. Unevenly spread means lower values take longer
74 // to change while higher values change quicker.
76 function invGapSmallValue(Value
, MaxValue
: double): double;
77 // This is the inverse operation of gapSmallValue. When you have altered
78 // the value internally with gapSmallValue and Cubase requests this value,
79 // use this function to return the representation between 0 and 1 from
80 // a range of 0 to maxValue.
82 // Tobybear's functions:
83 function GetDLLFilename
: string;
85 function GetDLLDirectory
: string;
87 function f_limit(v
, l
, u
: single): single;
88 function dB_to_Amp(g
: single): single;
89 function Amp_to_dB(v
: single): single;
90 function linear_interpolation(f
, a
, b
: single): single;
91 function cubic_interpolation(fr
, inm1
, inp
, inp1
, inp2
: single): single;
92 function f_frac(x
: single): single;
93 function f_int(x
: single): single;
94 function f_trunc(f
: single): integer;
95 function f_round(f
: single): integer;
96 function f_exp(x
: single): single;
100 function f_ln2(f
: single): single;
101 function f_floorln2(f
: single): longint;
102 function f_abs(f
: single): single;
103 function f_neg(f
: single): single;
104 function f_root(i
: single; n
: integer): single;
105 function f_power(i
: single; n
: integer): single;
106 function f_log2(val
: single): single;
107 function f_arctan(fValue
: single): single;
108 function f_sin(fAngle
: single): single;
109 function f_cos(fAngle
: single): single;
110 function f_sgn(f
: single): longint;
111 function f_clip(x
, l
, h
: single): single;
112 function f_cliplo(x
, l
: single): single;
113 function f_cliphi(x
, h
: single): single;
115 // scale logarithmicly from 20 Hz to 20 kHz
116 function FreqLinearToLog(Value
: single): single;
117 function FreqLogToLinear(Value
: single): single;
118 function OnOff(fvalue
: single): boolean;
124 // This prevents the FPU from entering denormal mode on very small values
125 // This precision is not necessary for Audio and can slow down the processing
126 // by as much as 700% !! in some cases.(Both Intel and AMD processors suffer
127 // from this problem)
128 // You should always check your code for denormal numbers as it leads to
129 // hickups and potentially crashes in realtime audio processing
130 function undenormalize(fvalue
: single): single;
132 // An alternative is to add a very small, but itself not a denormal, value
133 // before you enter a calculation that can cause a denormal value
134 // This cancels out in the audio, but is large enough to prevent the FPU
135 // going haywire. see below
137 // You should choose your strategy based on your application, though.
138 // Not any of the two methods is best:
139 // The function is more accurate but is slower,
140 // The addition is very fast but may propagate into the result.
141 // A third way is adding a small amount of white noise to the audio signal
142 // before processing.
143 // If you do that from a buffer, the speed is very good, but you may pollute
144 // the cache. If the processor cache is not important for your processing
145 // type, or irrelevant, i.e. much different tasks going on to process one single
146 // sample, this may be the best solution for pristine audioquality.
151 //Converts 16 bit integers to 32 bit floating point
152 procedure ConvertInt16toFloats(const Inbuffer
: array of smallint
;
153 var Outbuffer
: array of single; SampleCount
: integer);
155 //Converts 32 bitfloating point to 16 bit integers
156 procedure ConvertFloatsToInt16(const Inbuffer
: array of single;
157 var Outbuffer
: array of smallint
; SampleCount
: integer);
159 //Splits a 16 bit interleaved stereo file into two 32 bit floating point channels
160 procedure SplitChannels16ToFloatStereo(const Data
: array of smallint
; var ld
: array of single;
161 var RD
: array of single; Samples
: integer);
163 //Splits an interleaved 32 bit stereo file into two 32 bit floating point channels
164 procedure SplitChannels32ToFloatStereo(const Data
: array of single; var Ld
: array of single;
165 var Rd
: array of single; Samples
: integer);
168 function Distort(Value
: single; Amount
: single): single;
169 function Distort2(Value
: single; Amount
: single): single;
171 // Tube-like Soft saturation
172 function saturate(Value
, t
: single): single;
174 //BitCrusher, works on smallints
175 function KeepBitsFrom16(input
: smallint
; keepBits
: integer): smallint
;
180 uses kolmath
, kol
, windows
;
182 //Value = input in [-1..1]
184 function Distort(Value
: single; Amount
: single): single; register;
188 k
:= Undenormalize(2 * amount
/ (1 - amount
));
189 Result
:= (1 + k
) * Value
/ (1 + Value
* f_abs(Value
))
192 function Distort2(Value
: single; Amount
: single): single; register;
202 Result
:= sin(Value
* z
) * s
;
205 function saturate(Value
, t
: single): single; register;
207 //This can be looped from unknown source, so den. Value
208 //Threshold T is under our control
209 Value
:=Undenormalize(Value
);
210 if f_abs(Value
) < t
then
215 Result
:= t
+ (1 - t
) * tanh((Value
- t
) / (1 - t
))
217 Result
:= -(t
+ (1 - t
) * tanh((-Value
- t
) / (1 - t
)));
221 function KeepBitsFrom16(input
: smallint
; keepBits
: integer): smallint
;
223 Result
:= (input
and (-1 shl (16 - keepBits
)));
226 procedure ConvertInt16toFloats(const Inbuffer
: array of smallint
;
227 var Outbuffer
: array of single; SampleCount
: integer);
231 for i
:= 0 to Samplecount
- 1 do
232 Outbuffer
[i
] := Inbuffer
[i
] * (1.0 / 32767.0);
235 procedure ConvertFloatsToInt16(const Inbuffer
: array of single;
236 var Outbuffer
: array of smallint
; SampleCount
: integer);
240 for i
:= 0 to SampleCount
- 1 do
241 Outbuffer
[i
] := f_trunc(Inbuffer
[i
] * 32767);
244 procedure SplitChannels16ToFloatStereo(const Data
: array of smallint
; var ld
: array of single;
245 var RD
: array of single; Samples
: integer);
247 Tempdata
: array of single;
250 setlength(Tempdata
, samples
* 2);
251 ConvertInt16ToFloats(Data
, tempdata
, samples
);
253 for i
:= 0 to samples
- 1 do
255 ld
[i
] := Tempdata
[j
];
257 Rd
[i
] := Tempdata
[j
];
260 setlength(Tempdata
, 0);
263 procedure SplitChannels32ToFloatStereo(const Data
: array of single; var Ld
: array of single;
264 var Rd
: array of single; Samples
: integer);
269 for i
:= 0 to (Samples
div 2) - 1 do
279 function FourCharToLong(C1
, C2
, C3
, C4
: char): longint;
281 Result
:= Ord(C4
) + (Ord(C3
) shl 8) + (Ord(C2
) shl 16) + (Ord(C1
) shl 24);
284 function FMod(d1
, d2
: double): double;
289 Result
:= High(longint)
292 Result
:= f_Trunc(d1
/ d2
);
293 Result
:= d1
- (Result
* d2
);
297 function DbtoFloat(Value
: single): single;
299 if Value
<= 0 then Value
:= 0.1;
300 Result
:= 20 * Log10(Value
);
303 procedure dB2string(Value
: single; Text: PChar
);
305 if (Value
<= 0) then StrCopy(Text, ' -oo ')
307 float2string(20 * log10(Value
), Text);
310 procedure dB2stringRound(Value
: single; Text: PChar
);
312 if (Value
<= 0) then StrCopy(Text, ' -96 ')
314 long2string(Round(20 * log10(Value
)), Text);
317 procedure float2string(const Value
: single; Text: PChar
);
320 StrCopy(Text, PChar(Format('%s', ['-' + Num2Bytes(f_abs(Value
))])))
322 StrCopy(Text, PChar(Format('%s', [Num2Bytes(Value
)])))
325 procedure long2string(Value
: longint; Text: PChar
);
327 if (Value
>= 100000000) then
329 StrCopy(Text, ' Huge! ');
332 StrCopy(Text, PChar(Format('%7d', [Value
])));
335 procedure float2stringAsLong(Value
: single; Text: PChar
);
337 if (Value
>= 100000000) then
339 StrCopy(Text, ' Huge! ');
342 StrCopy(Text, PChar(Format('%7.0f', [Value
])));
345 procedure Hz2string(samples
, sampleRate
: single; Text: PChar
);
347 if (samples
= 0) then float2string(0, Text)
349 float2string(sampleRate
/ samples
, Text);
352 procedure ms2string(samples
, sampleRate
: single; Text: PChar
);
354 float2string(samples
* 1000 / sampleRate
, Text);
357 function gapSmallValue(Value
, MaxValue
: double): double;
359 Result
:= Power(MaxValue
, Value
);
362 function invGapSmallValue(Value
, MaxValue
: double): double;
365 if (Value
<> 0) then Result
:= logN(MaxValue
, Value
);
368 function GetDLLFilename
: string;
373 getmodulefilename(hinstance
, PChar(st
), 1500);
374 Result
:= extractfilename(trim(st
));
377 function GetDLLDirectory
: string;
382 getmodulefilename(hinstance
, PChar(st
), 1500);
383 Result
:= ExtractFilepath(trim(st
));
389 // Limit a value to be l<=v<=u
390 function f_limit(v
, l
, u
: single): single;
392 if v
< l
then Result
:= l
393 else if v
> u
then Result
:= u
398 // Convert a value in dB's to a linear amplitude
399 function dB_to_Amp(g
: single): single;
401 if (g
>-90.0) then Result
:= power(10,g
* 0.05)
406 function Amp_to_dB(v
: single): single;
408 Result
:= (20 * log10(v
));
411 function linear_interpolation(f
, a
, b
: single): single;
413 Result
:= (1 - f
) * a
+ f
* b
;
416 function cubic_interpolation(fr
, inm1
, inp
, inp1
, inp2
: single): single;
418 Result
:= inp
+ 0.5 * fr
* (inp1
- inm1
+ fr
*
419 (4 * inp1
+ 2 * inm1
- 5 * inp
- inp2
+ fr
* (3 * (inp
- inp1
) - inm1
+ inp2
)));
425 function f_trunc(f
: single): integer;
432 function f_frac(x
: single): single;
434 Result
:= x
- f_trunc(x
);
437 function f_int(x
: single): single;
439 Result
:= f_trunc(x
);
442 function f_round(f
: single): integer;
447 function f_exp(x
: single): single;
449 Result
:= power(2,x
* LN2R
);
452 function f_Sin(fAngle
: single): single;
456 fASqr
:= fAngle
* fAngle
;
458 fRes
:= fRes
* fASqr
;
459 fRes
:= fRes
- 1.6605e-01;
460 fRes
:= fRes
* fASqr
;
462 fRes
:= fRes
* fAngle
;
466 function f_Cos(fAngle
: single): single;
470 fASqr
:= fAngle
* fAngle
;
472 fRes
:= fRes
* fASqr
;
473 fRes
:= fRes
- 4.967e-01;
474 fRes
:= fRes
* fASqr
;
476 fRes
:= fRes
* fAngle
;
480 function f_arctan(fValue
: single): single;
484 fVSqr
:= fValue
* fValue
;
486 fRes
:= fRes
* fVSqr
;
487 fRes
:= fRes
- 0.085133;
488 fRes
:= fRes
* fVSqr
;
489 fRes
:= fRes
+ 0.180141;
490 fRes
:= fRes
* fVSqr
;
491 fRes
:= fRes
- 0.3302995;
492 fRes
:= fRes
* fVSqr
;
493 fRes
:= fRes
+ 0.999866;
494 fRes
:= fRes
* fValue
;
498 function f_ln2(f
: single): single;
500 Result
:= (((longint((@f
)^) and $7f800000) shr 23) - $7f) +
501 (longint((@f
)^) and $007fffff) / $800000;
505 function f_floorLn2(f
: single): longint; assembler;
513 function f_abs(f
: single): single; assembler;
520 function f_neg(f
: single): single; assembler;
527 function f_sgn(f
: single): longint; assembler;
532 xor eax, eax //faster than
mov eax,1
537 //here the compiler did a better job, TdK
538 function f_log2(val
: single): single;
542 x
:= longint((@val
)^);
543 log2
:= ((x
shr 23) and 255) - 128;
544 x
:= x
and (not (255 shl 23));
546 Result
:= single((@x
)^) + log2
;
550 //If you rewrite this in external assembler you must push ecx!!
551 function f_power(i
: single; n
: integer): single; assembler;
562 //Tiny bit faster, do not move to eax, because of sign
563 //If you rewrite this in external assembler you must push ecx!!
565 function f_root(i
: single; n
: integer): single; assembler;
576 //Change geberates more efficient code
577 //Can't improve on the compiler generated code, TdK
578 function f_cliplo(x
, l
: single): single;
581 Result
:= (x
+ f_abs(x
)) * 0.5 + l
;
584 //Change geberates more efficient code
585 //Can't improve on the compiler generated code, TdK
586 function f_cliphi(x
, h
: single): single;
589 Result
:= h
- (x
+ f_abs(x
)) * 0.5;
593 //Can't improve on the compiler generated code, TdK
594 function f_clip(x
, l
, h
: single): single;
598 Result
:= (f_abs(x
- l
) + (l
+ h
) - (f_abs(x
- h
))) * 0.5;
601 // scale logarithmicly from 20 Hz to 20 kHz
602 function FreqLinearToLog(Value
: single): single;
604 Result
:= (20.0 * power(2.0,Value
* 9.965784284662088765571752446703612804412841796875));
607 function FreqLogToLinear(Value
: single): single;
609 Result
:= (ln(Value
/ 20) / ln(2)) / 9.965784284662088765571752446703612804412841796875;
612 function OnOff(fvalue
: single): boolean;
614 Result
:= fvalue
> 0.5
617 // Much faster than even a C style float to int cast and more secure
618 function undenormalize(fValue
: single): single; assembler;