Skip to content

Add a phase-aligned formant generator and a gaussiam bell curve wavetable#218

Open
chilichesdog wants to merge 1 commit into
spluta:mainfrom
chilichesdog:main
Open

Add a phase-aligned formant generator and a gaussiam bell curve wavetable#218
chilichesdog wants to merge 1 commit into
spluta:mainfrom
chilichesdog:main

Conversation

@chilichesdog
Copy link
Copy Markdown

No description provided.

Comment thread mmm_audio/Synthesizers.mojo Outdated
Comment thread mmm_audio/Synthesizers.mojo Outdated
Comment thread mmm_audio/Oscillators.mojo
Comment thread mmm_audio/Oscillators.mojo Outdated
@spluta
Copy link
Copy Markdown
Owner

spluta commented May 9, 2026

Thinking about this a bit, we need to make some changes to make this merge-able:

  1. I don't want to change the basic waveforms, so don't add the waveforms to the OscBuffers.
  2. a cos wave is just a sin wave with a 1/4 phase offset, so for the cos lookups just offset the lookup point by OscBuffersSize/4. we don't need a separate table.
  3. the gaussian window is generally useful and can be added to Windows in Windows_Module.mojo but not basic oscillators
  4. the sine window already exists in the Windows struct, so use that instead

for both the gaussian window and the sine window, you can get the value from the window using the win_env function, which handles the lookup for you.

@spluta
Copy link
Copy Markdown
Owner

spluta commented May 9, 2026

One more thing. The cos waves should definitely use Osc instead of implementing their own lookup. To make this work, just give the Osc.next function a freq of 0 and a phase_offset value of your cosN_phase plus 0.25 (to make it a cos).

This will make this much more maintainable.

@chilichesdog chilichesdog marked this pull request as draft May 26, 2026 23:44
@chilichesdog chilichesdog changed the title Adds a phase-aligned formant generator, a cosine wavetable, and a bell curve wavetable Add a phase-aligned formant generator and a gaussiam bell curve wavetable May 27, 2026
@chilichesdog chilichesdog marked this pull request as ready for review May 27, 2026 02:06
Comment on lines +93 to +118
for chan in range(Self.num_chans):
cos1[chan] = self.cos1.next(
freq=0, phase_offset=cos1_phase[chan] + 0.25
)[chan]

cos2[chan] = self.cos2.next(
freq=0, phase_offset=cos2_phase[chan] + 0.25
)[chan]

sin[chan] = self.sin.at_phase[
window_type=WindowType.sine, interp=Self.interp
](self.world, phasor[chan], self.sin_last_phase[chan])

gaussian_phase[chan] = (
sin[chan] * ((bandwidth[chan] / fund[chan]) * 0.25)
) + 0.5

gaussian[chan] = self.gaussian.at_phase[
window_type=WindowType.gaussian, interp=Self.interp
](self.world, gaussian_phase[chan], self.gauss_last_phase[chan])

mod[chan] = ((cos2[chan] - cos1[chan]) * b[chan]) + cos1[chan]
out[chan] = mod[chan] * gaussian[chan]
self.gauss_last_phase[chan] = gaussian_phase[chan]
self.sin_last_phase[chan] = phasor[chan]
self.cos1_last_phase[chan] = cos1_phase[chan]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all looking really nice. Great work.

I've been looking at this code block for a while. I'm pretty sure this can be done without the for chan in that starts at line 93. The multichannel processing should be able to happen in parallel as a Self.num_chans SIMD vector.

Give that a shot. I know the SIMD stuff can be unfamiliar (it certainly was to me at first), so let me know if you want a more thorough explanation.

Once that is done, I feel like this is good for me to pull locally and take a listen, a which point, I think it'll be good to merge!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants