Coverage Summary for Class: TrainingClickTrackGeneratorKt (com.vsevolodganin.clicktrack.training)
Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
TrainingClickTrackGeneratorKt |
0%
(0/1)
|
0%
(0/1)
|
|
0%
(0/1)
|
0%
(0/6)
|
package com.vsevolodganin.clicktrack.training
import com.vsevolodganin.clicktrack.model.BeatsPerMinute
import com.vsevolodganin.clicktrack.model.ClickTrack
import com.vsevolodganin.clicktrack.model.Cue
import com.vsevolodganin.clicktrack.model.CueDuration
import com.vsevolodganin.clicktrack.model.TimeSignature
import com.vsevolodganin.clicktrack.model.asTimeGiven
import com.vsevolodganin.clicktrack.training.TrainingEditState.TrainingMode
import me.tatarka.inject.annotations.Inject
import kotlin.time.Duration
@Inject
class TrainingClickTrackGenerator() {
fun generate(trainingState: TrainingValidState, name: String): ClickTrack {
return ClickTrack(
name = name,
cues = when (trainingState.mode) {
TrainingMode.INCREASE_TEMPO -> when (val ending = trainingState.ending) {
is TrainingValidState.Ending.ByTempo -> generateIncreasingTempoCuesWithTempoEnding(
startingTempo = trainingState.startingTempo,
tempoIncrement = trainingState.tempoChange,
endingTempo = ending.endingTempo,
segmentLength = trainingState.segmentLength,
)
is TrainingValidState.Ending.ByTime -> generateIncreasingTempoCuesWithTimeEnding(
startingTempo = trainingState.startingTempo,
tempoIncrement = trainingState.tempoChange,
endingTime = ending.duration,
segmentLength = trainingState.segmentLength,
)
}
TrainingMode.DECREASE_TEMPO -> when (val ending = trainingState.ending) {
is TrainingValidState.Ending.ByTempo -> generateDecreasingTempoCuesWithTempoEnding(
startingTempo = trainingState.startingTempo,
tempoDecrement = trainingState.tempoChange,
endingTempo = ending.endingTempo,
segmentLength = trainingState.segmentLength,
)
is TrainingValidState.Ending.ByTime -> generateDecreasingTempoCuesWithTimeEnding(
startingTempo = trainingState.startingTempo,
tempoDecrement = trainingState.tempoChange,
endingTime = ending.duration,
segmentLength = trainingState.segmentLength,
)
}
},
loop = false,
)
}
private fun generateIncreasingTempoCuesWithTempoEnding(
startingTempo: BeatsPerMinute,
tempoIncrement: BeatsPerMinute,
endingTempo: BeatsPerMinute,
segmentLength: CueDuration,
): List<Cue> {
if (startingTempo > endingTempo) return emptyList()
return buildList {
var runningTempo = startingTempo
while (runningTempo < endingTempo) {
this += Cue(
bpm = runningTempo,
timeSignature = DefaultTimeSignature,
duration = segmentLength,
)
runningTempo += tempoIncrement
}
this += Cue(
bpm = endingTempo,
timeSignature = DefaultTimeSignature,
duration = segmentLength,
)
}
}
private fun generateDecreasingTempoCuesWithTempoEnding(
startingTempo: BeatsPerMinute,
tempoDecrement: BeatsPerMinute,
endingTempo: BeatsPerMinute,
segmentLength: CueDuration,
): List<Cue> {
if (startingTempo < endingTempo) return emptyList()
return buildList {
var runningTempo = startingTempo
while (runningTempo > endingTempo) {
this += Cue(
bpm = runningTempo,
timeSignature = DefaultTimeSignature,
duration = segmentLength,
)
if (runningTempo > tempoDecrement) {
runningTempo -= tempoDecrement
} else {
break
}
}
this += Cue(
bpm = endingTempo,
timeSignature = DefaultTimeSignature,
duration = segmentLength,
)
}
}
private fun generateIncreasingTempoCuesWithTimeEnding(
startingTempo: BeatsPerMinute,
tempoIncrement: BeatsPerMinute,
endingTime: Duration,
segmentLength: CueDuration,
): List<Cue> {
return buildList {
var runningDuration = Duration.ZERO
var runningTempo = startingTempo
while (runningDuration < endingTime) {
if (runningTempo < BeatsPerMinute.MAX) {
val segmentLengthAsTime = segmentLength.asTimeGiven(runningTempo, DefaultTimeSignature)
val segmentLengthCoerced = if (runningDuration + segmentLengthAsTime <= endingTime) {
segmentLength
} else {
CueDuration.Time(endingTime - runningDuration)
}
this += Cue(
bpm = runningTempo,
timeSignature = DefaultTimeSignature,
duration = segmentLengthCoerced,
)
runningDuration += segmentLengthAsTime
runningTempo += tempoIncrement
} else {
this += Cue(
bpm = runningTempo,
timeSignature = DefaultTimeSignature,
duration = CueDuration.Time(endingTime - runningDuration),
)
runningDuration = endingTime
}
}
}
}
private fun generateDecreasingTempoCuesWithTimeEnding(
startingTempo: BeatsPerMinute,
tempoDecrement: BeatsPerMinute,
endingTime: Duration,
segmentLength: CueDuration,
): List<Cue> {
return buildList {
var runningDuration = Duration.ZERO
var runningTempo = startingTempo
while (runningDuration < endingTime) {
if (runningTempo > tempoDecrement) {
val segmentLengthAsTime = segmentLength.asTimeGiven(runningTempo, DefaultTimeSignature)
val segmentLengthCoerced = if (runningDuration + segmentLengthAsTime <= endingTime) {
segmentLength
} else {
CueDuration.Time(endingTime - runningDuration)
}
this += Cue(
bpm = runningTempo,
timeSignature = DefaultTimeSignature,
duration = segmentLengthCoerced,
)
runningDuration += segmentLengthAsTime
runningTempo -= tempoDecrement
} else {
this += Cue(
bpm = runningTempo,
timeSignature = DefaultTimeSignature,
duration = CueDuration.Time(endingTime - runningDuration),
)
runningDuration = endingTime
}
}
}
}
}
private val DefaultTimeSignature = TimeSignature(4, 4)