mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-14 04:24:05 +09:00
sound on memory wip
This commit is contained in:
@@ -66,7 +66,7 @@ class AudioMixer : Disposable {
|
||||
else if (it == 9) "\u00D9Open\u00D9" // convolution1
|
||||
else if (it == 10) "\u00D9Cave\u00D9" // convolution2
|
||||
else if (it == 11) "\u00F0 \u00DA \u00F0" // fade
|
||||
else "Trk${it+1}", trackType = if (it >= 7 || it == 3) TrackType.BUS else TrackType.STATIC_SOURCE, maxVolumeFun = {
|
||||
else "Trk${it+1}", trackType = if (it >= 6 || it == 3) TrackType.BUS else TrackType.STATIC_SOURCE, maxVolumeFun = {
|
||||
when (it) {
|
||||
0 -> { musicVolume }
|
||||
4 -> { ambientVolume }
|
||||
@@ -115,10 +115,29 @@ class AudioMixer : Disposable {
|
||||
ambientTrack1, ambientTrack2, ambientTrack3, ambientTrack4
|
||||
)
|
||||
|
||||
val guiTracks = Array(4) { TerrarumAudioMixerTrack("GUI${it+1}", TrackType.STATIC_SOURCE) }
|
||||
|
||||
var processing = false
|
||||
|
||||
var actorNowPlaying = Terrarum.ingame?.actorNowPlaying; private set
|
||||
|
||||
fun getFreeGuiTrackNoMatterWhat(): TerrarumAudioMixerTrack {
|
||||
synchronized(this) {
|
||||
val it = getFreeGuiTrack() ?: guiTracks.minBy { it.playStartedTime }.also { it.checkedOutTime = System.nanoTime() }
|
||||
println("GuiTrack ${it.name}")
|
||||
return it
|
||||
}
|
||||
}
|
||||
|
||||
fun getFreeGuiTrack(): TerrarumAudioMixerTrack? {
|
||||
synchronized(this) {
|
||||
return guiTracks.minByOrNull { maxOf(it.checkedOutTime, it.playStartedTime) }
|
||||
.also {
|
||||
it?.checkedOutTime = System.nanoTime()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return oldest dynamic track, even if the track is currently playing
|
||||
*/
|
||||
@@ -169,6 +188,12 @@ class AudioMixer : Disposable {
|
||||
catch (e: Throwable) { e.printStackTrace() }
|
||||
}
|
||||
}
|
||||
guiTracks.forEach {
|
||||
if (!it.processor.paused) {
|
||||
try { it.processor.run() }
|
||||
catch (e: Throwable) { e.printStackTrace() }
|
||||
}
|
||||
}
|
||||
tracks.forEach {
|
||||
if (!it.processor.paused) {
|
||||
try { it.processor.run() }
|
||||
@@ -230,7 +255,10 @@ class AudioMixer : Disposable {
|
||||
it.filters[0] = Gain(1f)
|
||||
}
|
||||
|
||||
guiTrack.filters[1] = BinoPan(0f)
|
||||
guiTracks.forEach {
|
||||
guiTrack.addSidechainInput(it, 1.0)
|
||||
it.filters[0] = BinoPan(0f)
|
||||
}
|
||||
|
||||
masterTrack.filters[0] = SoftClp
|
||||
masterTrack.filters[1] = Buffer
|
||||
@@ -285,6 +313,7 @@ class AudioMixer : Disposable {
|
||||
/*parallelProcessingSchedule =
|
||||
arrayOf(musicTrack, ambientTrack, guiTrack).sliceEvenly(THREAD_COUNT / 2).toTypedArray() +
|
||||
dynamicTracks.sliceEvenly(THREAD_COUNT / 2).toTypedArray() +
|
||||
guiTracks +
|
||||
arrayOf(sfxSumBus, sumBus, convolveBusOpen, convolveBusCave).sliceEvenly(THREAD_COUNT / 2).toTypedArray() +
|
||||
arrayOf(fadeBus) +
|
||||
arrayOf(masterTrack)*/
|
||||
@@ -552,6 +581,7 @@ class AudioMixer : Disposable {
|
||||
fun reset() {
|
||||
ambientStopped = true
|
||||
dynamicTracks.forEach { it.stop() }
|
||||
guiTracks.forEach { it.stop() }
|
||||
tracks.filter { it.trackType == TrackType.STATIC_SOURCE }.forEach { it.stop() }
|
||||
tracks.forEach {
|
||||
it.processor.purgeBuffer()
|
||||
@@ -574,6 +604,7 @@ class AudioMixer : Disposable {
|
||||
// feedingThread.join()
|
||||
tracks.forEach { it.tryDispose() }
|
||||
dynamicTracks.forEach { it.tryDispose() }
|
||||
guiTracks.forEach { it.tryDispose() }
|
||||
masterTrack.tryDispose()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package net.torvald.terrarum.audio
|
||||
|
||||
import com.badlogic.gdx.utils.Queue
|
||||
import net.torvald.reflection.forceInvoke
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.audio.AudioMixer.Companion.DS_FLTIDX_LOW
|
||||
@@ -102,7 +101,7 @@ 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?.gdxMusic?.isLooping == true && bytesRead < buffer.size) {
|
||||
else if (track.currentTrack?.looping == true && bytesRead < buffer.size) {
|
||||
track.currentTrack?.reset()
|
||||
|
||||
bytesRead += read0(buffer, bytesRead)
|
||||
|
||||
@@ -12,28 +12,32 @@ 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
|
||||
import net.torvald.terrarum.tryDispose
|
||||
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 toRAM: Boolean = false,
|
||||
val name: String,
|
||||
val file: File,
|
||||
val loop: Boolean = false,
|
||||
val looping: Boolean = false,
|
||||
internal var songFinishedHook: (Music) -> Unit = {}
|
||||
): Disposable {
|
||||
val samplingRate: Int
|
||||
val codec: String
|
||||
|
||||
var samplesRead = 0L; internal set
|
||||
var samplesReadCount = 0L; internal set
|
||||
val samplesTotal: Long
|
||||
|
||||
val gdxMusic = Gdx.audio.newMusic(FileHandle(file))
|
||||
private val gdxMusic: Music = Gdx.audio.newMusic(FileHandle(file))
|
||||
|
||||
private var soundBuf: UnsafePtr? = null; private set
|
||||
|
||||
|
||||
init {
|
||||
gdxMusic.isLooping = loop
|
||||
gdxMusic.isLooping = looping
|
||||
|
||||
gdxMusic.setOnCompletionListener(songFinishedHook)
|
||||
|
||||
@@ -82,6 +86,45 @@ data class MusicContainer(
|
||||
else -> Long.MAX_VALUE
|
||||
}
|
||||
|
||||
|
||||
if (toRAM) {
|
||||
if (samplesTotal == 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)
|
||||
|
||||
while (readCount < samplesTotal) {
|
||||
val read = gdxMusic.forceInvoke<Int>("read", arrayOf(readBuf))!!.toLong()
|
||||
|
||||
UnsafeHelper.memcpyRaw(readBuf, UnsafeHelper.getArrayOffset(readBuf), null, soundBuf!!.ptr + readCount, read)
|
||||
|
||||
readCount += read
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun readBytes(buffer: ByteArray): Int {
|
||||
if (soundBuf == null) {
|
||||
val bytesRead = gdxMusic.forceInvoke<Int>("read", arrayOf(buffer)) ?: 0
|
||||
samplesReadCount += bytesRead / 4
|
||||
return bytesRead
|
||||
}
|
||||
else {
|
||||
val bytesToRead = minOf(buffer.size.toLong(), 4 * (samplesTotal - samplesReadCount))
|
||||
|
||||
UnsafeHelper.memcpyRaw(null, soundBuf!!.ptr, buffer, UnsafeHelper.getArrayOffset(buffer), bytesToRead)
|
||||
|
||||
samplesReadCount += bytesToRead / 4
|
||||
return bytesToRead.toInt()
|
||||
}
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
samplesReadCount = 0L
|
||||
gdxMusic.forceInvoke<Int>("reset", arrayOf())
|
||||
}
|
||||
|
||||
private fun getWavFileSampleCount(file: File): Long {
|
||||
@@ -133,14 +176,10 @@ data class MusicContainer(
|
||||
|
||||
override fun toString() = if (name.isEmpty()) file.nameWithoutExtension else name
|
||||
|
||||
fun reset() {
|
||||
samplesRead = 0L
|
||||
gdxMusic.forceInvoke<Int>("reset", arrayOf())
|
||||
}
|
||||
|
||||
override fun equals(other: Any?) = this.file.path == (other as MusicContainer).file.path
|
||||
|
||||
override fun dispose() {
|
||||
gdxMusic.dispose()
|
||||
soundBuf?.destroy()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user