A Beginner's Guide to Programming.pdf

(72 KB) Pobierz
A Beginner's Guide to Programming Digital Audio Effects in the kX Project
environment
Martin Borisov (Tiger M)
Santiago Munoz (eYagos)
revised by
Max Mikhailov (Max M.)
Introduction
Digital audio effects are a small branch of the science of digital signal processing (DSP), which comprises
many different types of applications such as image processing, communications, medical instrumentation,
military instrumentation, deep sea and space exploration etc. All these deal with processing different signals
(a signal being a stream of continuous data) and so does audio processing.
The digital signal processor of the sound card driven by kX gives us many possibilities for audio effects
implementation and kX itself consists of tools that help us a lot in achieving this. Not many people
comprehend the power that this combination puts in our hands. In fact we have a fully programmable digital
effects processor, which we can command in the most subtle way possible by using the lowest level
assembly instructions provided. We can program all possible types of effects known in the audio world.
Some things might seem complicated, but don't be scared, I can assure you that you would be able to
comprehend it.
In this guide I've tried to keep things as simple as possible and give examples, which are the essence of
learning DSP techniques in kX. We willl use the kX Editor (Dane) which is a very convenient assembler.
Although it doesn't give the flexibility of C++ programming, it will be enough for the basics and will give
you a jump start on DSP programming. And if you are familiar with object oriented programming in C++,
than you have all the power in your hands. But note: no C++ knowledge is required for understanding the
information in this guide.
The structure of the guide is practicaly oriented. I'll give examples coupled with explanations of the 16
instructions used in programming the E-mu10kx chips. You can copy/paste and test them in Dane. The
instructions are the programming language of the processor, often called the microcode/opcode.
In the end we'll "disect" several of the commonly used simple kX Project effects.
The digital signal processor
When a signal (in our case analog audio signal) enters the input of the soundcard it goes into an ADC
(analog to digital converter), which transforms the voltage of the sound signal in regular intervals of time
(in our case it does this 48000 times per second - 48KHz) to a number, thus making it digital (discrete). So,
48000 numbers form 1 second of audio signal or vice-versa. Then every number of this continuous array of
values passes through the digital signal processor where it gets transformed by the effects. After that it goes
into the DAC (digital to analog converter) where it gets analog again and goes to the sound card outputs. In
some cases the signal might be extracted before it gets transformed by the DAC, and sent to the digital
output of the sound card in digital form.
We transform the signal with audio effects when it is in the form of numbers and this means we have to
deal with math and nothing else! So, DSP effects are just mathematical functions, which most of us study in
school. Actually each instruction is a small mathematical function all by itself. A combination of these
forms a system - the audio effect. This system of mathematical functions is performed on each value of the
transformed signal and the processor does this 48000 times per second.
Let's begin
Let's start by opening kX Editor. Rigt-click the kX icon in the taskbar and open kX Editor.
In the editor window you'll see lines starting with ; - these are just comments, in the upcomming examples
there will be many of these. You'll see lines like "name", "copyright" and so on, which are only for
providing information for the plugin and are not related to DSP. You can write your own information there
for each effect. The "guid" line is important, because it guarantees the uniqueness of the plugin, so it doesn't
overwrite existing effects when it is registered in kX. You can obtain an unique guid by going to the
'settings' tab and selecting 'generate guid'. This copies the new guid to the clipboard and you just have to
paste it in your code. You'll also see an "end" word, which indicates where the code ends. It should always
be there for the code to get compiled (parsed).
NOTE: In kX editor you can use both the decimal and hexadecimal (aka machine) number systems. It is
advisable to use decimal, because this is the natural “human” number system and decimal numbers are
automaticly transformed into hexadecimal.
For example, if you write 1 it will be transformed to 0x7fffffff. You don't have to know hexadecimal
numbers to program audio effects in kX, in fact it will just be a waste of time. You can convert hexadecimal
to decimal in windows calculator for instance, with the following formula: hex/(2^31 + 1) = dec, or decimal
to hexadecimal: dec*(2^31 – 1) = hex.
Numbers processed by the E-mu10kx digital signal processor are fixed-point 32 bit fractional between -1
and 1 or integer values (whole numbers).
Registers
Unprocessed, intermediate and processed data of the audio signal stream is stored in physical registers.
There are several types of registers:
1.
Input
and
output
registers. Incomming data unprocessed by the current effect is stored in the input
register, so subsequently it can get processed. Already processed data is stored in the output register, so it
can be rooted to physical outputs or other effects. Each microcode can have several input and output
registers depending on how many channels we want it to have. For example, if it's going to be stereo we
would need two of each type. If it's only mono we will need just one of each type. The use of such registers
is not necessary for effects which don't need both inputs or outputs – for instance peak meters or wave
generating effects. But at least one type is needed, otherwise the system would be meaningless and useless.
Declaration:
input
in
output
out
; in and out are just names, you can assign the registers
any name
NOTE: the value of the output register can be reused in the next sample cycle before the processor gets to
calculating the operation, the result of which is written to the same output register, when it gets overwritten
with the next output value.
2.Static and
temp
registers. They are used for storing intermediate data during instruction execution. The
value of a static register is preserved until it is overwritten (next sample cycle), or the microcode is
reinitialized (reloading or resetting the plugin). Temp registers are used for the present sample cycle only,
so their last value can not be used in the next cycle – it will be zero. The idea behind the temp register is
that it can be shared by all loaded effects, but such sharing is not supported by kX at the present time, so it
is recommended that static be used most of the time. Despite that we'll use temp registers in the examples
for learning purposes only.
Declaration:
static
st
temp
tmp
; st and tmp are again just names
Static and temp registers don't have to be initialized with a value, but if an initial value is needed you can
assign such to a static register:
static
st = 0.8
NOTE: when you use certain numbers (constants) directly in the microcode which are not present in
hardware (in a special read-only memory), they are automatically transferred to static registers when the
code is compiled.
3.Control register. This is a read-only register and has to be initialized with a value. When the code is
compiled, a fader is automatically created for that register, so it can be user controlled. It can have values
between 0 and 1 (although you can assign values greater than that, when you move the corresponding slider
the value is automaticaly transformed between 0 and 1).
Declaration:
control
volume = 0.2
The assigned value is the default value, so each time the code is reinitialized the control register will have
this value.
4.
Constants.
There are certain constant values, which are defined in hardware in a read-only memory on
the chip and can be used directly in the code (not with a static register) for the purpose of saving some
resources. Such are 0, 0.125, 0.5, 0.75, -1, 1, 2, 3, 4, 8, 10, 20, 100, etc. If not hardware-defined constants
are used, they will be automatically transformed to static registers, as mentioned before.
5.
Accum
register. This register gives us access to the dsp accumulator. When an instruction is executed, its
result is automatically stored in it overwriting the previous value and then copied to the result register of
that particular instruction. You can access the accumulator with the accum keyword and it can be used only
as an A operand. It is 67 bit wide and has 4 guard bits. It can be used when we want an unsaturated or
unwrapped intermediate result, for instance:
macs
0, 1, 0.5, 1
;1+ 0.5 = 1.5
macsn
out,
accum,
0.6, 1
;out=1.5-0.6=0.9
6.CCR (Condition Code Register). This register is used in the skip instruction. Its value is set after each
instruction, based on its result. You can acces it with the ccr keyword.
7.TRAM
Access Data Registers.
These registers are for delay lines. There are write registers (which write
samples in the delay line) and read registers (which read (extract) samples from the delay line). You can
change the address of these registers within the declared delay line, thus changing the lenght of the delay
line and the lenght of the actual delay. In Dane this is done by putting an & sign before the name of the
corresponding register.
Instructions
All instructions have the following syntax:
instruction result R ,operand A, operand X, operand Y
Operands are registers.
1.MACS and
MACSN
(multiply-accumulate with saturation on overflow) That means that you multiply
two numbers, then add them to a third number and store the value in the result register. These instructions
operate with fractional numbers only (they perform fractional multiplication)! If the result exeeds -1 or 1 it
is truncated to -1 or 1. This means that you can't use whole (integer) numbers with these two instructions
except “fractional” 1.
Formulae:
MACS R = A + X*Y
MACSN R = A - X*Y
Example:
This is a simple volume control program.
name
"Volume control";
copyright
"Copyright (c) 2004.";
created
"06/27/2004";
engine
"kX";
guid
"...It will be automatically generated!!!..."; Don't copy this
;we define the registers
input
in
output
out
control
volume=1
macs
out, 0, in, volume
;out = 0 + in * volume
end
;don't forget this
You can try it in kX Editor. Click on "Save Dane Source" (on the right of the window) not "Export to C++".
Save it, then right click on the DSP window and select "Register Plugin". Open the file and it should now
be with the other effects - you know where they are. Or you can find the file in windows explorer and
double-click on it – it will automatically get registered.
2.MACW and
MACWN
(MAC with wraparound on overflow) Same as MACS and MACSN, but when
the value exeeds -1 or 1 it wraps around. This is presumably to minimize noise when saturation occurs with
MACS and MACSN. If you have 0.5 + 0.7, the result instead of 1 on saturation, will be -0.8 with
warparound.
3.MACINTS (saturation) and
MACINTW
(wraparound). Same as MACS and MACW, but they perform
integer multiplication. That means that you can multiply a fractional value with an integer value as well as
integer with an integer. These two instructions always assume that the Y operand is an integer.
Formulae:
MACINTS R = A + X*Y
MACINTW R = A + X*Y
Example 1:
NOTE: I won't write the info part (name, copyright etc.) anymore. You can do that yourselves.
A simple gain. We multiply the input by 4 (that's a mono version of the x4 effect).
input
in
output
out
macints
out, 0, in, 0x4
; out = 0 + in * 4
end
Example 2 :
If we want to control the amount of gain:
input
in
output
out
control
gain=0.25
temp
t
macints
t, 0, in, 0x4
; t = 0 + in * 4
macs
out, 0, t ,gain
; out = 0 + t * gain - its actually a level
control
Zgłoś jeśli naruszono regulamin