mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
musicplayer: playlist printing
This commit is contained in:
@@ -21,6 +21,7 @@ import net.torvald.terrarum.utils.JsonFetcher
|
|||||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction
|
import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction
|
||||||
import org.apache.commons.math3.analysis.interpolation.SplineInterpolator
|
import org.apache.commons.math3.analysis.interpolation.SplineInterpolator
|
||||||
|
import java.util.BitSet
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,36 +86,6 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
|||||||
|
|
||||||
private val colourControlButton = Color(0xeeeeee_cc.toInt())
|
private val colourControlButton = Color(0xeeeeee_cc.toInt())
|
||||||
|
|
||||||
init {
|
|
||||||
if (App.getConfigBoolean("musicplayer:usemusicplayer")) {
|
|
||||||
setAsAlwaysVisible()
|
|
||||||
|
|
||||||
// test code
|
|
||||||
// val albumDir = App.customMusicDir + "/Gapless Test 2"
|
|
||||||
val albumDir = App.customMusicDir + "/FurryJoA 2023 Live"
|
|
||||||
// val albumDir = App.customMusicDir + "/Audio Test"
|
|
||||||
val playlistFile = JsonFetcher.invoke("$albumDir/playlist.json")
|
|
||||||
|
|
||||||
val diskJockeyingMode = playlistFile.get("diskJockeyingMode").asString()
|
|
||||||
val shuffled = playlistFile.get("shuffled").asBoolean()
|
|
||||||
val fileToName = playlistFile.get("titles")
|
|
||||||
|
|
||||||
|
|
||||||
AudioMixer.musicTrack.let { track ->
|
|
||||||
track.doGaplessPlayback = (diskJockeyingMode == "continuous")
|
|
||||||
if (track.doGaplessPlayback) {
|
|
||||||
track.pullNextTrack = {
|
|
||||||
track.currentTrack = ingame.musicGovernor.pullNextMusicTrack(true)
|
|
||||||
setMusicName(track.currentTrack?.name ?: "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
registerPlaylist(albumDir, fileToName, shuffled, diskJockeyingMode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val playlist: List<MusicContainer>
|
private val playlist: List<MusicContainer>
|
||||||
get() = ingame.musicGovernor.extortField<List<MusicContainer>>("songs")!!
|
get() = ingame.musicGovernor.extortField<List<MusicContainer>>("songs")!!
|
||||||
private val playlistName: String
|
private val playlistName: String
|
||||||
@@ -146,6 +117,8 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPlaylistDisplayVars(playlist)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var currentMusicName = ""
|
private var currentMusicName = ""
|
||||||
@@ -223,6 +196,32 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode >= MODE_SHOW_LIST) {
|
||||||
|
for (i in playlistNameScrolls.indices) {
|
||||||
|
if (playlistNameOverflown[i]) { // name overflown
|
||||||
|
when (musicPlayingTimer % 60f) {
|
||||||
|
// start scroll
|
||||||
|
in 0f..5f -> {
|
||||||
|
playlistNameScrolls[i] = 0f
|
||||||
|
}
|
||||||
|
in 5f..10f -> {
|
||||||
|
playlistNameScrolls[i] = (playlistNameScrolls[i] + NAME_SCROLL_PER_SECOND * delta).coerceIn(0f, (playlistRealNameLen[i] - playlistNameLenMax).toFloat())
|
||||||
|
}
|
||||||
|
in 10f..15f -> {
|
||||||
|
playlistNameScrolls[i] = (playlistRealNameLen[i] - playlistNameLenMax).toFloat()
|
||||||
|
}
|
||||||
|
// start unscroll
|
||||||
|
in 15f..20f -> {
|
||||||
|
playlistNameScrolls[i] = (playlistNameScrolls[i] - NAME_SCROLL_PER_SECOND * delta).coerceIn(0f, (playlistRealNameLen[i] - playlistNameLenMax).toFloat())
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
playlistNameScrolls[i] = 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
musicPlayingTimer += delta
|
musicPlayingTimer += delta
|
||||||
}
|
}
|
||||||
@@ -527,8 +526,8 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
|||||||
val drawAlpha = 0.75f * (if (reverse) 1f - alpha0 else alpha0).pow(3f)// + (playListAnimAkku[i].pow(2f) * 1.2f)
|
val drawAlpha = 0.75f * (if (reverse) 1f - alpha0 else alpha0).pow(3f)// + (playListAnimAkku[i].pow(2f) * 1.2f)
|
||||||
|
|
||||||
// assuming both view has the same list dimension
|
// assuming both view has the same list dimension
|
||||||
drawAlbumList(camera, delta, batch, (anchorX + offX2).roundToFloat(), (y + 11).roundToFloat(), drawAlpha * alpha1, width / (widthForList + METERS_WIDTH + maskOffWidth))
|
drawAlbumList(camera, delta, batch, (anchorX + offX2).roundToFloat(), (y + 5).roundToFloat(), drawAlpha * alpha1, width / (widthForList + METERS_WIDTH + maskOffWidth))
|
||||||
drawPlayList(camera, delta, batch, (anchorX + offX1).roundToFloat(), (y + 11).roundToFloat(), drawAlpha * alpha2, width / (widthForList + METERS_WIDTH + maskOffWidth))
|
drawPlayList(camera, delta, batch, (anchorX + offX1).roundToFloat(), (y + 5).roundToFloat(), drawAlpha * alpha2, width / (widthForList + METERS_WIDTH + maskOffWidth))
|
||||||
|
|
||||||
// update playListAnimAkku
|
// update playListAnimAkku
|
||||||
for (i in playListAnimAkku.indices) {
|
for (i in playListAnimAkku.indices) {
|
||||||
@@ -550,13 +549,33 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
|||||||
private val widthForMouseUp = (nameStrMaxLen + METERS_WIDTH + maskOffWidth).toInt()
|
private val widthForMouseUp = (nameStrMaxLen + METERS_WIDTH + maskOffWidth).toInt()
|
||||||
private val heightThin = 28
|
private val heightThin = 28
|
||||||
private val heightControl = 80
|
private val heightControl = 80
|
||||||
private val heightList = 109 + PLAYLIST_LINES * PLAYLIST_LINE_HEIGHT.toInt()
|
private val heightList = 103 + PLAYLIST_LINES * PLAYLIST_LINE_HEIGHT.toInt()
|
||||||
|
|
||||||
|
private val playlistNameLenMax = widthForList - 2*maskOffWidth
|
||||||
private var playlistScroll = 0
|
private var playlistScroll = 0
|
||||||
|
|
||||||
private val playlistFBOs = Array(PLAYLIST_LINES) {
|
private val playlistFBOs = Array(PLAYLIST_LINES) {
|
||||||
FrameBuffer(Pixmap.Format.RGBA8888, PLAYLIST_NAME_LEN, PLAYLIST_LINE_HEIGHT.toInt(), false)
|
FrameBuffer(Pixmap.Format.RGBA8888, PLAYLIST_NAME_LEN, PLAYLIST_LINE_HEIGHT.toInt(), false)
|
||||||
}
|
}
|
||||||
|
private val playlistNameScrolls = FloatArray(1024) // use absolute index
|
||||||
|
private val playlistRealNameLen = IntArray(1024) // use absolute index
|
||||||
|
private val playlistNameOverflown = BitSet(1024) // use absolute index
|
||||||
|
|
||||||
|
private fun resetPlaylistDisplay() {
|
||||||
|
playlistScroll = 0
|
||||||
|
playlistNameScrolls.fill(0f)
|
||||||
|
playlistNameOverflown.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setPlaylistDisplayVars(plist: List<MusicContainer>) {
|
||||||
|
resetPlaylistDisplay()
|
||||||
|
plist.forEachIndexed { i, music ->
|
||||||
|
val len = App.fontGameFBO.getWidth(music.name)
|
||||||
|
val overflown = (len >= playlistNameLenMax)
|
||||||
|
playlistRealNameLen[i] = len
|
||||||
|
if (overflown) playlistNameOverflown.set(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun drawPlayList(camera: OrthographicCamera, delta: Float, batch: SpriteBatch, x: Float, y: Float, alpha: Float, scale: Float) {
|
private fun drawPlayList(camera: OrthographicCamera, delta: Float, batch: SpriteBatch, x: Float, y: Float, alpha: Float, scale: Float) {
|
||||||
batch.end()
|
batch.end()
|
||||||
@@ -569,7 +588,7 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
|||||||
blendNormalStraightAlpha(batch)
|
blendNormalStraightAlpha(batch)
|
||||||
|
|
||||||
// draw text
|
// draw text
|
||||||
App.fontGameFBO.draw(batch, if (i + playlistScroll in playlist.indices) playlist[i].name else "", maskOffWidth.toFloat(), (PLAYLIST_LINE_HEIGHT - 24) / 2)
|
App.fontGameFBO.draw(batch, if (i + playlistScroll in playlist.indices) playlist[i].name else "", maskOffWidth - playlistNameScrolls[i + playlistScroll], (PLAYLIST_LINE_HEIGHT - 24) / 2)
|
||||||
|
|
||||||
// mask off the area
|
// mask off the area
|
||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
@@ -588,15 +607,33 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
|||||||
blendNormalStraightAlpha(batch)
|
blendNormalStraightAlpha(batch)
|
||||||
if (alpha > 0f) {
|
if (alpha > 0f) {
|
||||||
playlistFBOs.forEachIndexed { i, it ->
|
playlistFBOs.forEachIndexed { i, it ->
|
||||||
batch.color = Color(1f, 1f, 1f, alpha)
|
val m1 = playlist.getOrNull(i + playlistScroll)
|
||||||
|
val m2 = AudioMixer.musicTrack.currentTrack
|
||||||
|
val currentlyPlaying = if (m1 == null || m2 == null) false else (m1 == m2)
|
||||||
|
|
||||||
// print number
|
// print number
|
||||||
val xoff = maskOffWidth + (if (i < 9) 3 else 0)
|
|
||||||
val yoff = 8 + (PLAYLIST_LINE_HEIGHT - 24) / 2
|
// print bars instead of numbers if the song is currently being played
|
||||||
App.fontSmallNumbers.draw(batch, if (i + playlistScroll in playlist.indices) "${i + playlistScroll + 1}" else "", x + xoff, y + yoff + PLAYLIST_LINE_HEIGHT * i * scale)
|
if (currentlyPlaying) {
|
||||||
// TODO draw playing marker if the song is being played
|
val xoff = 5
|
||||||
|
val yoff = 5 + 7 + (PLAYLIST_LINE_HEIGHT - 24) / 2
|
||||||
|
// it will set the colour on its own
|
||||||
|
drawFreqMeter(batch, x + xoff, y + yoff + PLAYLIST_LINE_HEIGHT * i * scale, alpha)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val xoff = maskOffWidth + (if (i < 9) 3 else 0)
|
||||||
|
val yoff = 7 + (PLAYLIST_LINE_HEIGHT - 24) / 2
|
||||||
|
batch.color = Color(1f, 1f, 1f, alpha * 0.75f)
|
||||||
|
App.fontSmallNumbers.draw(
|
||||||
|
batch,
|
||||||
|
if (i + playlistScroll in playlist.indices) "${i + playlistScroll + 1}" else "",
|
||||||
|
x + xoff,
|
||||||
|
y + yoff + PLAYLIST_LINE_HEIGHT * i * scale
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// print the name
|
// print the name
|
||||||
|
batch.color = Color(1f, 1f, 1f, alpha)
|
||||||
batch.draw(it.colorBufferTexture, x + PLAYLIST_LEFT_GAP * scale, y + PLAYLIST_LINE_HEIGHT * i * scale, it.width * scale, it.height * scale)
|
batch.draw(it.colorBufferTexture, x + PLAYLIST_LEFT_GAP * scale, y + PLAYLIST_LINE_HEIGHT * i * scale, it.width * scale, it.height * scale)
|
||||||
|
|
||||||
// separator
|
// separator
|
||||||
@@ -741,9 +778,7 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FFT.fftInto(chsum, fftOut)
|
FFT.fftInto(chsum, fftOut)
|
||||||
}
|
|
||||||
|
|
||||||
private fun drawFreqMeter(batch: SpriteBatch, posX: Float, posY: Float) {
|
|
||||||
// apply slope to the fft bins, also converts fullscale to decibels
|
// apply slope to the fft bins, also converts fullscale to decibels
|
||||||
for (bin in binHeights.indices) {
|
for (bin in binHeights.indices) {
|
||||||
val freqR = (TerrarumAudioMixerTrack.SAMPLING_RATED / FFTSIZE) * (bin + 1)
|
val freqR = (TerrarumAudioMixerTrack.SAMPLING_RATED / FFTSIZE) * (bin + 1)
|
||||||
@@ -757,17 +792,19 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
|||||||
|
|
||||||
oldFFTmagn[bin] = magn
|
oldFFTmagn[bin] = magn
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun drawFreqMeter(batch: SpriteBatch, posX: Float, posY: Float, alpha: Float = 1f) {
|
||||||
fftBinIndices.mapIndexed { i, range ->
|
fftBinIndices.mapIndexed { i, range ->
|
||||||
fftBarHeights[i] = binHeights.slice(range).average().toFloat()
|
fftBarHeights[i] = binHeights.slice(range).average().toFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.color = colourMeter2
|
batch.color = colourMeter2 mul Color(1f, 1f, 1f, alpha)
|
||||||
fftBarHeights.forEachIndexed { index, h ->
|
fftBarHeights.forEachIndexed { index, h ->
|
||||||
Toolkit.fillArea(batch, posX + index*4f, posY - h, 3f, 2*h + 1)
|
Toolkit.fillArea(batch, posX + index*4f, posY - h, 3f, 2*h + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.color = colourMeter
|
batch.color = colourMeter mul Color(1f, 1f, 1f, alpha)
|
||||||
fftBarHeights.forEachIndexed { index, h ->
|
fftBarHeights.forEachIndexed { index, h ->
|
||||||
Toolkit.fillArea(batch, posX + index*4f, posY - h, 2f, 2*h)
|
Toolkit.fillArea(batch, posX + index*4f, posY - h, 2f, 2*h)
|
||||||
}
|
}
|
||||||
@@ -809,4 +846,36 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun Float.organicOvershoot() = splineFunction.value(this.toDouble()).toFloat()
|
private fun Float.organicOvershoot() = splineFunction.value(this.toDouble()).toFloat()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (App.getConfigBoolean("musicplayer:usemusicplayer")) {
|
||||||
|
setAsAlwaysVisible()
|
||||||
|
|
||||||
|
// test code
|
||||||
|
// val albumDir = App.customMusicDir + "/Gapless Test 2"
|
||||||
|
val albumDir = App.customMusicDir + "/FurryJoA 2023 Live"
|
||||||
|
// val albumDir = App.customMusicDir + "/Audio Test"
|
||||||
|
val playlistFile = JsonFetcher.invoke("$albumDir/playlist.json")
|
||||||
|
|
||||||
|
val diskJockeyingMode = playlistFile.get("diskJockeyingMode").asString()
|
||||||
|
val shuffled = playlistFile.get("shuffled").asBoolean()
|
||||||
|
val fileToName = playlistFile.get("titles")
|
||||||
|
|
||||||
|
|
||||||
|
AudioMixer.musicTrack.let { track ->
|
||||||
|
track.doGaplessPlayback = (diskJockeyingMode == "continuous")
|
||||||
|
if (track.doGaplessPlayback) {
|
||||||
|
track.pullNextTrack = {
|
||||||
|
track.currentTrack = ingame.musicGovernor.pullNextMusicTrack(true)
|
||||||
|
setMusicName(track.currentTrack?.name ?: "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
registerPlaylist(albumDir, fileToName, shuffled, diskJockeyingMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user