Panning input channels

Apr 4, 2011 at 12:59 PM

Hi Mark,

It seems that the panning rules are hard coded in the WaveChannel32.AdjustVolume:

 

  // implement better panning laws. 
  float leftVolume = (pan <= 0) ? volume : (volume * (1 - pan) / 2.0f);
  float rightVolume = (pan >= 0) ? volume : (volume * (pan + 1) / 2.0f);

 

I don't understand why the channel volume gets maximum value if it is below or above zero? I think it should be a linear mix.
For example: pan of -0.5 would make left volume always equal to volume regardless of the pan value. Only the right volume would change in that case. Seems wrong.

Could you please extract this logic out into a virtual method that can be overridden?

Thanks,
Yuval Naveh
Author of Practice# - http://code.google.com/p/practicesharp/

 

Coordinator
Apr 4, 2011 at 1:05 PM

Its a tough one. The issue is if you say it is a liear mix then if you pan centrally you half the maximum amplitude on each channel. I've not investigated the algorithms behind pan laws used in pro consoles, but I suppose it would be good if WaveChannel32's pan law function was virtual so you could override it

Apr 4, 2011 at 2:28 PM
Edited Apr 4, 2011 at 2:28 PM

Hi Mark,

Linear mix is indeed not the only way to do it.

It seems that the problem with panning is that energy levels of sound are made of sum of squares of the amplitudes for each channels, not the plain sum of amplitudes.

I found these article that explain the problems and solutions:

http://booki.flossmanuals.net/csound/_v/1.0/b-panning-and-spatialization/

http://www.rosspenniman.com/Pro_Files/Stereo_Position_Simulator.pdf (See diagram on page 3: Square Root Gain Curves)

 

Making the method virtual is a good solution for sure, but you might want to provide a better default panning logic based on this information.

Thanks,

Yuval

Coordinator
Apr 4, 2011 at 3:04 PM

yes, the slightly odd current implementation is based on requirements for a commercial telephony application that was one of the first applications to use NAudio

Mark

Apr 4, 2011 at 5:44 PM
Edited Apr 4, 2011 at 5:44 PM

If I may suggest a solution:

I would recommend using the Strategy Design Pattern for the panning algorithms, by providing a base interface (or class).

This way you can keep the existing one and name it for example TelephonyPanStrategy, and also add other panning strategy classes as: LinearMixPanStrategy, SquareRootPanStrategy, SinPanStrategy etc.

Then the user of WaveChannel32 can pick the the desired panning strategy using a property (PanStrategy). The built in strategies can be created as static instances, I think the default should be SquareRoot (just not the current telephony one).

 

Yuval

Apr 5, 2011 at 12:50 AM

OK, so I started playing around and implementing it using the design I purposed. It is really clean and simple.

In a few days, I'll send you the changes, just want to test properly first.

Let me know if this path is OK, don't want to waste our time on this, but I would like to help make NAudio have proper panning.

Yuval

Coordinator
Apr 6, 2011 at 3:14 PM

Hi Yuval, I'd be interested to see your changes and hopefully they can be easily incorporated into NAudio. So long as we choose a good default panning law it should be fine.

MMark

Apr 6, 2011 at 3:38 PM

Sure, great.

The beauty of this design is that the default can be chosen by the user in runtime. In fact I added a Telephony panning (your current panning) as one strategy, since existing functionality must be kept.

I already have a test application that does panning from side to side with all three strategies (Telephony, Square Root and Sinus). Linear panning was not added since it is faulty.. but I that would also be very easy to add. Maybe I'll add it just to show why it should not be used..

In a few days I'll finish it and send the source codes to your private email. I think it would be a piece of cake for you to incorporate these changes into NAudio.

Yuval

Coordinator
Apr 6, 2011 at 4:16 PM

Cool. the issue that is hard to decide is what the gain for a centrally panned signal is. If you have 0dB in the centre, do you have +3dB or more when panned to one side to get constant volume and risk clipping, or do you make it -3dB in the centre, meaning that when you are just panning a single mono input centrally, you lose a bit of volume?

May 12, 2011 at 11:18 PM

Hi Mark,
Sorry for the very long delay - spring break, kids, work..you get it.. ;)

I uploaded a demo of how to pan NAudio input channels:
http://code.google.com/p/practicesharp/downloads/detail?name=NAudioPan.zip


The demo shows three Panning Strategies (Classes):
1. TelephonyPanStrategy - The default panning strategy found in 'Stock' NAudio
2. SinPanStrategy - A panning that using a sinus function
3. SquareRootPanStrategy - A panning that uses a square root function


There are two NAudio files that are needed: (Please look in zip under sub folder: NAudioChangedFiles)
1. NAudio\Wave\WaveStreams\PanStrategies.cs - NEW file, contains the the IPanStrategy interface and three implementations for panning strategies
2. NAudio\Wave\WaveStreams\WaveChannel32.cs - Modified file. I took out the hard coded telephony logic that existed in the original file, and refactored it.
Also the code supports dynamic choice of a panning strategy through a method:  

SetPanStrategy()

Please note that I've used NAudio 1.3.15, but I don't think it would make a big difference for 1.4.X

Please let me know if you have any questions - I would prefer if this feature gets incorporated into NAudio so that I don't have my own private branch.
Thanks,Yuval

 


Coordinator
May 13, 2011 at 8:08 PM

thanks for this. The pan strategies look great. I may incorporate them into WaveChannel32 in a slightly different way. I may also attempt to upgrade the pan laws to allow setting the centre volume. Will get it in for NAudio 1.5

Mark

May 16, 2011 at 12:22 PM

No problem, glad to assist you.

Any rough idea when NAudio 1.5 should be out? No pressure, just so that I plan.

Thanks,

Yuval

Coordinator
May 16, 2011 at 12:39 PM

I'm not in a hurry to get it out, but there's quite a bit going on so it might be in the next few months. There will be a new way to construct 32 bit floating point mixing engines to make writing effects etc much easier. WaveChannel32 will therefore become a less important part of the framework (but there will be an equivalent replacement).

Mark

Coordinator
May 16, 2011 at 10:29 PM

hi Yuval,

have a look here for a sneak peak at how panning will be done with NAudio 1.5. Classes like WaveChannel32 (which will be a less important part of the library) will be composed of a chain of several smaller sample providers such as the panning sample provider.

Mark

May 16, 2011 at 10:33 PM

Hi Mark,

That is very cool! I like it!

I'm just a little worried over re-writing the whole integration layer above NAudio. Let's hope it would be easy and in particular stable.

 

Cheers

Yuval

Coordinator
May 16, 2011 at 10:40 PM

Well none of the existing classes will go away or change very much. You don't need to use the new sample providers directly if you don't want to. I might completely re-implement WaveChannel32 using the new stuff, but leaving its public interface pretty much the same.

Mark

May 16, 2011 at 11:04 PM

Yes I agree, the public interface should remain intact for backwards compatibility.

It would make the transition much easier, otherwise some of the users might not upgrade for a long time if at all - there is a risk of branching into two NAudio repositories ('old' and 'new' styles).

1.5 looks more like 2.0 - changes are quite major.

Yuval