For more information about the examples, such as how the Python and Mojo files interact with each other, see the Examples Overview
BiquadEQ¶
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_python package.
# 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_python.MMMAudio import MMMAudio
from mmm_python.GUI import Handle, ControlSpec
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel
def main():
mmm_audio = MMMAudio(128, graph_name="BiquadEQ", package_name="examples")
mmm_audio.start_audio()
app = QApplication([])
window = QWidget()
window.setWindowTitle("5-Band Biquad EQ")
window.resize(400, 500)
window.closeEvent = lambda event: (mmm_audio.stop_audio(), event.accept())
layout = QVBoxLayout()
# Low Shelf
layout.addWidget(QLabel("<b>Low Shelf</b>"))
ls_freq = Handle("LS Freq", ControlSpec(50, 200, 0.5), 100,
callback=lambda v: mmm_audio.send_float("ls_freq", v), run_callback_on_init=True)
ls_gain = Handle("LS Gain (dB)", ControlSpec(-12, 12), 0,
callback=lambda v: mmm_audio.send_float("ls_gain", v), run_callback_on_init=True)
layout.addWidget(ls_freq)
layout.addWidget(ls_gain)
# Bell 1
layout.addWidget(QLabel("<b>Bell 1</b>"))
b1_freq = Handle("B1 Freq", ControlSpec(200, 500, 0.5), 250,
callback=lambda v: mmm_audio.send_float("b1_freq", v), run_callback_on_init=True)
b1_gain = Handle("B1 Gain (dB)", ControlSpec(-12, 12), 0,
callback=lambda v: mmm_audio.send_float("b1_gain", v), run_callback_on_init=True)
b1_q = Handle("B1 Q", ControlSpec(0.5, 5), 1.0,
callback=lambda v: mmm_audio.send_float("b1_q", v), run_callback_on_init=True)
layout.addWidget(b1_freq)
layout.addWidget(b1_gain)
layout.addWidget(b1_q)
# Bell 2
layout.addWidget(QLabel("<b>Bell 2</b>"))
b2_freq = Handle("B2 Freq", ControlSpec(500, 2000, 0.5), 1000,
callback=lambda v: mmm_audio.send_float("b2_freq", v), run_callback_on_init=True)
b2_gain = Handle("B2 Gain (dB)", ControlSpec(-12, 12), 0,
callback=lambda v: mmm_audio.send_float("b2_gain", v), run_callback_on_init=True)
b2_q = Handle("B2 Q", ControlSpec(0.5, 5), 1.0,
callback=lambda v: mmm_audio.send_float("b2_q", v), run_callback_on_init=True)
layout.addWidget(b2_freq)
layout.addWidget(b2_gain)
layout.addWidget(b2_q)
# Bell 3
layout.addWidget(QLabel("<b>Bell 3</b>"))
b3_freq = Handle("B3 Freq", ControlSpec(2000, 8000, 0.5), 4000,
callback=lambda v: mmm_audio.send_float("b3_freq", v), run_callback_on_init=True)
b3_gain = Handle("B3 Gain (dB)", ControlSpec(-12, 12), 0,
callback=lambda v: mmm_audio.send_float("b3_gain", v), run_callback_on_init=True)
b3_q = Handle("B3 Q", ControlSpec(0.5, 5), 1.0,
callback=lambda v: mmm_audio.send_float("b3_q", v), run_callback_on_init=True)
layout.addWidget(b3_freq)
layout.addWidget(b3_gain)
layout.addWidget(b3_q)
# High Shelf
layout.addWidget(QLabel("<b>High Shelf</b>"))
hs_freq = Handle("HS Freq", ControlSpec(5000, 12000, 0.5), 8000,
callback=lambda v: mmm_audio.send_float("hs_freq", v), run_callback_on_init=True)
hs_gain = Handle("HS Gain (dB)", ControlSpec(-12, 12), 0,
callback=lambda v: mmm_audio.send_float("hs_gain", v), run_callback_on_init=True)
layout.addWidget(hs_freq)
layout.addWidget(hs_gain)
window.setLayout(layout)
window.show()
app.exec()
if __name__ == "__main__":
main()
Mojo Code¶
from mmm_audio import *
struct EQSynth(Movable, Copyable):
"""5-band parametric EQ processor using Biquad filters.
Demonstrates: lowshelf, 3x bell, highshelf
"""
var world: World
var buffer: Buffer
var num_chans: Int64
var play_buf: Play
var lowshelf: Biquad[2]
var bell1: Biquad[2]
var bell2: Biquad[2]
var bell3: Biquad[2]
var highshelf: Biquad[2]
var messenger: Messenger
# EQ parameters
var ls_freq: Float64
var ls_gain: Float64
var b1_freq: Float64
var b1_gain: Float64
var b1_q: Float64
var b2_freq: Float64
var b2_gain: Float64
var b2_q: Float64
var b3_freq: Float64
var b3_gain: Float64
var b3_q: Float64
var hs_freq: Float64
var hs_gain: Float64
fn __init__(out self, world: World):
self.world = world
# Load the audio buffer
self.buffer = Buffer.load("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 = Play(self.world)
self.lowshelf = Biquad[2](self.world)
self.bell1 = Biquad[2](self.world)
self.bell2 = Biquad[2](self.world)
self.bell3 = Biquad[2](self.world)
self.highshelf = Biquad[2](self.world)
self.messenger = Messenger(self.world)
# Default EQ settings (flat response)
self.ls_freq = 100.0
self.ls_gain = 0.0
self.b1_freq = 250.0
self.b1_gain = 0.0
self.b1_q = 1.0
self.b2_freq = 1000.0
self.b2_gain = 0.0
self.b2_q = 1.0
self.b3_freq = 4000.0
self.b3_gain = 0.0
self.b3_q = 1.0
self.hs_freq = 8000.0
self.hs_gain = 0.0
fn next(mut self) -> MFloat[2]:
self.messenger.update(self.ls_freq, "ls_freq")
self.messenger.update(self.ls_gain, "ls_gain")
self.messenger.update(self.b1_freq, "b1_freq")
self.messenger.update(self.b1_gain, "b1_gain")
self.messenger.update(self.b1_q, "b1_q")
self.messenger.update(self.b2_freq, "b2_freq")
self.messenger.update(self.b2_gain, "b2_gain")
self.messenger.update(self.b2_q, "b2_q")
self.messenger.update(self.b3_freq, "b3_freq")
self.messenger.update(self.b3_gain, "b3_gain")
self.messenger.update(self.b3_q, "b3_q")
self.messenger.update(self.hs_freq, "hs_freq")
self.messenger.update(self.hs_gain, "hs_gain")
var out = self.play_buf.next[num_chans=2](self.buffer, 1.0, True)
out = self.lowshelf.lowshelf(out, self.ls_freq, 0.707, self.ls_gain)
out = self.bell1.bell(out, self.b1_freq, self.b1_q, self.b1_gain)
out = self.bell2.bell(out, self.b2_freq, self.b2_q, self.b2_gain)
out = self.bell3.bell(out, self.b3_freq, self.b3_q, self.b3_gain)
out = self.highshelf.highshelf(out, self.hs_freq, 0.707, self.hs_gain)
return out
struct BiquadEQ(Movable, Copyable):
var world: World
var eq_synth: EQSynth
fn __init__(out self, world: World):
self.world = world
self.eq_synth = EQSynth(self.world)
fn next(mut self) -> MFloat[2]:
return self.eq_synth.next()