
Audio from Scratch with Go: Stereo Panning - Insanity
https://dylanmeeus.github.io/posts/audio-from-scratch-pt4/
======
akx
Wonder if this should take into account pan laws:

* [https://en.wikipedia.org/wiki/Pan_law](https://en.wikipedia.org/wiki/Pan_law)

* [https://www.image-line.com/support/flstudio_online_manual/ht...](https://www.image-line.com/support/flstudio_online_manual/html/songsettings_settings.htm) (search for "panning law")

~~~
pierrec
I believe this minimal implementation actually over-compensates for pan law
because it has a -6dB center. In other words, if you ask this tool for zero
panning, it will actually divide the amplitude by 2 (probably not what most
people would expect!) In DAWs, -3dB or 0dB center is more common. In a tool
like this I would suggest a 0dB center by default, so that zero panning does
not change the amplitude. This would be what you second link calls triangular
pan law.

------
BookPage
Having had to do some mass audio stuff on datasets recently I discovered SoX -
a self proclaimed "swiss army knife" for sound processing. Delighted to find
multiple bindings in Go, I eventually decided to just do it in python as there
was a very solid library there and it was just simpler for my use case.

~~~
tekstar
The command line application is also quite useful. Usually you wouldn't need
to go into a programming language at all to wield its power

~~~
BookPage
Yeah you're right it is. I was strongly considering just writing a bash script
but I had a bunch of probabilistic stuff going on for using effects, so stuck
with python.

~~~
tekstar
I've had good luck writing ruby scripts that just shell out to Sox because I
didn't feel like learning the API

------
mgraczyk
This is a fun tutorial for processing audio in Go, but generally panning will
sound bad if you only adjust the amplitude/level.

The two important missing pieces are phase delay and frequency-specific
attenuation (the "head" model). Audio coming from the left side of your head
reaches your left ear first, then your right ear later. Also, your head blocks
certain frequencies more than others. Both of these effects are super
noticeable and necessary to make panning sound "3D".

Adding these things to the Go code would actually be fairly straightforward,
you just need to add a filter to `applyPan`. The filter would only need around
12 taps to sound good.

Here's a javascript tutorial which includes both of these additional features:

[https://developer.mozilla.org/en-
US/docs/Web/API/Web_Audio_A...](https://developer.mozilla.org/en-
US/docs/Web/API/Web_Audio_API/Web_audio_spatialization_basics)

~~~
qmmmur
You say this like it's bog standard but adding HRTF and compensation for
speaker distance are not part of a standard panning algorithm. This is more
likely to exist in another module, such as for ambisonics or correction.

~~~
TheOtherHobbes
HRTF is often used in game audio and AR [2], but never [1] as a mix effect in
commercial DAWs.

HRTF is a blunt instrument anyway. It's supposed to model _your_ head and not
just a standard imaginary generic head, and that's impossible without sticking
a microphone inside each ear.

It's also a headphone-only effect. As soon as you play the sound through
speakers you get room reflections and all kinds of other artefacts which wash
out the spatial detail.

[1] Almost never. There are HRTF plugins, but they're hardly ever used in
music mixing.

[2] Apple has some HRTF patents for recording audio on multiple channels - not
just two - using HRTFs to capture apparent depth.

~~~
qmmmur
Sorry this is just wrong. What is your basis for saying that HRTF are never
used in commerical DAWs? Have you read anything by Bob Katz or Rashad Becker?
Or perhaps you're not aware of the several options people reach for to perform
multichannel mixing using ambisonics:

[https://plugins.iem.at/](https://plugins.iem.at/)

[https://www.ssa-plugins.com/](https://www.ssa-plugins.com/)

[http://www.ambisonictoolkit.net/documentation/reaper/](http://www.ambisonictoolkit.net/documentation/reaper/)

------
sramsay
Wow, this is really cool. I wonder how far the author plans to go with this?
DSP gets pretty complex pretty quickly . . .

~~~
Insanity
Her, author here! :)

Glad you liked it! I don't have concrete plans actually, just doing this for
fun so we'll see how far I get :)

~~~
nkozyra
Might have been an interesting point to stream this data (basic sine) to an
audio output instead of file. That's more immediately hands on.

(Sorry, this refers to the first entry in your audio/go series)

~~~
slx26
that can easily get pretty tricky if you don't want to depend a lot on
libraries, which the last time I checked weren't great for golang in this
area. I have worked with ALSA (advanced linux sound architecture) a bit,
implementing basic midi input from a keyboard + sound generators + plugins
with go interfaces and pkg/plugin + stream to audio output... and it's a mess
of devices, buffers and formats. and that's only for one OS. and if you start
doing anything non-trivial, making the programs work well in real-time is not
for the faint of heart.

if there was a single format supported everywhere, minimum buffer sizes and a
common API for all OSes, it would be a whole another, much more pleasant story

------
PaulDavisThe1st
[ Edited/Deleted reply because I missed the fact that this code distributes a
single mono signal across 2 outputs. The terminology for this stuff is never
totally clear: some people would call this a mono panner, some would call it a
stereo panner, some call it a 1in/2out panner ]

~~~
Insanity
Hey there, yep I'm actually aware of what you're saying. I actually wrote this
at the bottom of the post:

"There is actually a flaw with this panning function that we are using.
However it is not apparent to us yet because we can only set a pan for an
entire audio source"

I'm working from something simple up to something more complex, but tackling
it in small parts. Next I'm writing about applying breakpoints where the pan
can be set throughout the track and you can notice the power dip - and then
we'll work on fixing that. ;-)

~~~
PaulDavisThe1st
For some reason, I just realized that despite your talk about 2 channel WAV
files, this code is actually a 1 input to 2 output panner.

So I take back what I said about it being a balance control entirely. Sorry
for that.

