HackerPoet / FractalSoundExplorer

Explore fractals in an audio-visual sandbox
MIT License
1.15k stars 135 forks source link

Detailed explanation of the tone generation algorithm #11

Open splatpope opened 3 years ago

splatpope commented 3 years ago

The comments are somewhat vague, and the video only mentions that "the left and right channels are mapped to the x,y coordinates of the orbit points [...] sampled at 8000hz, then interpolated to 48000hz", iirc.

I understand that this is a POC and I wont hold it against you that it is not throughly documented, but a detailed explanation would be welcome.


I have studied the algorithm thoroughly, but the only conclusive statement I can make is that with the global constants defined in Main.cpp, the following behavior arises :

"steps" is computed as samplerate / max_freq -> steps = 48000/4000 = 12 I posit that this represents the number of samples necessary to represent a cycle of a sinusoidal of frequency max_freq. Then, the audio buffer is filled. A time cursor named "m_audio_time" advances at half the rate of the buffer cursor, simply because we fill the two channels at every loop.

A cursor inside this "steps" window, called j, is made equal to m_audio_time % steps, meaning that it serves as a sample cursor inside the "steps" window. A new fractal point is computed every time j is zero, AKA we have spanned "steps" samples.

Meaning that every point in the orbit generates 12 samples. (Obviously, if they make a cycle, each point will generate way more)

Apparently, distance values, dx/y and dpx/y, are calculated relative either to the first point then normalized, either to the advancing mean of all previously computed point.

A time cursor named t is computed as j/steps, meaning it represents the relative advancement throughout the window. Its value is then updated through the function : 0.5 - 0.5 cos(t *pi) Thus, for every calculated point, t will represent 12 samples of half a cycle of a cosine, bounded between 1 and 0.

I suppose that the magic happens right after that, when you set the value of the output sample to be : w = t d + (1-t) dp or w = dp + t * (d - dp)

What it seems to me is that, every time a new orbit point is calculated, it generates a cosine half cycle, spanning 12 samples, and its distance to the previous point is used to manipulate these samples so that their interleaving in the buffer somehow generate different frequencies.

I may certainly have misunderstood some things and would love to be englightened.