Skip to content

Commit 72e664c

Browse files
committed
WIP: midi device simulator
1 parent 3580ff8 commit 72e664c

19 files changed

Lines changed: 222 additions & 124 deletions

File tree

src/commonMain/kotlin/baaahs/ShowPlayer.kt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package baaahs
22

3+
import baaahs.gl.GlContext
34
import baaahs.gl.Toolchain
5+
import baaahs.gl.data.EngineFeedContext
46
import baaahs.gl.data.FeedContext
7+
import baaahs.gl.data.ProgramFeedContext
8+
import baaahs.gl.glsl.GlslProgram
59
import baaahs.gl.shader.OpenShader
610
import baaahs.gl.withCache
711
import baaahs.scene.SceneProvider
@@ -11,6 +15,9 @@ import baaahs.show.Show
1115
import baaahs.show.ShowState
1216
import baaahs.show.live.OpenShow
1317
import baaahs.show.live.ShowOpener
18+
import baaahs.util.Logger
19+
import baaahs.util.RefCounted
20+
import baaahs.util.RefCounter
1421

1522
interface ShowPlayer {
1623
val toolchain: Toolchain
@@ -47,7 +54,19 @@ abstract class BaseShowPlayer(
4754
// TODO: This is another reference to feeds, so we should .use() it... but then we'll never release them!
4855
// TODO: Also, it could conceivably be handed out after it's had onRelease() called. How should we handle this?
4956
return feeds.getOrPut(feed) {
50-
feed.open(this, id)
57+
try {
58+
feed.open(this, id)
59+
} catch (e: Error) {
60+
logger.error(e) { "Can't open feed $id" }
61+
62+
return object : FeedContext, RefCounted by RefCounter() {
63+
override fun bind(gl: GlContext): EngineFeedContext = object : EngineFeedContext {
64+
override fun bind(glslProgram: GlslProgram): ProgramFeedContext {
65+
return object : ProgramFeedContext {}
66+
}
67+
}
68+
}
69+
}
5170
}
5271
}
5372

@@ -74,4 +93,8 @@ abstract class BaseShowPlayer(
7493
if (!openShader.inUse()) shaders.remove(shader)
7594
}
7695
}
96+
97+
companion object {
98+
private val logger = Logger<BaseShowPlayer>()
99+
}
77100
}

src/commonMain/kotlin/baaahs/di/Modules.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import baaahs.scene.SceneProvider
3434
import baaahs.sim.FakeDmxUniverse
3535
import baaahs.sim.FakeFs
3636
import baaahs.sim.FakeNetwork
37+
import baaahs.sim.SimulatorSettingsManager
3738
import baaahs.sm.brain.BrainManager
3839
import baaahs.sm.brain.FirmwareDaddy
3940
import baaahs.sm.brain.ProdBrainSimulator
@@ -195,6 +196,7 @@ interface SimulatorModule : KModule {
195196
single(named(Qualifier.MapperFs)) { FakeFs("Temporary Mapping Files") }
196197
single<Fs>(named(Qualifier.MapperFs)) { get<FakeFs>(named(Qualifier.MapperFs)) }
197198
single(named(WebClientModule.Qualifier.PinkyAddress)) { get<Network.Link>(named(Qualifier.PinkyLink)).myAddress }
199+
single { SimulatorSettingsManager(get(named(Qualifier.PinkyFs))) }
198200
}
199201

200202
enum class Qualifier {

src/commonMain/kotlin/baaahs/plugin/OpenPlugin.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import baaahs.show.FeedBuilder
1414
import baaahs.show.mutable.MutableControl
1515
import baaahs.show.mutable.MutableShow
1616
import baaahs.sim.BridgeClient
17+
import baaahs.sim.SimulatorSettingsManager
1718
import baaahs.ui.Icon
1819
import baaahs.util.Clock
1920
import kotlinx.cli.ArgParser
@@ -99,6 +100,14 @@ interface OpenSimulatorPlugin {
99100

100101
/** This plugin is used on the client when running in the Simulator. */
101102
fun getClientPlugin(pluginContext: PluginContext): OpenClientPlugin
103+
104+
fun getHardwareSimulators(): List<HardwareSimulator> = emptyList()
105+
}
106+
107+
interface HardwareSimulator {
108+
val title: String
109+
110+
suspend fun start() {}
102111
}
103112

104113
class SerializerRegistrar<T : Any>(val klass: KClass<T>, val serializer: KSerializer<T>) {
@@ -149,7 +158,7 @@ interface Plugin<T> {
149158
* client plugins via [#openForSimulator].
150159
*/
151160
interface SimulatorPlugin {
152-
fun openForSimulator(): OpenSimulatorPlugin
161+
fun openForSimulator(simulatorSettingsManager: SimulatorSettingsManager): OpenSimulatorPlugin
153162
}
154163

155164
class PluginContext(

src/commonMain/kotlin/baaahs/plugin/Plugins.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import baaahs.scene.MutableControllerConfig
2929
import baaahs.show.*
3030
import baaahs.show.mutable.MutableFeedPort
3131
import baaahs.sim.BridgeClient
32+
import baaahs.sim.SimulatorSettingsManager
3233
import baaahs.sm.brain.BrainControllerConfig
3334
import baaahs.sm.brain.BrainManager
3435
import baaahs.sm.server.PinkyArgs
@@ -108,18 +109,20 @@ class ClientPlugins : Plugins {
108109
}
109110

110111
class SimulatorPlugins(
112+
simulatorSettingsManager: SimulatorSettingsManager,
111113
private val bridgeClient: BridgeClient,
112114
plugins: List<Plugin<*>>
113115
) {
114116
private val simulatorPlugins: List<OpenSimulatorPlugin>
115117
private var pluginsToSimulatorPlugins: List<Pair<Plugin<*>, OpenSimulatorPlugin?>>
118+
lateinit var hardwareSimulators: List<HardwareSimulator>
116119

117120
init {
118121
val forSimulator = mutableListOf<OpenSimulatorPlugin>()
119122

120123
pluginsToSimulatorPlugins = plugins.map {
121124
it as Plugin<Any>
122-
it to (it as? SimulatorPlugin)?.openForSimulator()
125+
it to (it as? SimulatorPlugin)?.openForSimulator(simulatorSettingsManager)
123126
}
124127
simulatorPlugins = forSimulator
125128
}
@@ -148,6 +151,11 @@ class SimulatorPlugins(
148151
},
149152
pluginContext
150153
)
154+
155+
fun getHardwareSimulators() =
156+
pluginsToSimulatorPlugins.flatMap { (plugin, simulatorPlugin) ->
157+
simulatorPlugin?.getHardwareSimulators() ?: emptyList()
158+
}
151159
}
152160

153161
sealed class Plugins(
@@ -432,8 +440,12 @@ sealed class Plugins(
432440
fun buildForClient(pluginContext: PluginContext, plugins: List<Plugin<*>>): ClientPlugins =
433441
ClientPlugins(pluginContext, listOf(CorePlugin) + plugins)
434442

435-
fun buildForSimulator(bridgeClient: BridgeClient, plugins: List<Plugin<*>>): SimulatorPlugins =
436-
SimulatorPlugins(bridgeClient, listOf(CorePlugin) + plugins)
443+
fun buildForSimulator(
444+
simulatorSettingsManager: SimulatorSettingsManager,
445+
bridgeClient: BridgeClient,
446+
plugins: List<Plugin<*>>
447+
): SimulatorPlugins =
448+
SimulatorPlugins(simulatorSettingsManager, bridgeClient, listOf(CorePlugin) + plugins)
437449

438450
fun safe(pluginContext: PluginContext): Plugins =
439451
SafePlugins(pluginContext, listOf(CorePlugin.openSafe(pluginContext)))

src/commonMain/kotlin/baaahs/plugin/beatlink/BeatLinkPlugin.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import baaahs.plugin.*
1616
import baaahs.show.Feed
1717
import baaahs.show.FeedBuilder
1818
import baaahs.sim.BridgeClient
19+
import baaahs.sim.SimulatorSettingsManager
1920
import baaahs.ui.Observable
2021
import baaahs.ui.addObserver
2122
import baaahs.util.Logger
@@ -275,7 +276,7 @@ class BeatLinkPlugin internal constructor(
275276
override fun openForClient(pluginContext: PluginContext): OpenClientPlugin =
276277
BeatLinkPlugin(PubSubSubscriber(pluginContext.pubSub), pluginContext)
277278

278-
override fun openForSimulator(): OpenSimulatorPlugin =
279+
override fun openForSimulator(simulatorSettingsManager: SimulatorSettingsManager): OpenSimulatorPlugin =
279280
object : OpenSimulatorPlugin {
280281
override fun getBridgePlugin(pluginContext: PluginContext): OpenBridgePlugin =
281282
BeatLinkBridgePlugin(createServerBeatSource(pluginContext), pluginContext)

src/commonMain/kotlin/baaahs/plugin/midi/MidiData.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,26 @@ data class MidiData(
1616

1717

1818
interface MidiSource : IObservable {
19+
val name: String
20+
1921
fun getMidiData(): MidiData
2022

2123
object None : Observable(), MidiSource {
22-
val none = MidiData(0, 0)
24+
override val name = "None"
25+
26+
private val none = MidiData(0, 0)
2327

2428
override fun getMidiData(): MidiData = none
2529
}
2630
}
2731

32+
interface MidiSystem : IObservable {
33+
val midiSources: List<MidiSource>
34+
35+
suspend fun start() {}
36+
37+
object None : Observable(), MidiSystem {
38+
override val midiSources: List<MidiSource>
39+
get() = emptyList()
40+
}
41+
}

src/commonMain/kotlin/baaahs/plugin/midi/MidiPlugin.kt

Lines changed: 33 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package baaahs.plugin.midi
22

3-
import baaahs.PubSub
43
import baaahs.ShowPlayer
54
import baaahs.gl.GlContext
65
import baaahs.gl.data.EngineFeedContext
@@ -14,8 +13,8 @@ import baaahs.plugin.*
1413
import baaahs.show.Feed
1514
import baaahs.show.FeedBuilder
1615
import baaahs.sim.BridgeClient
16+
import baaahs.sim.SimulatorSettingsManager
1717
import baaahs.ui.Observable
18-
import baaahs.ui.addObserver
1918
import baaahs.util.Logger
2019
import baaahs.util.RefCounted
2120
import baaahs.util.RefCounter
@@ -25,8 +24,10 @@ import kotlinx.cli.default
2524
import kotlinx.serialization.SerialName
2625

2726
class MidiPlugin internal constructor(
28-
internal val midiSource: MidiSource,
27+
internal val midiSystem: MidiSystem,
2928
) : OpenServerPlugin, OpenClientPlugin {
29+
private val midiSource = midiSystem.midiSources.firstOrNull() ?: MidiSource.None
30+
3031
override val packageName: String = MidiPlugin.id
3132
override val title: String = "Midi"
3233

@@ -98,7 +99,6 @@ class MidiPlugin internal constructor(
9899

99100
interface Args {
100101
val enableMidi: Boolean
101-
val midiSource: MidiSource? get() = null
102102
}
103103

104104
companion object : Plugin<Args>, SimulatorPlugin {
@@ -120,90 +120,52 @@ class MidiPlugin internal constructor(
120120
override fun getArgs(parser: ArgParser): Args = ParserArgs(parser)
121121

122122
override fun openForServer(pluginContext: PluginContext, args: Args): OpenServerPlugin {
123-
val midiSource = if (args.enableMidi) {
124-
args.midiSource ?: createServerMidiSource(pluginContext)
125-
} else MidiSource.None
126-
return MidiPlugin(
127-
PubSubPublisher(midiSource, pluginContext)
128-
)
123+
val midiSystem = if (args.enableMidi) {
124+
createMidiSystem(pluginContext)
125+
} else MidiSystem.None
126+
127+
return MidiPlugin(midiSystem)
129128
}
130129

131130
override fun openForClient(pluginContext: PluginContext): OpenClientPlugin =
132-
MidiPlugin(PubSubSubscriber(pluginContext.pubSub))
131+
MidiPlugin(MidiSystem.None)
133132

134-
override fun openForSimulator(): OpenSimulatorPlugin =
133+
override fun openForSimulator(
134+
simulatorSettingsManager: SimulatorSettingsManager
135+
): OpenSimulatorPlugin =
135136
object : OpenSimulatorPlugin {
136-
override fun getBridgePlugin(pluginContext: PluginContext): OpenBridgePlugin =
137-
MidiBridgePlugin(createServerMidiSource(pluginContext), pluginContext)
137+
private val midiHardwareSimulator = MidiHardwareSimulator(simulatorSettingsManager)
138+
139+
override fun getBridgePlugin(pluginContext: PluginContext): OpenBridgePlugin? = null
138140

139141
override fun getServerPlugin(pluginContext: PluginContext, bridgeClient: BridgeClient) =
140-
MidiPlugin(
141-
PubSubPublisher(
142-
PubSubSubscriber(bridgeClient.pubSub, simulatorDefaultMidi),
143-
pluginContext
144-
)
145-
)
142+
MidiPlugin(midiHardwareSimulator)
146143

147144
override fun getClientPlugin(pluginContext: PluginContext): OpenClientPlugin =
148145
openForClient(pluginContext)
149-
}
150-
151-
private val midiDataTopic = PubSub.Topic("plugins/$id/midiData", MidiData.serializer())
152-
}
153-
154-
/** Copy beat data from [midiSource] to a bridge PubSub channel. */
155-
class MidiBridgePlugin(
156-
private val midiSource: MidiSource,
157-
pluginContext: PluginContext
158-
) : OpenBridgePlugin {
159-
private val channel = pluginContext.pubSub.openChannel(midiDataTopic, unknownMidi) { }
160-
161-
init {
162-
midiSource.addObserver { channel.onChange(it.getMidiData()) }
163-
}
164-
}
165146

166-
class PubSubPublisher(
167-
midiSource: MidiSource,
168-
pluginContext: PluginContext
169-
) : Observable(), MidiSource {
170-
private var midiData: MidiData = midiSource.getMidiData()
171-
172-
val channel = pluginContext.pubSub.openChannel(midiDataTopic, midiData) {
173-
logger.warn { "MidiData update from client? Huh?" }
174-
midiData = it
175-
notifyChanged()
176-
}
177-
178-
init {
179-
midiSource.addObserver {
180-
val newMidiData = it.getMidiData()
181-
midiData = newMidiData
182-
notifyChanged()
183-
channel.onChange(newMidiData)
147+
override fun getHardwareSimulators(): List<HardwareSimulator> =
148+
listOf(midiHardwareSimulator)
184149
}
185-
}
186-
187-
override fun getMidiData(): MidiData = midiData
188-
189150
}
151+
}
190152

191-
class PubSubSubscriber(
192-
pubSub: PubSub.Endpoint,
193-
defaultMidiData: MidiData = unknownMidi
194-
) : Observable(), MidiSource {
195-
private var midiData: MidiData = defaultMidiData
153+
class MidiHardwareSimulator(
154+
private val simulatorSettingsManager: SimulatorSettingsManager
155+
) : HardwareSimulator, MidiSystem, Observable() {
156+
override val title: String = "MIDI"
196157

197-
init {
198-
pubSub.openChannel(midiDataTopic, midiData) {
199-
midiData = it
200-
notifyChanged()
201-
}
202-
}
158+
override val midiSources: List<MidiSource>
159+
get() = TODO("not implemented")
203160

204-
override fun getMidiData(): MidiData = midiData
161+
override suspend fun start() {
162+
logger.info { "Starting MIDI hardware simulator." }
163+
// simulatorSettingsManager
164+
}
205165

166+
companion object {
167+
private val logger = Logger<MidiHardwareSimulator>()
206168
}
207169
}
208170

209-
internal expect fun createServerMidiSource(pluginContext: PluginContext): MidiSource
171+
internal expect fun createMidiSystem(pluginContext: PluginContext): MidiSystem

src/commonMain/kotlin/baaahs/plugin/sound_analysis/SoundAnalysisPlugin.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import baaahs.show.Control
1717
import baaahs.show.Feed
1818
import baaahs.show.FeedBuilder
1919
import baaahs.sim.BridgeClient
20+
import baaahs.sim.SimulatorSettingsManager
2021
import baaahs.util.*
2122
import com.danielgergely.kgl.*
2223
import kotlinx.cli.ArgParser
@@ -106,7 +107,7 @@ class SoundAnalysisPlugin internal constructor(
106107
return SoundAnalysisPlugin(PubSubSubscriber(pluginContext.pubSub))
107108
}
108109

109-
override fun openForSimulator(): OpenSimulatorPlugin =
110+
override fun openForSimulator(simulatorSettingsManager: SimulatorSettingsManager): OpenSimulatorPlugin =
110111
object : OpenSimulatorPlugin {
111112
override fun getBridgePlugin(pluginContext: PluginContext): OpenBridgePlugin =
112113
PubSubPublisher(createServerSoundAnalyzer(pluginContext), pluginContext)

0 commit comments

Comments
 (0)