Skip to content

synthio.Note panning is reversed #11188

Description

@FoamyGuy

CircuitPython version and board name

Adafruit CircuitPython 10.3.0-alpha.3-25-g50a1195c55-dirty on 2026-08-11; Adafruit Metro RP2350 with rp2350b

Code/REPL

# boot.py
import usb_audio

usb_audio.enable(
    sample_rate=22050, channel_count=2, microphone=True
)

# code.py

import time, usb_audio, synthio
import audiomixer

mixer = audiomixer.Mixer(voice_count=2, sample_rate=22050, channel_count=2,
                         bits_per_sample=16)
usb_audio.usb_microphone.play(mixer, loop=True)

mixer.voice[0].level = 0.5
mixer.voice[1].level = 0.5

synth1 = synthio.Synthesizer(sample_rate=22050, channel_count=2)
mixer.voice[0].play(synth1)


synth2 = synthio.Synthesizer(sample_rate=22050, channel_count=2)
mixer.voice[1].play(synth2)

scale = [60, 62, 64, 65, 67, 69, 71, 72]
while True:
    for up, down in zip(scale, reversed(scale)):
        print(f"up: {up}, down: {down}")
        left  = synthio.Note(synthio.midi_to_hz(up), panning=-1)
        right = synthio.Note(synthio.midi_to_hz(down), panning=1)
        synth1.press(left)
        # synth2.press(right)

        time.sleep(0.33)

        synth1.release(left)
        # synth2.release(right)

        time.sleep(0.1)
    time.sleep(1)

Behavior

In the code above an ascending scale should be playing on the left channel according the panning docs: https://docs.circuitpython.org/en/latest/shared-bindings/synthio/index.html#synthio.Note.panning but when recording this in audacity it is actually playing audio on the right channel only.

synthio.Note panning behaves oppositely from audiomixer.MixerVoice panning

Their code shows opposite functionality with regards to panning value.

synthio.Note:

if (panning >= 0) {
left_panning_scaled = 32768;
right_panning_scaled = 32767 - panning;
} else {
right_panning_scaled = 32768;
left_panning_scaled = 32767 + panning;
}

audiomixer.MixerVoice:

uint16_t left_panning_scaled = 32768, right_panning_scaled = 32768;
if (MP_LIKELY(self->base.channel_count == 2)) {
if (panning >= 0) {
left_panning_scaled = 32767 - panning;
} else {
right_panning_scaled = 32767 + panning;
}
}

Description

No response

Additional information

LLM points to AudioMixer being correct, and synthio.Note being wrong.

I discovered this while testing #11102, but the issue is not related to the USB stereo functionality, it is a preexisting inconsistency between synthio and audiomixer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions