For more information about the examples, such as how the Python and Mojo files interact with each other, see the Examples Overview
FreeverbExample¶
Python Code¶
import sys
from pathlib import Path
# This example is able to run by pressing the "play" button in VSCode
# that executes the whole file.
# In order to do this, it needs to add the parent directory to the path
# (the next line here) so that it can find the mmm_src and mmm_utils packages.
# If you want to run it line by line in a REPL, skip this line!
sys.path.insert(0, str(Path(__file__).parent.parent))
from mmm_src.MMMAudio import MMMAudio
from mmm_utils.functions import *
from mmm_utils.GUI import Handle, ControlSpec
from mmm_src.MMMAudio import MMMAudio
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QCheckBox
mmm_audio = MMMAudio(128, graph_name="FreeverbExample", package_name="examples")
mmm_audio.start_audio() # start the audio thread - or restart it where it left off
app = QApplication([])
# Create the main window
window = QWidget()
window.setWindowTitle("Freeverb Controller")
window.resize(300, 100)
# stop audio when window is closed
window.closeEvent = lambda event: (mmm_audio.stop_audio(), event.accept())
# Create layout
layout = QVBoxLayout()
# Create a slider
roomsize_slider = Handle("room size", ControlSpec(0, 1.0, 4), 0.5, callback=lambda v: mmm_audio.send_float("room_size", v), run_callback_on_init=True)
layout.addWidget(roomsize_slider)
lpf = Handle("lpf",ControlSpec(100.0, 20000.0, 0.5), 2000, callback=lambda v: mmm_audio.send_float("lpf_comb", v), run_callback_on_init=True)
layout.addWidget(lpf)
added_space = Handle("added space",ControlSpec(0.2, 1.0), 0.0, callback=lambda v: mmm_audio.send_float("added_space", v), run_callback_on_init=True)
layout.addWidget(added_space)
mix_slider = Handle("mix",ControlSpec(0.1, 1.0, 0.5), 0.2, callback=lambda v: mmm_audio.send_float("mix", v), run_callback_on_init=True)
layout.addWidget(mix_slider)
# Set the layout for the main window
window.setLayout(layout)
# Show the window
window.show()
# Start the application's event loop
app.exec()
Mojo Code¶
from mmm_src.MMMWorld import MMMWorld
from mmm_utils.Messenger import Messenger
from mmm_src.MMMTraits import *
from mmm_utils.functions import *
from mmm_dsp.Delays import LP_Comb
from mmm_dsp.Buffer import *
from mmm_dsp.PlayBuf import *
from mmm_dsp.Filters import VAMoogLadder
from mmm_dsp.Reverb import Freeverb
struct FreeverbSynth(Copyable, Movable):
var world: UnsafePointer[MMMWorld]
var buffer: Buffer
var num_chans: Int64
var play_buf: PlayBuf
var freeverb: Freeverb[2]
var m: Messenger
var room_size: Float64
var lpf_comb: Float64
var added_space: Float64
var mix: Float64
fn __init__(out self, world: UnsafePointer[MMMWorld]):
self.world = world
# load the audio buffer
self.buffer = Buffer("resources/Shiverer.wav")
self.num_chans = self.buffer.num_chans
# without printing this, the compiler wants to free the buffer for some reason
print("Loaded buffer with", self.buffer.num_chans, "channels and", self.buffer.num_frames, "frames.")
self.play_buf = PlayBuf(self.world)
self.freeverb = Freeverb[2](self.world)
self.room_size = 0.9
self.lpf_comb = 1000.0
self.added_space = 0.5
self.mix = 0.2
self.m = Messenger(self.world)
@always_inline
fn next(mut self) -> SIMD[DType.float64, 2]:
self.m.update(self.room_size,"room_size")
self.m.update(self.lpf_comb,"lpf_comb")
self.m.update(self.added_space,"added_space")
self.m.update(self.mix,"mix")
added_space_simd = SIMD[DType.float64, 2](self.added_space, self.added_space * 0.99)
out = self.play_buf.next[N=2](self.buffer, 0, 1.0, True)
out = self.freeverb.next(out, self.room_size, self.lpf_comb, added_space_simd) * 0.2 * self.mix + out * (1.0 - self.mix)
return out
struct FreeverbExample(Representable, Movable, Copyable):
var world: UnsafePointer[MMMWorld]
var freeverb_synth: FreeverbSynth # Instance of the FreeverbSynth
fn __init__(out self, world: UnsafePointer[MMMWorld]):
self.world = world
self.freeverb_synth = FreeverbSynth(world)
fn __repr__(self) -> String:
return String("Freeverb_Graph")
fn next(mut self) -> SIMD[DType.float64, 2]:
#return SIMD[DType.float64, 2](0.0)
return self.freeverb_synth.next() # Return the combined output sample