Skip to content

Commit

Permalink
Tweak and fix signal processing
Browse files Browse the repository at this point in the history
  • Loading branch information
Danand committed Mar 15, 2024
1 parent 89e7e06 commit 7a2ae3d
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,43 +49,52 @@ class AudioOutput(

audioTrack.play()

val floatArray = FloatArray(bufferSize)
val bufferStereo = FloatArray(bufferSize)

val sampleTimeStep = 1.0f / samplingRate
val bufferSizeMono = bufferSize / 2

val timeStart = System.currentTimeMillis() * 1000.0f
val bufferMono = FloatArray(bufferSizeMono)

var timeCurrent = timeStart
val sampleTimeStep = 1.0f / samplingRate

while (isActive) {
val timeElapsedSeconds = timeCurrent - timeStart
var timeElapsedSeconds = 0.0f

var sampleMax = 0.0f
while (isActive) {
for (sampleIndex in bufferMono.indices) {
val sampleTime = timeElapsedSeconds + (sampleIndex * sampleTimeStep)

for (i in floatArray.indices) {
val sampleTime = timeElapsedSeconds + (i * sampleTimeStep)
var sampleValueMax = 0.0f

for (signalProcessor in signalProcessors) {
val sample = signalProcessor.process(sampleTime)
sampleMax = max(sampleMax, sample)
val sampleValue = signalProcessor.process(sampleTime)
sampleValueMax = max(sampleValueMax, sampleValue)
}

floatArray[i] = sampleMax
bufferMono[sampleIndex] = sampleValueMax
}

// TODO: Uncomment when delay effect will be fixed.
//for (effect in effects) {
// effect.process(floatArray, bufferSize)
//}

timeElapsedSeconds += bufferSizeMono * sampleTimeStep

var sampleIndexStereo = 0

for (sampleIndexMono in bufferMono.indices) {
bufferStereo[sampleIndexStereo] = bufferMono[sampleIndexMono]
bufferStereo[sampleIndexStereo + 1] = bufferMono[sampleIndexMono]

sampleIndexStereo += 2
}

audioTrack.write(
floatArray,
bufferStereo,
0,
bufferSize,
AudioTrack.WRITE_NON_BLOCKING,
AudioTrack.WRITE_BLOCKING,
)

timeCurrent += bufferSize * sampleTimeStep
}

audioTrack.stop()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.danand.juicynoise.signalprocessors

import com.danand.juicynoise.data.Sensors
import com.danand.juicynoise.utils.WeightedChoice
import com.danand.juicynoise.interfaces.SignalProcessor
import com.danand.juicynoise.interfaces.Synth
import com.danand.juicynoise.utils.magnitude
import com.danand.juicynoise.utils.normalizeOnto
import com.danand.juicynoise.synths.SynthExotic
import com.danand.juicynoise.utils.weightedChoice
import com.danand.juicynoise.synths.SynthSawtooth
import com.danand.juicynoise.synths.SynthSine
import com.danand.juicynoise.synths.SynthSquare
Expand All @@ -15,6 +14,8 @@ import androidx.compose.runtime.MutableState

import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
import kotlin.math.tanh
import kotlin.random.Random

class SignalProcessorSensors(private val sensorsState: MutableState<Sensors>) : SignalProcessor {
Expand Down Expand Up @@ -55,9 +56,16 @@ class SignalProcessorSensors(private val sensorsState: MutableState<Sensors>) :
SynthSine(),
SynthSquare(),
SynthSawtooth(),
SynthExotic(),
)

private val initRandomizedPhases = {
Random.nextFloat()
}

private val phases: Array<Float> = Array(this.synths.count()) {
initRandomizedPhases()
}

private val initRandomizedMapping = {
Random.nextInt(0, this.sensorGetters.count())
}
Expand All @@ -66,12 +74,27 @@ class SignalProcessorSensors(private val sensorsState: MutableState<Sensors>) :
initRandomizedMapping()
}

private val frequencyMaxToWeights = listOf(
700.0f to 0.6,
2500.0f to 0.3,
7000.0f to 0.1,
private val sensorGetterMinValues = FloatArray(this.sensorGetters.count())

private val sensorGetterMaxValues = FloatArray(this.sensorGetters.count())

private val frequencyMaxToWeights = mapOf(
30.0f to 0.2,
50.0f to 0.3,
75.0f to 0.5,
110.0f to 0.3,
250.0f to 0.5,
650.0f to 0.3,
1000.0f to 0.1,
9000.0f to 0.05,
)

private var frequenciesMax: Array<Float> = Array(this.synths.count()) {
Random.nextInt(35, 70).toFloat()
}

private var weirdEffectDivider = 9

override fun process(time: Float): Float {
val angularSpeedMagnitude = magnitude(
this.sensorsState.value.angularSpeedX,
Expand All @@ -89,7 +112,6 @@ class SignalProcessorSensors(private val sensorsState: MutableState<Sensors>) :
this.sensorsState.value.accelerationZ,
)

var frequencyMax = 700.0f
val amplitudeMax = 0.9f

var sampleValueTotal = 0.0f
Expand All @@ -101,28 +123,52 @@ class SignalProcessorSensors(private val sensorsState: MutableState<Sensors>) :
val sensorValue = sensorGetter()

if (accelerationMagnitude > 40) {
frequencyMax = WeightedChoice(frequencyMaxToWeights).next()
this.frequenciesMax[index] = weightedChoice(frequencyMaxToWeights)
}

if (angularSpeedMagnitude > 15) {
weirdEffectDivider = Random.nextInt(1, 31)
}

val sensorGetterMinValue = this.sensorGetterMinValues[this.mapping[index]]
this.sensorGetterMinValues[this.mapping[index]] = min(sensorGetterMinValue, sensorValue)

val sensorGetterMaxValue = this.sensorGetterMaxValues[this.mapping[index]]
this.sensorGetterMaxValues[this.mapping[index]] = max(sensorGetterMaxValue, sensorValue)

var frequencyMax = this.frequenciesMax[index]

if ((sensorValue * 10000.0f).toInt() % weirdEffectDivider == 0) {
frequencyMax += (this.frequenciesMax.random() * tanh(time))
}

val frequency = normalizeOnto(
sensorValue,
10.0f,
1000.0f,
40.0f,
sensorGetterMinValue,
sensorGetterMaxValue,
35.0f,
frequencyMax,
).toInt()

if (accelerationMagnitude > 30) {
randomizePhases(this.phases) {
initRandomizedPhases()
}
}

val phase = this.phases[index]

val sampleValueSynth = synth.getSample(
time,
frequency,
amplitudeMax,
0.0f,
phase,
)

sampleValueTotal = max(sampleValueTotal, sampleValueSynth)
}

if ((this.sensorsState.value.light % this.sensorsState.value.magneticZ).toInt() % 3 == 0) {
if ((this.sensorsState.value.light % (this.sensorsState.value.magneticZ * 10.0f)).toInt() % 3 == 0) {
val sampleValueRandom = Random.nextFloat() * amplitudeMax
sampleValueTotal = max(sampleValueTotal, sampleValueRandom)
}
Expand All @@ -135,4 +181,10 @@ class SignalProcessorSensors(private val sensorsState: MutableState<Sensors>) :
mapping[index] = init()
}
}

private fun randomizePhases(phases: Array<Float>, init: () -> Float) {
for (index in phases.indices) {
phases[index] = init()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.danand.juicynoise.utils

import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
import kotlin.math.sqrt

fun magnitude(x: Float, y: Float, z: Float): Float {
Expand Down Expand Up @@ -40,8 +42,11 @@ fun normalizeOnto(
toStart: Float,
toEnd: Float,
): Float {
val normalizedValue = (value - fromStart) / (fromEnd - fromStart)
val mappedValue = normalizedValue * (toEnd - toStart) + toStart
val ratio = (value - fromStart) / (fromEnd - fromStart)
val normalizedValue = ratio * (toEnd - toStart) + toStart

return mappedValue
var normalizedValueClamped = max(normalizedValue, toStart)
normalizedValueClamped = min(normalizedValue, toEnd)

return normalizedValueClamped
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.danand.juicynoise.utils

fun <T> weightedChoice(options: Map<T, Double>): T {
val totalWeight = options.values.sum()
val normalizedOptions = options.mapValues { it.value / totalWeight }

var random = Math.random()

for ((option, weight) in normalizedOptions) {
if (random < weight) {
return option
}

random -= weight
}
throw IllegalStateException("No option selected")
}

This file was deleted.

0 comments on commit 7a2ae3d

Please sign in to comment.