TDKDSPLIB 1.00
Written and
©2004, Thaddy de Koning
mailto:thaddy[at]thaddy.com
This
library is copyrighted freeware.
Please give
credits if you use it or part of it in your code
If you use
this in commercial programs, please send me at least a copy to evaluate.
No warranty whatsoever about usability or applicability concerning this code
for any purpose is given.
Use this code at your own risk.
Only Dutch law is applicable.
Dutch law understands the "whatsoever" part. No means No.
If you do not agree, don't use it or contact me.
Introduction
This is a
small library with routines to do audio bit rate conversion and clipping in
It does not
depend on any other units. It also does not use any operating system specific
code. It should therefore be fully compatible with BCB6+ and Kylix too, but
this is not tested. If you try it with one of them, please let me know if it
works.
I first
started this library to do fast single-sample conversions, but when I thought
about it, it seemed a lot more efficient to do the conversions in a buffer.
I couldn’t
stop counting the
For I := 0 to SampleCount
-1 do
CallSomeFunctionThatJustDoesOneSampleAtaTimePushingAndPoppingIntoAndOutOfStackFramesUselessly;
(Example
available on request)
in my
code. So, buffered handling could potentially save a lot of overhead, since you
have only at the most one stack frame per buffer.
On a
typical buffer of 256 32 bit samples this saves 3 instructions per sample, that
is 765 instructions too many. This may not sound a lot, but on simple routines
that alone can take up to 20% of the processing because this is just a
procedure’s internal cost. Externally, before the routine is called, there is
also overhead, because parameters have to be moved to registers and or pushed
on the stack. And again, that is times 256.
It proved
to be very simple and fun to write this library. Frankly, I was amazed I
couldn’t find anything similar, not even in the C (++) community.
As a
general rule, these routines are not only written to be fast. They are also
written to be small and concise. That means that fanatics may be
able to optimize the code a lot –I seldom unroll loops for example-, but it
also means that the code is very readable, even for people with just a hint of
experience with inline assembler. And it still beats even highly optimized
equivalent pure
I decided
to focus on two main topics, for both of which I couldn’t find any usable free
Bit rate
conversion
Clipping
I also
added some handy off topic routines that just happened to need about the same
basic code:
Note that
all routines use the
Note that
all routines assume LSB type, also known as Intel, byte order
Note that
this code may still contain bugs, although it is thoroughly tested on both
Intel and AMD machines.
Some code
uses 3DNow and is only for AMD processors. I am not yet familiar with SSE but I
will add that flavour in a future release.
If you find
bugs or want additions to this library, please contact me per email at thaddy[at]thaddy.com
A
warning should be given that the user has to be very careful to use the correct
buffer sizes as indicated. No checks are done. The buffers need to be
preferably a power of two, but most need at the least to be an even size. The
routines will most likely crash if you do not obey these rules!
The programmer
is always responsible to allocate the buffers in the correct sizes before
calling any of these routines. Both the input and the output buffers need to be
allocated. Again, no checks are done, be very, very careful!
Bit rate conversions
The bit
rate buffer-conversion routines come in four flavours:
Cvt<Input Type>To<Output
Type>()
: One
in, One out
Cvt<Input Type>To<Output
Type>Inplace()
: One and the same in-out
Cvt<Input Type>StereoTo<Output
Type>Mono() : One in, two out
Cvt<Input Type>MonoTo<Output
Type>Stereo() : Two in, One out
They are
for 8, 16 and 32 bit integer and 32 bit single precision floating point only, but
I also added some 24 bit LSB per-sample converters.
The types
are indicated as Int8, Int16, Int32 and 32f respectively.
The "samplecount" or “Sample” parameter is always relative
to the sample size of the input buffer, again: in samples, not in bytes. As a
general rule the sample count is relative to the leftmost parameter.
Integer 8 to XXX conversions
Procedure CvtInt8toInt16(Inbuffer:Pshortint; Outbuffer:PSmallInt;
SampleCount: integer);
This
converts 8 bit signed integer to 16 bit signed integer samples
It works
for both interleaved and non interleaved buffers.
The output
buffer needs to be exactly twice the size in bytes of the input buffer
Procedure
CvtInt8toInt32(Inbuffer:Pshortint; Outbuffer:PInteger;
SampleCount: integer);
This converts
8 bit signed integers to 32 bit signed integer samples
It works
for both interleaved and non interleaved buffers.
The output
buffer needs to be exactly four times the size in bytes of the input buffer
Procedure CvtInt8to32f(Inbuffer:PShortint; Outbuffer:Psingle;
SampleCount: integer);
This
converts 8 bit signed integers to 32 bit single precision floating point
samples
It works
for both interleaved and non interleaved buffers.
The output
buffer needs to be exactly four times the size in bytes of the input buffer
Procedure CvtInt8MonotoInt8Stereo(InLeft,InRight:Pshortint;Outbuffer:PSHortint; SampleCount: integer);
Mixes two 8
bit mono channels to 8 bit stereo
Integer 16 to XXX conversions
Procedure
CvtInt16toInt8(Inbuffer:PSmallInt; Outbuffer:PShortInt;
SampleCount: integer);
This
converts 16 bit signed integers to 8 bit signed integer samples
It works
for both interleaved and non interleaved buffers.
The output
buffer needs to be exactly half the size in bytes of the input buffer
Procedure CvtInt16to32f(Inbuffer:Psmallint; Outbuffer:Psingle;
SampleCount: integer);
This
converts 16 bit signed integers to 32 bit single precision floating point
samples
It works
for both interleaved and non interleaved buffers.
The output
buffer needs to be exactly half the size in bytes of the input buffer
Procedure CvtInt16to32fInPlace(buffer:
Pointer;SampleCount: integer);
This
expands a half full 16 bit integer buffer in place to a full 32bit singles
buffer
The buffer
should be exactly twice the size in bytes as the input!
This is a
tiny bit slower, but saves on memory moves and buffer allocations.
Use it like this:
Procedure CvtInt16toInt32(Inbuffer:Psmallint;Outbuffer:PInteger; SampleCount:
integer);
This
converts a 16 bit signed integer buffer to 32 bit signed integers.
It works
for both interleaved and non interleaved buffers.
The output buffer needs to be
exactly twice the size in bytes of the input buffer
Procedure CvtInt16StereoToInt16Mono(Inbuffer:Psmallint; OutLeft,OutRight:PSmallInt;
SampleCount: integer);
This
converts a 16 bit signed integer stereo buffer to two 16bit signed integer mono
buffers.
The output
buffers each need to be exactly half the size in bytes of the input buffer
Procedure
CvtInt16StereoToInt32Mono(Inbuffer:Psmallint;OutLeft,OutRight:PInteger; SampleCount:
integer);
This
converts a 16bit signed integer stereo buffer to two 32bit signed integer mono buffers
The output
buffers each need to be exactly the same size in bytes of the input buffer
Procedure CvtInt16StereoTo32fMono(Inbuffer:Psmallint;OutbufferLeft: Psingle;OutbufferRight:PSingle;
SampleCount: integer);
This
converts a stereo 16 bit signed integer input
buffer to two floating point mono channels
Input is a
stereo buffer, output two 32 bit single buffers, SampleCount equals the total number of input samples left +
right
Procedure CvtInt16MonoTo32fStereo(InLeft,InRight:Psmallint; Outbuffer:PSingle;
SampleCount: integer);
This
creates a 32 bit single stereo buffer from two 16 bit signed
integer mono channels. Samplecount
refers to the size of one mono buffer. The output buffer needs to be four times
that size.
Procedure CvtInt16StereoTo32fMakeMono(Inbuffer:Psmallint; Outbuffer:Psingle;
SampleCount: integer);
This
creates a 32 bit floating point single mono channel from a 16 bit integer
stereo buffer.
The buffers
should be exactly the same size
Procedure CvtInt16MonoToInt16Stereo(InLeft,InRight:Psmallint; Outbuffer:PSmallInt;SampleCount:
integer);
Mixes two
16 bit mono files to a 16 bit stereo buffer
Integer 32 to XXX conversions
Procedure CvtInt32toInt8(Inbuffer:PInteger; Outbuffer:PShortInt;
SampleCount: integer);
This
converts a 32 bit signed integer buffer to 8 bit signed integer
The output
buffer is a fourth the size of the input buffer.
It works on
both interleaved and non interleaved buffers
Procedure CvtInt32toInt16(Inbuffer:PInteger; Outbuffer:PSmallInt;
SampleCount: integer);
This
converts a 32 bit signed integer buffer to 16 bit signed integer
The output
buffer is half the size of the input buffer
It works on
both interleaved and non interleaved buffers
Procedure CvtInt32To32f(Inbuffer,Outbuffer: PInteger;SampleCount:
integer);
This
converts a 32 bit signed integer stereo buffer to 32 bit single precision
floating point.
Procedure CvtInt32to32fInplace(buffer:
PInteger; SampleCount:
integer);
This
converts a 32 bit signed integer stereo buffer to 32 bit single precision
floating point in place,
Procedure CvtInt32to32fInplace3DNow(buffer:
PInteger; SampleCount:
integer);
This does
the same as the last one, but uses AMD 3DNow!
The AMD
routines need multiples of 32 bytes, since I unroll the loop 8 times in 4 mmx registers. I do not know of
any ASIO buffers that are (buffer size mod 32) <> 0, but be warned! What
you get back is raw speed!
Procedure CvtInt32StereoTo32fMakeMono(Inbuffer,Outbuffer: PInteger;SampleCount:
integer);
This
converts a 32bit stereo buffer to 32 singles and sums them result to
mono before storing
The output
buffer is half the size of the input buffer
Procedure CvtInt32StereoToInt16Mono(Inbuffer:PInteger; OutLeft,OutRight:PSmallInt;
SampleCount: integer);
This
converts a 32 bit signed integer buffer to 16 bit signed integer
The output
buffers are a fourth the size of the input buffers
Procedure CvtInt32StereoToInt32Mono(Inbuffer:PInteger; OutLeft,OutRight:Pinteger;
SampleCount: integer);
This
converts a 32 bit signed integer stereo buffer to 32 bit signed integer mono.
The output
buffers are half the size of the input buffer.
Procedure CvtInt32StereoTo32fMono(Inbuffer:PInteger;OutLeft,OutRight:PSingle; SampleCount: integer);
This converts
a 32 bit signed integer stereo buffer to 32 bit single precision floating point
mono buffers.
The output
buffers are half the size of the input buffer.
Procedure CvtInt32MonoTo32fStereo(InLeft,InRight:Pinteger; Outbuffer:PSingle;
SampleCount: integer);
This
routine creates a 32 bit single precision floating point stereo buffer from two
32 bit signed integer mono channels.
“Samplecount” refers to the size of one mono buffer.
The output
buffer needs to be two times that size!
Procedure CvtInt32StereoTo32fMono(InBuffer:pInteger; OutLeft,OutRight:PSingle;samples:integer);
This
converts a 32 bit signed integer stereo buffer to two single precision floating
point buffers
The output
buffers are half the size of the input buffer.
32 bit single precision floating point to XXX conversions
Procedure Cvt32fToInt16(Inbuffer: Psingle; Outbuffer: Psmallint; SampleCount: integer);
This
converts a 32 bit single precision floating point buffer to 16 bit signed
integers, ASIOSTInt16LSB
It works
for both interleaved and non interleaved buffers.
The output
buffer needs to be exactly half the size in bytes of the input buffer.
Procedure Cvt32fToInt16Dithered(InBuffer:Psingle;OutBuffer:PSmallInt;Samples:integer);
This
procedure converts 32 bit single precision floating points to 16bit integers
and applies a simple and fast triangular dither to reduce the noise floor.
It works
for both interleaved and non interleaved buffers.
The output
buffer needs to be exactly half the size in bytes of the input buffer.
It is a
good idea to call ClipBuffer16 after you have called this procedure.
Normally
you would call this procedure at the end of the audio chain, before you write a
16 bit mono wave file to disk.
It improves
the audio quality compared to un-dithered material, but it is slower.
Procedure Cvt32fStereoToInt16MonoDithered(InBuffer:Psingle;OutBuffer:PSmallInt;Samples:integer);
This
procedure converts 32 bit single precision floating points to two 16bit integer
mono channels and applies a simple and fast triangular dither to reduce the
noise floor.
It works
for both interleaved and non interleaved buffers.
The outputs
buffer needs to be exactly a fourth of the size in bytes of the input buffer.
Normally
you would call this procedure at the end of the audio chain, before you write a
16 bit stereo wave file to disk.
It greatly
improves the audio quality compared to un-dithered material, but it is
definitely slower.
Procedure Cvt32fStereoToInt16MonoClipDithered(InBuffer:Psingle;OutLeft,OutRight:PSmallInt;Samples:integer);
This
procedure converts 32 bit single precision floating points to two 16bit integer
mono channels and applies a simple and fast triangular dither to reduce the
noise floor. It then clips the signal to 32767 – 1/32768.
It works
for both interleaved and non interleaved buffers.
The outputs
buffer needs to be exactly a fourth of the size in bytes of the input buffer.
Normally
you would call this procedure at the end of the audio chain, before you write a
16 bit wave file to disk.
It greatly
improves the audio quality compared to un-dithered material, but it is
definitely slower.
Note: Does
anyone really needs and 8 bit blockdither?
Can do, but I think it’s a bit pointless right
now.
Procedure Cvt32fStereoToInt16Mono(Inbuffer: Psingle; OutLeft,OutRight: Psmallint; SampleCount: integer);
This
converts a 32 bit single precision floating point stereo buffer to two 16 bit signed integer mono buffers, ASIOSTInt16LSB
The output
buffers need to be exactly one fourth the size in
bytes of the input buffer.
Procedure Cvt32fStereoToMono(InBuffer,OutLeft,OutRight:Psingle; samples:integer);
This
converts a 32 bit single precision floating point buffer to two mono buffers.
The output
buffers are exactly half the size of the input buffer.
Procedure Cvt32fMonoToStereo(InBuffer,OutLeft,OutRight:Psingle; samples:integer);
This
converts two 32 bit single precision floating point buffer into one stereo
buffer.
The output
buffer is exactly twice the size of one input buffer.
Procedure Cvt32fStereoToInt32Mono(InBuffer:pSingle; OutLeft,OutRight:PInteger;samples:integer);
This
converts a 32 bit single precision floating point buffer to two 32 bit signed
integer buffers.
The output
buffers are half the size of the input buffer.
Procedure Cvt32fToInt32(InBuffer,OutBuffer:Pointer;samples:integer);
This
converts a 32 bit single precision floating point buffer to 32 a bit signed
integer buffer.
Some 24 bit
cards use this format for their output buffers too,
It works
for both interleaved and non interleaved buffers.
Procedure Cvt32fToInt323DNow(Inbuffer,OutBuffer: PInteger;
SampleCount: integer);
This
converts a 32 bit single precision floating point buffer to 32 a bit signed
integer buffer using AMD 3DNow.
Some 24 bit
cards use this format for their output buffers too,
It works
for both interleaved and non interleaved buffers.
Procedure Cvt32fToInt32InPlace(Buffer:Pointer;samples:integer);
This
converts a 32 bit single precision floating point buffer to 32 bit signed
integer in place.
Some 24 bit
cards use this format for their output buffers too,
It works
for both interleaved and non interleaved buffers.
Procedure Cvt32fToInt32Inplace3DNow(buffer:
PInteger; SampleCount:
integer);
This does
the same as the previous one, but uses AMD 3DNow!
The AMD
routines need multiples of 32 bytes, since I unroll the
loop 8
times into 4 mmx registers. I do not know of any ASIO
buffers
that
are BufSize mod 32 <> 0, but you have
been warned!
What you
get back is raw speed!
Function Cvt32fToInt32(value:single):integer;overload;
This does
the same as the like-named buffer procedure, but on a single sample
Function Cvt32fToInt16(value:single):SmallInt;overload;
This does
the same as the like-named buffer procedure, but on a single sample
Procedure CvtInt32MonoToInt32Stereo(InLeft,InRight:pInteger;OutBuffer:PInteger;samples:integer);
Mixes two
32 bit integer mono channels to a 32 bit integer stereo file
(Can also
be used for floats)
Buffer clipping
Note: if
you are processing singles, it is often enough to clip just once at the end of
the audio chain, unless you are sure your processing absolutely positively
requires ranges -1...1.
I did not
overload these functions, because you possibly might want to use un-typed
buffer pointers.
Procedure ClipBuffer32f(Buffer:Psingle; samples:integer);
This
procedure takes a buffer of 32 bit single precision floating point
samples and hard clips it to -1..1 range.
Procedure
ClipBuffer32fDN(Buffer:Psingle;samples:integer):single;
This
procedure implements a different algorithm that has a fortunate de-normalizing
side effect.
It may
reduce accuracy for small numbers. I.e. if you clip to [-1; 1], fractional part
of the result will be quantized to 23 bits (or more, depending on the bit depth
of the temporary results). Thus, 1e-20 will be rounded to 0. This has the side
effect of de-normal number elimination.
The first
clipping function is best used at the end of the audio chain.
The second
one is best used to de-normalize a buffer before de-normal sensitive
processing.
If you read
this correctly, you’ll notice it actually performs two different clips,
one on the min and max values and one on very small values around 0!
Therefore
this may be more efficient for some tasks than the other hard-clipping
procedure combined with separate de-normal elimination code.
Procedure ClipBuffer32fAtLimit(Buffer:Psingle; Value:single; samples:integer);
This is a
simple limiter procedure. The value parameter should be in the range of 0…1.
Do not
confuse this with Volume control. It hard-clips all samples that are above the
value or below the negated value.
Of course
it’s faster than the volume procedures. See also AdjustVolume32fAndClipDN
The next clipping functions do not work on older Pentiums! They need a
Pentium Pro, AMD Duron or better CPU.
I do not
think this is really an issue, because intensive real time floating point audio
processing requires a better specification than a Pentium 1 anyway.
Procedure ClipBuffer32(Buffer:PInteger; samples:integer);
Takes a
buffer of 32 bit signed integers and hard clips between $7FFFFFFF and $80000000
Procedure
ClipBuffer24(Buffer:PInteger;
samples:integer);
Takes a
buffer of 32 bit signed integers and hard clips to 24 bit range, $7FFFFF,
$800000
Procedure
ClipBuffer16(Buffer:Psmallint;
samples:integer);
Takes a
buffer of 16 bit signed integers and hard clips between $7FFF and $8000
Procedure ClipBuffer8(Buffer:Pshortint; samples:integer);
Takes a
buffer of 8 bit signed integers and hard clips between $7F and $80
Volume control
Procedure AdjustVolume32f(Buffer:PSingle;Volume:single; samples:integer);
This adjusts the volume on a 32 bit
single buffer.
It works
for both interleaved and non interleaved buffers.
Volume
values should be in the range of 0...1, unless you want to amplify very soft
material
Warning:
Any value is accepted!
Procedure AdjustVolume32fDN(Buffer:Psingle;Volume:single; samples:integer);
This does
the same as the previous one, but inlined
checking/repairing de-normal values on the fly.
Procedure AdjustVolume32fAndClipDN (Buffer:Psingle;Volume:single;samples:integer);
This
procedure adjusts the volume and clips it both on min and max values as on very
small de-normal values around zero.
This is
very useful for gain control, since it keeps volume at workable limits under
all circumstances, both very loud and very soft.
It works by
first adjusting the volume to the requested value and then clipping it to -1…1
using the ClipBuffer32fDN algorithm.
Procedure
AdjustVolume32fLeft(Buffer:PSingle;Volume:single;
samples:integer);
This
adjusts the volume from buffer start, skipping every other sample, for separate
treatment on interleaved buffers.
Volume
values should be 0...1, unless you want to amplify very soft material
Warning:
Any value is accepted!
Procedure AdjustVolume32fLeftDN(Buffer:Psingle;Volume:single; samples:integer);
The same,
but with inline checking/repairing de-normal values on the fly
Procedure AdjustVolume32fRight(Buffer:PSingle;Volume:single; samples:integer);
This
adjusts the volume from buffer start + 1 sample, skipping every other sample,
for separate treatment on stereo buffers.
Volume
values should be 0...1, unless you want to amplify very soft material
Warning:
Any value is accepted!
Procedure
AdjustVolume32fRightDN(Buffer:Psingle;Volume:single; samples:integer);
The same
but with inline checking/repairing de-normal values on the fly
Function SoftestSample32f(Inbuffer: Psingle;SampleCount:
integer):single;
This
function traces a buffer for the softest sample.
This is
mainly useful as a development function to evaluate signal levels, but is also useful
in off-line audio processing or look-ahead on smaller buffers.
It is
perfectly acceptable to use it real-time with the ASIO buffers of a good
quality audio card.
It returns
the absolute value of the softest signal in the buffer, a positive range nearing
to zero.
Function LoudestSample32f(Inbuffer: Psingle;SampleCount:
integer):single;
This
function traces a buffer for the loudest sample.
This is
mainly a development utility to evaluate signal levels, but you can also use it
for off-line audio processing or look ahead on smaller buffers.
It is
perfectly acceptable to use it real-time with the ASIO buffers of a good
quality audio card.
It returns
the absolute value of the loudest signal in the buffer, so it’s in the range of
0…1
24 bit integer single sample manipulation
Function Cvt24BitTo32(Sample
: T24BitSample) : integer;
This
function converts a single 24bit lsb sample to a 32
bit sample
Function Cvt32BitTo24(Sample
: integer) : T24BitSample;
This
function converts a 32bit integer sample to a 24 bit lsb
sample
Function Cvt32fTo24LSB(Sample
: single) : T24BitSample;
This
function converts a 32 bit single precision floating point sample to a 24 bit lsb sample
Phase handling and voice cancelling
Procedure InvertPhase32fMono(Inbuffer: Psingle;Outbuffer: PSingle; SampleCount: integer);
This
procedure inverts the phase of all the samples in the inputbuffer
Procedure InvertPhase32fMonoInplace(buffer:
Psingle;SampleCount: integer);
This procedure
inverts the phase of all the samples in the buffer in place.
Procedure InvertPhase32fStereo(Inbuffer: Psingle;Outbuffer: PSingle; SampleCount: integer);
This
procedure inverts the phase of the right channel in a stereo buffer
Procedure InvertPhase32fStereoInplace(buffer:
PSingle; SampleCount:
integer);
This
procedure inverts the phase of the right channel of a stereo buffer in place.
Procedure VoiceCancel32f(Inbuffer: Psingle;OutBuffer:Psingle;SampleCount:
integer);
This
procedure inverts the phase of one of the stereo channels, and then mixes the
stereo signal to mono.
This has
the effect of eliminating the centre of the audio and thus it is sometimes inaccurately
called “Voice Cancellation” since the singer is often mixed in the centre. Note
that for best results you should combine it with something like a >12dB/Oct
low pass filter on a copy of the input signal at 200 ~ 300Hz before you do the
cancelling and add the signals together after processing. Otherwise you may
also loose the bass frequencies which tend to take up much of the middle of the
spectrum as well. You may further enhance the result by feeding it through a 3D
sound processor first. This basically changes the phase of parts of the signal
to obtain a roomy illusion and can improve the accuracy of the voice removal,
since it influences the stereo spread. See below, use them in series.
The output
buffer is half the size of the input buffer.
Procedure TwoChannelVoiceCancel32f(Inbuffer: Psingle;OutBuffer:Psingle;SampleCount:
integer);
This
procedure inverts the phase of one of the two stereo channels and mixes them
down to mono.
It then
outputs both mono channels as an interleaved buffer, thus ensuring that the
output buffer is the same length as the input buffer.
Procedure Sound3D32f(Buffer:Psingle,Volume:Single, Samplecount:Integer);
This
procedure creates the well known three-dimensional sound effect by adding a
small amount of the average of the left and right channels to the left and
right samples, thus creating a spatial effect. Values below 0.1 have the effect
of narrowing the stereo image. Recommended values are between 0 and 1 or a bit
higher and must be positive. I have included it here, because it is a really a
phase effect. Note that the DC-DSP library
for
Utilities
Function FastEnsureRange(const Test, Min,Max: Integer) : Integer;overload;
Function FastEnsureRange(const Test,
Min, max:single):single;overload;
Function FastEnsureRangeDN(const
Test, Min, max:single):single;overload;
These are
fast RTL EnsureRange replacement functions. The first
two need a Pentium Pro, AMD Duron or better.
The last
one is based on an algorithm by Laurent de Soras of Ohmforce fame: It may reduce accuracy for small numbers.
I.e. if you clip to [-1; 1], the fractional part of the result will be
quantized to 23 bits, or more, depending on the bit depth of the temporary
results. Thus, 1e-20 will be rounded to 0. This has the fortunate side effect
of de-normal number elimination.
If you read
this correctly, it actually performs two different range checks,
one on the min and max values and one on very small values around 0!
Therefore
this may be more efficient for some tasks than the other range procedure.
Procedure SwapChannels32 (Buffer:Pointer;samples:integer);
Swaps right
and left channel for any 32bit type, both 32 bit Integer and 32 bit single
precision floating point.
Procedure SwapChannels16 (Buffer:PsmallInt;samples:integer);
Swaps right
and left channel for 16 bit
Procedure SwapChannels8 (Buffer:PShortInt;samples:integer);
Swaps right
and left channel for 8 bit integers
Function Undenormalize(fValue:single):single;assembler;
A simple
un-de-normalize function, based on a widely used C inline macro
Recommended resources
Here are
some very useful resources regarding programming Audio with
The website
of Milenko Mitrovic
contains discussions about using his DC-DSP lib and you can download his
brilliant DC_DSP library there.
Its focus
is more on DirectX than on generic audio programming, but the components are
very good and do not rely on DirectX.
(Important
to me, since I almost only use ASIO)
TobyBear’s
website contains a lot of example code for writing VST plug-in and hosts and
you can download his very good VST plug-in template library, a VST host
component that is now way better than my own and many other freebies there. He
also has very extensive links pages to whatever dsp
resource you may ever need. He also has some of the most original shareware
plug-ins on the web (and has a knack for quirky coloured user interface
designs).
Frederic VanMol’s website contains his original translations of both
the Steinberg ASIO SDK and the VST SDK.
The
musicdsp.org website contains a lot of information, algorithms and a very good pdf file full of almost ready to use dsp
stuff. Most of the source code is in C or C++, but the algorithms are pretty
well explained. Not much
The KOL
website holds most of my sources and examples, as well as lots of other audio
related stuff and lots more freeware sources to write very small applications
with Vladimir Kladov’s brilliant KOL VCL replacement
library. Check it out, it’s brilliant! For years I use nothing else for my home
programming and only use the VCL or CLX for commercial work. Using KOL your
native code 32 bit Windows applications are about a tenth the size of the VCL
equivalent. That makes them compare favourably to JAVA appletsJ for distributions on the web. The
KOL framework is almost entirely written in BASM, but you don’t have to bother
about that: all classes -actually they are objects- have an exact equivalent in
pure
Not audio
related, but of interest to pascal and Delphi fans
should be the Freepascal Delphi compatible cross-platform compiler, that has
become truly amazingly good in the newest versions. It beats Borland’s products
hands down in cross-platform compatibity, although its development environment
is not yet as productive.
Did
you know one of the best audio programs ever was written in
There are
really not many more really good resources, which is a bit sour.
But check out the Linux community for lots of audio related material in C and
C++. It is often very good and very translatable.
Conclusion
Well, my
previous really comprehensive and topical inline assembler library was the
TDKLIB GUI utility library for DOS which was of course 16 bits and for Turbo C,
Turbo Pascal and Powerbasic and was released in 1989.
It was distributed via pre-web era bulletin boards and had during its four year
life-cycle a total of about 13.400 downloads. It reached version 4 in 1993.
After more
than fourteen years it was time to do another one! I am pretty sure it can grow
and improve over time. If you use it, please give me feedback to motivate me to
do so. Additional code to include in this library is also appreciated. I will
include it along with credits.
Have fun,
Thaddy