mirror of
https://gitlab.com/cc-ru/ocelot/ocelot-desktop.git
synced 2025-12-20 02:59:19 +01:00
Have each sound card create its own sound stream
In addition to that, fixes a long-standing bug concerning brain event dispatch to inventory items: items could receive events coming from a component with a different address. Fixes #175.
This commit is contained in:
parent
d1d2deddff
commit
4bcdebedfa
@ -62,6 +62,8 @@ object Audio extends Logging {
|
||||
|
||||
sources.put(source, sourceId)
|
||||
|
||||
logger.debug(s"created new source $sourceId for $source")
|
||||
|
||||
sourceId
|
||||
}
|
||||
}
|
||||
@ -70,6 +72,7 @@ object Audio extends Logging {
|
||||
|
||||
val bufferId = samples.genBuffer().getOrElse { tx.abort() }
|
||||
tx.onFailure { AL10W.alDeleteBuffers(bufferId) }
|
||||
logger.debug(s"enqueued buffer $bufferId for source $sourceId ($source)", new Exception())
|
||||
AL10W.alSourceQueueBuffers(sourceId, bufferId)
|
||||
|
||||
if (AL10W.alGetSourcei(sourceId, AL10.AL_SOURCE_STATE) != AL10.AL_PLAYING) {
|
||||
@ -226,6 +229,7 @@ object Audio extends Logging {
|
||||
|
||||
@throws[OpenAlException]
|
||||
private def deleteSource(sourceId: Int): Unit = {
|
||||
logger.debug(s"deleting source $sourceId")
|
||||
AL10W.alSourceStop(sourceId)
|
||||
cleanupSourceBuffers(sourceId)
|
||||
AL10W.alDeleteSources(sourceId)
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
package ocelot.desktop.inventory
|
||||
|
||||
import ocelot.desktop.inventory.Inventory.SlotObserver
|
||||
import ocelot.desktop.ui.event.{Event, EventAware}
|
||||
import ocelot.desktop.ui.event.{BrainEvent, Event, EventAware}
|
||||
import ocelot.desktop.util.Disposable
|
||||
import totoro.ocelot.brain.event.NodeEvent
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
/** Provides an inventory — a collection of [[Item]]s indexed by slots. */
|
||||
trait Inventory extends EventAware {
|
||||
trait Inventory extends EventAware with Disposable {
|
||||
// parallels totoro.ocelot.brain.entity.traits.Inventory
|
||||
// this is intentional
|
||||
|
||||
@ -20,6 +21,16 @@ trait Inventory extends EventAware {
|
||||
private val itemSlots = mutable.HashMap.empty[I, Int]
|
||||
private val observers = mutable.HashMap.empty[Int, WeakHashSet[SlotObserver]]
|
||||
|
||||
override def dispose(): Unit = {
|
||||
super.dispose()
|
||||
|
||||
for (slot <- inventoryIterator) {
|
||||
val item = slot.get
|
||||
slot.remove()
|
||||
item.foreach(_.dispose())
|
||||
}
|
||||
}
|
||||
|
||||
/** Called after a new item is added to the inventory.
|
||||
*
|
||||
* @param slot the slot the item was added to
|
||||
@ -72,7 +83,7 @@ trait Inventory extends EventAware {
|
||||
|
||||
for (slot <- inventoryIterator; item <- slot.get) {
|
||||
event match {
|
||||
case n: NodeEvent if !item.shouldReceiveEventsFor(n.address) => // ignore
|
||||
case BrainEvent(e: NodeEvent) if !item.shouldReceiveEventsFor(e.address) => // ignore
|
||||
case _ => item.handleEvent(event)
|
||||
}
|
||||
}
|
||||
@ -148,7 +159,6 @@ trait Inventory extends EventAware {
|
||||
}
|
||||
|
||||
final object Slot {
|
||||
|
||||
/** Creates a proxy to an inventory slot. */
|
||||
def apply(index: Int) = new Slot(index)
|
||||
}
|
||||
|
||||
@ -1,22 +1,50 @@
|
||||
package ocelot.desktop.inventory.item
|
||||
|
||||
import ocelot.desktop.audio.{Audio, SoundCategory, SoundSamples, SoundSource, SoundStream}
|
||||
import ocelot.desktop.graphics.IconSource
|
||||
import ocelot.desktop.inventory.traits.{CardItem, ComponentItem, PersistableItem}
|
||||
import ocelot.desktop.inventory.{Item, ItemFactory, ItemRecoverer}
|
||||
import ocelot.desktop.ui.event.BrainEvent
|
||||
import ocelot.desktop.ui.widget.card.SoundCardWindow
|
||||
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry}
|
||||
import ocelot.desktop.ui.widget.window.Windowed
|
||||
import ocelot.desktop.util.Lazy
|
||||
import totoro.ocelot.brain.Settings
|
||||
import totoro.ocelot.brain.entity.sound_card.SoundCard
|
||||
import totoro.ocelot.brain.entity.traits.{Entity, Environment}
|
||||
import totoro.ocelot.brain.event.SoundCardAudioEvent
|
||||
import totoro.ocelot.brain.util.Tier
|
||||
import totoro.ocelot.brain.util.Tier.Tier
|
||||
|
||||
class SoundCardItem(val soundCard: SoundCard)
|
||||
extends Item with ComponentItem with PersistableItem with CardItem with Windowed[SoundCardWindow] {
|
||||
extends Item
|
||||
with ComponentItem
|
||||
with PersistableItem
|
||||
with CardItem
|
||||
with Windowed[SoundCardWindow] {
|
||||
|
||||
override def createWindow(): SoundCardWindow = new SoundCardWindow(soundCard)
|
||||
|
||||
override def entity: Entity with Environment = soundCard
|
||||
override def entity: SoundCard = soundCard
|
||||
|
||||
private val streamPair = Lazy(Audio.newStream(SoundCategory.Records))
|
||||
private def stream: SoundStream = streamPair.getSync._1
|
||||
private def source: SoundSource = streamPair.getSync._2
|
||||
|
||||
eventHandlers += {
|
||||
case BrainEvent(event: SoundCardAudioEvent) if !Audio.isDisabled =>
|
||||
val samples = SoundSamples(event.data, Settings.get.soundCardSampleRate, SoundSamples.Format.Mono8)
|
||||
stream.enqueue(samples)
|
||||
source.volume = event.volume
|
||||
}
|
||||
|
||||
override def dispose(): Unit = {
|
||||
super.dispose()
|
||||
|
||||
for (stream <- streamPair.getOption) {
|
||||
stream._2.stop()
|
||||
}
|
||||
}
|
||||
|
||||
override def fillRmbMenu(menu: ContextMenu): Unit = {
|
||||
menu.addEntry(ContextMenuEntry("Open card interface", IconSource.Window) {
|
||||
|
||||
@ -11,7 +11,6 @@ import ocelot.desktop.ui.event.handlers.DiskActivityHandler
|
||||
import ocelot.desktop.ui.particle.Particle
|
||||
import ocelot.desktop.util.Messages
|
||||
import ocelot.desktop.{ColorScheme, Settings => DesktopSettings}
|
||||
import totoro.ocelot.brain.Settings
|
||||
import totoro.ocelot.brain.entity.traits.{Entity, Environment, WorkspaceAware}
|
||||
import totoro.ocelot.brain.event._
|
||||
|
||||
@ -25,10 +24,6 @@ abstract class ComputerAwareNode(entity: Entity with Environment with WorkspaceA
|
||||
with BoomCardFxHandler
|
||||
with ShiftClickNode {
|
||||
|
||||
private lazy val soundCardSounds: (SoundStream, SoundSource) = Audio.newStream(SoundCategory.Records)
|
||||
private def soundCardStream: SoundStream = soundCardSounds._1
|
||||
private def soundCardSource: SoundSource = soundCardSounds._2
|
||||
|
||||
eventHandlers += {
|
||||
case BrainEvent(event: MachineCrashEvent) =>
|
||||
val message = Messages.lift(event.message) match {
|
||||
@ -46,11 +41,6 @@ abstract class ComputerAwareNode(entity: Entity with Environment with WorkspaceA
|
||||
|
||||
case BrainEvent(event: BeepPatternEvent) if !Audio.isDisabled =>
|
||||
BeepGenerator.newBeep(event.pattern, 1000, 200).play()
|
||||
|
||||
case BrainEvent(event: SoundCardAudioEvent) if !Audio.isDisabled =>
|
||||
val samples = SoundSamples(event.data, Settings.get.soundCardSampleRate, SoundSamples.Format.Mono8)
|
||||
soundCardStream.enqueue(samples)
|
||||
soundCardSource.volume = event.volume
|
||||
}
|
||||
|
||||
protected def drawOverlay(g: Graphics): Unit = HolidayIcon match {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package ocelot.desktop.ui.widget.window
|
||||
|
||||
import ocelot.desktop.util.Persistable
|
||||
import ocelot.desktop.util.{Disposable, Persistable}
|
||||
import totoro.ocelot.brain.nbt.NBTTagCompound
|
||||
|
||||
trait Windowed[T <: Window] extends Persistable {
|
||||
trait Windowed[T <: Window] extends Persistable with Disposable {
|
||||
protected def createWindow(): T
|
||||
|
||||
private var _window: Option[T] = None
|
||||
@ -33,6 +33,10 @@ trait Windowed[T <: Window] extends Persistable {
|
||||
window
|
||||
}
|
||||
|
||||
override def dispose(): Unit = {
|
||||
super.dispose()
|
||||
closeAndDisposeWindow()
|
||||
}
|
||||
// ------------------------------- NBT -------------------------------
|
||||
|
||||
protected def windowNBTKey: String = "window"
|
||||
|
||||
@ -17,7 +17,13 @@ import totoro.ocelot.brain.util.Tier.Tier
|
||||
import scala.math.Ordering.Implicits.infixOrderingOps
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
trait ComputerAware extends Logging with SyncedInventory with DefaultSlotItemsFillable with Windowed[ComputerWindow] {
|
||||
trait ComputerAware
|
||||
extends Logging
|
||||
with SyncedInventory
|
||||
with DefaultSlotItemsFillable
|
||||
with Windowed[ComputerWindow]
|
||||
with Disposable {
|
||||
|
||||
override type I = Item with EntityItem
|
||||
|
||||
def computer: Computer with TieredPersistable
|
||||
|
||||
23
src/main/scala/ocelot/desktop/util/Lazy.scala
Normal file
23
src/main/scala/ocelot/desktop/util/Lazy.scala
Normal file
@ -0,0 +1,23 @@
|
||||
package ocelot.desktop.util
|
||||
|
||||
class Lazy[A](init: () => A) {
|
||||
private var _value = Option.empty[A]
|
||||
|
||||
def get: A = _value match {
|
||||
case Some(value) => value
|
||||
|
||||
case None =>
|
||||
val v = init()
|
||||
_value = Some(v)
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
def getSync: A = synchronized(get)
|
||||
|
||||
def getOption: Option[A] = _value
|
||||
}
|
||||
|
||||
object Lazy {
|
||||
def apply[A](init: => A): Lazy[A] = new Lazy(() => init)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user