generateFilters()
function to wait to allow me to load the set of filters in REW, and after the steps that were already there, I did a merge from the spinorama filter to the one generated by the code. It sounds good to me, but what do you think of this idea? async function generateFilters() {
console.info(`Crafting custom room correction filters...`);
delay *= 2;
const measurements = await fetch_mREW();
let indexTC = dChannels + 1;
await postNext('Minimum phase version', indexTC, {
"include cal": false,
"append lf tail": false,
"append hf tail": false,
"frequency warping": false,
"replicate data": false
});
await postDelete(indexTC);
await fetch_mREW(indexTC,'PUT', {title: "Dr Toole target curve"});
await new Promise(resolve => setTimeout(resolve, delay * 1.15));
const result1 = await swal.fire({
confirmButtonColor: "#6fa3e7",
text: "Import the speaker targets",
input: 'text',
showCancelButton: true
});
for (let i = 1; i <= dChannels; i++)
{
await postNext('Minimum phase version', i, {
"include cal": false,
"append lf tail": false,
"append hf tail": false,
"frequency warping": false,
"replicate data": false
});
ii = 2* dChannels + i * 2;
await postNext('Arithmetic', [ii, indexTC], {
function: "A / B",
regularisation: "0",
lowerLimit: "0",
upperLimit: "0"});
await postNext('Arithmetic', [ii + 1, ii + 1], {
function: "1 / A",
maxGain: "0",
lowerLimit: "0",
upperLimit: "200",
autoTarget: "0",
excludeNotches: false});
await postNext('Arithmetic', [dChannels + 1 + i, ii + 2], {
function: "Merge B to A",
mergeFrequency: "300",
mergeBlend: true});
await postNext('Minimum phase version', ii + 3, {
"include cal": false,
"append lf tail": false,
"append hf tail": false,
"frequency warping": false,
"replicate data": false
});
await postNext('Arithmetic', [i, ii + 4], {function: "A * B"});
const finTitle = measurements[i].title.replace("o","final");
await fetch_mREW(ii + 5, 'PUT', {title: finTitle});
const filtTitle = measurements[i].title.replace("o","");
await fetch_mREW(ii + 4, 'PUT', {title: filtTitle});
console.log(`Optimal filter generation for speaker ${filtTitle} is completed.`);
await postDelete(ii);
await new Promise(resolve => setTimeout(resolve, delay * 1.15));
await postDelete(ii);
await new Promise(resolve => setTimeout(resolve, delay * 1.15));
await postDelete(ii);
await new Promise(resolve => setTimeout(resolve, delay * 1.15));
await postDelete(ii);
await new Promise(resolve => setTimeout(resolve, delay * 1.15));
}
for (let xxx = 0; xxx < dChannels; xxx++) {
await postDelete(dChannels + 2);
await new Promise(resolve => setTimeout(resolve, delay * 1.15));
}
console.log(`Done!`);
console.info(`************************************************************************************************************************`);
}
Nicely coded but Merge A to B would shift phase and SPL of one or both of the responses to match them and can have major unforeseen effects. The right way is multiplying your additional filter with the final one.OCA created an even more automated approach explained in this video.
@OCA, what I noticed is that you don't allow any boost anymore up to 200Hz. In a previous video you were using a max of 5dB if I remember correctly. Why is that?
While I do agree with your insight that the room should not be corrected above a certain frequency, I think the speaker response should be corrected. As my speakers are on spinorama.org, I entered the EQs found there in REW and multiplied them with the antiHF curve. E.g. for my bookshelf speaker I use as a surround the resulting curve is:
View attachment 358949
I changed thegenerateFilters()
function to wait to allow me to load the set of filters in REW, and after the steps that were already there, I did a merge from the spinorama filter to the one generated by the code. It sounds good to me, but what do you think of this idea?
JavaScript:async function generateFilters() { console.info(`Crafting custom room correction filters...`); delay *= 2; const measurements = await fetch_mREW(); let indexTC = dChannels + 1; await postNext('Minimum phase version', indexTC, { "include cal": false, "append lf tail": false, "append hf tail": false, "frequency warping": false, "replicate data": false }); await postDelete(indexTC); await fetch_mREW(indexTC,'PUT', {title: "Dr Toole target curve"}); await new Promise(resolve => setTimeout(resolve, delay * 1.15)); const result1 = await swal.fire({ confirmButtonColor: "#6fa3e7", text: "Import the speaker targets", input: 'text', showCancelButton: true }); for (let i = 1; i <= dChannels; i++) { await postNext('Minimum phase version', i, { "include cal": false, "append lf tail": false, "append hf tail": false, "frequency warping": false, "replicate data": false }); ii = 2* dChannels + i * 2; await postNext('Arithmetic', [ii, indexTC], { function: "A / B", regularisation: "0", lowerLimit: "0", upperLimit: "0"}); await postNext('Arithmetic', [ii + 1, ii + 1], { function: "1 / A", maxGain: "0", lowerLimit: "0", upperLimit: "200", autoTarget: "0", excludeNotches: false}); await postNext('Arithmetic', [dChannels + 1 + i, ii + 2], { function: "Merge B to A", mergeFrequency: "300", mergeBlend: true}); await postNext('Minimum phase version', ii + 3, { "include cal": false, "append lf tail": false, "append hf tail": false, "frequency warping": false, "replicate data": false }); await postNext('Arithmetic', [i, ii + 4], {function: "A * B"}); const finTitle = measurements[i].title.replace("o","final"); await fetch_mREW(ii + 5, 'PUT', {title: finTitle}); const filtTitle = measurements[i].title.replace("o",""); await fetch_mREW(ii + 4, 'PUT', {title: filtTitle}); console.log(`Optimal filter generation for speaker ${filtTitle} is completed.`); await postDelete(ii); await new Promise(resolve => setTimeout(resolve, delay * 1.15)); await postDelete(ii); await new Promise(resolve => setTimeout(resolve, delay * 1.15)); await postDelete(ii); await new Promise(resolve => setTimeout(resolve, delay * 1.15)); await postDelete(ii); await new Promise(resolve => setTimeout(resolve, delay * 1.15)); } for (let xxx = 0; xxx < dChannels; xxx++) { await postDelete(dChannels + 2); await new Promise(resolve => setTimeout(resolve, delay * 1.15)); } console.log(`Done!`); console.info(`************************************************************************************************************************`); }
Why is that?
I made sure to clean up after myself in order to not mess up the indices. I also removed the anti-HF stuff, as this is already compensated for in my filters.That extra generated response would mess with the indices in the later parts of the code though.
Is it possible to only multiply from 300Hz and up?Nicely coded but Merge A to B would shift phase and SPL of one or both of the responses to match them and can have major unforeseen effects. The right way is multiplying your additional filter with the final one.
You need a filter with 0dB freq magnitude and 0 degree phase response somewhere around 300Hz, merge it A B with a Dirac pulse (which you can create in EQ window with generate filters when there are no filters) at 300 Hz. Then you can multiply that merged response safely with the bass filter.I made sure to clean up after myself in order to not mess up the indices. I also removed the anti-HF stuff, as this is already compensated for in my filters.
Is it possible to only multiply from 300Hz and up?
I did a merge from the spinorama filter to the one generated by the code.
The right way is multiplying your additional filter with the final one.
Is it possible to only multiply from 300Hz and up?
Yes, that would totally work but again, it wouldn't sound better If you really have to, use the new automated shelving EQ filters of the REW beta for HF on gated frequency response.Curious if this alternative approach would work:
- Run A-1 without modification
- Create filter curves by only entering spinorama EQ data above 300 Hz
- Multiply the final filters generated by A-1 with these
- Export the multiplication results
- Use the older AudysseyX_OCA script to insert these into the ady file
Are you saying the general approach of correcting speaker (not room) FR above the transition frequency is inaudible or counterproductive? Or is there something about the method outlined that would fail to achieve the goal?Yes, that would totally work but again, it wouldn't sound better
So if one does try to correct speaker FR, why would filters based on a gated measurement be better than filters based on a NFS measurement? They are both meant to be quasi-anechoic, aren't they?If you really have to, use the new automated shelving EQ filters of the REW beta for HF on gated frequency response.
The explanation is in the video (starts at the right time) above (#104).Are you saying the general approach of correcting speaker (not room) FR above the transition frequency is inaudible or counterproductive?
Neither NF nor gated can measure the directions of the HF rays because you are using an "omnidirectional mic". There seems to be some confusion between headphone EQ and speaker EQ along the way. But between the two, I'd personally go for the old school gating method because I am not sure if these measurements or the algo used to EQ them is flawed but figures like below don't appear to me as anechoic response filter requirements of a speaker in this day and age:They are both meant to be quasi-anechoic, aren't they?
I watched the video previously, but apparently misunderstood. It seemed, with the emphasis on reflections and directional cues, that it mostly applied to not filtering based on in-room measurements.The explanation is in the video (starts at the right time) above (#104).
Those extreme spinorama filter examples are also fascinating. The generated EQ for my speakers doesn't have anything like that. I'm also mostly interested to see if there's room for improvement in the midrange. So I don't expect, in my case, that the difference would be instantly obvious or throttled. But if I find the time I might try it both ways just to see if I can tell the difference at all.I'd personally go for the old school gating method because I am not sure if these measurements or the algo used to EQ them is flawed but figures like below don't appear to me as anechoic response filter requirements of a speaker in this day and age:
There's recent work to properly measure directional sound vectors at the LP with spherical 64 mic arrays like this one:Ok, thanks, this is really interesting.
I watched the video previously, but apparently misunderstood. It seemed, with the emphasis on reflections and directional cues, that it mostly applied to not filtering based on in-room measurements.
The argument for not filtering based on anechoic speaker response is much more subtle, and I suspect I'm not the only one who missed it. Is this a correct distillation of this second, finer point?:
1. Filtering based on quasi-anechoic (gated, NF, what-have-you) response seems like a good idea because it ignores reflected sound at the LP and purports to only affect the sound coming out of the speaker before any reflectivity in the room.
However,
2. Applying these filters will also affect off-access reproduction in unpredictable ways, which in turn affects reflected sound in-room and can reduce sound quality at the LP.
Those extreme spinorama filter examples are also fascinating. The generated EQ for my speakers doesn't have anything like that. I'm also mostly interested to see if there's room for improvement in the midrange. So I don't expect, in my case, that the difference would be instantly obvious or throttled. But if I find the time I might try it both ways just to see if I can tell the difference at all.
It might also be interesting to compare filters generated from a gated measurement with the ones on spinorama.org.
Sort your bass and the rest will all come out beautifully. I don't think there're many speakers today with mids and highs that would audibly disturb listeners despite correct placement and toe-in.if there's room for improvement in the midrange
Actually, that's not quite true. The EQ I'm listening to now is based on an earlier @OCA methodology and is very similar to the filters plotted above:Haven't had a chance yet to actually apply any of these and listen to the results.
Actually, I thought a lot about it and would normally not add filters that high but at the end I tried to make the exact reverse of what Audyssey does and avoid effecting the speaker's original output. However, I have been taking direct pre-amp out measurements in the last couple of days (and guess to add what to One) and I have reshaped that inverse filter. I'll upload that version very soon.I experimented with some of the options above, and also did not really like how the "spinorama version" turned out. I, of course, cannot draw any generic conclusions based on this, just my preference.
@OCA, instead of adding the anti-HF array to the result, why don't you limit equalization to 300Hz?