Skip to content

For more information about the examples, such as how the Python and Mojo files interact with each other, see the Examples Overview

VectorBasePanning

An example of Vector Base Amplitude Panning. Inclues a 4 channel speaker array example where speakers are placed at azimuths of -55, 55, -110, and 110 degrees. Also includes a 7-channel surround sound example.

The position of the audio source is controlled by the mouse. The corners of the screen are positioned directly on top of the speakers.

Python Code

from mmm_python import *
from math import pi

# instantiate and load the graph, change num_output_channels to 7 and uncomment the 7-channel code in the mojo file for a 7-channel surround sound example.
mmm_audio = MMMAudio(128, num_output_channels=8, graph_name="VectorBasePanning", package_name="examples")

mmm_audio.start_audio()

mmm_audio.send_float("az", 0.0 * 2 * pi)
mmm_audio.send_float("az", 0.125 * 2 * pi)
mmm_audio.send_float("az", 0.25 * 2 * pi)
mmm_audio.send_float("az", 0.375 * 2 * pi)
mmm_audio.send_float("az", 0.5 * 2 * pi)
mmm_audio.send_float("az", 0.625 * 2 * pi)
mmm_audio.send_float("az", 0.75 * 2 * pi)
mmm_audio.send_float("az", 0.875 * 2 * pi)


#Enable/disable mouse
mmm_audio.send_bool("mouse", True)
mmm_audio.send_bool("mouse", False)

# for Wayland use the fake mouse
MMMAudio.fake_mouse()

mmm_audio.stop_audio()

mmm_audio.plot(48000)

Mojo Code

from mmm_audio import *

# THE SYNTH


struct VectorBasePanning(Movable, Copyable):
    var world: World  
    var dust: Dust[1] 
    var messenger: Messenger
    var az: Float64
    var filt: Reson[1]
    var wsl: Int
    var pos: List[Float64]
    var mouse: Bool
    var vbap_4: VBAP2D
    var vbap_7: VBAP2D
    def __init__(out self, world: World):
        self.world = world
        self.dust = Dust[1](world)
        self.filt = Reson[1](world)
        self.messenger = Messenger(self.world)
        self.az = 0.0
        self.wsl = 0
        self.pos = [0.0, -1.0]
        self.mouse = False
        self.vbap_4 = VBAP2D([
            deg_to_rad(-55),
            deg_to_rad(55),
            deg_to_rad(-110),
            deg_to_rad(110)
            ])

        #A Left-Front, Left-Right, Center, Left, Right, Rear-Left, Rear-Right array where Center is channel 3
        self.vbap_7 = VBAP2D([
            deg_to_rad(-30),
            deg_to_rad(30),
            0,
            deg_to_rad(-90),
            deg_to_rad(90),
            deg_to_rad(-150),
            deg_to_rad(150)
        ])

    def next(mut self) -> MFloat[8]:

        self.messenger.update("az", self.az)
        self.messenger.update("pos", self.pos)
        self.messenger.update("mouse", self.mouse)

        comptime offset = deg_to_rad(90)
        if self.mouse:
            var x = linlin(self.world[].mouse_x(), 0.0, 1.0, -1.0, 1.0)
            var y = linlin(self.world[].mouse_y(), 0.0, 1.0, 1.0, -1.0)
            self.az = atan2(y, x) + offset

        var sig = self.dust.next(10, 40) * 0.5
        sig = self.filt.bpf(sig, 1200, 10.0, 1.0)

        # 4 speaker setup
        # var pan = self.vbap_4.next[4](sig, self.az)
        # var out = MFloat[max_simd](pan[0], pan[1], pan[2], pan[3], 0.0, 0.0, 0.0, 0.0)

        # 7 speaker setup, note that the simd_out_size must be a power of two and larger than the speaker array size.
        var out = self.vbap_7.next[8](sig, self.az)

        # output for a 7.1 surround sound setup
        return MFloat[8](out[0], out[1], out[2], 0.0,out[3], out[4], out[5], out[6]) * 0.5
        # send all the outs directly
        # return out * 0.5