Skip to content

Adds a phase-aligned formant generator, a cosine wavetable, and a bell curve wavetable#218

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

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

Conversation

@chilichesdog
Copy link
Copy Markdown

No description provided.

@@ -0,0 +1,205 @@
from mmm_audio import *

struct PAF[num_chans: Int = 1, interp: Int = Interp.linear, os_index: Int = 0, bell_bWrap: Bool = False](Representable, Movable, Copyable):
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.

Can you explain why bell_bWrap is False? For synthesis it seems like it would always be True? Also, why is this a Parameter that could be set by a user? Why would a user set it to True instead of False?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Miller Puckette's design in Pure Data only reads the second half of the bell curve table. It uses tabread4~ which does not wrap - instead it sends the first or last value in the table (depending on which direction the index value exceeds the bounds), which in the bell curve, is negligible (1e-7). In this case in MMMAudio, setting bWrap to False by default has the same effect, sending 0 if the index is out of range. I found in testing that the user can achieve different sounds by setting bWrap to true, thus reading the entire bell curve many times continuously rather than reading half of it only at the beginning and end of the sinusoidal phase.

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.

Awesome. An example file demonstrating these options would be excellent. Also, a very brief description (basically what you've put above) can go in the mojo docstrings.

mod = ((cos2 - cos1)*b)+cos1
out = mod * bell
return out
else:
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.

There is a lot of duplicated code in either path of this if/else. Can it be tightened up to make the struct more maintainable?

Comment thread mmm_audio/Oscillators.mojo
fn init_cos(mut self):
for i in range(OscBuffersSize):
v = cos(2.0 * 3.141592653589793 * Float64(i) / Float64(OscBuffersSize))
self.buffers[4].append(v)
Copy link
Copy Markdown
Collaborator

@tedmoore tedmoore May 8, 2026

Choose a reason for hiding this comment

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

Is the buffers list allocated to have 6 elements? I don't see where that happens?

@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.

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