pulse duty cycle and a bunch of other fixes
This commit is contained in:
parent
c72730f1a2
commit
c682d69a3e
18 changed files with 350 additions and 215 deletions
Binary file not shown.
|
|
@ -1,5 +1,5 @@
|
|||
// 1.19.2 2023-05-03T17:34:34.425318453 Models
|
||||
ff88cf4c4547ef552e4ed2f859978e7b875c0b56 assets/dawd3/models/block/amplifier.json
|
||||
// 1.19.2 2023-05-03T22:15:16.62168443 Models
|
||||
5919f5e0f79620a682f481a8e02995f95724b2ce assets/dawd3/models/block/amplifier.json
|
||||
c3ea3e310d8fe7796b5b055d34db712cb8c7ac5a assets/dawd3/blockstates/triangle_oscillator.json
|
||||
97f0b7f5e19cd8c92915c4dfdedcee0e0b2a4b7f assets/dawd3/models/item/amplifier.json
|
||||
0fb5cd695c2a82a2353809529dc8b5086ee2c87d assets/dawd3/blockstates/phase.json
|
||||
|
|
@ -7,24 +7,24 @@ c3ea3e310d8fe7796b5b055d34db712cb8c7ac5a assets/dawd3/blockstates/triangle_oscil
|
|||
a4e8bc89d39021eb8d56ad7735216cb851d67287 assets/dawd3/models/item/light_blue_patch_cable.json
|
||||
aa1a1807d2c46f1f25e3d0c507952fefb5b3cd9f assets/dawd3/models/item/knob.json
|
||||
d65fd7b21da2adf55a0b076103103da7e7bb453a assets/dawd3/models/block/speaker.json
|
||||
df1b924ee7f1a4f9a6496f52a27d74b449ef05fc assets/dawd3/models/block/triangle_oscillator.json
|
||||
fe4987cffd1253462cc8440c90ff2341ac3026a4 assets/dawd3/models/block/triangle_oscillator.json
|
||||
d1e691559156bd4bf0ec0d488d1a28ac193f4967 assets/dawd3/blockstates/adsr.json
|
||||
123ed8aa83a77b4714cee4dfc6747832cf72c75c assets/dawd3/blockstates/mixer.json
|
||||
becb814a10bcf2d3e071a6479e9b2289165d0059 assets/dawd3/models/item/modulator.json
|
||||
f69a4acfdf715c64f64830ce0a79aa452ad4760a assets/dawd3/models/item/saw_oscillator.json
|
||||
e289094bba4daa5de7873e6af154a25f4defc16b assets/dawd3/models/block/modulator.json
|
||||
851149820d465dc203cc75e8808a5387e8eb5426 assets/dawd3/models/block/modulator.json
|
||||
32bb0e6e3bf75b9005602e8fb1042ad5d41286ad assets/dawd3/models/item/lime_patch_cable.json
|
||||
bb8b84a5a98c77aaf9ee25760dfc352b760fc2d3 assets/dawd3/models/item/keyboard.json
|
||||
b5cc6f4b4af952380a1539489f2e406bc6ebe5fa assets/dawd3/blockstates/amplifier.json
|
||||
2a6b9e841be2ba74ff159488c86d5a569f28798b assets/dawd3/models/block/phase.json
|
||||
019bcf77479bfc64a04555f9864e2cbac2055b9f assets/dawd3/models/block/phase.json
|
||||
292685c025f28911bca9252da3e4ac72998b3c7a assets/dawd3/blockstates/pulse_oscillator.json
|
||||
63c9e9521285c0a1041709a42b2232517debee38 assets/dawd3/blockstates/keyboard.json
|
||||
956d8f117df95cf62c8cac375cff853df96840d6 assets/dawd3/models/item/pink_patch_cable.json
|
||||
9c18a8292a0c9990cd23bebf5c6191c2114ccc6d assets/dawd3/models/item/black_patch_cable.json
|
||||
96135c420e211d0cfee4aff9e1ae98484b4603c4 assets/dawd3/models/block/saw_oscillator.json
|
||||
0afd7ba8d87444961a33cb87bba122fca5ebef8e assets/dawd3/models/block/saw_oscillator.json
|
||||
67ff4ae22c5f716f1aa2b6e2dac31d12be2336d1 assets/dawd3/blockstates/modulator.json
|
||||
64c9ff6a94721f17a823c9d253559e5b9e73662a assets/dawd3/models/block/sine_oscillator.json
|
||||
03377aa722945c78e2746f199d558f8338f61c96 assets/dawd3/models/block/mixer.json
|
||||
012ae6bec3490e1e4f4b8a4677ce46600e1a501c assets/dawd3/models/block/mixer.json
|
||||
0812a674d14cfc6fbb7c0e2ac1b473bf2afe1965 assets/dawd3/models/item/brown_patch_cable.json
|
||||
6e01a1aa07f3a36d7950a1b00d1bc6e9045b9995 assets/dawd3/blockstates/knob.json
|
||||
bf0e322e33123cb6873c2da4e8c6ab85688deb4e assets/dawd3/models/item/gray_patch_cable.json
|
||||
|
|
@ -40,12 +40,12 @@ f7b47538f17992177e97e06842c0039ae5096b2b assets/dawd3/blockstates/speaker.json
|
|||
0d899dc2bd693c95d582231a00faf40bf1d67a47 assets/dawd3/blockstates/saw_oscillator.json
|
||||
8c4b8147bfea2bdb8c1d348bc332a60d2cd82d68 assets/dawd3/models/item/phase.json
|
||||
8aa966337109315240614d5257eb72f959eba5d8 assets/dawd3/models/item/orange_patch_cable.json
|
||||
46e362f3f96c54438c29132f76441e6cddb94564 assets/dawd3/models/block/pulse_oscillator.json
|
||||
0b8f2a8c456a65c5dd415fc6ad3459dd8b43f954 assets/dawd3/models/block/pulse_oscillator.json
|
||||
12c4bfd825b2476955afcd3bb23c1f736ce68caa assets/dawd3/models/item/yellow_patch_cable.json
|
||||
aab1bce7ec4e7c7dccd3d33d4242de12b63a981d assets/dawd3/models/item/white_patch_cable.json
|
||||
6cdda36e539e23acf3db70d761338e88932a6ebb assets/dawd3/models/item/purple_patch_cable.json
|
||||
e3c6aacd49a6395f37047d3df31f91a18a411267 assets/dawd3/models/item/speaker.json
|
||||
49d732a11ba0d66d716dcb6d86718075b6ccf5aa assets/dawd3/models/block/keyboard.json
|
||||
4be49e87d036188e4c9d5285d7fcebbb25954dfe assets/dawd3/models/block/keyboard.json
|
||||
2adb4f854a9f13090dffaf8ab9dfe0553cc59a80 assets/dawd3/models/item/triangle_oscillator.json
|
||||
3b1811bab3ba394ba03b67ac2efc72cb35316dc8 assets/dawd3/blockstates/sine_oscillator.json
|
||||
8688de3eadb6579cac89522683c394f18733e614 assets/dawd3/models/block/knob.json
|
||||
|
|
|
|||
|
|
@ -40,6 +40,30 @@
|
|||
16.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
4.0,
|
||||
0.0,
|
||||
8.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
3.0,
|
||||
3.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
7.0,
|
||||
7.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
|
|
@ -87,30 +111,6 @@
|
|||
7.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
4.0,
|
||||
0.0,
|
||||
8.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
3.0,
|
||||
3.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
7.0,
|
||||
7.0,
|
||||
0.01
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,30 @@
|
|||
16.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
4.0,
|
||||
0.0,
|
||||
8.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
9.0,
|
||||
9.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
13.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
|
|
@ -87,30 +111,6 @@
|
|||
7.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
4.0,
|
||||
0.0,
|
||||
8.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
9.0,
|
||||
9.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
13.0,
|
||||
0.01
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": {
|
||||
|
|
|
|||
|
|
@ -40,30 +40,6 @@
|
|||
16.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
0.0,
|
||||
0.0,
|
||||
4.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
9.0,
|
||||
3.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
7.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
|
|
@ -88,6 +64,30 @@
|
|||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
0.0,
|
||||
0.0,
|
||||
4.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
9.0,
|
||||
3.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
7.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
|
|
|
|||
|
|
@ -40,30 +40,6 @@
|
|||
16.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
4.0,
|
||||
0.0,
|
||||
8.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
3.0,
|
||||
6.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
7.0,
|
||||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
|
|
@ -87,6 +63,30 @@
|
|||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
4.0,
|
||||
0.0,
|
||||
8.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
3.0,
|
||||
6.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
7.0,
|
||||
10.0,
|
||||
0.01
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": {
|
||||
|
|
|
|||
|
|
@ -64,30 +64,6 @@
|
|||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
0.0,
|
||||
0.0,
|
||||
4.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
9.0,
|
||||
3.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
7.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
|
|
@ -111,6 +87,30 @@
|
|||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
0.0,
|
||||
0.0,
|
||||
4.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
9.0,
|
||||
3.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
7.0,
|
||||
0.01
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": {
|
||||
|
|
|
|||
|
|
@ -55,12 +55,12 @@
|
|||
},
|
||||
"from": [
|
||||
9.0,
|
||||
3.0,
|
||||
9.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
7.0,
|
||||
13.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
|
|
@ -79,11 +79,35 @@
|
|||
},
|
||||
"from": [
|
||||
3.0,
|
||||
3.0,
|
||||
6.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
7.0,
|
||||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
0.0,
|
||||
0.0,
|
||||
4.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
9.0,
|
||||
3.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
7.0,
|
||||
0.01
|
||||
]
|
||||
|
|
|
|||
|
|
@ -40,30 +40,6 @@
|
|||
16.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
4.0,
|
||||
0.0,
|
||||
8.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
3.0,
|
||||
6.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
7.0,
|
||||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
|
|
@ -87,6 +63,30 @@
|
|||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
4.0,
|
||||
0.0,
|
||||
8.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
3.0,
|
||||
6.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
7.0,
|
||||
10.0,
|
||||
0.01
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": {
|
||||
|
|
|
|||
|
|
@ -40,30 +40,6 @@
|
|||
16.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
4.0,
|
||||
0.0,
|
||||
8.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
3.0,
|
||||
6.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
7.0,
|
||||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
|
|
@ -87,6 +63,30 @@
|
|||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
4.0,
|
||||
0.0,
|
||||
8.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
3.0,
|
||||
6.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
7.0,
|
||||
10.0,
|
||||
0.01
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": {
|
||||
|
|
|
|||
|
|
@ -7,37 +7,56 @@ import net.liquidev.dawd3.audio.math.oversample
|
|||
import net.liquidev.dawd3.audio.math.polyBLEP
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class PulseOscillatorDevice : Device<NoControls> {
|
||||
class PulseOscillatorDevice : Device<PulseOscillatorDevice.Controls> {
|
||||
companion object : DeviceDescriptor {
|
||||
override val id = Identifier(Mod.id, "pulse_oscillator")
|
||||
|
||||
val dutyCycleControl = ControlDescriptor(id, "duty_cycle", 0.5f)
|
||||
val dutyCycleCVControl = ControlDescriptor(id, "duty_cycle_cv", 0.5f)
|
||||
|
||||
val phasePort = InputPortName(id, "phase")
|
||||
val dutyCyclePort = InputPortName(id, "duty_cycle")
|
||||
val outputPort = OutputPortName(id, "output")
|
||||
|
||||
// TODO: Make this into a couple controls and put it into a nice UI
|
||||
const val usePolyBLEP = true
|
||||
const val oversampling = 4
|
||||
}
|
||||
|
||||
// Especially this should be a knob+CV controlled thing.
|
||||
const val dutyCycle = 0.5f
|
||||
class Controls : ControlSet {
|
||||
val dutyCycle = FloatControl(dutyCycleControl)
|
||||
val dutyCycleCV = FloatControl(dutyCycleCVControl)
|
||||
|
||||
override fun visitControls(visit: (ControlName, Control) -> Unit) {
|
||||
visit(dutyCycleControl.name, dutyCycle)
|
||||
visit(dutyCycleCVControl.name, dutyCycleCV)
|
||||
}
|
||||
}
|
||||
|
||||
private val phase = InputPort()
|
||||
private val dutyCycle = InputPort()
|
||||
private val output = OutputPort(bufferCount = 1)
|
||||
|
||||
private val phaseDerivative = PhaseDerivative()
|
||||
|
||||
override fun process(sampleCount: Int, controls: NoControls) {
|
||||
override fun process(sampleCount: Int, controls: Controls) {
|
||||
val phaseBuffer = phase.getConnectedOutputBuffer(0, sampleCount)
|
||||
|
||||
val dutyCycleBuffer = dutyCycle.getConnectedOutputBuffer(0, sampleCount)
|
||||
val outputBuffer = output.buffers[0].getOrReallocate(sampleCount)
|
||||
|
||||
val constantDutyCycle = controls.dutyCycle.value
|
||||
val dutyCycleCV = controls.dutyCycleCV.value
|
||||
|
||||
for (i in 0 until sampleCount) {
|
||||
val phase = phaseBuffer[i]
|
||||
val deltaPhase = phaseDerivative.stepNextDerivative(phase)
|
||||
outputBuffer[i] = oversample(phase, deltaPhase, oversampling, ::pulse)
|
||||
val dutyCycle = constantDutyCycle + dutyCycleBuffer[i] * dutyCycleCV
|
||||
outputBuffer[i] =
|
||||
oversample(phase, deltaPhase, oversampling) { t, dt -> pulse(t, dt, dutyCycle) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun pulse(t: Float, dt: Float): Float {
|
||||
private fun pulse(t: Float, dt: Float, dutyCycle: Float): Float {
|
||||
val naivePulse = if (t > 1f - dutyCycle) 1f else -1f
|
||||
return if (usePolyBLEP) {
|
||||
naivePulse + polyBLEP((t + dutyCycle) % 1f, dt) - polyBLEP(t, dt)
|
||||
|
|
@ -48,6 +67,7 @@ class PulseOscillatorDevice : Device<NoControls> {
|
|||
|
||||
override fun visitInputPorts(visit: (InputPortName, InputPort) -> Unit) {
|
||||
visit(phasePort, phase)
|
||||
visit(dutyCyclePort, dutyCycle)
|
||||
}
|
||||
|
||||
override fun visitOutputPorts(visit: (OutputPortName, OutputPort) -> Unit) {
|
||||
|
|
|
|||
|
|
@ -200,8 +200,7 @@ class DeviceBlockEntityRenderer(context: BlockEntityRendererFactory.Context) : B
|
|||
val startAbsolute = blockEntity.pos.toVec3d()
|
||||
val endAbsolute = connection.blockPosition.toVec3d()
|
||||
|
||||
// TODO: Null checks here?
|
||||
val inputPort = blockEntity.descriptor.portLayout[inputPortName]!!
|
||||
val inputPort = blockEntity.descriptor.portLayout[inputPortName] ?: continue
|
||||
val outputBlockState = world.getBlockState(connection.blockPosition)
|
||||
// TODO: The line below will crash if the block is destroyed (becomes air)
|
||||
// Though it never crashed for me during testing?
|
||||
|
|
@ -280,14 +279,27 @@ class DeviceBlockEntityRenderer(context: BlockEntityRendererFactory.Context) : B
|
|||
colorIndex: Float,
|
||||
) {
|
||||
val forward = to - from
|
||||
|
||||
val right = forward.copy()
|
||||
right.cross(Vec3f.POSITIVE_Y)
|
||||
right.normalize()
|
||||
right.multiplyComponentwise(cableThickness, cableThickness, cableThickness)
|
||||
val up = right.copy()
|
||||
up.cross(forward)
|
||||
up.normalize()
|
||||
up.multiplyComponentwise(cableThickness, cableThickness, cableThickness)
|
||||
|
||||
if (forward.x == 0f && forward.y != 0f && forward.z == 0f) {
|
||||
// Special case: the cross product fails if the cable is going straight up, so we have
|
||||
// to set the vectors ourself.
|
||||
right.set(Vec3f.POSITIVE_X)
|
||||
right.multiplyComponentwise(cableThickness, cableThickness, cableThickness)
|
||||
up.set(Vec3f.POSITIVE_Z)
|
||||
up.multiplyComponentwise(cableThickness, cableThickness, cableThickness)
|
||||
} else {
|
||||
right.cross(Vec3f.POSITIVE_Y)
|
||||
right.normalize()
|
||||
right.multiplyComponentwise(cableThickness, cableThickness, cableThickness)
|
||||
up.set(right)
|
||||
up.cross(forward)
|
||||
up.normalize()
|
||||
up.multiplyComponentwise(cableThickness, cableThickness, cableThickness)
|
||||
}
|
||||
|
||||
renderCableWithThicknessVector(
|
||||
world,
|
||||
matrixStack,
|
||||
|
|
|
|||
|
|
@ -2,35 +2,78 @@ package net.liquidev.dawd3.block.devices.oscillator
|
|||
|
||||
import net.liquidev.dawd3.Mod
|
||||
import net.liquidev.dawd3.audio.device.DeviceInstance
|
||||
import net.liquidev.dawd3.audio.device.NoControls
|
||||
import net.liquidev.dawd3.audio.devices.oscillator.PulseOscillatorDevice
|
||||
import net.liquidev.dawd3.block.device.DeviceBlockDescriptor
|
||||
import net.liquidev.dawd3.block.device.PhysicalPort
|
||||
import net.liquidev.dawd3.ui.units.PercentageValue
|
||||
import net.liquidev.dawd3.ui.widget.Knob
|
||||
import net.liquidev.dawd3.ui.widget.Window
|
||||
import net.minecraft.client.world.ClientWorld
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Vec2f
|
||||
|
||||
object PulseOscillatorBlockDescriptor : DeviceBlockDescriptor<PulseOscillatorBlockDescriptor.ClientState, NoControls> {
|
||||
object PulseOscillatorBlockDescriptor : DeviceBlockDescriptor<PulseOscillatorBlockDescriptor.ClientState, PulseOscillatorDevice.Controls> {
|
||||
override val id = Identifier(Mod.id, "pulse_oscillator")
|
||||
|
||||
override val portLayout = PhysicalPort.layout {
|
||||
port(
|
||||
PulseOscillatorDevice.phasePort,
|
||||
position = Vec2f(0.25f, 0.25f),
|
||||
PhysicalPort.Side.Front
|
||||
)
|
||||
port(
|
||||
PulseOscillatorDevice.dutyCyclePort,
|
||||
position = Vec2f(0.25f, 0.75f),
|
||||
side = PhysicalPort.Side.Front,
|
||||
PhysicalPort.Side.Front
|
||||
)
|
||||
port(
|
||||
PulseOscillatorDevice.outputPort,
|
||||
position = Vec2f(0.75f, 0.75f),
|
||||
side = PhysicalPort.Side.Front
|
||||
position = Vec2f(0.75f, 0.5f),
|
||||
PhysicalPort.Side.Front
|
||||
)
|
||||
}
|
||||
|
||||
class ClientState(controls: NoControls) : DeviceBlockDescriptor.ClientState {
|
||||
class ClientState(controls: PulseOscillatorDevice.Controls) : DeviceBlockDescriptor.ClientState {
|
||||
override val logicalDevice = DeviceInstance.create(PulseOscillatorDevice(), controls)
|
||||
}
|
||||
|
||||
override fun initControls() = NoControls
|
||||
override fun initControls() = PulseOscillatorDevice.Controls()
|
||||
|
||||
override fun onClientLoad(controls: NoControls, world: ClientWorld) = ClientState(controls)
|
||||
override fun onClientLoad(controls: PulseOscillatorDevice.Controls, world: ClientWorld) =
|
||||
ClientState(controls)
|
||||
|
||||
override val ui = object : DeviceBlockDescriptor.UI<PulseOscillatorDevice.Controls> {
|
||||
override fun open(controls: PulseOscillatorDevice.Controls, x: Int, y: Int) =
|
||||
Window(
|
||||
x,
|
||||
y,
|
||||
width = 78,
|
||||
height = 48,
|
||||
Text.translatable("block.dawd3.pulse_oscillator")
|
||||
).apply {
|
||||
children.add(
|
||||
Knob(
|
||||
x = 14,
|
||||
y = 18,
|
||||
control = controls.dutyCycle,
|
||||
min = 0f,
|
||||
max = 1f,
|
||||
color = Knob.Color.Blue,
|
||||
unit = PercentageValue,
|
||||
)
|
||||
)
|
||||
children.add(
|
||||
Knob(
|
||||
x = 42,
|
||||
y = 18,
|
||||
control = controls.dutyCycleCV,
|
||||
min = 0f,
|
||||
max = 1f,
|
||||
color = Knob.Color.Green,
|
||||
unit = PercentageValue,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import net.liquidev.dawd3.render.Atlas
|
|||
import net.liquidev.dawd3.render.Render
|
||||
import net.liquidev.dawd3.render.Sprite
|
||||
import net.liquidev.dawd3.ui.widget.Widget
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.client.world.ClientWorld
|
||||
|
|
@ -14,6 +15,7 @@ import net.minecraft.text.Text
|
|||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
import kotlin.math.max
|
||||
|
||||
class Rack(
|
||||
val world: ClientWorld,
|
||||
|
|
@ -24,20 +26,38 @@ class Rack(
|
|||
val widget: Widget,
|
||||
)
|
||||
|
||||
private var openWidgets = run {
|
||||
var windowX = 32
|
||||
private var openWidgets =
|
||||
ArrayList(shownDevices.mapNotNull { blockPosition ->
|
||||
val blockEntity = world.getBlockEntity(blockPosition) as DeviceBlockEntity
|
||||
blockEntity.descriptor.ui
|
||||
?.open(blockEntity.controls, windowX, 32)
|
||||
?.let { widget ->
|
||||
windowX += widget.width + 8
|
||||
OpenWidget(blockPosition, widget)
|
||||
}
|
||||
?.open(blockEntity.controls, 0, 0)
|
||||
?.let { widget -> OpenWidget(blockPosition, widget) }
|
||||
})
|
||||
|
||||
private fun layoutWindows() {
|
||||
var x = 16
|
||||
var y = 16
|
||||
var rowHeight = 0
|
||||
for (openWidget in openWidgets) {
|
||||
if (x + openWidget.widget.width >= width - 16) {
|
||||
x = 16
|
||||
y += rowHeight + 8
|
||||
rowHeight = 0
|
||||
}
|
||||
openWidget.widget.x = x
|
||||
openWidget.widget.y = y
|
||||
x += openWidget.widget.width + 8
|
||||
rowHeight = max(rowHeight, openWidget.widget.height)
|
||||
}
|
||||
}
|
||||
|
||||
fun hasOpenWindows(): Boolean = openWidgets.isNotEmpty()
|
||||
override fun init() {
|
||||
layoutWindows()
|
||||
}
|
||||
|
||||
override fun resize(client: MinecraftClient?, width: Int, height: Int) {
|
||||
layoutWindows()
|
||||
}
|
||||
|
||||
override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
renderBackground(matrices)
|
||||
|
|
@ -52,7 +72,15 @@ class Rack(
|
|||
openWidget.widget.draw(matrices, mouseX, mouseY, delta)
|
||||
}
|
||||
|
||||
Render.sprite(matrices, 8, 8, badge.width * 2, badge.height * 2, atlas, badge)
|
||||
Render.sprite(
|
||||
matrices,
|
||||
8,
|
||||
height - badge.height - 8,
|
||||
badge.width * 2,
|
||||
badge.height * 2,
|
||||
atlas,
|
||||
badge
|
||||
)
|
||||
}
|
||||
|
||||
private fun propagateEvent(event: Event): Boolean {
|
||||
|
|
|
|||
|
|
@ -161,6 +161,9 @@ class Knob(
|
|||
alterValue(control.value, by = deltaY.toFloat())
|
||||
)
|
||||
draggingInfo.previousMouseY = event.absoluteMouseY
|
||||
// Consume the events so that other controls don't get triggered while the knob
|
||||
// is being dragged.
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,13 +33,16 @@ class Keyboard(
|
|||
}
|
||||
|
||||
override val width = children.maxOf { it.x + it.width }
|
||||
override val height = 24
|
||||
override val height = children.maxOf { it.y + it.height }
|
||||
|
||||
private var pressedKey: Key? = null
|
||||
|
||||
override fun event(context: EventContext, event: Event): Boolean {
|
||||
if (event is MouseButton && event.button == GLFW.GLFW_MOUSE_BUTTON_LEFT) {
|
||||
mouseIsDown = event.action == Action.Down
|
||||
mouseIsDown = event.action == Action.Down && containsRelativePoint(
|
||||
event.mouseX.toInt(),
|
||||
event.mouseY.toInt()
|
||||
)
|
||||
if (mouseIsDown) {
|
||||
setPressedKey(context, findPressedKey(event.mouseX.toInt(), event.mouseY.toInt()))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -39,5 +39,7 @@
|
|||
"dawd3.control.dawd3.fma.add": "ADD",
|
||||
"dawd3.control.dawd3.fma.multiply": "MUL",
|
||||
"dawd3.control.dawd3.mix.a_amplitude": "A",
|
||||
"dawd3.control.dawd3.mix.b_amplitude": "B"
|
||||
"dawd3.control.dawd3.mix.b_amplitude": "B",
|
||||
"dawd3.control.dawd3.pulse_oscillator.duty_cycle": "%",
|
||||
"dawd3.control.dawd3.pulse_oscillator.duty_cycle_cv": "CV"
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 342 B After Width: | Height: | Size: 350 B |
Reference in a new issue