NDF - NASPRO Digital Filter 0.1
File Format Overview
===============================
Introduction
------------
NDF, acronym for NASPRO Digital Filter, is a simple and open file format to
represent FIR and IIR sound processing filters.
The main idea here is to make it possible to define filters in simple data
files, hence without writing a single line of code in whatever programming
language; the host program (possibly via a standard library yet to be coded)
will use generic algorithms to perform sound processing using the data in the
NDF file.
The current version of this standard, although implemented and functional enough
to define and use some classes of filters, still lacks important features like
parametrization, use of mathematical expressions and only supports convolution
in time-domain as processing algorithm.
Simluated system
----------------
As just said, the only supported sound processing algorithm as of now is
convolution in time-domain.
Output data for a given output channel is calculated summing up a series of
independent components, each related to one of the input channels. Every
component is calculated simulating a system which looks like this:
.----,
.---| h1 |-----.
| '----' |
.-----. | .----. v
x ---| LAT >---+---| h2 |--->(+)---->(+)---------------------- y
'-----' | '----' ^ ^ |
| ... | | .----. |
| .----. | | .-----| r1 |---+
'---| hn |-----' | | '----' |
'----' | v .----. |
'---(+)<---| r2 |---+
^ '----' |
| ... |
| .----. |
'-----| rm |---'
'----'
Where:
- x is the input channel;
- y is the output channel;
- h1, h2, ..., hn are parts of the "direct impulse response";
- r1, r2, ..., rm are parts of the "feedback impulse response";
- LAT is the filter latency in case the direct impulse reponse is anti-causal.
The feedback impulse response can only be causal and r*[0] must be equal to 0.
This also ensures that parts of the feedback impulse response "do not interfer"
with each other.
Such a structure was chosen to make it easy to implement efficient algorithms
in the cases where significant parts of the impulse response are quite "distant"
among them (for example echos and reverbs).
Syntax
------
N.B.: This is not a specification, but rather an overview of the file format
syntax.
The file is split in three sections, delimited by the string "%%" placed alone
on one line, like this:
<section one>
%%
<section two>
%%
<section three>
The first section must start with the string "NDF0001T", followed by a newline
character, optionally followed by space, newline and tabulation characters and
comments.
Comments start with a hash sign (#) and end with a newline character; everything
in beetween must be silently ignored by the implementation.
Section two describes the input/output configuration of the filter. An example:
in : mono;
out: mono;
You can put comments and insert space, newline and tabulation characters as you
like (without splitting the keywords).
As of now only mono and stereo streams are supported.
Section three defines each part of the direct and feedback impulse response (h1,
... hn and r1, ... rm). Each of these parts looks like this:
in_channel->out_channel: time
{
<hi and/or rj definition(s)>
}
Where in_channel is the name of the input channel (mono for mono streams, left
or right for stereo streams) and out_channel is the name of the output channel
(as before).
The part inside brackets is made of a series of assignments like the following:
h[0] = 1.0;
h[0:10] = 1.0;
h[0:10:100] = 1.0;
r[1] = 1.0;
r[1:10] = 1.0;
r[1:10:100] = 1.0;
The first and the fourth assignment should be just straightforward to
understand. The second one is equivalent to:
h[0] = 1.0;
h[1] = 1.0;
h[2] = 1.0;
...
h[10] = 1.0;
And similairly for the fifth one. The third one is equivalent to:
h[0] = 1.0;
h[10] = 1.0;
h[20] = 1.0;
...
h[100] = 1.0;
And similairly for the sixth one.
At the moment you can only use integers as indices (which must also be >=1 for
r) and simple floating point values (everything a scanf("%f", &value);
recognizes) as values to be assigned.
As usual you can put coments, spaces, etc. almost everywhere (exceptions are:
you cannot split numbers and the x[...] string).
It is strongly suggested to define different parts for the global impulse
response when this has long periods with null samples, since the implementation
might not be smart enough to actually split it out in a clever way. In other
words, do this:
mono->mono: time
{
h[0] = 1.0;
}
mono->mono: time
{
h[10000] = 1.0;
}
mono->mono: time
{
h[20000] = 1.0;
}
Instead of this:
mono->mono: time
{
h[0] = 1.0;
h[10000] = 1.0;
h[20000] = 1.0;
}
ndfapply
--------
This is the NDF (demo) implementation developed for Google Summer of Code 2008.
Type ndfapply --help to get usage information.
At the moment it supports "regular" PCM encoded WAV files with
Subchunk1Size == 16. In other words use arecord ;-)