Skip to content

Commit 0f29a17

Browse files
SiriusZaelxian
authored andcommitted
WIP
1 parent 88e2ec4 commit 0f29a17

File tree

10 files changed

+351
-34
lines changed

10 files changed

+351
-34
lines changed

src/commonMain/kotlin/baaahs/Pluggables.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ package baaahs
22

33
import baaahs.plugin.Plugin
44
import baaahs.plugin.beatlink.BeatLinkPlugin
5+
import baaahs.plugin.midi.MidiPlugin
56
import baaahs.plugin.sound_analysis.SoundAnalysisPlugin
67
import baaahs.plugin.webcam.VideoInPlugin
78

89
object Pluggables {
910
val plugins = listOf<Plugin<*>>(
1011
BeatLinkPlugin,
12+
MidiPlugin,
1113
SoundAnalysisPlugin,
12-
VideoInPlugin,
14+
VideoInPlugin
1315
)
14-
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package baaahs.plugin.midi
2+
3+
import baaahs.ui.IObservable
4+
import baaahs.ui.Observable
5+
import kotlinx.serialization.Serializable
6+
7+
@Serializable
8+
data class MidiData(
9+
val sustainPedalCount: Int = 0,
10+
val noteCount: Int = 0
11+
) {
12+
companion object {
13+
val UNKNOWN = MidiData(0, 0)
14+
}
15+
}
16+
17+
18+
interface MidiSource : IObservable {
19+
fun getMidiData(): MidiData
20+
21+
object None : Observable(), MidiSource {
22+
val none = MidiData(0, 0)
23+
24+
override fun getMidiData(): MidiData = none
25+
}
26+
}
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
package baaahs.plugin.midi
2+
3+
import baaahs.PubSub
4+
import baaahs.ShowPlayer
5+
import baaahs.gl.GlContext
6+
import baaahs.gl.data.EngineFeedContext
7+
import baaahs.gl.data.FeedContext
8+
import baaahs.gl.data.ProgramFeedContext
9+
import baaahs.gl.glsl.GlslProgram
10+
import baaahs.gl.glsl.GlslType
11+
import baaahs.gl.patch.ContentType
12+
import baaahs.gl.shader.InputPort
13+
import baaahs.plugin.*
14+
import baaahs.show.Feed
15+
import baaahs.show.FeedBuilder
16+
import baaahs.sim.BridgeClient
17+
import baaahs.ui.Observable
18+
import baaahs.ui.addObserver
19+
import baaahs.util.Logger
20+
import baaahs.util.RefCounted
21+
import baaahs.util.RefCounter
22+
import kotlinx.cli.ArgParser
23+
import kotlinx.cli.ArgType
24+
import kotlinx.cli.default
25+
import kotlinx.serialization.SerialName
26+
27+
class MidiPlugin internal constructor(
28+
internal val midiSource: MidiSource,
29+
) : OpenServerPlugin, OpenClientPlugin {
30+
override val packageName: String = MidiPlugin.id
31+
override val title: String = "Midi"
32+
33+
internal val midiFeed = MidiFeed()
34+
35+
override val contentTypes: List<ContentType>
36+
get() = listOf(
37+
midiContentType
38+
)
39+
40+
override val feedBuilders
41+
get() = listOf(
42+
MidiFeedBuilder()
43+
)
44+
45+
inner class MidiFeedBuilder : FeedBuilder<MidiFeed> {
46+
override val title: String get() = "Midi"
47+
override val description: String get() = "A struct containing information about the midi events."
48+
override val resourceName: String get() = "Midi"
49+
override val contentType: ContentType get() = midiContentType
50+
override val serializerRegistrar
51+
get() = objectSerializer("$id:Midi", midiFeed)
52+
53+
override fun looksValid(inputPort: InputPort, suggestedContentTypes: Set<ContentType>): Boolean =
54+
inputPort.contentType == midiContentType
55+
|| suggestedContentTypes.contains(midiContentType)
56+
|| inputPort.type == midiStruct
57+
58+
override fun build(inputPort: InputPort): MidiFeed = midiFeed
59+
}
60+
61+
62+
@SerialName("baaahs.Midi:Midi")
63+
inner class MidiFeed internal constructor() : Feed {
64+
override val pluginPackage: String get() = id
65+
override val title: String get() = "Midi"
66+
override fun getType(): GlslType = midiStruct
67+
override val contentType: ContentType
68+
get() = midiContentType
69+
70+
override fun open(showPlayer: ShowPlayer, id: String): FeedContext {
71+
val varPrefix = getVarName(id)
72+
return object : FeedContext, RefCounted by RefCounter() {
73+
override fun bind(gl: GlContext): EngineFeedContext = object : EngineFeedContext {
74+
override fun bind(glslProgram: GlslProgram): ProgramFeedContext {
75+
return object : ProgramFeedContext {
76+
val sustainPedalCount = glslProgram.getUniform("${varPrefix}.sustainPedalCount")
77+
val noteCount = glslProgram.getUniform("${varPrefix}.noteCount")
78+
override val isValid: Boolean
79+
get() = sustainPedalCount != null && noteCount != null
80+
81+
override fun setOnProgram() {
82+
val midiData = midiSource.getMidiData()
83+
84+
sustainPedalCount?.set(midiData.sustainPedalCount)
85+
noteCount?.set(midiData.noteCount)
86+
}
87+
}
88+
}
89+
}
90+
}
91+
}
92+
}
93+
94+
class ParserArgs(parser: ArgParser) : Args {
95+
override val enableMidi by parser.option(ArgType.Boolean, description = "Enable midi detection")
96+
.default(true)
97+
}
98+
99+
interface Args {
100+
val enableMidi: Boolean
101+
val midiSource: MidiSource? get() = null
102+
}
103+
104+
companion object : Plugin<Args>, SimulatorPlugin {
105+
private val logger = Logger<MidiPlugin>()
106+
107+
override val id = "baaahs.Midi"
108+
109+
val midiStruct = GlslType.Struct(
110+
"Midi",
111+
"sustainPedalCount" to GlslType.Int,
112+
"noteCount" to GlslType.Int
113+
)
114+
115+
val midiContentType = ContentType("midi", "Midi", midiStruct)
116+
117+
private val simulatorDefaultMidi = MidiData(0, 0)
118+
private val unknownMidi = MidiData(0, 0)
119+
120+
override fun getArgs(parser: ArgParser): Args = ParserArgs(parser)
121+
122+
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+
)
129+
}
130+
131+
override fun openForClient(pluginContext: PluginContext): OpenClientPlugin =
132+
MidiPlugin(PubSubSubscriber(pluginContext.pubSub))
133+
134+
override fun openForSimulator(): OpenSimulatorPlugin =
135+
object : OpenSimulatorPlugin {
136+
override fun getBridgePlugin(pluginContext: PluginContext): OpenBridgePlugin =
137+
MidiBridgePlugin(createServerMidiSource(pluginContext), pluginContext)
138+
139+
override fun getServerPlugin(pluginContext: PluginContext, bridgeClient: BridgeClient) =
140+
MidiPlugin(
141+
PubSubPublisher(
142+
PubSubSubscriber(bridgeClient.pubSub, simulatorDefaultMidi),
143+
pluginContext
144+
)
145+
)
146+
147+
override fun getClientPlugin(pluginContext: PluginContext): OpenClientPlugin =
148+
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+
}
165+
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)
184+
}
185+
}
186+
187+
override fun getMidiData(): MidiData = midiData
188+
189+
}
190+
191+
class PubSubSubscriber(
192+
pubSub: PubSub.Endpoint,
193+
defaultMidiData: MidiData = unknownMidi
194+
) : Observable(), MidiSource {
195+
private var midiData: MidiData = defaultMidiData
196+
197+
init {
198+
pubSub.openChannel(midiDataTopic, midiData) {
199+
midiData = it
200+
notifyChanged()
201+
}
202+
}
203+
204+
override fun getMidiData(): MidiData = midiData
205+
206+
}
207+
}
208+
209+
internal expect fun createServerMidiSource(pluginContext: PluginContext): MidiSource

src/commonMain/resources/shader-libraries/built-in/shaders/BAAAHS_Eclipse.glsl

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ struct SoundAnalysis {
1616
};
1717
uniform SoundAnalysis soundAnalysis; // @@baaahs.SoundAnalysis:SoundAnalysis
1818

19+
struct Midi {
20+
int sustainPedalCount;
21+
int noteCount;
22+
};
23+
uniform Midi midi; // @@baaahs.Midi:Midi
24+
1925
struct BeatInfo {
2026
float beat;
2127
float bpm;

0 commit comments

Comments
 (0)