Right click on any DSP filter in the right panel and select Export coefficients
opens a file chooser dialog
box that allow you te select the output file for the corresonding filter.
Available extensions are .dsp for binary file output and .dspa
for ascii file output.
⚠ ascii file output is not recommended because all the digits
of the filter coeffictients will not be saved to the file
and importing the file afterwards will not exactly reproduce the
filer frequency response.
The
button in the top toolbar
()
exports all filters (selected and unselected) filter coefficients.
The
button in the right panel
() exports only the selected filters.
⚠ Only binary file format (.dsp) is available for filter banks.
Selecting Import as filter type opens a file chooser dialog box that allows you to select the input file. Available extensions are .dsp for binary files and .dspa for ascii files.
The
button
imports a DSP filter bank from file.
⚠ Only binary file format (.dsp) is available for filter banks.
We will first decribe the ascii file format. A C++ function that imports binary files is provided afterwards. The first line is the filter label that will be displayed in the left panel of the DSP dialog box. The second line contains:
Then, for each filter in the file
The two coefficient line contains the ai and bi. ⚠ a0=1.
In that case, the a line contains only 1.
The following exemple is a 2nd order zero. The b line conains the 3 coefficients.
Zero f=5000 B=100
1 44100
1 3 0
1
2.07048 -3.11167 2.04119
The following exemple is a 6th order Kaiser Window filter and the b line conains the 7 coefficients.
KWL(2000,10000,20) O(6)
1 44100
1 7 0
1
0.0578831 0.157622 0.240157 0.272109 0.240157 0.157622 0.0578831
In that case, the a line contains more than one coefficient but you still must have a0=1.
Below is a 2nd order pole thas has 3 a coefficients and a single b0 coefficient.
Pole f=5000 B=100
1 44100
3 1 0
1 1.50287 -0.985853
0.48298
The next example is Butterworth 6th order lowpass filter written as a cascade of 3 iir filter, each one has 3 a and 3 b coefficients.
BW low f=2000 O=6 G=0
3 44100
3 3 0
1 1.78918 -0.864355
0.0187949 0.0375899 0.0187949
3 3 0
1 1.60109 -0.668369
0.0168192 0.0336383 0.0168192
3 3 0
1 1.50948 -0.572905
0.0158568 0.0317135 0.0158568
A sparse filter contains only few coefficients that are not 0. Int that case, null coefficients are not stored and their contribution to the frequency response are not computed. Each non-zero coefficient is represented by two numbers:
a and b lines has contains therefore two times the number of non-zero coefficient
The next example is Feedforward Comb filter. It is a FIR filter since the a line contains 0 1 which means a0=1. The b line contains two coefficient: b0=1 and b1223=0.77.
Feedforward Comb N=1223 ; g= 0.77
1 44100
1 2 1
0 1
0 1 1223 0.77
Here is a Feedback Comb filter (FIR). Note that in this case the a0=1 term is not present as in the previous case because otherwise the a line would have been empty. The non-zero terms for this example are a0=1, a13=0.77 and b0=1.
Feedback Comb N=13 ; g= 0.77 d= 0
1 44100
1 1 1
13 0.77
0 1
The next example is Schroeder Allpass Sections without lowpass filter tap.
All-Pass N=5 ; b0= 0.9
1 44100
1 2 1
5 -0.9
0 0.9 5 1
The last example is a lowpass-filtered Schroeder Allpass Sections.
All-Pass N=5 ; b0= 0.9 ; d= 0.2
1 44100
2 3 1
1 0.2 5 -0.72
0 0.9 1 -0.18 5 0.8
The binary format is similar the the ASCII one except that
If the file contains a filter bank, you nead first to read the header that contains:
Example of C++ functions that reads dsp filter binary files
bool importFilterFromBinaryFile(std::string fileName)
{
// The file contains a single DSP filter
ifstream ifile;
ifile.open(fileName, ios::in | ios::binary);
if (!ifile.is_open()) return false;
return importCoefficientsFromBinaryFile(ifile);
}
bool importBankFromBinaryFile(std::string fileName)
{
// The file contains DSP filter bank.
ifstream ifile;
ifile.open(fileName, ios::in | ios::binary);
if (!ifile.is_open()) return false;
int headerSize;
if (!ifile.read((char*)&headerSize, sizeof(int)).good()) return false;
char* header = new char[headerSize + 1];
if (!ifile.read(header, headerSize * sizeof(char)).good()) return false;
header[headerSize] = '\0';
bool ok = true;
bool readActive = false;
if (strcmp(header, "dsp_filter_bank")) {
if (strcmp(header, "dsp_filter_bank_all")) {
lfout << "Invalid filter bank header " << header << " in " << fileName << endl;
ok = false;
}
else
{
readActive = true; // File contains all filters => also read active status
}
}
else{
// only active filters are saved (dsp_filter_bank)
}
delete[] header;
if (!ok) return false;
int nFliters;
if (!ifile.read((char*)&nFliters, sizeof(int)).good()) return false;
std::vector activeFilters(nFliters);
if (readActive) {
//Also read active status;
if (!ifile.read(activeFilters.data(), nFliters).good()) return false;
}
for (int i = 0; i < nFliters; i++) {
if (!(ifile.good() && importCoefficientsFromBinaryFile(ifile))) {
return false;
}
if (readActive) {
// filter is active
}
}
}
bool importCoefficientsFromBinaryFile(ifstream& ifile)
{
int labelSize, nFilter;
double sampleRate;
if (!ifile.read((char*)&labelSize, sizeof(int)).good()) return false;
char* label = new char[labelSize + 1];
if (!ifile.read(label, labelSize * sizeof(char)).good()) return false;
label[labelSize] = '\0';
// The filter label is known, use it before deleting it
delete[] label;
ifile.read((char*)&nFilter, sizeof(int));
ifile.read((char*)&sampleRate, sizeof(double));
for (size_t i = 0; i < nFilter; i++) {
int sz_a = 0, sz_b = 0, flag = 0;
if (!ifile.read((char*)&sz_a, sizeof(int)).good()) return false;
if (!ifile.read((char*)&sz_b, sizeof(int)).good()) return false;
if (!ifile.read((char*)&flag, sizeof(int)).good()) return false;
if (flag == 0) {// Not Sparse
double* a = new double[sz_a];
double* b = new double[sz_b];
if (!ifile.read((char*)a, sz_a * sizeof(double)).good()) return false;
if (!ifile.read((char*)b, sz_b * sizeof(double)).good()) return false;
// You have your coefficients
// Use it here before deleting
delete[] a; delete[] b;
}
else
{// Sparse
std::vector> spa(sz_a);
std::vector> spb(sz_b);
size_t ic;
if (sz_a == 1) {
int testi; double testd;
if (!ifile.read((char*)&testi, sizeof(int)).good()) return false;
if (!ifile.read((char*)&testd, sizeof(double)).good()) return false;
if (testi > 0) {
spa[0].first = testi;
spa[0].second = testd;
}
else{
// Not needed (a[0]=1) but written to keep file format constant
spa.resize(0);
}
}
else {
for (ic = 0; ic < sz_a; ic++) {
if (!ifile.read((char*)&spa[ic].first, sizeof(int)).good()) return false;
if (!ifile.read((char*)&spa[ic].second, sizeof(double)).good()) return false;
}
}
for (ic = 0; ic < sz_b; ic++) {
if (!ifile.read((char*)&spb[ic].first, sizeof(int)).good()) return false;
if (!ifile.read((char*)&spb[ic].second, sizeof(double)).good()) return false;
}
// Here you have your not-null coefficients and their indexes
}
}
return true;
}
Here are the functions that can be called from Python scripts.
DSPFilterExport(string "filterName", string "fileName")
# Export filter filterName in file fileName.
# Binary file if the file extension is .dsp
# and ascii file if the file extension is .dspa.
DSPFilterImport(string "fileName")
# Import a single filter from file fileName
# Binary file if the file extension is .dsp
# and ascii file if the file extension is .dspa.
DSPSaveSelection(string "fileName")
# Export active filters in file fileName
# Only binary file is supported (.dsp)
DSPSaveAll(string "fileName")
# Export active and inactive filters in file fileName
# Only binary file is supported (.dsp)
DSPImportBank(string "fileName")
# Import filer band from file fileName
# Only binary file is supported (.dsp)