Created
June 22, 2019 01:00
-
-
Save joslloand/b25273e0894ccbc4b186c3fc048cdd01 to your computer and use it in GitHub Desktop.
Test: magnitude design for multi-band decoding filters with focalisation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
define: | |
~meanE | |
~matchWeight | |
*/ | |
// meanE from degree weights | |
( | |
~meanE = { |beamWeights, dim = 3| | |
var m = beamWeights.size - 1; // order | |
(dim == 2).if({ | |
beamWeights.removeAt(0).squared + (2*beamWeights.squared.sum) // 2D | |
}, { | |
(Array.series(m + 1, 1, 2) * beamWeights.squared).sum // 3D | |
}).asFloat | |
} | |
) | |
~hoaOrder.meanE(\controlled, 3) | |
~meanE.value( ~hoaOrder.beamWeights(\controlled, 3), 3) | |
// matchWeight from degree weights | |
( | |
~matchWeight = { |beamWeights, dim = 3, match = 'amp', numChans = nil| | |
var m = beamWeights.size - 1; // order | |
var n; | |
switch( match, | |
'amp', { 1.0 }, | |
'rms', { | |
(dim == 2).if({ | |
n = 2*m + 1 // 2D | |
}, { | |
n = (m + 1).squared // 3D | |
}); | |
(n/~meanE.value(beamWeights, dim)).sqrt | |
}, | |
'energy', { | |
n = numChans; | |
(n/~meanE.value(beamWeights, dim)).sqrt | |
} | |
).asFloat | |
} | |
) | |
~hoaOrder.matchWeight(\controlled, 2, \rms) | |
~matchWeight.value( ~hoaOrder.beamWeights(\controlled, 2), 2, \rms) | |
~hoaOrder.matchWeight(\controlled, 2, \energy, 60) | |
~matchWeight.value( ~hoaOrder.beamWeights(\controlled, 2), 2, \energy, 60) | |
( | |
// "three band" dictionary version | |
~foclShelf = { arg size, radius, beamDict, dim = 3, match = \amp, numChans, order = (AtkHoa.defaultOrder), window = \reg, phase = \lin, sampleRate, speedOfSound = (AtkHoa.speedOfSound); | |
var hoaOrder, dftFreqs; | |
var foclMags, beamMags, mags; | |
hoaOrder = HoaOrder.new(order); | |
dftFreqs = size.dftFreqs(sampleRate); // dft freqs | |
// focalisation? | |
(radius != nil).if({ | |
// focal magnitude - collected by degree | |
foclMags = dftFreqs.collectAs({ arg freq; | |
hoaOrder.foclWeights(freq, radius, window, speedOfSound); | |
}, | |
List | |
).flop.asArray; // collect as List, due to Array -flop bug | |
}, { | |
// or... just unity | |
foclMags = Array.fill((order + 1) * size, { 1.0 }).reshape((order + 1), size); | |
}); | |
switch( beamDict.at(\beamShapes).size, | |
1, { | |
beamMags = hoaOrder.beamWeights(beamDict.at(\beamShapes).first, dim) | |
}, | |
2, { | |
(beamDict.at(\edgeFreqs).size != 2).if({ | |
Error("Must supply two edge frequencies for a two band shelf. Supplied: % ".format(beamDict.at(\edgeFreqs).size)).throw | |
}, { var freqs = beamDict.at(\edgeFreqs).sort; | |
var beamWeights = beamDict.at(\beamShapes).collect({ arg beamShape; | |
hoaOrder.beamWeights(beamShape, dim) | |
}); | |
beamMags = (order + 1).collect({ arg degree; | |
Array.logShelf(size, freqs.at(0), freqs.at(1), beamWeights.at(0).at(degree).ampdb, beamWeights.at(1).at(degree).ampdb, sampleRate) | |
}) | |
}) | |
}, | |
3, { | |
(beamDict.at(\edgeFreqs).size != 4).if({ | |
Error("Must supply four edge frequencies for a two band shelf. Supplied: % ".format(beamDict.at(\edgeFreqs).size)).throw | |
}, { var freqs = beamDict.at(\edgeFreqs).sort; | |
var beamWeights = beamDict.at(\beamShapes).collect({ arg beamShape; | |
hoaOrder.beamWeights(beamShape, dim) | |
}); | |
beamMags = (order + 1).collect({ arg degree; | |
Array.logShelf(size, freqs.at(0), freqs.at(1), beamWeights.at(0).at(degree).ampdb, beamWeights.at(1).at(degree).ampdb, sampleRate) * | |
Array.logShelf(size, freqs.at(2), freqs.at(3), 0.0, (beamWeights.at(2).at(degree) / beamWeights.at(1).at(degree)).ampdb, sampleRate) | |
}) | |
}) | |
} | |
); | |
// // normalization | |
// (match != \amp).if({ | |
// mags = mags * mags.flop.collect({ arg item; | |
// ~matchWeight.value(item, dim, match, numChans) | |
// }).flop | |
// }); | |
// | |
// mags; | |
// normalization - two cases | |
case | |
{ match.class == Symbol } { // single match | |
mags = foclMags * beamMags; | |
(match != \amp).if({ | |
mags = mags * mags.flop.collect({ arg item; | |
~matchWeight.value(item, dim, match, numChans) | |
}).flop | |
}) | |
} | |
{ ((match.class == Array) && (match.size == 2)) } { // dual match | |
// [ foclMags, beamMags] | |
}; | |
mags; | |
/* now need to generate the kernel! */ | |
} | |
) | |
/* | |
Set params | |
*/ | |
~order = 1 | |
~order = 3 | |
~order = 5 | |
( | |
~beamDict = Dictionary.with(*[ | |
// \beamShapes-> [ \basic ], | |
// \beamShapes-> [ \energy ], | |
\beamShapes-> [ \basic, \energy ], | |
// \beamShapes-> [ \basic, \controlled ], | |
// \beamShapes-> [ \energy, \controlled ], | |
\edgeFreqs-> [ 700.0, 1400.0 ], | |
// \edgeFreqs-> [ 400.0, 8000.0 ], | |
// \beamShapes-> [ \basic, \energy, \controlled ], | |
// \edgeFreqs-> [ 700.0, 1400.0, 4000.0, 8000.0 ], | |
]) | |
) | |
~win = \hp | |
~win = \reg | |
~radius = nil // no focalisation | |
~radius = ~order.asHoaOrder.radiusAtFreq(1400.0, ~speedOfSound); // set effective radius for 1400.0 Hz | |
~mags = ~foclShelf.value(~kernelSize, ~radius, ~beamDict, 3, \amp, nil, ~order, ~win, \lin, ~sampleRate, (AtkHoa.speedOfSound)) // normalize amplitude, aka pressure | |
~mags = ~foclShelf.value(~kernelSize, ~radius, ~beamDict, 3, \rms, nil, ~order, ~win, \lin, ~sampleRate, (AtkHoa.speedOfSound)) // normalize rms, energy of spherical harmonics | |
~mags.do({ arg item, i; (item.keep(200) + -180.dbamp).ampdb.plot(i.asString, minval: -20.0, maxval: 20.0)}) // plot in dB | |
~mags.do({ arg item, i; (item.keep((~kernelSize/2).asInteger + 1) + -180.dbamp).ampdb.plot(i.asString, minval: -90.0, maxval: 20.0)}) // plot in dB | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment