• Welcome to ASR. There are many reviews of audio hardware and expert members to help answer your questions. Click here to have your audio equipment measured for free!

Localization Cue Correction (LCC)

westonlast

Member
Joined
Dec 23, 2024
Messages
7
Likes
2

I only just learned about this because it showed up as a component for Foobar2000.


It reads like a promising solution to stereo comb filtering, retrofitting stereo recordings playback to sound better. Of course there's much more to it than that, with timing and such.

It's appealing because it's a software solution. You can try it today. Only two speakers needed.

At the very least, could be a cool new toy, similar to things like Trifield decoding: https://www.foobar2000.org/components/view/foo_dsp_trifield

My vague understanding is it makes stereo loudspeaker playback better by intelligently processing the 2-channel signal to provide more separation, based on ScienceTM. Not 100% separation like with headphones, but more than what isn't provided by conventional 60 degree equilateral stereo. Like an optimized solution that falls between headphones and speakers.

It appears this was backed by a company in 2020, but then they went radio silent.

Thoughts? A solution without a problem?
 
Not a single reply? Not even a nibble? I thought people here would be interested.
 
Interesting. I have been using Ambiophonics and later Pano Phase Shuffler for a long time. I will test it out tomorrow.
 
Not a single reply? Not even a nibble? I thought people here would be interested.
It appears to be based on the Race paper.
There are already several threads on XTC in ASR, including signal-based channel matrix, IR ping-pong, and universial or personal HRTF-based crosstalk canceling.

There are several threads as follows.


 
So the effect is quite strong and works somewhat. I would be good to have a manual to tell you how to setup the settings. I had the Delays set to 228us with other XTC solutions, but doing it with this plugin it completely doesn't work. There must be a formula to correctly calculate the delay, probably based on speaker distance.

e: Found it here https://docs.google.com/spreadsheet...---------------&gid=1037737478#gid=1037737478

I am not sure if the "suggested attenuation" is the LLC Decay gain? It is hard to a find a setting that will give you the spaciousness only without also changing the sound itself.

1738251227701.png

Here are my settings. I need the low gain to not affect the sound, otherwise it will get brighter. As with most XTC solutions, the sound is released better from the speakers, they disappear more.


Also, there is no .exe for windows, so I have to use the fb2k plugin. It would be good to have a VST plugin, that I could load into EqAPO and apply it systemwide.

e: The .exe is in the source code, but not on the release page. Still I don't like this virtual audio cable loopback solution.

e: I just realized the github repo is 5 years old already, or rather there were no updates since 2021. So probably just another dead project.
 
Last edited:
So the effect is quite strong and works somewhat. I would be good to have a manual to tell you how to setup the settings. I had the Delays set to 228us with other XTC solutions, but doing it with this plugin it completely doesn't work. There must be a formula to correctly calculate the delay, probably based on speaker distance.

e: Found it here https://docs.google.com/spreadsheet...---------------&gid=1037737478#gid=1037737478

I am not sure if the "suggested attenuation" is the LLC Decay gain? It is hard to a find a setting that will give you the spaciousness only without also changing the sound itself.

View attachment 424791
Here are my settings. I need the low gain to not affect the sound, otherwise it will get brighter. As with most XTC solutions, the sound is released better from the speakers, they disappear more.


Also, there is no .exe for windows, so I have to use the fb2k plugin. It would be good to have a VST plugin, that I could load into EqAPO and apply it systemwide.

e: The .exe is in the source code, but not on the release page. Still I don't like this virtual audio cable loopback solution.

e: I just realized the github repo is 5 years old already, or rather there were no updates since 2021. So probably just another dead project.
It will not be different from the Race method you originally used. Nevertheless, thank you for testing.
 
LCC Calculator. I set these parameters in foobar2000. I like it.
 

Attachments

  • lcc.jpg
    lcc.jpg
    43.3 KB · Views: 102
When you add the LCC DSP on the DSP Preferences page, double-click on the LCC row to open the component's settings.

I wish there was a way to apply this to all sources into my home theater stereo DAC. :( Like Blu-ray players, game consoles and such.
 
When you add the LCC DSP on the DSP Preferences page, double-click on the LCC row to open the component's settings.

I wish there was a way to apply this to all sources into my home theatre stereo DAC. :( Like Blu-ray players, game consoles and such.
Thanks very much! Trying this on my temporary system after moving house, but I like what I'm hearing. Had to ignore the spreadsheet calculation as it did not work at all for me.

Indeed, I am looking at how to get this working in the future with all my media as you are. On Najda dsp preamp currently, though if Minidsp had this covered/updated I could move to their preamp.

This may be interesting - have not gone through it yet myself.
https://ambiophonics.wordpress.com/2023/08/17/guide-to-ambiophonics-home-theater/
 
I have no idea what Im doing but like it :)
Untitled.jpg

The VU meter got third graph (FC) !
 
Last edited:
See, that has too many settings and knobs. I like that LCC seems to work enough for me out of the box without even moving my speakers close together. I don't want to tinker with this endlessly. I want it to just work.
 
What is missing from the LCC's implementation seems to be any kind of filtering. The algorithm seems to be on the web, and it's just feeding decaying copies of the sound between the channels.

Now, I worked with this myself for a bit just over this weekend. Description of the algorithm I came up with is here:

for (size_t n = 0U; n < left_in.size(); n ++) {
auto ao = left_in[n] - decay_gain * b.get_sample();
auto bo = right_in[n] - decay_gain * a.get_sample();
left_out[n] = ao;
right_out[n] = bo;
a.put_sample(ao);
b.put_sample(bo);
}
For those who can't read C++ at all (and it isn't my forte, either), word description follows. You read input audio from left_in and right_in, and write audio to left_out, right_out, using the subscription [n] operator that writes to memory slot for the n'th sample. In actual processing, you ask for left channel input, and subtract the processing unit b (right)'s current sample with a decay gain factor (< 1, to make it quieter). You then do the same with right channel but this time use processing unit a (left). After writing the produced audio, the processing unit a receives the produced audio output sample for left channel, and unit b receives the output sample for the right channel. This achieves the expected infinite recursion where decaying copies of past audio loop across the channels, until they decay to nothing, and they invert during each pass also.

But what is the processing unit doing? Well, get_sample reads a sample from a delay line. If delay line is 15 samples long, the sample returned now was put in 15 samples ago.

float get_sample() {
return data[data_index];
}

My put_sample performs audio filtering for each copy and stores the sample in the end:

void put_sample(float sample) {
sample = f1.process(sample);
sample = f2.process(sample);
sample = f3.process(sample);
sample = f4.process(sample);
sample = f5.process(sample);
data[data_index] = sample;
data_index = (data_index + 1) % data.size();
}

f1-f5 variables are all instances of generic 2nd order biquad filters. These are from the classic audiodsp cookbook.

This is the configuration I have ended up with. It optimizes the response between the HRTF differences for a KEMAR dummy head at 30 degree ipsilateral and contralateral angles.

f1.set_high_pass(300, rate, 0.710); /* frequency, sampling rate, quality */
f2.set_peaking_band(1042, rate, -7.4, 1.798); /* frequency, sampling rate, gain, quality */
f3.set_peaking_band(2221, rate, -6.2, 3.140);
f4.set_low_pass(3000, rate, 1.0); /* same arguments as high pass */
f5.set_peaking_band(3702, rate, -5.4, 3.108);
The delay line should be 313 us long if you work with equilateral triangle, which is what this is designed for because the HRTF data is also for 30 degree angles to left and right. At 48000 Hz sampling rate, 15 samples long delay achieves an almost bang-on match 312.5 us, so that will be the length of delay line in many cases.

1748116443461.png


I'm reasoning that the red trace is the sensitivity of the ear to the contralateral sound and generally what is left of the sound that made it to other side of the head. The green curve is the ear's sensitivity to sound from the same side. To cancel this sound, I need to produce the filter shape in yellow and apply it, so that it would match with the tonality of the sound hitting the ear as precisely as possible. In reality, this is barely anything more than a bandpass made of a highpass filter at 300 Hz and lowpass at 3000 Hz.

In this implementation, even the decay gain (-2 dB) is a fixed value because it's part of this general filter fit. If you change the overall level of the filter shape, you mess up the cancellation, in theory. The only real user-tunable parameter is the delay, but even that should also always be 313 us if you follow recommended equilateral layout.

Edit addendum: I read all kinds of wild claims on the Internet about what the inter-ear distance is, from 17 cm to 23 cm. I measured mine with tape measure to be about 21 cm apart, but I saw previously 21.5 cm being recommended as this value, so I went with that one. I also see all sorts of really funky claims about what the time of flight difference is between e.g. right ear and the left speaker, and the right ear and the right speaker. I've even seen claims that go pretty low, like < 300 us, which I don't think can be correct.

I performed some geometry to arrive at 313 us, because I need to know when to play the sound that comes from the nearer speaker to account for the travel time difference from the speaker farther away from that ear. For this effect, what I needed to know is not related to what the interaural time delay is for some 30 degree incident angle. It can be something like 200 us for all I care. What I actually need to know is when I send the inverted copy of the audio out from the speaker that is nearer that ear. I think this is different from interaural time delay, but the geometric result should be robust (or at least I can't find any fault in how I reasoned it).
 
Last edited:
I also realized that the effect is not complete without inclusion of an allpass filter that corrects the phase error between direct and feedback sound. An effect like this really calls for a linear phase equalizer, but I am not too thrilled about making one if it involves computing a long FIR impulse response and running the response through that, or introducing large time delay and running minimum phase filters at half strength in both directions, or whatever. I figured I'll do the simple thing and allow the phase to warp 360 degrees across the feedback path, but then also process the direct sound with an allpass filter that minimizes the phase error to something like 10-20 degrees within the overlap range of the effect.

I think I'm finally happy with how this sounds like. The effect does remove the sense that the sound is coming from an area between the speakers and doesn't appear to exhibit any obvious phasing or sound artifacts. In fact, it can be left on permanently and all music seems to work with it, including stuff already spatialized with something like QSound. This is somewhat a surprise. I don't think doing any additional processing on top of QSound is a good idea, but at least it doesn't obviously break the sound. The spatial effects tend to become ultra-pronounced, though.
 
My last post -- sorry for hijacking the thread nearly entirely. Those that have Linux and want to play with the effect, can build my version of EasyEffects. https://github.com/alankila/easyeffects/

I named the plugin "Crosstalk Canceller", and it is right next to the Crossfeed that does something similarly useful for headphones.
 
Back
Top Bottom