bmc0 / dsp

An audio processing program with an interactive mode.
ISC License
219 stars 31 forks source link

FR - Stereo widener, Virtual bass #37

Open arjunmenon opened 5 years ago

arjunmenon commented 5 years ago

Hey I have been wanting to post this for quite some time. I was investigating on some effects, for instance, stereo widener, psychoacoustic bass boost

These effects are really helpful when setting up a system.

I wanted to see if I could study these and I have been teaching myself the subject, but my knowledge on C and by extensions DSP is at present limited. I thought I could start a discussion here with you. I have linked existing implementations I could find on Github.

How do you propose we can work on this. This would be really interesting.

bmc0 commented 5 years ago

Both appear to be quite easy to implement. You can actually make the stereo widener with existing effects:

# extract mid/side channels
mult 0.5 remix 0,1 0 1 mult 2 -1 remix 0 1,2
# apply gain (X is mid level and Y is side level)
gain 0 X
gain 1 Y
# switch back to standard stereo
remix 0 1 1 mult 2 -1 remix 0,1 0,2

Decreasing the mid gain will widen the stereo image and decreasing the side gain will make it narrower.

Anyway, I can probably write a "virtual bass" effect based on the code you linked pretty quickly.

arjunmenon commented 5 years ago

Decreasing the mid gain will widen the stereo image and decreasing the side gain will make it narrower.

Okay so only one of them should be adjusted at a time?

Anyway, I can probably write a "virtual bass" effect based on the code you linked pretty quickly.

I found this MATLAB description very accurate to what I have known about virtual bass. The repo I linked was the only thing I could find as a code., though all it does is add distortion, which isn't entirely accurate.

bmc0 commented 5 years ago

Okay so only one of them should be adjusted at a time?

Technically both should be changed in order to keep the overall level the same, but the exact amount depends on how correlated the left and right channels are. The code you linked uses a "weight" of 0.2 for the mid channel and 1.0 for the side, so the side level changes more than the mid level.

all it does is add distortion, which isn't entirely accurate.

I've been looking into different techniques a bit, and there are quite a few different algorithms out there. The simplest ones use full-wave rectifiers, full-wave integrators, or nonlinear devices (which add various kinds of distortion, depending on the function used). I also found this paper (PDF warning), which proposes a modified envelope detector for generating the harmonics. There are more complex approaches such as those using phase vocoders, as well as hybrid approaches.

Using a full-wave integrator or modified envelope detector would probably be the easiest way to get acceptable performance, but it seems that there are better (albeit much more complex) algorithms out there.

arjunmenon commented 5 years ago

Hey I had bookmarked this analog version which describes the physics of what is going on.

Not certain if this is helpful, but this git repo separates audio into its harmonics. I tried filtering out parts of low ends manually from the generated samples in Audacity to replicate the psychouacoustic boost. It was nice.

Also, I found a LADSPA plugin. I presume this uses an IIR filter. But the PDF you linked suggested to use FIR filters.

ariendj commented 5 years ago

In the book 'Small signal audio design' by Douglas self I read about another way of increasing stereo width: On page 254 a circuit is mentioned that increases percieved stereo width by mixing a little bit of the phase inverted right channel into the left channel and vice versa. This results in some slight left-right crosstalk cancellation. This is done instead of just splitting mid and side signals and increasing the volume on the side channel and mixing the resulting signals back into left and right channel. My question is: can I achieve this 'slight crosstalk cancelling' stereo widening effect with dsp? I imagine it should be doable but so far I could not figure out how to invert a channels phase in the config of dsp.

This quote is from the book, it probably explains what I want to achieve in a better way:

By cross-feeding anti-phase signals, the width of a stereo image can be increased. A famous circuit published by Mullard back in 1972 [4] gave continuous variation between mono, normal, and enhanced-width stereo. It was stated that anti-phase cross-feed of greater than 24% should not be used as it would cause the sound image to come apart into two halves.

bmc0 commented 5 years ago

You can invert polarity with mult by giving a negative value (e.g. mult -1). For stereo, the effect you describe can be implemented like this:

remix 0 1 0 1 :2,3 mult -0.1 : remix 0,3 1,2

The anti-phase component in this example is 10% (not sure what value might be optimal).

ariendj commented 5 years ago

Thank you so much, that worked right away :) I tried it out yesterday and I immediately liked the effect: The stereo image does indeed become more wide, it extends way beyond the speakers on both sides. There is a drawback however. As the bass region is usually close to being a mono signal the crossfeed subtracts from the bass signal as a whole. Right now I am testing the following: I split the signal into the sub 300hz region and the remaining signal above 300. The signal above 300Hz gets the 10% anti-phase signal from the opposite channel added in. I then mix everything back into two channels. remix 0 1 0 1 0 1 :0,1 lowpass 300 0.707 lowpass 300 0.707 :2,3 highpass 300 0.707 highpass 300 0.707 :4,5 highpass 300 0.707 highpass 300 0.707 :4,5 mult -0.1 remix 0,2,5 1,3,4 This is quite ok, the only thing I don't like is that mono signals above 300Hz still get affected by this and sounds that are in the center of the stereo image seem a little dampened, for lack of a better expression.

The next thing I'll play with is mid-side separation. I want to generate a mid-side channel so that I can phase reverse the mid channel and mix it with the regular stereo signal so that I have a 'stereo-without-mid' signal, process that with anti-phase crossfeed and then add the mid signal back to get my 'enhanced stereo' with the mid signal and bass still intact. I think this could also be a cool trick to use on my boombox that has 2 nice coax speakers mounted close together,

arjunmenon commented 5 years ago

Hi @bmc0 were you able to look into psychoacoustic bass boost? Would like to know your ideas.

bmc0 commented 5 years ago

I've played around with it a bit, but I haven't come up with anything worth adding yet. Truth be told, it's not that high on my priority list since I'm unlikely to use the effect myself.

arjunmenon commented 5 years ago

In small setups, boosting the low end is extremely difficult. It creates a lot of distortion. Virtual bass boost helps a lot in that regard, without loading the drivers to their excursion limit. Since, I play around with lot of small units, this was one solution to help with the overall system response.

I am keen to know what can be done otherwise. Generally I have relied on Linkwitz transform, but that itself can push the driver to its excursion limit and moreover only specific type of drivers can handle the transform.

arjunmenon commented 5 years ago

Hey @bmc0 Any updates on this?

arjunmenon commented 4 years ago

Hey, I would really appreciate if there is support for psychoacoustic bass boost in this package. I like your project a lot. I have found this to be a really decent framework to work with DSP. If you are willing, would love to support your work on Github Sponsors. Would love to see this project evolve into an industrial DSP program, available to everyone.

bmc0 commented 4 years ago

I decided to spend a little time on this today. There's a virtual_bass branch now with a very simple psychoacoustic bass enhancement effect. It works similarly to what is described in the article by Jan Meier that you linked above: a polynomial waveshaper and an envelope follower.

Usage is as follows:

virtual_bass cutoff [level]

Where cutoff is the cutoff frequency and level is a level adjustment for the added harmonics (default is 1 and values significantly higher than that probably won't sound good).

The algorithm probably needs some refinement. I don't know what the optimal levels for the individual harmonics might be.

bmc0 commented 4 years ago

Oh, and the effect makes no attempt to avoid clipping, so you'll need to pad the output down a bit.

richardpl commented 4 years ago

The implementation is little strange, the input is split into low and high component, to just be added back again. Also that paper talks about taking input from band-passed signal (extreme low and extreme highs being filtered out) to harmonics generator.

arjunmenon commented 4 years ago

Nice, let me study and play with it.

The algorithm probably needs some refinement. I don't know what the optimal levels for the individual harmonics might be.

There is this MATLAB version which implements something true to what you generally find Waves Audio implementing it, for example. Have actually tried these with TI DSP chip which integrate their tech.