Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow volume control of Music & Sound with property #1311

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 46 additions & 14 deletions fxgl-core/src/main/kotlin/com/almasb/fxgl/audio/Audio.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
package com.almasb.fxgl.audio

import com.almasb.fxgl.core.Disposable
import javafx.beans.property.DoubleProperty
import javafx.beans.property.SimpleDoubleProperty

enum class AudioType {
MUSIC, SOUND
enum class AudioType(val volume: DoubleProperty) {
MUSIC(SimpleDoubleProperty(0.5)),
SOUND(SimpleDoubleProperty(0.5))
}

/**
Expand All @@ -19,6 +22,10 @@ enum class AudioType {
*/
abstract class Audio(val type: AudioType) {

internal fun mix(volume: Double) : Double {
return type.volume.value * volume
}

abstract fun setLooping(looping: Boolean)

abstract fun setVolume(volume: Double)
Expand Down Expand Up @@ -52,31 +59,56 @@ private val audio: Audio by lazy {

fun getDummyAudio() = audio

abstract class Media(internal val audio : Audio) : Disposable {

internal var isDisposed = false
internal val volume = SimpleDoubleProperty(1.0)

init {
audio.type.volume.addListener { _, _, _ ->
audio.setVolume(volume.value)
}
volume.addListener { _, _, _ ->
audio.setVolume(volume.value)
}
}

fun setVolume(value: Double) {
volume.value = value
}

fun getVolume() : Double {
return volume.value
}

fun volumeProperty() : DoubleProperty {
return volume
}

fun setLooping(looping: Boolean) {
audio.setLooping(looping)
}

override fun dispose() {
isDisposed = true
}
}

/**
* Represents a long-term audio in mp3 file.
* Use for background (looping) music or recorded dialogues.
*
* @author Almas Baimagambetov (AlmasB) (almaslvl@gmail.com)
*/
class Music(val audio: Audio) : Disposable {
class Music(audio : Audio) : Media(audio) {

internal var isDisposed = false

override fun dispose() {
isDisposed = true
}
}

/**
* Represents a short sound in .wav file.
*
* @author Almas Baimagambetov (AlmasB) (almaslvl@gmail.com)
*/
class Sound(val audio: Audio) : Disposable {

internal var isDisposed = false
class Sound(audio : Audio) : Media(audio) {

override fun dispose() {
isDisposed = true
}
}
20 changes: 1 addition & 19 deletions fxgl-core/src/main/kotlin/com/almasb/fxgl/audio/AudioPlayer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import com.almasb.fxgl.core.EngineService
import com.almasb.fxgl.core.Inject
import com.almasb.fxgl.core.collection.UnorderedArray
import com.almasb.fxgl.logging.Logger
import javafx.beans.property.DoubleProperty
import java.net.URL

/**
Expand All @@ -27,27 +26,11 @@ class AudioPlayer : EngineService() {
private val activeMusic = UnorderedArray<Music>()
private val activeSounds = UnorderedArray<Sound>()

@Inject("globalMusicVolumeProperty")
private lateinit var musicVolume: DoubleProperty

@Inject("globalSoundVolumeProperty")
private lateinit var soundVolume: DoubleProperty

@Inject("isPauseMusicWhenMinimized")
private var isPauseMusicWhenMinimized = true

private val loader = DesktopAndMobileAudioLoader()

override fun onMainLoopStarting() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automatically handled by the Audio with Property change listeners

musicVolume.addListener { _, _, newVolume ->
activeMusic.forEach { it.audio.setVolume(newVolume.toDouble()) }
}

soundVolume.addListener { _, _, newVolume ->
activeSounds.forEach { it.audio.setVolume(newVolume.toDouble()) }
}
}

override fun onMainLoopPausing() {
if (isPauseMusicWhenMinimized) {
pauseAllMusic()
Expand All @@ -74,7 +57,6 @@ class AudioPlayer : EngineService() {
if (!activeSounds.containsByIdentity(sound))
activeSounds.add(sound)

sound.audio.setVolume(soundVolume.value)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need anymore, the global volumes are automatically mixed with the Media configured sound

sound.audio.play()
}

Expand Down Expand Up @@ -106,7 +88,6 @@ class AudioPlayer : EngineService() {
activeMusic.add(music)
}

music.audio.setVolume(musicVolume.value)
music.audio.play()
}

Expand Down Expand Up @@ -192,4 +173,5 @@ class AudioPlayer : EngineService() {
fun loadAudio(audioType: AudioType, url: URL, isMobile: Boolean): Audio {
return loader.loadAudio(audioType, url, isMobile)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class DesktopAndMobileAudioLoader : AudioLoader {
}

override fun setVolume(volume: Double) {
nativeAudio.ifPresent { it.setVolume(volume) }
nativeAudio.ifPresent { it.setVolume(mix(volume)) }
}

override fun setOnFinished(action: Runnable) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class DesktopMusic(private val mediaPlayer: MediaPlayer) : Audio(AudioType.MUSIC
}

override fun setVolume(volume: Double) {
mediaPlayer.volume = volume
mediaPlayer.volume = mix(volume)
}

override fun setOnFinished(action: Runnable) {
Expand Down Expand Up @@ -52,7 +52,7 @@ class DesktopSound(private val clip: AudioClip) : Audio(AudioType.SOUND) {
}

override fun setVolume(volume: Double) {
clip.volume = volume
clip.volume = mix(volume)
}

override fun setOnFinished(action: Runnable) {
Expand Down
32 changes: 6 additions & 26 deletions fxgl/src/main/kotlin/com/almasb/fxgl/app/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.almasb.fxgl.achievement.AchievementService
import com.almasb.fxgl.app.scene.SceneFactory
import com.almasb.fxgl.app.services.*
import com.almasb.fxgl.audio.AudioPlayer
import com.almasb.fxgl.audio.AudioType
import com.almasb.fxgl.core.EngineService
import com.almasb.fxgl.core.math.FXGLMath
import com.almasb.fxgl.core.serialization.Bundle
Expand Down Expand Up @@ -765,28 +766,6 @@ class ReadOnlyGameSettings internal constructor(
get() = gameDifficultyProp.value
set(value) { gameDifficultyProp.value = value }

@get:JvmName("globalMusicVolumeProperty")
val globalMusicVolumeProperty = SimpleDoubleProperty(0.5)

/**
* Set global music volume in the range [0..1],
* where 0 = 0%, 1 = 100%.
*/
var globalMusicVolume: Double
get() = globalMusicVolumeProperty.value
set(value) { globalMusicVolumeProperty.value = value }

@get:JvmName("globalSoundVolumeProperty")
val globalSoundVolumeProperty = SimpleDoubleProperty(0.5)

/**
* Set global sound volume in the range [0..1],
* where 0 = 0%, 1 = 100%.
*/
var globalSoundVolume: Double
get() = globalSoundVolumeProperty.value
set(value) { globalSoundVolumeProperty.value = value }

private val mouseSensitivityProp = SimpleDoubleProperty(mouseSensitivity)

var mouseSensitivity: Double
Expand All @@ -804,15 +783,16 @@ class ReadOnlyGameSettings internal constructor(

override fun write(bundle: Bundle) {
bundle.put("fullscreen", fullScreen.value)
bundle.put("globalMusicVolume", globalMusicVolume)
bundle.put("globalSoundVolume", globalSoundVolume)

bundle.put("globalMusicVolume", AudioType.MUSIC.volume.value)
bundle.put("globalSoundVolume", AudioType.SOUND.volume.value)
}

override fun read(bundle: Bundle) {
fullScreen.value = bundle.get("fullscreen")

globalMusicVolume = bundle.get("globalMusicVolume")
globalSoundVolume = bundle.get("globalSoundVolume")
AudioType.MUSIC.volume.value = bundle.get("globalMusicVolume")
AudioType.SOUND.volume.value = bundle.get("globalSoundVolume")

applySettings()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.almasb.fxgl.animation.Animation
import com.almasb.fxgl.animation.Interpolators
import com.almasb.fxgl.app.ApplicationMode
import com.almasb.fxgl.app.MenuItem
import com.almasb.fxgl.audio.AudioType
import com.almasb.fxgl.core.math.FXGLMath.noise1D
import com.almasb.fxgl.core.util.InputPredicates
import com.almasb.fxgl.dsl.*
Expand Down Expand Up @@ -699,7 +700,7 @@ open class FXGLDefaultMenu(type: MenuType) : FXGLMenu(type) {
val sliderMusic = getUIFactoryService().newSlider()
sliderMusic.min = 0.0
sliderMusic.max = 1.0
sliderMusic.valueProperty().bindBidirectional(getSettings().globalMusicVolumeProperty)
sliderMusic.valueProperty().bindBidirectional(AudioType.MUSIC.volume)

val textMusic = getUIFactoryService().newText(localizedStringProperty("menu.music.volume").concat(": "))
val percentMusic = getUIFactoryService().newText("")
Expand All @@ -708,7 +709,7 @@ open class FXGLDefaultMenu(type: MenuType) : FXGLMenu(type) {
val sliderSound = getUIFactoryService().newSlider()
sliderSound.min = 0.0
sliderSound.max = 1.0
sliderSound.valueProperty().bindBidirectional(getSettings().globalSoundVolumeProperty)
sliderSound.valueProperty().bindBidirectional(AudioType.SOUND.volume)

val textSound = getUIFactoryService().newText(localizedStringProperty("menu.sound.volume").concat(": "))
val percentSound = getUIFactoryService().newText("")
Expand Down