mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
fix: RAM music should loop as they should now
This commit is contained in:
@@ -376,7 +376,7 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
||||
App.audioMixer.requestFadeOut(App.audioMixer.musicTrack, AudioMixer.DEFAULT_FADEOUT_LEN / 3f)
|
||||
App.audioMixer.musicTrack.nextTrack = null
|
||||
ingame.musicGovernor.stopMusic(this)
|
||||
thisMusic?.let { ingame.musicGovernor.queueMusicToPlayNext(it) }
|
||||
if (thisMusic is MusicContainer) thisMusic.let { ingame.musicGovernor.queueMusicToPlayNext(it) }
|
||||
iHitTheStopButton = true
|
||||
}
|
||||
else if (!shouldPlayerBeDisabled) {
|
||||
@@ -472,7 +472,7 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
||||
iHitTheStopButton = false
|
||||
stopRequested = false
|
||||
}
|
||||
resetPlaylistScroll(App.audioMixer.musicTrack.nextTrack)
|
||||
resetPlaylistScroll(App.audioMixer.musicTrack.nextTrack as? MusicContainer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.github.strikerx3.jxinput.XInputDevice;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import kotlin.text.Charsets;
|
||||
import net.torvald.getcpuname.GetCpuName;
|
||||
import net.torvald.terrarum.audio.AudioBank;
|
||||
import net.torvald.terrarum.audio.AudioMixer;
|
||||
import net.torvald.terrarum.audio.MusicContainer;
|
||||
import net.torvald.terrarum.audio.dsp.BinoPan;
|
||||
@@ -554,11 +555,11 @@ public class App implements ApplicationListener {
|
||||
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("title_health1", () -> new Texture(Gdx.files.internal("./assets/graphics/gui/health_take_a_break.tga")));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("title_health2", () -> new Texture(Gdx.files.internal("./assets/graphics/gui/health_distance.tga")));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bup", () -> new MusicContainer("haptic_bup", Gdx.files.internal("./assets/audio/effects/haptic_bup.ogg").file(), false, true, (MusicContainer m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bap", () -> new MusicContainer("haptic_bap", Gdx.files.internal("./assets/audio/effects/haptic_bap.ogg").file(), false, true, (MusicContainer m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bop", () -> new MusicContainer("haptic_bop", Gdx.files.internal("./assets/audio/effects/haptic_bop.ogg").file(), false, true, (MusicContainer m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bep", () -> new MusicContainer("haptic_bep", Gdx.files.internal("./assets/audio/effects/haptic_bep.ogg").file(), false, true, (MusicContainer m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bip", () -> new MusicContainer("haptic_bip", Gdx.files.internal("./assets/audio/effects/haptic_bip.ogg").file(), false, true, (MusicContainer m) -> { highPrioritySoundPlaying = false; return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bup", () -> new MusicContainer("haptic_bup", Gdx.files.internal("./assets/audio/effects/haptic_bup.ogg").file(), false, true, (AudioBank m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bap", () -> new MusicContainer("haptic_bap", Gdx.files.internal("./assets/audio/effects/haptic_bap.ogg").file(), false, true, (AudioBank m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bop", () -> new MusicContainer("haptic_bop", Gdx.files.internal("./assets/audio/effects/haptic_bop.ogg").file(), false, true, (AudioBank m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bep", () -> new MusicContainer("haptic_bep", Gdx.files.internal("./assets/audio/effects/haptic_bep.ogg").file(), false, true, (AudioBank m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bip", () -> new MusicContainer("haptic_bip", Gdx.files.internal("./assets/audio/effects/haptic_bip.ogg").file(), false, true, (AudioBank m) -> { highPrioritySoundPlaying = false; return null; }));
|
||||
// make loading list
|
||||
CommonResourcePool.INSTANCE.loadAll();
|
||||
|
||||
|
||||
32
src/net/torvald/terrarum/audio/AudioBank.kt
Normal file
32
src/net/torvald/terrarum/audio/AudioBank.kt
Normal file
@@ -0,0 +1,32 @@
|
||||
package net.torvald.terrarum.audio
|
||||
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2024-04-05.
|
||||
*/
|
||||
abstract class AudioBank : Disposable {
|
||||
|
||||
companion object {
|
||||
fun fromMusic(name: String, file: File, looping: Boolean = false, toRAM: Boolean = false, songFinishedHook: (AudioBank) -> Unit = {}): AudioBank {
|
||||
return MusicContainer(name, file, looping, toRAM, songFinishedHook)
|
||||
}
|
||||
}
|
||||
|
||||
protected val hash = System.nanoTime()
|
||||
|
||||
abstract fun makeCopy(): AudioBank
|
||||
|
||||
abstract val name: String
|
||||
|
||||
abstract val samplingRate: Int
|
||||
abstract val channels: Int
|
||||
abstract val totalSizeInSamples: Long
|
||||
abstract fun currentPositionInSamples(): Long
|
||||
|
||||
abstract fun readBytes(buffer: ByteArray): Int
|
||||
abstract fun reset()
|
||||
|
||||
abstract val songFinishedHook: (AudioBank) -> Unit
|
||||
}
|
||||
@@ -485,7 +485,7 @@ class AudioMixer : Disposable {
|
||||
|
||||
private var ambientStopped = true
|
||||
|
||||
fun startMusic(song: MusicContainer) {
|
||||
fun startMusic(song: AudioBank) {
|
||||
if (musicTrack.isPlaying) {
|
||||
requestFadeOut(musicTrack, DEFAULT_FADEOUT_LEN)
|
||||
}
|
||||
@@ -496,7 +496,7 @@ class AudioMixer : Disposable {
|
||||
requestFadeOut(musicTrack, DEFAULT_FADEOUT_LEN)
|
||||
}
|
||||
|
||||
fun startAmb(song: MusicContainer) {
|
||||
fun startAmb(song: AudioBank) {
|
||||
val ambientTrack = if (!ambientTrack1.streamPlaying.get())
|
||||
ambientTrack1
|
||||
else if (!ambientTrack2.streamPlaying.get())
|
||||
@@ -513,7 +513,7 @@ class AudioMixer : Disposable {
|
||||
// fade will be processed by the update()
|
||||
}
|
||||
|
||||
fun startAmb1(song: MusicContainer) {
|
||||
fun startAmb1(song: AudioBank) {
|
||||
if (ambientTrack1.isPlaying == true) {
|
||||
requestFadeOut(musicTrack, DEFAULT_FADEOUT_LEN)
|
||||
}
|
||||
@@ -521,7 +521,7 @@ class AudioMixer : Disposable {
|
||||
// fade will be processed by the update()
|
||||
}
|
||||
|
||||
fun startAmb2(song: MusicContainer) {
|
||||
fun startAmb2(song: AudioBank) {
|
||||
if (ambientTrack2.isPlaying == true) {
|
||||
requestFadeOut(musicTrack, DEFAULT_FADEOUT_LEN)
|
||||
}
|
||||
|
||||
@@ -98,12 +98,6 @@ class MixerTrackProcessor(bufferSize: Int, val rate: Int, val track: TerrarumAud
|
||||
|
||||
bytesRead += read0(buffer, bytesRead)
|
||||
}
|
||||
// if isLooping=true, do gapless sampleRead but reads from itself
|
||||
else if (track.currentTrack?.looping == true && bytesRead < buffer.size) {
|
||||
track.currentTrack?.reset()
|
||||
|
||||
bytesRead += read0(buffer, bytesRead)
|
||||
}
|
||||
|
||||
bytesRead
|
||||
}, { purgeStreamBuf() }).also {
|
||||
|
||||
@@ -5,9 +5,9 @@ import net.torvald.terrarum.tryDispose
|
||||
|
||||
class MusicCache(val trackName: String) : Disposable {
|
||||
|
||||
private val cache = HashMap<String, MusicContainer>()
|
||||
private val cache = HashMap<String, AudioBank>()
|
||||
|
||||
fun getOrPut(music: MusicContainer?): MusicContainer? {
|
||||
fun getOrPut(music: AudioBank?): AudioBank? {
|
||||
if (music != null)
|
||||
return cache.getOrPut(music.name) { music.makeCopy() }
|
||||
return null
|
||||
|
||||
@@ -7,41 +7,51 @@ import com.badlogic.gdx.backends.lwjgl3.audio.Ogg
|
||||
import com.badlogic.gdx.backends.lwjgl3.audio.OggInputStream
|
||||
import com.badlogic.gdx.backends.lwjgl3.audio.Wav
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.jcraft.jorbis.VorbisFile
|
||||
import javazoom.jl.decoder.Bitstream
|
||||
import net.torvald.reflection.extortField
|
||||
import net.torvald.reflection.forceInvoke
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.unsafe.UnsafeHelper
|
||||
import net.torvald.unsafe.UnsafePtr
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import javax.sound.sampled.AudioSystem
|
||||
|
||||
data class MusicContainer(
|
||||
val name: String,
|
||||
class MusicContainer(
|
||||
override val name: String,
|
||||
val file: File,
|
||||
val looping: Boolean = false,
|
||||
val toRAM: Boolean = false,
|
||||
internal var songFinishedHook: (MusicContainer) -> Unit = {}
|
||||
): Disposable {
|
||||
val samplingRate: Int
|
||||
override var songFinishedHook: (AudioBank) -> Unit = {}
|
||||
): AudioBank() {
|
||||
override val samplingRate: Int
|
||||
override val channels: Int
|
||||
val codec: String
|
||||
|
||||
var samplesReadCount = 0L; internal set
|
||||
var samplesTotal: Long
|
||||
override val totalSizeInSamples: Long
|
||||
private val totalSizeInBytes: Long
|
||||
|
||||
private val gdxMusic: Music = Gdx.audio.newMusic(FileHandle(file))
|
||||
|
||||
private var soundBuf: UnsafePtr? = null; private set
|
||||
|
||||
private val hash = System.nanoTime()
|
||||
private val bytesPerSample: Int
|
||||
|
||||
init {
|
||||
gdxMusic.isLooping = looping
|
||||
|
||||
// gdxMusic.setOnCompletionListener(songFinishedHook)
|
||||
|
||||
channels = when (gdxMusic) {
|
||||
is Wav.Music -> gdxMusic.extortField<Wav.WavInputStream>("input")!!.channels
|
||||
is Ogg.Music -> gdxMusic.extortField<OggInputStream>("input")!!.channels
|
||||
else -> 2
|
||||
}
|
||||
|
||||
bytesPerSample = 2 * channels
|
||||
|
||||
samplingRate = when (gdxMusic) {
|
||||
is Wav.Music -> {
|
||||
val rate = gdxMusic.extortField<Wav.WavInputStream>("input")!!.sampleRate
|
||||
@@ -80,55 +90,147 @@ data class MusicContainer(
|
||||
if (it.last() == "Music") it.dropLast(1).last() else it.last()
|
||||
}
|
||||
|
||||
samplesTotal = when (gdxMusic) {
|
||||
totalSizeInSamples = when (gdxMusic) {
|
||||
is Wav.Music -> getWavFileSampleCount(file)
|
||||
is Ogg.Music -> getOggFileSampleCount(file)
|
||||
is Mp3.Music -> getMp3FileSampleCount(file)
|
||||
else -> Long.MAX_VALUE
|
||||
}
|
||||
totalSizeInBytes = totalSizeInSamples * 2 * channels
|
||||
|
||||
|
||||
if (toRAM) {
|
||||
if (samplesTotal == Long.MAX_VALUE) throw IllegalStateException("Could not read sample count")
|
||||
if (totalSizeInSamples == Long.MAX_VALUE) throw IllegalStateException("Could not read sample count")
|
||||
|
||||
val readSize = 8192
|
||||
var readCount = 0L
|
||||
val readBuf = ByteArray(readSize)
|
||||
|
||||
soundBuf = UnsafeHelper.allocate(4L * samplesTotal)
|
||||
soundBuf = UnsafeHelper.allocate(totalSizeInBytes)
|
||||
|
||||
while (readCount < samplesTotal) {
|
||||
val read = gdxMusic.forceInvoke<Int>("read", arrayOf(readBuf))!!.toLong()
|
||||
while (readCount < totalSizeInBytes) {
|
||||
gdxMusic.forceInvoke<Int>("read", arrayOf(readBuf))!!.toLong() // its return value will be useless for looping=true
|
||||
val read = minOf(readSize.toLong(), (totalSizeInBytes - readCount))
|
||||
|
||||
UnsafeHelper.memcpyRaw(readBuf, UnsafeHelper.getArrayOffset(readBuf), null, soundBuf!!.ptr + readCount, read)
|
||||
|
||||
readCount += read
|
||||
|
||||
// printdbg(this, "read $readCount/$totalSizeInBytes bytes (${readCount/(2*channels)}/$totalSizeInSamples samples)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun readBytes(buffer: ByteArray): Int {
|
||||
private fun read0(buffer: ByteArray, bytesRead: Int): Int {
|
||||
val tmpBuf = ByteArray(buffer.size - bytesRead)
|
||||
val newRead = readBytes(tmpBuf)
|
||||
|
||||
System.arraycopy(tmpBuf, 0, buffer, bytesRead, tmpBuf.size)
|
||||
|
||||
return newRead
|
||||
}
|
||||
|
||||
override fun readBytes(buffer: ByteArray): Int {
|
||||
if (soundBuf == null) {
|
||||
val bytesRead = gdxMusic.forceInvoke<Int>("read", arrayOf(buffer)) ?: 0
|
||||
samplesReadCount += bytesRead / 4
|
||||
samplesReadCount += bytesRead / bytesPerSample
|
||||
|
||||
if (looping && bytesRead < buffer.size) {
|
||||
reset()
|
||||
|
||||
val remainder = buffer.size - bytesRead
|
||||
|
||||
val fullCopyCounts = remainder / totalSizeInBytes
|
||||
val partialCopyCountsInBytes = (remainder % totalSizeInBytes).toInt()
|
||||
|
||||
var start = UnsafeHelper.getArrayOffset(buffer).toInt() + bytesRead
|
||||
|
||||
val fullbuf = ByteArray(totalSizeInBytes.toInt())
|
||||
// make full block copies
|
||||
for (i in 0 until fullCopyCounts) {
|
||||
gdxMusic.forceInvoke<Int>("read", arrayOf(fullbuf))
|
||||
reset()
|
||||
|
||||
System.arraycopy(fullbuf, 0, buffer, start, fullbuf.size)
|
||||
|
||||
start += totalSizeInBytes.toInt()
|
||||
}
|
||||
|
||||
// copy the remainders from the start of the samples
|
||||
val partialBuf = ByteArray(partialCopyCountsInBytes)
|
||||
gdxMusic.forceInvoke<Int>("read", arrayOf(partialBuf))
|
||||
System.arraycopy(partialBuf, 0, buffer, start, partialCopyCountsInBytes)
|
||||
|
||||
samplesReadCount += partialCopyCountsInBytes / bytesPerSample
|
||||
}
|
||||
|
||||
return bytesRead
|
||||
}
|
||||
else {
|
||||
val bytesToRead = minOf(buffer.size.toLong(), 4 * (samplesTotal - samplesReadCount))
|
||||
if (bytesToRead <= 0) return bytesToRead.toInt()
|
||||
val bytesToRead = minOf(buffer.size.toLong(), 2 * channels * (totalSizeInSamples - samplesReadCount))
|
||||
|
||||
UnsafeHelper.memcpyRaw(null, soundBuf!!.ptr + samplesReadCount * 4, buffer, UnsafeHelper.getArrayOffset(buffer), bytesToRead)
|
||||
if (!looping && bytesToRead <= 0) return bytesToRead.toInt()
|
||||
// if (looping) printdbg(this, "toRAM music loop (bytes cursor: $samplesReadCount/$totalSizeInSamples, bytesToRead=$bytesToRead, buffer.size=${buffer.size})")
|
||||
|
||||
UnsafeHelper.memcpyRaw(
|
||||
null,
|
||||
soundBuf!!.ptr + samplesReadCount * bytesPerSample,
|
||||
buffer,
|
||||
UnsafeHelper.getArrayOffset(buffer),
|
||||
bytesToRead
|
||||
)
|
||||
|
||||
samplesReadCount += bytesToRead / bytesPerSample
|
||||
|
||||
|
||||
// reached the end of the "tape"
|
||||
if (looping && bytesToRead < buffer.size) {
|
||||
|
||||
val remainder = buffer.size - bytesToRead
|
||||
|
||||
val fullCopyCounts = remainder / totalSizeInBytes
|
||||
val partialCopyCountsInBytes = remainder % totalSizeInBytes
|
||||
|
||||
var start = UnsafeHelper.getArrayOffset(buffer) + bytesToRead
|
||||
|
||||
// make full block copies
|
||||
for (i in 0 until fullCopyCounts) {
|
||||
UnsafeHelper.memcpyRaw(
|
||||
null,
|
||||
soundBuf!!.ptr,
|
||||
buffer,
|
||||
start,
|
||||
totalSizeInBytes
|
||||
)
|
||||
|
||||
start += totalSizeInBytes
|
||||
}
|
||||
|
||||
// copy the remainders from the start of the "tape"
|
||||
UnsafeHelper.memcpyRaw(
|
||||
null,
|
||||
soundBuf!!.ptr,
|
||||
buffer,
|
||||
start,
|
||||
partialCopyCountsInBytes
|
||||
)
|
||||
|
||||
samplesReadCount = partialCopyCountsInBytes / bytesPerSample
|
||||
}
|
||||
|
||||
if (looping) return buffer.size
|
||||
|
||||
samplesReadCount += bytesToRead / 4
|
||||
return bytesToRead.toInt()
|
||||
}
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
override fun reset() {
|
||||
samplesReadCount = 0L
|
||||
gdxMusic.forceInvoke<Int>("reset", arrayOf())
|
||||
}
|
||||
|
||||
override fun currentPositionInSamples() = samplesReadCount
|
||||
|
||||
private fun getWavFileSampleCount(file: File): Long {
|
||||
return try {
|
||||
val ais = AudioSystem.getAudioInputStream(file)
|
||||
@@ -186,7 +288,7 @@ data class MusicContainer(
|
||||
soundBuf?.destroy()
|
||||
}
|
||||
|
||||
fun makeCopy(): MusicContainer {
|
||||
override fun makeCopy(): AudioBank {
|
||||
val new = MusicContainer(name, file, looping, false, songFinishedHook)
|
||||
|
||||
synchronized(this) {
|
||||
|
||||
@@ -42,7 +42,7 @@ class TerrarumAudioMixerTrack(
|
||||
acc or (c shl (5*i))
|
||||
}
|
||||
|
||||
var currentTrack: MusicContainer? = null
|
||||
var currentTrack: AudioBank? = null
|
||||
set(value) {
|
||||
field = if (value == null)
|
||||
null
|
||||
@@ -50,7 +50,7 @@ class TerrarumAudioMixerTrack(
|
||||
musicCache.getOrPut(value)
|
||||
}
|
||||
|
||||
var nextTrack: MusicContainer? = null
|
||||
var nextTrack: AudioBank? = null
|
||||
set(value) {
|
||||
field = if (value == null)
|
||||
null
|
||||
|
||||
@@ -6,6 +6,7 @@ import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.App.printdbgerr
|
||||
import net.torvald.terrarum.INGAME
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.audio.AudioBank
|
||||
import net.torvald.terrarum.audio.MusicContainer
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import net.torvald.terrarum.audio.TrackVolume
|
||||
@@ -216,7 +217,7 @@ abstract class Actor : Comparable<Actor>, Runnable {
|
||||
|
||||
}*/
|
||||
|
||||
open @Event fun onAudioInterrupt(music: MusicContainer) {
|
||||
open @Event fun onAudioInterrupt(music: AudioBank) {
|
||||
music.songFinishedHook(music)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.audio.AudioBank
|
||||
import net.torvald.terrarum.audio.AudioMixer
|
||||
import net.torvald.terrarum.audio.MusicContainer
|
||||
import net.torvald.terrarum.gameworld.WorldTime.Companion.DAY_LENGTH
|
||||
@@ -199,18 +200,16 @@ class TerrarumMusicGovernor : MusicGovernor() {
|
||||
var playCaller: Any? = null; private set
|
||||
var stopCallTime: Long? = null; private set
|
||||
|
||||
private fun stopMusic0(song: MusicContainer?, callStopMusicHook: Boolean = true, customPauseLen: Float? = null) {
|
||||
private fun stopMusic0(song: AudioBank?, callStopMusicHook: Boolean = true, customPauseLen: Float? = null) {
|
||||
musicState = if (customPauseLen == Float.POSITIVE_INFINITY) STATE_INIT else STATE_INTERMISSION
|
||||
// printdbg(this, "stopMusic1 customLen=$customPauseLen, stateNow: $musicState, called by")
|
||||
// printStackTrace(this)
|
||||
intermissionAkku = 0f
|
||||
intermissionLength = customPauseLen ?: getRandomMusicInterval()
|
||||
musicFired = false
|
||||
if (callStopMusicHook && musicStopHooks.isNotEmpty()) musicStopHooks.forEach {
|
||||
if (song != null) {
|
||||
if (callStopMusicHook && musicStopHooks.isNotEmpty() && song is MusicContainer) musicStopHooks.forEach {
|
||||
it(song)
|
||||
}
|
||||
}
|
||||
// printdbg(this, "StopMusic Intermission: $intermissionLength seconds")
|
||||
}
|
||||
|
||||
|
||||
@@ -664,7 +664,7 @@ class BasicDebugInfoWindow : UICanvas() {
|
||||
if (it.length > 7) it.replace(" ", "").let { it.substring(0 until minOf(it.length, 7)) }
|
||||
else it
|
||||
},
|
||||
"C:${track.currentTrack?.codec ?: ""}",
|
||||
//"C:${track.currentTrack?.codec ?: ""}",
|
||||
"R:${track.currentTrack?.samplingRate ?: ""}",
|
||||
).forEachIndexed { i, s ->
|
||||
// gauge background
|
||||
@@ -673,7 +673,7 @@ class BasicDebugInfoWindow : UICanvas() {
|
||||
|
||||
// fill the song title line with a progress bar
|
||||
if (i == 0 && track.currentTrack != null) {
|
||||
val perc = (track.currentTrack!!.samplesReadCount.toFloat() / track.currentTrack!!.samplesTotal).coerceAtMost(1f)
|
||||
val perc = (track.currentTrack!!.currentPositionInSamples().toFloat() / track.currentTrack!!.totalSizeInSamples).coerceAtMost(1f)
|
||||
batch.color = COL_PROGRESS_GRAD2
|
||||
Toolkit.fillArea(batch, x.toFloat(), faderY - (i + 1) * 16f, STRIP_W * perc, 14f)
|
||||
batch.color = COL_PROGRESS_GRAD
|
||||
|
||||
Reference in New Issue
Block a user