Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 27 additions & 22 deletions src/main/scala/li/cil/oc/client/Sound.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ import paulscode.sound.SoundSystemConfig
import java.net.{MalformedURLException, URL, URLConnection, URLStreamHandler}
import java.util.UUID
import scala.collection.mutable
import scala.ref.WeakReference

object Sound {

private val sources = mutable.Map.empty[TileEntity, PseudoLoopingStream]
private val sources = mutable.WeakHashMap.empty[TileEntity, PseudoLoopingStream]
private val commandQueue = mutable.PriorityQueue.empty[Command]
private var lastVolume = FMLClientHandler.instance.getClient.gameSettings.getSoundLevel(SoundCategory.BLOCKS)

Expand Down Expand Up @@ -52,34 +53,38 @@ object Sound {
if (commandQueue.nonEmpty) {
commandQueue.synchronized {
while (commandQueue.nonEmpty && commandQueue.head.when < System.currentTimeMillis()) {
try commandQueue.dequeue()() catch {
case t: Throwable => OpenComputers.log.warn("Error processing sound command.", t)
if (commandQueue.head.tileEntity.get.isEmpty) {
commandQueue.dequeue()
} else {
try commandQueue.dequeue()() catch {
case t: Throwable => OpenComputers.log.warn("Error processing sound command.", t)
}
}
}
}
}
}

def startLoop(tileEntity: TileEntity, name: String, volume: Float = 1f, delay: Long = 0) {
if (Settings.get.soundVolume > 0 && Minecraft.getMinecraft.theWorld != null) {
if (Settings.get.soundVolume > 0) {
commandQueue.synchronized {
commandQueue += new StartCommand(System.currentTimeMillis() + delay, tileEntity, name, volume)
commandQueue += new StartCommand(System.currentTimeMillis() + delay, new WeakReference[TileEntity](tileEntity), name, volume)
}
}
}

def stopLoop(tileEntity: TileEntity) {
if (Settings.get.soundVolume > 0 && Minecraft.getMinecraft.theWorld != null) {
if (Settings.get.soundVolume > 0) {
commandQueue.synchronized {
commandQueue += new StopCommand(tileEntity)
commandQueue += new StopCommand(new WeakReference[TileEntity](tileEntity))
}
}
}

def updatePosition(tileEntity: TileEntity) {
if (Settings.get.soundVolume > 0 && Minecraft.getMinecraft.theWorld != null) {
if (Settings.get.soundVolume > 0) {
commandQueue.synchronized {
commandQueue += new UpdatePositionCommand(tileEntity)
commandQueue += new UpdatePositionCommand(new WeakReference[TileEntity](tileEntity))
}
}
}
Expand Down Expand Up @@ -107,31 +112,31 @@ object Sound {

@SubscribeEvent(priority = EventPriority.LOWEST)
def onWorldUnload(event: WorldEvent.Unload) {
commandQueue.synchronized(commandQueue.clear())
sources.synchronized(try sources.foreach(_._2.stop()) catch {
case _: Throwable => // Ignore.
})
sources.synchronized(sources.clear())
commandQueue.synchronized(commandQueue.clear())
sources.clear()
}

private abstract class Command(val when: Long, val tileEntity: TileEntity) extends Ordered[Command] {
private abstract class Command(val when: Long, val tileEntity: WeakReference[TileEntity]) extends Ordered[Command] {
def apply(): Unit

override def compare(that: Command) = (that.when - when).toInt
}

private class StartCommand(when: Long, tileEntity: TileEntity, val name: String, val volume: Float) extends Command(when, tileEntity) {
private class StartCommand(when: Long, tileEntity: WeakReference[TileEntity], val name: String, val volume: Float) extends Command(when, tileEntity) {
override def apply() {
sources.synchronized {
sources.getOrElseUpdate(tileEntity, new PseudoLoopingStream(tileEntity, volume)).play(name)
sources.getOrElseUpdate(tileEntity.get.get, new PseudoLoopingStream(tileEntity, volume)).play(name)
}
}
}

private class StopCommand(tileEntity: TileEntity) extends Command(System.currentTimeMillis() + 1, tileEntity) {
private class StopCommand(tileEntity: WeakReference[TileEntity]) extends Command(System.currentTimeMillis() + 1, tileEntity) {
override def apply() {
sources.synchronized {
sources.remove(tileEntity) match {
sources.remove(tileEntity.get.get) match {
case Some(sound) => sound.stop()
case _ =>
}
Expand All @@ -140,31 +145,31 @@ object Sound {
// Remove all other commands for this tile entity from the queue. This
// is inefficient, but we generally don't expect the command queue to
// be very long, so this should be OK.
commandQueue ++= commandQueue.dequeueAll.filter(_.tileEntity != tileEntity)
commandQueue ++= commandQueue.dequeueAll.filter(_.tileEntity.get.get == tileEntity.get.get)
}
}
}

private class UpdatePositionCommand(tileEntity: TileEntity) extends Command(System.currentTimeMillis(), tileEntity) {
private class UpdatePositionCommand(tileEntity: WeakReference[TileEntity]) extends Command(System.currentTimeMillis(), tileEntity) {
override def apply() {
sources.synchronized {
sources.get(tileEntity) match {
sources.get(tileEntity.get.get) match {
case Some(sound) => sound.updatePosition()
case _ =>
}
}
}
}

private class PseudoLoopingStream(val tileEntity: TileEntity, val volume: Float, val source: String = UUID.randomUUID.toString) {
private class PseudoLoopingStream(val tileEntity: WeakReference[TileEntity], val volume: Float, val source: String = UUID.randomUUID.toString) {
var initialized = false

def updateVolume() {
soundSystem.setVolume(source, lastVolume * volume * Settings.get.soundVolume)
}

def updatePosition() {
if (tileEntity != null) soundSystem.setPosition(source, tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord)
if (tileEntity.get.isDefined) soundSystem.setPosition(source, tileEntity.get.get.xCoord, tileEntity.get.get.yCoord, tileEntity.get.get.zCoord)
else soundSystem.setPosition(source, 0, 0, 0)
}

Expand All @@ -174,7 +179,7 @@ object Sound {
val resource = (sound.func_148720_g: SoundPoolEntry).getSoundPoolEntryLocation
if (!initialized) {
initialized = true
if (tileEntity != null) soundSystem.newSource(false, source, toUrl(resource), resource.toString, true, tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord, SoundSystemConfig.ATTENUATION_LINEAR, 16)
if (tileEntity.get.isDefined) soundSystem.newSource(false, source, toUrl(resource), resource.toString, true, tileEntity.get.get.xCoord, tileEntity.get.get.yCoord, tileEntity.get.get.zCoord, SoundSystemConfig.ATTENUATION_LINEAR, 16)
else soundSystem.newSource(false, source, toUrl(resource), resource.toString, false, 0, 0, 0, SoundSystemConfig.ATTENUATION_NONE, 0)
updateVolume()
soundSystem.activate(source)
Expand Down