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

PanAzExample

Python Code

from mmm_src.MMMAudio import MMMAudio

# instantiate and load the graph

# PanAz is not quite right as of yet
mmm_audio = MMMAudio(128, graph_name="PanAzExample", package_name="examples", num_output_channels=8)
mmm_audio.start_audio() 

mmm_audio.send_int("num_speakers", 2 ) # set the number of speakers to between 2 and 8

mmm_audio.send_int("num_speakers", 8 ) # set the number of speakers to between 2 and 8
mmm_audio.send_float("width", 1.0 ) # set the width to 1.0 (one speaker at a time)
mmm_audio.send_float("width", 3.0 ) # set the width to 3.0 (extra wide stereo width)

from random import random
mmm_audio.send_float("freq", random() * 500 + 100 ) # set the frequency to a random value

Mojo Code

from mmm_src.MMMWorld import MMMWorld
from mmm_utils.Messenger import Messenger
from mmm_utils.functions import *
from mmm_src.MMMTraits import *

from mmm_dsp.Osc import Phasor, Osc
from mmm_dsp.Pan import pan_az

struct PanAz_Synth(Representable, Movable, Copyable):
    var world: UnsafePointer[MMMWorld]  
    var osc: Osc
    var freq: Float64

    var pan_osc: Phasor
    var num_speakers: Int64
    var width: Float64
    var messenger: Messenger

    fn __init__(out self, world: UnsafePointer[MMMWorld]):
        self.world = world
        self.osc = Osc(self.world)
        self.freq = 440.0

        self.pan_osc = Phasor(self.world)
        self.num_speakers = 7  # default to 7 speakers
        self.width = 2.0
        self.messenger = Messenger(self.world)

    fn __repr__(self) -> String:
        return String("Default")

    fn next(mut self) -> SIMD[DType.float64, 8]:
        self.messenger.update(self.freq, "freq")
        self.messenger.update(self.num_speakers, "num_speakers")
        self.messenger.update(self.width, "width")

        # PanAz needs to be given a SIMD size that is a power of 2, in this case [8], but the speaker size can be anything smaller than that
        panned = pan_az[8](self.osc.next(self.freq, osc_type=2), self.pan_osc.next(0.1), self.num_speakers, self.width) * 0.1

        if self.num_speakers == 2:
            return SIMD[DType.float64, 8](panned[0], panned[1], 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
        else:
            return SIMD[DType.float64, 8](panned[0], panned[2], panned[1], 0.0, panned[6], panned[3], panned[5], panned[4])


# there can only be one graph in an MMMAudio instance
# a graph can have as many synths as you want
struct PanAzExample(Representable, Movable, Copyable):
    var world: UnsafePointer[MMMWorld]
    var synth: PanAz_Synth

    fn __init__(out self, world: UnsafePointer[MMMWorld]):
        self.world = world
        self.synth = PanAz_Synth(self.world)

    fn __repr__(self) -> String:
        return String("PanAzExample")

    fn next(mut self) -> SIMD[DType.float64, 8]:

        sample = self.synth.next()  # Get the next sample from the synth

        # the output will pan to the number of channels available 
        # if there are fewer than 5 channels, only those channels will be output
        return sample  # Return the combined output samples