mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
MusicContainer extracted out of the modulebasegame
This commit is contained in:
@@ -10,10 +10,8 @@ import com.badlogic.gdx.utils.JsonValue
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.reflection.extortField
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.audio.*
|
||||
import net.torvald.terrarum.gameworld.fmod
|
||||
import net.torvald.terrarum.modulebasegame.MusicContainer
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.PlaysMusic
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow
|
||||
|
||||
@@ -6,5 +6,5 @@ entrypoint=net.torvald.terrarum.musicplayer.EntryPoint
|
||||
releasedate=2024-02-10
|
||||
version=1.0.0
|
||||
jar=MusicPlayer.jar
|
||||
jarhash=7cadf1c1ffb8c87563413cabd3bab08c5111b045a7f02e770888188bca576445
|
||||
jarhash=3b8db936a76ffbd3fb4909de9582254e2ffc6eab7c4587ced0a738b21d05202a
|
||||
dependency=basegame 0.4.0
|
||||
|
||||
@@ -1221,7 +1221,7 @@ public class App implements ApplicationListener {
|
||||
|
||||
|
||||
audioBufferSize = getConfigInt("audio_buffer_size");
|
||||
audioMixer = new AudioMixer(audioBufferSize);
|
||||
audioMixer = new AudioMixer();
|
||||
audioMixerInitialised = true;
|
||||
audioManagerThread = new Thread(new AudioManagerRunnable(audioMixer), "TerrarumAudioManager");
|
||||
audioManagerThread.setPriority(MAX_PRIORITY); // higher = more predictable; audio delay is very noticeable so it gets high priority
|
||||
@@ -1257,7 +1257,7 @@ public class App implements ApplicationListener {
|
||||
audioMixer.dispose();
|
||||
|
||||
audioBufferSize = bufferSize;
|
||||
audioMixer = new AudioMixer(audioBufferSize);
|
||||
audioMixer = new AudioMixer();
|
||||
|
||||
// paste music tracks
|
||||
for (int i = 0; i < audioMixer.getDynamicTracks().length; i++) {
|
||||
|
||||
@@ -2,7 +2,6 @@ package net.torvald.terrarum.audio
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import net.torvald.terrarum.modulebasegame.MusicContainer
|
||||
import net.torvald.terrarum.tryDispose
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,6 @@ import net.torvald.terrarum.audio.dsp.*
|
||||
import net.torvald.terrarum.concurrent.ThreadExecutor
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.modulebasegame.BuildingMaker
|
||||
import net.torvald.terrarum.modulebasegame.MusicContainer
|
||||
import java.lang.Thread.MAX_PRIORITY
|
||||
import java.util.*
|
||||
import kotlin.math.*
|
||||
@@ -23,7 +22,7 @@ import kotlin.math.*
|
||||
*
|
||||
* Created by minjaesong on 2023-11-07.
|
||||
*/
|
||||
class AudioMixer(val bufferSize: Int): Disposable {
|
||||
class AudioMixer : Disposable {
|
||||
|
||||
companion object {
|
||||
const val SPEED_OF_SOUND_AIR = 340f
|
||||
|
||||
135
src/net/torvald/terrarum/audio/MusicContainer.kt
Normal file
135
src/net/torvald/terrarum/audio/MusicContainer.kt
Normal file
@@ -0,0 +1,135 @@
|
||||
package net.torvald.terrarum.audio
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.audio.Music
|
||||
import com.badlogic.gdx.backends.lwjgl3.audio.Mp3
|
||||
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.jcraft.jorbis.VorbisFile
|
||||
import javazoom.jl.decoder.Bitstream
|
||||
import net.torvald.reflection.extortField
|
||||
import net.torvald.reflection.forceInvoke
|
||||
import net.torvald.terrarum.App
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import javax.sound.sampled.AudioSystem
|
||||
|
||||
data class MusicContainer(
|
||||
val name: String,
|
||||
val file: File,
|
||||
val gdxMusic: Music,
|
||||
internal var songFinishedHook: (Music) -> Unit = {}
|
||||
) {
|
||||
val samplingRate: Int
|
||||
val codec: String
|
||||
|
||||
var samplesRead = 0L; internal set
|
||||
val samplesTotal: Long
|
||||
|
||||
init {
|
||||
gdxMusic.setOnCompletionListener(songFinishedHook)
|
||||
|
||||
samplingRate = when (gdxMusic) {
|
||||
is Wav.Music -> {
|
||||
val rate = gdxMusic.extortField<Wav.WavInputStream>("input")!!.sampleRate
|
||||
|
||||
App.printdbg(this, "music $name is WAV; rate = $rate")
|
||||
rate
|
||||
}
|
||||
is Ogg.Music -> {
|
||||
val rate = gdxMusic.extortField<OggInputStream>("input")!!.sampleRate
|
||||
|
||||
App.printdbg(this, "music $name is OGG; rate = $rate")
|
||||
rate
|
||||
}
|
||||
is Mp3.Music -> {
|
||||
val tempMusic = Gdx.audio.newMusic(Gdx.files.absolute(file.absolutePath))
|
||||
val bitstream = tempMusic.extortField<Bitstream>("bitstream")!!
|
||||
val header = bitstream.readFrame()
|
||||
val rate = header.sampleRate
|
||||
tempMusic.dispose()
|
||||
|
||||
// val bitstream = gdxMusic.extortField<Bitstream>("bitstream")!!
|
||||
// val header = bitstream.readFrame()
|
||||
// val rate = header.sampleRate
|
||||
// gdxMusic.reset()
|
||||
|
||||
App.printdbg(this, "music $name is MP3; rate = $rate")
|
||||
rate
|
||||
}
|
||||
else -> {
|
||||
App.printdbg(this, "music $name is ${gdxMusic::class.qualifiedName}; rate = default")
|
||||
TerrarumAudioMixerTrack.SAMPLING_RATE
|
||||
}
|
||||
}
|
||||
|
||||
codec = gdxMusic::class.qualifiedName!!.split('.').let {
|
||||
if (it.last() == "Music") it.dropLast(1).last() else it.last()
|
||||
}
|
||||
|
||||
samplesTotal = when (gdxMusic) {
|
||||
is Wav.Music -> getWavFileSampleCount(file)
|
||||
is Ogg.Music -> getOggFileSampleCount(file)
|
||||
is Mp3.Music -> getMp3FileSampleCount(file)
|
||||
else -> Long.MAX_VALUE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun getWavFileSampleCount(file: File): Long {
|
||||
return try {
|
||||
val ais = AudioSystem.getAudioInputStream(file)
|
||||
val r = ais.frameLength
|
||||
ais.close()
|
||||
r
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
Long.MAX_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOggFileSampleCount(file: File): Long {
|
||||
return try {
|
||||
val vorbisFile = VorbisFile(file.absolutePath)
|
||||
vorbisFile.pcm_total(0)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
Long.MAX_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMp3FileSampleCount(file: File): Long {
|
||||
return try {
|
||||
val fis = FileInputStream(file)
|
||||
val bs = Bitstream(fis)
|
||||
|
||||
var header = bs.readFrame()
|
||||
val rate = header.frequency()
|
||||
var totalSamples = 0L
|
||||
|
||||
while (header != null) {
|
||||
totalSamples += (header.ms_per_frame() * rate / 1000).toLong()
|
||||
bs.closeFrame()
|
||||
header = bs.readFrame()
|
||||
}
|
||||
|
||||
bs.close()
|
||||
fis.close()
|
||||
|
||||
totalSamples
|
||||
}
|
||||
catch (_: Throwable) {
|
||||
Long.MAX_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import net.torvald.terrarum.audio.dsp.TerrarumAudioFilter
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.getHashStr
|
||||
import net.torvald.terrarum.hashStrMap
|
||||
import net.torvald.terrarum.modulebasegame.MusicContainer
|
||||
import kotlin.math.log10
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.INGAME
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.audio.MusicContainer
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import net.torvald.terrarum.audio.TrackVolume
|
||||
import net.torvald.terrarum.modulebasegame.MusicContainer
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
||||
import net.torvald.terrarum.savegame.toBigEndian
|
||||
|
||||
@@ -1,145 +1,14 @@
|
||||
package net.torvald.terrarum.modulebasegame
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.audio.Music
|
||||
import com.badlogic.gdx.backends.lwjgl3.audio.Mp3
|
||||
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.backends.lwjgl3.audio.Wav.WavInputStream
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import com.jcraft.jorbis.VorbisFile
|
||||
import com.jme3.math.FastMath
|
||||
import javazoom.jl.decoder.Bitstream
|
||||
import net.torvald.reflection.extortField
|
||||
import net.torvald.reflection.forceInvoke
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.audio.AudioMixer
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATE
|
||||
import net.torvald.terrarum.audio.MusicContainer
|
||||
import net.torvald.terrarum.gameworld.WorldTime.Companion.DAY_LENGTH
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import javax.sound.sampled.AudioSystem
|
||||
|
||||
data class MusicContainer(
|
||||
val name: String,
|
||||
val file: File,
|
||||
val gdxMusic: Music,
|
||||
internal var songFinishedHook: (Music) -> Unit = {}
|
||||
) {
|
||||
val samplingRate: Int
|
||||
val codec: String
|
||||
|
||||
var samplesRead = 0L; internal set
|
||||
val samplesTotal: Long
|
||||
|
||||
init {
|
||||
gdxMusic.setOnCompletionListener(songFinishedHook)
|
||||
|
||||
samplingRate = when (gdxMusic) {
|
||||
is Wav.Music -> {
|
||||
val rate = gdxMusic.extortField<WavInputStream>("input")!!.sampleRate
|
||||
|
||||
printdbg(this, "music $name is WAV; rate = $rate")
|
||||
rate
|
||||
}
|
||||
is Ogg.Music -> {
|
||||
val rate = gdxMusic.extortField<OggInputStream>("input")!!.sampleRate
|
||||
|
||||
printdbg(this, "music $name is OGG; rate = $rate")
|
||||
rate
|
||||
}
|
||||
is Mp3.Music -> {
|
||||
val tempMusic = Gdx.audio.newMusic(Gdx.files.absolute(file.absolutePath))
|
||||
val bitstream = tempMusic.extortField<Bitstream>("bitstream")!!
|
||||
val header = bitstream.readFrame()
|
||||
val rate = header.sampleRate
|
||||
tempMusic.dispose()
|
||||
|
||||
// val bitstream = gdxMusic.extortField<Bitstream>("bitstream")!!
|
||||
// val header = bitstream.readFrame()
|
||||
// val rate = header.sampleRate
|
||||
// gdxMusic.reset()
|
||||
|
||||
printdbg(this, "music $name is MP3; rate = $rate")
|
||||
rate
|
||||
}
|
||||
else -> {
|
||||
printdbg(this, "music $name is ${gdxMusic::class.qualifiedName}; rate = default")
|
||||
SAMPLING_RATE
|
||||
}
|
||||
}
|
||||
|
||||
codec = gdxMusic::class.qualifiedName!!.split('.').let {
|
||||
if (it.last() == "Music") it.dropLast(1).last() else it.last()
|
||||
}
|
||||
|
||||
samplesTotal = when (gdxMusic) {
|
||||
is Wav.Music -> getWavFileSampleCount(file)
|
||||
is Ogg.Music -> getOggFileSampleCount(file)
|
||||
is Mp3.Music -> getMp3FileSampleCount(file)
|
||||
else -> Long.MAX_VALUE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun getWavFileSampleCount(file: File): Long {
|
||||
return try {
|
||||
val ais = AudioSystem.getAudioInputStream(file)
|
||||
val r = ais.frameLength
|
||||
ais.close()
|
||||
r
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
Long.MAX_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOggFileSampleCount(file: File): Long {
|
||||
return try {
|
||||
val vorbisFile = VorbisFile(file.absolutePath)
|
||||
vorbisFile.pcm_total(0)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
Long.MAX_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMp3FileSampleCount(file: File): Long {
|
||||
return try {
|
||||
val fis = FileInputStream(file)
|
||||
val bs = Bitstream(fis)
|
||||
|
||||
var header = bs.readFrame()
|
||||
val rate = header.frequency()
|
||||
var totalSamples = 0L
|
||||
|
||||
while (header != null) {
|
||||
totalSamples += (header.ms_per_frame() * rate / 1000).toLong()
|
||||
bs.closeFrame()
|
||||
header = bs.readFrame()
|
||||
}
|
||||
|
||||
bs.close()
|
||||
fis.close()
|
||||
|
||||
totalSamples
|
||||
}
|
||||
catch (_: Throwable) {
|
||||
Long.MAX_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
class TerrarumMusicGovernor : MusicGovernor() {
|
||||
private val STATE_INIT = 0
|
||||
|
||||
@@ -11,6 +11,7 @@ import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
||||
import net.torvald.terrarum.audio.AudioMixer.Companion.DEFAULT_FADEOUT_LEN
|
||||
import net.torvald.terrarum.audio.MusicContainer
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import net.torvald.terrarum.audio.dsp.NullFilter
|
||||
import net.torvald.terrarum.audio.dsp.Phono
|
||||
@@ -20,7 +21,6 @@ import net.torvald.terrarum.gameactors.Hitbox
|
||||
import net.torvald.terrarum.gameactors.Lightbox
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.MusicContainer
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumMusicGovernor
|
||||
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
|
||||
import net.torvald.terrarum.modulebasegame.gameitems.ItemFileRef
|
||||
|
||||
@@ -5,12 +5,12 @@ import net.torvald.spriteanimation.SheetSpriteAnimation
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.audio.AudioMixer
|
||||
import net.torvald.terrarum.audio.MusicContainer
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.MusicContainer
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumMusicGovernor
|
||||
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
|
||||
import net.torvald.terrarum.modulebasegame.gameitems.ItemFileRef
|
||||
|
||||
Reference in New Issue
Block a user