For more information about the examples, such as how the Python and Mojo files interact with each other, see the Examples Overview
PitchShiftExample¶
Demonstrates how to use the PitchShift grain-based pitch shifter with microphone input.
This example assumes you have a microphone input device set up and selected as the default input device on your system.
A couple of settings in the .py file are important:
- num_input_channels: This can be set to any value, but it should be at least as high as the input channel you want to use.
- in_chan: This should be set to the input channel number of your microphone input source (0-indexed).
The graph allows you to set various parameters for the pitch shifter:
- which_input: Selects which input channel to use from the multi-channel input (0-indexed).
- pitch_shift: Sets the pitch shift factor (e.g., 1.0 = no shift, 2.0 = one octave up, 0.5 = one octave down).
- grain_dur: Sets the duration of the grains in seconds.
- pitch_dispersion: Sets the amount of random variation in pitch for each grain.
- time_dispersion: Sets the amount of random variation in timing for each grain.
Python Code¶
from mmm_python.MMMAudio import MMMAudio
mmm_audio = MMMAudio(128, num_input_channels = 12, graph_name="PitchShiftExample", package_name="examples")
mmm_audio.send_int("in_chan", 0) # set input channel to your input source
mmm_audio.start_audio() # start the audio thread - or restart it where it left off
mmm_audio.send_float("which_input", 2)
mmm_audio.send_float("pitch_shift", 1.5)
mmm_audio.send_float("grain_dur", 0.4)
mmm_audio.send_float("pitch_dispersion", 0.4)
mmm_audio.send_float("time_dispersion", 0.5)
mmm_audio.send_float("pitch_dispersion", 0.0)
mmm_audio.send_float("time_dispersion", 0.0)
mmm_audio.start_audio()
mmm_audio.stop_audio() # stop the audio thread
mmm_audio.plot(44000)
Mojo Code¶
from mmm_audio import *
# THE SYNTH
struct PitchShiftExample(Representable, Movable, Copyable):
var world: UnsafePointer[MMMWorld]
var pitch_shift: PitchShift[num_chans=2, overlaps=4]
var messenger: Messenger
var shift: Float64
var grain_dur: Float64
var pitch_dispersion: Float64
var time_dispersion: Float64
var in_chan: Int64
var which_input: Float64
var noise: WhiteNoise
fn __init__(out self, world: UnsafePointer[MMMWorld]):
self.world = world
self.pitch_shift = PitchShift[num_chans=2, overlaps=4](self.world, 1.0) # the duration of the buffer needs to == grain size*(max_pitch_shift-1).
self.messenger = Messenger(self.world)
self.shift = 1.0
self.grain_dur = 0.2
self.pitch_dispersion = 0.0
self.time_dispersion = 0.0
self.in_chan = 0
self.which_input = 0.0
self.noise = WhiteNoise()
@always_inline
fn next(mut self) -> SIMD[DType.float64, 2]:
self.messenger.update(self.which_input, "which_input")
self.messenger.update(self.in_chan, "in_chan")
temp = self.world[].sound_in[self.in_chan]
input_sig = select(self.which_input, [SIMD[DType.float64, 2](temp, temp), SIMD[DType.float64, 2](temp, 0.0), SIMD[DType.float64, 2](0.0, temp)])
self.messenger.update(self.shift,"pitch_shift")
self.messenger.update(self.grain_dur,"grain_dur")
self.messenger.update(self.pitch_dispersion,"pitch_dispersion")
self.messenger.update(self.time_dispersion,"time_dispersion")
# shift = linexp(self.world[].mouse_y, 0.0, 1.0, 0.25, 4.0)
# grain_dur = linexp(self.world[].mouse_x, 0.0, 1.0, 0.05, 0.3)
out = self.pitch_shift.next(input_sig, self.grain_dur, self.shift, self.pitch_dispersion, self.time_dispersion)
return out
fn __repr__(self) -> String:
return String("PitchShift")