In my previous example, I showed how to create a basic sine wave oscillator. Now, I want to make it a little bit better.
In my next step, I want to factor out the oscillator function that produces a signal. Now, this function should not rely on any outside processing to produce the correct signal: the goal is to pass in a variable that represents the next sample to insert into the source data line, and get a Short value that we will actually put into the source data line.
So, we'll need to pass in more than just the next sample index: we will also need to pass in the frequency and the sample rate. And, instead of just passing in the max value of Short to produce our volume, let's also add a way of controlling for volume. Our function will end up having a signature like this:
getSignal(position, amplitude, frequency, sampleRate)
Translated, position is our time unit, amplitude is our volume, frequency is the actual note we are playing, and sampleRate is how many time units per second we will have.
Now, we want to get the same output, but our inputs are a little bit different. We are still going to do a sine on 2*pi*r just like we were doing last time - but now we need to calculate the r.
We can calculate r by dividing frequency by sample rate, and multiplying that by position. Then, we do a sin(2*pi*r) and multiply by amplitude to produce our volume.
Oh, one other thing - this is all based on a radius of 1, so we need to keep our r below 1. The code ends up looking like this:
fun getSignal(position: Int, amplitude: Short, frequency: Double, sampleRate: Double): Short =
(amplitude * sin( 2 * PI * getRadius(position, frequency, sampleRate))).toInt().toShort()
private fun getRadius(position: Int, frequency: Double, sampleRate: Double): Double {
val radius = position * (frequency / sampleRate)
return if (radius > 1) radius - 1 else radius
}
Comments
Post a Comment