keyboard device
This commit is contained in:
parent
64162a30ff
commit
da71bcf1ad
35 changed files with 558 additions and 172 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 553 B After Width: | Height: | Size: 553 B |
Binary file not shown.
Binary file not shown.
|
|
@ -1,10 +1,10 @@
|
|||
// 1.19.2 2023-05-02T12:20:58.184760864 Models
|
||||
// 1.19.2 2023-05-03T14:08:42.976687848 Models
|
||||
0812a674d14cfc6fbb7c0e2ac1b473bf2afe1965 assets/dawd3/models/item/brown_patch_cable.json
|
||||
6e01a1aa07f3a36d7950a1b00d1bc6e9045b9995 assets/dawd3/blockstates/knob.json
|
||||
bf0e322e33123cb6873c2da4e8c6ab85688deb4e assets/dawd3/models/item/gray_patch_cable.json
|
||||
215b221d48639e96de11914625a770a389d65b81 assets/dawd3/models/item/green_patch_cable.json
|
||||
6a9fb209d82556f5941422a8d047a0ae2af1dc8f assets/dawd3/models/item/sine_oscillator.json
|
||||
5919f5e0f79620a682f481a8e02995f95724b2ce assets/dawd3/models/block/amplifier.json
|
||||
48ec7ba345d918e9cdd74c026dc5d705f1679a65 assets/dawd3/models/block/amplifier.json
|
||||
8ba890b28c5ac57c59f19ccc8c72825caac10677 assets/dawd3/models/item/magenta_patch_cable.json
|
||||
e34001d3c974aecfa347d435beb6bc0b9d325897 assets/dawd3/models/item/cyan_patch_cable.json
|
||||
c3ea3e310d8fe7796b5b055d34db712cb8c7ac5a assets/dawd3/blockstates/triangle_oscillator.json
|
||||
|
|
@ -19,20 +19,23 @@ a4e8bc89d39021eb8d56ad7735216cb851d67287 assets/dawd3/models/item/light_blue_pat
|
|||
8c4b8147bfea2bdb8c1d348bc332a60d2cd82d68 assets/dawd3/models/item/phase.json
|
||||
aa1a1807d2c46f1f25e3d0c507952fefb5b3cd9f assets/dawd3/models/item/knob.json
|
||||
d65fd7b21da2adf55a0b076103103da7e7bb453a assets/dawd3/models/block/speaker.json
|
||||
fe4987cffd1253462cc8440c90ff2341ac3026a4 assets/dawd3/models/block/triangle_oscillator.json
|
||||
df1b924ee7f1a4f9a6496f52a27d74b449ef05fc assets/dawd3/models/block/triangle_oscillator.json
|
||||
becb814a10bcf2d3e071a6479e9b2289165d0059 assets/dawd3/models/item/modulator.json
|
||||
8aa966337109315240614d5257eb72f959eba5d8 assets/dawd3/models/item/orange_patch_cable.json
|
||||
4748361fec856c3fe328ac0036ee642a5865fa99 assets/dawd3/models/block/pulse_oscillator.json
|
||||
46e362f3f96c54438c29132f76441e6cddb94564 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
|
||||
f69a4acfdf715c64f64830ce0a79aa452ad4760a assets/dawd3/models/item/saw_oscillator.json
|
||||
851149820d465dc203cc75e8808a5387e8eb5426 assets/dawd3/models/block/modulator.json
|
||||
e289094bba4daa5de7873e6af154a25f4defc16b 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
|
||||
1358574aaed0a49a6a4fdaba4ceb330463dcc421 assets/dawd3/models/block/phase.json
|
||||
0e38af638352ff27a8ee1e42c72266ce34578db7 assets/dawd3/models/block/phase.json
|
||||
292685c025f28911bca9252da3e4ac72998b3c7a assets/dawd3/blockstates/pulse_oscillator.json
|
||||
63c9e9521285c0a1041709a42b2232517debee38 assets/dawd3/blockstates/keyboard.json
|
||||
5d03886e98a219deed68eecf53a2453916401fc0 assets/dawd3/models/block/keyboard.json
|
||||
956d8f117df95cf62c8cac375cff853df96840d6 assets/dawd3/models/item/pink_patch_cable.json
|
||||
2adb4f854a9f13090dffaf8ab9dfe0553cc59a80 assets/dawd3/models/item/triangle_oscillator.json
|
||||
3b1811bab3ba394ba03b67ac2efc72cb35316dc8 assets/dawd3/blockstates/sine_oscillator.json
|
||||
|
|
|
|||
|
|
@ -40,30 +40,6 @@
|
|||
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": {
|
||||
|
|
@ -88,6 +64,30 @@
|
|||
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
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
|
|
|
|||
|
|
@ -40,30 +40,6 @@
|
|||
16.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
0.0,
|
||||
0.0,
|
||||
4.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
9.0,
|
||||
6.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
|
|
@ -87,6 +63,30 @@
|
|||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
0.0,
|
||||
0.0,
|
||||
4.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
9.0,
|
||||
6.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
10.0,
|
||||
0.01
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": {
|
||||
|
|
|
|||
|
|
@ -46,21 +46,21 @@
|
|||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
4.0,
|
||||
0.0,
|
||||
8.0,
|
||||
0.0,
|
||||
4.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
9.0,
|
||||
3.0,
|
||||
6.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
7.0,
|
||||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
|
|
@ -79,11 +79,35 @@
|
|||
},
|
||||
"from": [
|
||||
9.0,
|
||||
6.0,
|
||||
9.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
13.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
|
||||
]
|
||||
|
|
|
|||
|
|
@ -40,30 +40,6 @@
|
|||
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,6 +63,30 @@
|
|||
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,30 +40,6 @@
|
|||
16.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
0.0,
|
||||
0.0,
|
||||
4.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
9.0,
|
||||
6.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
|
|
@ -87,6 +63,30 @@
|
|||
10.0,
|
||||
0.01
|
||||
]
|
||||
},
|
||||
{
|
||||
"faces": {
|
||||
"north": {
|
||||
"cullface": "north",
|
||||
"texture": "#port",
|
||||
"uv": [
|
||||
0.0,
|
||||
0.0,
|
||||
4.0,
|
||||
4.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"from": [
|
||||
9.0,
|
||||
6.0,
|
||||
-0.01
|
||||
],
|
||||
"to": [
|
||||
13.0,
|
||||
10.0,
|
||||
0.01
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
package net.liquidev.dawd3.audio.device
|
||||
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
|
||||
import net.liquidev.dawd3.net.TweakControl
|
||||
import net.minecraft.nbt.NbtElement
|
||||
import net.minecraft.nbt.NbtFloat
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
|
|
@ -85,3 +88,17 @@ class ControlMap(set: ControlSet) {
|
|||
|
||||
operator fun get(name: ControlName): Control? = map[name]
|
||||
}
|
||||
|
||||
object BlockEntityControls {
|
||||
fun setFloatControlValue(blockPosition: BlockPos, control: FloatControl, value: Float) {
|
||||
control.value = value
|
||||
ClientPlayNetworking.send(
|
||||
TweakControl.id,
|
||||
TweakControl(
|
||||
blockPosition,
|
||||
control.descriptor.name.id,
|
||||
control.valueToBytes()
|
||||
).serialize()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package net.liquidev.dawd3.audio.devices.math
|
||||
package net.liquidev.dawd3.audio.devices.io
|
||||
|
||||
import net.liquidev.dawd3.Mod
|
||||
import net.liquidev.dawd3.audio.device.*
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package net.liquidev.dawd3.audio.devices.io
|
||||
|
||||
import net.liquidev.dawd3.Mod
|
||||
import net.liquidev.dawd3.audio.device.*
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class KeyboardDevice : Device<KeyboardDevice.Controls> {
|
||||
companion object : DeviceDescriptor {
|
||||
override val id = Identifier(Mod.id, "keyboard")
|
||||
|
||||
val pitchControl = ControlDescriptor(id, "pitch", 0f)
|
||||
val triggerControl = ControlDescriptor(id, "trigger", 0f)
|
||||
val velocityControl = ControlDescriptor(id, "velocity", 0f)
|
||||
|
||||
val pitchOutput = OutputPortName(id, "pitch")
|
||||
val triggerOutput = OutputPortName(id, "trigger")
|
||||
val velocityOutput = OutputPortName(id, "velocity")
|
||||
}
|
||||
|
||||
class Controls : ControlSet {
|
||||
val pitch = FloatControl(pitchControl)
|
||||
val trigger = FloatControl(triggerControl)
|
||||
val velocity = FloatControl(velocityControl)
|
||||
|
||||
override fun visitControls(visit: (ControlName, Control) -> Unit) {
|
||||
visit(pitchControl.name, pitch)
|
||||
visit(triggerControl.name, trigger)
|
||||
visit(velocityControl.name, velocity)
|
||||
}
|
||||
}
|
||||
|
||||
val pitch = OutputPort(bufferCount = 1)
|
||||
val trigger = OutputPort(bufferCount = 1)
|
||||
val velocity = OutputPort(bufferCount = 1)
|
||||
|
||||
override fun process(sampleCount: Int, controls: Controls) {
|
||||
val pitchBuffer = pitch.buffers[0].getOrReallocate(sampleCount)
|
||||
val triggerBuffer = trigger.buffers[0].getOrReallocate(sampleCount)
|
||||
val velocityBuffer = velocity.buffers[0].getOrReallocate(sampleCount)
|
||||
|
||||
val pitch = controls.pitch.value
|
||||
val trigger = controls.trigger.value
|
||||
val velocity = controls.velocity.value
|
||||
|
||||
for (i in 0 until sampleCount) {
|
||||
pitchBuffer[i] = pitch
|
||||
}
|
||||
for (i in 0 until sampleCount) {
|
||||
triggerBuffer[i] = trigger
|
||||
}
|
||||
for (i in 0 until sampleCount) {
|
||||
velocityBuffer[i] = velocity
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitOutputPorts(visit: (OutputPortName, OutputPort) -> Unit) {
|
||||
visit(pitchOutput, pitch)
|
||||
visit(triggerOutput, trigger)
|
||||
visit(velocityOutput, velocity)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import net.liquidev.dawd3.Mod
|
|||
import net.liquidev.dawd3.audio.Audio
|
||||
import net.liquidev.dawd3.audio.AudioBuffer
|
||||
import net.liquidev.dawd3.audio.device.*
|
||||
import net.liquidev.dawd3.audio.math.Trigger
|
||||
import net.liquidev.dawd3.audio.unit.VOct
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
|
|
@ -11,14 +12,17 @@ class PhaseDevice : Device<NoControls> {
|
|||
companion object : DeviceDescriptor {
|
||||
override val id = Identifier(Mod.id, "phase")
|
||||
val frequencyCVPort = InputPortName(id, "frequency_cv")
|
||||
val resetPort = InputPortName(id, "reset")
|
||||
val outputPort = OutputPortName(id, "output")
|
||||
}
|
||||
|
||||
private val frequencyCV = InputPort()
|
||||
private val reset = InputPort()
|
||||
private val output = OutputPort(bufferCount = 1)
|
||||
|
||||
private val frequencyBuffer = AudioBuffer()
|
||||
private var phase = 0.0f
|
||||
private val resetTrigger = Trigger()
|
||||
|
||||
override fun process(sampleCount: Int, controls: NoControls) {
|
||||
val voctBuffer = frequencyCV.getConnectedOutputBuffer(0, sampleCount)
|
||||
|
|
@ -27,17 +31,25 @@ class PhaseDevice : Device<NoControls> {
|
|||
frequencyBuffer[i] = VOct(voctBuffer[i]).toFrequency(Audio.a4).value
|
||||
}
|
||||
|
||||
val resetBuffer = reset.getConnectedOutputBuffer(0, sampleCount)
|
||||
val outputBuffer = output.buffers[0].getOrReallocate(sampleCount)
|
||||
for (i in 0 until sampleCount) {
|
||||
val phaseStep = Audio.sampleRateFInv * frequencyBuffer[i]
|
||||
phase += phaseStep
|
||||
phase %= 1.0f
|
||||
phase %= 1f
|
||||
|
||||
if (resetTrigger.stepEdge(resetBuffer[i]) == Trigger.Edge.Rising) {
|
||||
println("resetting phase")
|
||||
phase = 0f
|
||||
}
|
||||
|
||||
outputBuffer[i] = phase
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitInputPorts(visit: (InputPortName, InputPort) -> Unit) {
|
||||
visit(frequencyCVPort, frequencyCV)
|
||||
visit(resetPort, reset)
|
||||
}
|
||||
|
||||
override fun visitOutputPorts(visit: (OutputPortName, OutputPort) -> Unit) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package net.liquidev.dawd3.audio.devices.oscillator
|
|||
|
||||
import net.liquidev.dawd3.Mod
|
||||
import net.liquidev.dawd3.audio.device.*
|
||||
import net.liquidev.dawd3.audio.math.PhaseDerivative
|
||||
import net.liquidev.dawd3.audio.math.oversample
|
||||
import net.liquidev.dawd3.audio.math.polyBLEP
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class PulseOscillatorDevice : Device<NoControls> {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package net.liquidev.dawd3.audio.devices.oscillator
|
|||
|
||||
import net.liquidev.dawd3.Mod
|
||||
import net.liquidev.dawd3.audio.device.*
|
||||
import net.liquidev.dawd3.audio.math.PhaseDerivative
|
||||
import net.liquidev.dawd3.audio.math.oversample
|
||||
import net.liquidev.dawd3.audio.math.polyBLEP
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class SawOscillatorDevice : Device<NoControls> {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package net.liquidev.dawd3.audio.devices.oscillator
|
|||
|
||||
import net.liquidev.dawd3.Mod
|
||||
import net.liquidev.dawd3.audio.device.*
|
||||
import net.liquidev.dawd3.audio.math.PhaseDerivative
|
||||
import net.liquidev.dawd3.audio.math.oversample
|
||||
import net.liquidev.dawd3.audio.math.polyBLEP
|
||||
import net.minecraft.util.Identifier
|
||||
import kotlin.math.abs
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package net.liquidev.dawd3.audio.devices.oscillator
|
||||
package net.liquidev.dawd3.audio.math
|
||||
|
||||
import kotlin.math.abs
|
||||
|
||||
|
|
@ -14,4 +14,4 @@ class PhaseDerivative {
|
|||
previousDeltaPhase = deltaPhase
|
||||
return smoothDeltaPhase
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/main/kotlin/net/liquidev/dawd3/audio/math/Trigger.kt
Normal file
23
src/main/kotlin/net/liquidev/dawd3/audio/math/Trigger.kt
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package net.liquidev.dawd3.audio.math
|
||||
|
||||
class Trigger {
|
||||
var isTriggered = false
|
||||
|
||||
fun stepEdge(nextSample: Float): Edge {
|
||||
val wasTriggered = isTriggered
|
||||
isTriggered = nextSample > 0.5
|
||||
return if (!wasTriggered && isTriggered) {
|
||||
Edge.Rising
|
||||
} else if (wasTriggered && !isTriggered) {
|
||||
Edge.Falling
|
||||
} else {
|
||||
Edge.Constant
|
||||
}
|
||||
}
|
||||
|
||||
enum class Edge {
|
||||
Constant,
|
||||
Rising,
|
||||
Falling,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package net.liquidev.dawd3.audio.devices.oscillator
|
||||
package net.liquidev.dawd3.audio.math
|
||||
|
||||
inline fun oversample(
|
||||
phase: Float,
|
||||
|
|
@ -11,8 +11,9 @@ import net.liquidev.dawd3.block.device.DeviceBlock
|
|||
import net.liquidev.dawd3.block.device.DeviceBlockEntity
|
||||
import net.liquidev.dawd3.block.device.DeviceBlockEntityRenderer
|
||||
import net.liquidev.dawd3.block.devices.SpeakerBlockDescriptor
|
||||
import net.liquidev.dawd3.block.devices.io.KeyboardBlockDescriptor
|
||||
import net.liquidev.dawd3.block.devices.io.KnobBlockDescriptor
|
||||
import net.liquidev.dawd3.block.devices.math.AmplifierBlockDescriptor
|
||||
import net.liquidev.dawd3.block.devices.math.KnobBlockDescriptor
|
||||
import net.liquidev.dawd3.block.devices.math.ModulatorBlockDescriptor
|
||||
import net.liquidev.dawd3.block.devices.oscillator.*
|
||||
import net.liquidev.dawd3.item.Items
|
||||
|
|
@ -64,6 +65,7 @@ object Blocks {
|
|||
val speaker = registerDeviceBlock(SpeakerBlockDescriptor)
|
||||
|
||||
val knob = registerDeviceBlock(KnobBlockDescriptor)
|
||||
val keyboard = registerDeviceBlock(KeyboardBlockDescriptor)
|
||||
val amplifier = registerDeviceBlock(AmplifierBlockDescriptor)
|
||||
val modulator = registerDeviceBlock(ModulatorBlockDescriptor)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
package net.liquidev.dawd3.block.devices.io
|
||||
|
||||
import net.liquidev.dawd3.Mod
|
||||
import net.liquidev.dawd3.audio.device.DeviceInstance
|
||||
import net.liquidev.dawd3.audio.devices.io.KeyboardDevice
|
||||
import net.liquidev.dawd3.block.device.DeviceBlockDescriptor
|
||||
import net.liquidev.dawd3.block.device.PhysicalPort
|
||||
import net.liquidev.dawd3.ui.widget.Window
|
||||
import net.liquidev.dawd3.ui.widget.keyboard.Keyboard
|
||||
import net.minecraft.client.world.ClientWorld
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Vec2f
|
||||
|
||||
object KeyboardBlockDescriptor : DeviceBlockDescriptor<KeyboardBlockDescriptor.ClientState, KeyboardDevice.Controls> {
|
||||
override val id = Identifier(Mod.id, "keyboard")
|
||||
|
||||
override val portLayout = PhysicalPort.layout {
|
||||
port(KeyboardDevice.pitchOutput, position = Vec2f(0.25f, 0.25f), PhysicalPort.Side.Front)
|
||||
port(KeyboardDevice.triggerOutput, position = Vec2f(0.75f, 0.25f), PhysicalPort.Side.Front)
|
||||
port(KeyboardDevice.velocityOutput, position = Vec2f(0.5f, 0.75f), PhysicalPort.Side.Front)
|
||||
}
|
||||
|
||||
class ClientState(controls: KeyboardDevice.Controls) : DeviceBlockDescriptor.ClientState {
|
||||
override val logicalDevice = DeviceInstance.create(KeyboardDevice(), controls)
|
||||
}
|
||||
|
||||
override fun initControls() = KeyboardDevice.Controls()
|
||||
|
||||
override fun onClientLoad(controls: KeyboardDevice.Controls, world: ClientWorld) =
|
||||
ClientState(controls)
|
||||
|
||||
override val ui = object : DeviceBlockDescriptor.UI<KeyboardDevice.Controls> {
|
||||
override fun open(controls: KeyboardDevice.Controls, x: Int, y: Int) =
|
||||
Window(
|
||||
x, y,
|
||||
width = 332,
|
||||
height = 56,
|
||||
title = Text.translatable("block.dawd3.keyboard")
|
||||
).apply {
|
||||
children.add(Keyboard(x = 8, y = 16, firstNote = -33, lastNote = 27, controls))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package net.liquidev.dawd3.block.devices.math
|
||||
package net.liquidev.dawd3.block.devices.io
|
||||
|
||||
import net.liquidev.dawd3.Mod
|
||||
import net.liquidev.dawd3.audio.device.DeviceInstance
|
||||
import net.liquidev.dawd3.audio.devices.math.ConstantDevice
|
||||
import net.liquidev.dawd3.audio.devices.io.ConstantDevice
|
||||
import net.liquidev.dawd3.block.device.DeviceBlockDescriptor
|
||||
import net.liquidev.dawd3.block.device.PhysicalPort
|
||||
import net.liquidev.dawd3.block.device.descriptor.FaceTextures
|
||||
|
|
@ -6,7 +6,6 @@ import net.liquidev.dawd3.audio.device.NoControls
|
|||
import net.liquidev.dawd3.audio.devices.oscillator.PhaseDevice
|
||||
import net.liquidev.dawd3.block.device.DeviceBlockDescriptor
|
||||
import net.liquidev.dawd3.block.device.PhysicalPort
|
||||
import net.liquidev.dawd3.block.device.descriptor.FaceTextures
|
||||
import net.minecraft.client.world.ClientWorld
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Vec2f
|
||||
|
|
@ -15,18 +14,10 @@ object PhaseBlockDescriptor : DeviceBlockDescriptor<PhaseBlockDescriptor.ClientS
|
|||
override val id = Identifier(Mod.id, "phase")
|
||||
|
||||
override val portLayout = PhysicalPort.layout {
|
||||
port(
|
||||
PhaseDevice.frequencyCVPort,
|
||||
position = Vec2f(0.25f, 0.5f),
|
||||
side = PhysicalPort.Side.Front,
|
||||
)
|
||||
port(
|
||||
PhaseDevice.outputPort,
|
||||
position = Vec2f(0.75f, 0.5f),
|
||||
side = PhysicalPort.Side.Front
|
||||
)
|
||||
port(PhaseDevice.frequencyCVPort, position = Vec2f(0.25f, 0.25f), PhysicalPort.Side.Front)
|
||||
port(PhaseDevice.resetPort, position = Vec2f(0.25f, 0.75f), PhysicalPort.Side.Front)
|
||||
port(PhaseDevice.outputPort, position = Vec2f(0.75f, 0.5f), PhysicalPort.Side.Front)
|
||||
}
|
||||
override val faceTextures = FaceTextures.withFrontAndSide { id }
|
||||
|
||||
class ClientState(controls: NoControls) : DeviceBlockDescriptor.ClientState {
|
||||
override val logicalDevice = DeviceInstance.create(PhaseDevice(), controls)
|
||||
|
|
|
|||
|
|
@ -17,14 +17,14 @@ import kotlin.math.sin
|
|||
import kotlin.math.sqrt
|
||||
|
||||
object Render {
|
||||
fun icon(
|
||||
fun sprite(
|
||||
matrices: MatrixStack,
|
||||
x: Int,
|
||||
y: Int,
|
||||
width: Int,
|
||||
height: Int,
|
||||
atlas: Atlas,
|
||||
icon: Icon,
|
||||
sprite: Sprite,
|
||||
) {
|
||||
RenderSystem.setShaderTexture(0, atlas.asset)
|
||||
DrawableHelper.drawTexture(
|
||||
|
|
@ -33,17 +33,17 @@ object Render {
|
|||
y,
|
||||
width,
|
||||
height,
|
||||
icon.u.toFloat(),
|
||||
icon.v.toFloat(),
|
||||
icon.width,
|
||||
icon.height,
|
||||
sprite.u.toFloat(),
|
||||
sprite.v.toFloat(),
|
||||
sprite.width,
|
||||
sprite.height,
|
||||
atlas.size,
|
||||
atlas.size
|
||||
)
|
||||
}
|
||||
|
||||
fun icon(matrices: MatrixStack, x: Int, y: Int, atlas: Atlas, icon: Icon) {
|
||||
icon(matrices, x, y, icon.width, icon.height, atlas, icon)
|
||||
fun sprite(matrices: MatrixStack, x: Int, y: Int, atlas: Atlas, icon: Sprite) {
|
||||
sprite(matrices, x, y, icon.width, icon.height, atlas, icon)
|
||||
}
|
||||
|
||||
fun line(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package net.liquidev.dawd3.render
|
||||
|
||||
data class Icon(
|
||||
data class Sprite(
|
||||
val u: Int,
|
||||
val v: Int,
|
||||
val width: Int,
|
||||
|
|
@ -3,8 +3,8 @@ package net.liquidev.dawd3.ui
|
|||
import net.liquidev.dawd3.Mod
|
||||
import net.liquidev.dawd3.block.device.DeviceBlockEntity
|
||||
import net.liquidev.dawd3.render.Atlas
|
||||
import net.liquidev.dawd3.render.Icon
|
||||
import net.liquidev.dawd3.render.Render
|
||||
import net.liquidev.dawd3.render.Sprite
|
||||
import net.liquidev.dawd3.ui.widget.Widget
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
|
|
@ -52,18 +52,19 @@ class Rack(
|
|||
openWidget.widget.draw(matrices, mouseX, mouseY, delta)
|
||||
}
|
||||
|
||||
Render.icon(matrices, 8, 8, badge.width * 2, badge.height * 2, atlas, badge)
|
||||
Render.sprite(matrices, 8, 8, badge.width * 2, badge.height * 2, atlas, badge)
|
||||
}
|
||||
|
||||
private fun propagateEvent(event: Event): Boolean {
|
||||
for (openWidget in openWidgets) {
|
||||
if (openWidget.widget.event(
|
||||
if (
|
||||
openWidget.widget.event(
|
||||
EventContext(world, openWidget.blockPosition),
|
||||
event.relativeTo(
|
||||
openWidget.widget.x.toDouble(),
|
||||
openWidget.widget.y.toDouble(),
|
||||
)
|
||||
) == null
|
||||
)
|
||||
) return true
|
||||
}
|
||||
return false
|
||||
|
|
@ -96,7 +97,7 @@ class Rack(
|
|||
|
||||
companion object {
|
||||
val atlas = Atlas(asset = Identifier(Mod.id, "textures/ui/rack.png"), size = 64)
|
||||
val badge = Icon(u = 0, v = 16, width = 6, height = 3)
|
||||
val badge = Sprite(u = 0, v = 16, width = 6, height = 3)
|
||||
|
||||
val smallFont = Identifier(Mod.id, "altopixel")
|
||||
val smallText = Style.EMPTY.withFont(smallFont)!!
|
||||
|
|
|
|||
19
src/main/kotlin/net/liquidev/dawd3/ui/widget/Container.kt
Normal file
19
src/main/kotlin/net/liquidev/dawd3/ui/widget/Container.kt
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package net.liquidev.dawd3.ui.widget
|
||||
|
||||
import net.liquidev.dawd3.ui.Event
|
||||
import net.liquidev.dawd3.ui.EventContext
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
|
||||
abstract class Container(x: Int, y: Int) : Widget(x, y) {
|
||||
abstract val children: List<Widget>
|
||||
|
||||
override fun drawContent(matrices: MatrixStack, mouseX: Int, mouseY: Int, deltaTime: Float) {
|
||||
for (child in children) {
|
||||
child.draw(matrices, mouseX, mouseY, deltaTime)
|
||||
}
|
||||
}
|
||||
|
||||
override fun event(context: EventContext, event: Event): Boolean {
|
||||
return propagateEvent(context, event, children.reversed())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
package net.liquidev.dawd3.ui.widget
|
||||
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
|
||||
import net.liquidev.dawd3.audio.device.BlockEntityControls
|
||||
import net.liquidev.dawd3.audio.device.FloatControl
|
||||
import net.liquidev.dawd3.common.Degrees
|
||||
import net.liquidev.dawd3.common.Radians
|
||||
import net.liquidev.dawd3.common.clamp
|
||||
import net.liquidev.dawd3.common.mapRange
|
||||
import net.liquidev.dawd3.net.ControlTweaked
|
||||
import net.liquidev.dawd3.net.TweakControl
|
||||
import net.liquidev.dawd3.render.Render
|
||||
import net.liquidev.dawd3.render.TextureStrip
|
||||
import net.liquidev.dawd3.render.Tooltip
|
||||
|
|
@ -28,12 +28,13 @@ class Knob(
|
|||
val min: Float,
|
||||
val max: Float,
|
||||
val color: Color,
|
||||
size: Int = normalSize,
|
||||
val unit: FloatUnit = RawValue,
|
||||
// Pick a default sensitivity such that for pitch ranges we move by steps of 0.25.
|
||||
val sensitivity: Float = (max - min) * 0.25f / 96f,
|
||||
) : Widget(x, y) {
|
||||
override val width = 20
|
||||
override val height = 24
|
||||
override val width = size
|
||||
override val height = size + 4
|
||||
|
||||
private data class DraggingInfo(var previousMouseY: Double)
|
||||
|
||||
|
|
@ -109,7 +110,7 @@ class Knob(
|
|||
}
|
||||
}
|
||||
|
||||
override fun event(context: EventContext, event: Event): Event? {
|
||||
override fun event(context: EventContext, event: Event): Boolean {
|
||||
val client = MinecraftClient.getInstance()
|
||||
when (event) {
|
||||
is MouseButton -> if (event.button == GLFW.GLFW_MOUSE_BUTTON_LEFT) {
|
||||
|
|
@ -129,7 +130,7 @@ class Knob(
|
|||
event.absoluteMouseX * guiScale,
|
||||
event.absoluteMouseY * guiScale,
|
||||
)
|
||||
return null
|
||||
return true
|
||||
}
|
||||
Action.Up -> {
|
||||
val draggingInfo = draggingInfo
|
||||
|
|
@ -154,22 +155,17 @@ class Knob(
|
|||
if (draggingInfo != null) {
|
||||
val guiScale = client.options.guiScale.value.toFloat()
|
||||
val deltaY = (draggingInfo.previousMouseY - event.absoluteMouseY) * guiScale
|
||||
// Reflect the change locally immediately for lower latency.
|
||||
control.value = alterValue(control.value, by = deltaY.toFloat())
|
||||
ClientPlayNetworking.send(
|
||||
TweakControl.id,
|
||||
TweakControl(
|
||||
context.blockPosition,
|
||||
control.descriptor.name.id,
|
||||
control.valueToBytes()
|
||||
).serialize()
|
||||
BlockEntityControls.setFloatControlValue(
|
||||
context.blockPosition,
|
||||
control,
|
||||
alterValue(control.value, by = deltaY.toFloat())
|
||||
)
|
||||
draggingInfo.previousMouseY = event.absoluteMouseY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return event
|
||||
return false
|
||||
}
|
||||
|
||||
private fun alterValue(value: Float, by: Float): Float =
|
||||
|
|
@ -195,5 +191,8 @@ class Knob(
|
|||
val u = 18f + color.index.toFloat()
|
||||
return TextureStrip(u, 16f, u, 32f)
|
||||
}
|
||||
|
||||
const val normalSize = 20
|
||||
const val smallSize = 16
|
||||
}
|
||||
}
|
||||
|
|
@ -15,8 +15,8 @@ abstract class Widget(var x: Int, var y: Int) {
|
|||
deltaTime: Float,
|
||||
)
|
||||
|
||||
/** Returns non-null to propagate the event, or null to consume it. */
|
||||
abstract fun event(context: EventContext, event: Event): Event?
|
||||
/** Returns false to propagate the event, or true to consume it. */
|
||||
abstract fun event(context: EventContext, event: Event): Boolean
|
||||
|
||||
fun draw(matrices: MatrixStack, mouseX: Int, mouseY: Int, deltaTime: Float) {
|
||||
matrices.push()
|
||||
|
|
@ -36,10 +36,11 @@ abstract class Widget(var x: Int, var y: Int) {
|
|||
through: Iterable<Widget>,
|
||||
): Boolean {
|
||||
for (widget in through) {
|
||||
if (widget.event(
|
||||
if (
|
||||
widget.event(
|
||||
context,
|
||||
event.relativeTo(widget.x.toDouble(), widget.y.toDouble())
|
||||
) == null
|
||||
)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,19 @@ package net.liquidev.dawd3.ui.widget
|
|||
|
||||
import net.liquidev.dawd3.render.NinePatch
|
||||
import net.liquidev.dawd3.render.Render
|
||||
import net.liquidev.dawd3.ui.Event
|
||||
import net.liquidev.dawd3.ui.EventContext
|
||||
import net.liquidev.dawd3.ui.Rack
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
|
||||
class Window(x: Int, y: Int, override val width: Int, override val height: Int, val title: Text) :
|
||||
Widget(x, y) {
|
||||
class Window(
|
||||
x: Int,
|
||||
y: Int,
|
||||
override val width: Int,
|
||||
override val height: Int,
|
||||
val title: Text,
|
||||
) : Container(x, y) {
|
||||
|
||||
val children = mutableListOf<Widget>()
|
||||
override val children = mutableListOf<Widget>()
|
||||
|
||||
override fun drawContent(matrices: MatrixStack, mouseX: Int, mouseY: Int, deltaTime: Float) {
|
||||
Render.ninePatch(matrices, 2, 2, width, height, Rack.atlas, windowShadow)
|
||||
|
|
@ -25,13 +28,7 @@ class Window(x: Int, y: Int, override val width: Int, override val height: Int,
|
|||
0x111111
|
||||
)
|
||||
|
||||
for (child in children) {
|
||||
child.draw(matrices, mouseX, mouseY, deltaTime)
|
||||
}
|
||||
}
|
||||
|
||||
override fun event(context: EventContext, event: Event): Event? {
|
||||
return if (propagateEvent(context, event, children)) null else event
|
||||
super.drawContent(matrices, mouseX, mouseY, deltaTime)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
64
src/main/kotlin/net/liquidev/dawd3/ui/widget/keyboard/Key.kt
Normal file
64
src/main/kotlin/net/liquidev/dawd3/ui/widget/keyboard/Key.kt
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
package net.liquidev.dawd3.ui.widget.keyboard
|
||||
|
||||
import net.liquidev.dawd3.audio.devices.io.KeyboardDevice
|
||||
import net.liquidev.dawd3.render.Render
|
||||
import net.liquidev.dawd3.render.Sprite
|
||||
import net.liquidev.dawd3.ui.Event
|
||||
import net.liquidev.dawd3.ui.EventContext
|
||||
import net.liquidev.dawd3.ui.Rack
|
||||
import net.liquidev.dawd3.ui.widget.Widget
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
|
||||
class Key(
|
||||
x: Int,
|
||||
y: Int,
|
||||
val type: Type,
|
||||
val note: Float,
|
||||
val controls: KeyboardDevice.Controls,
|
||||
) : Widget(x, y) {
|
||||
|
||||
enum class Type(
|
||||
val width: Int,
|
||||
val height: Int,
|
||||
val idleSprite: Sprite,
|
||||
val pressedSprite: Sprite,
|
||||
) {
|
||||
White(
|
||||
width = 10,
|
||||
height = 32,
|
||||
idleSprite = Sprite(u = 32, v = 16, width = 10, height = 32),
|
||||
pressedSprite = Sprite(u = 42, v = 16, width = 10, height = 32),
|
||||
),
|
||||
Black(
|
||||
width = 5,
|
||||
height = 20,
|
||||
idleSprite = Sprite(u = 52, v = 16, width = 7, height = 20),
|
||||
pressedSprite = Sprite(u = 52, v = 36, width = 7, height = 20)
|
||||
),
|
||||
}
|
||||
|
||||
override val width = type.width
|
||||
override val height = type.height
|
||||
|
||||
private var isPressed = false
|
||||
|
||||
override fun drawContent(matrices: MatrixStack, mouseX: Int, mouseY: Int, deltaTime: Float) {
|
||||
Render.sprite(
|
||||
matrices,
|
||||
x = 0,
|
||||
y = 0,
|
||||
Rack.atlas,
|
||||
if (isPressed) type.pressedSprite else type.idleSprite
|
||||
)
|
||||
}
|
||||
|
||||
override fun event(context: EventContext, event: Event) = false
|
||||
|
||||
internal fun triggerDown() {
|
||||
isPressed = true
|
||||
}
|
||||
|
||||
internal fun triggerUp() {
|
||||
isPressed = false
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
package net.liquidev.dawd3.ui.widget.keyboard
|
||||
|
||||
import net.liquidev.dawd3.audio.device.BlockEntityControls
|
||||
import net.liquidev.dawd3.audio.devices.io.KeyboardDevice
|
||||
import net.liquidev.dawd3.ui.*
|
||||
import net.liquidev.dawd3.ui.widget.Container
|
||||
import org.lwjgl.glfw.GLFW
|
||||
|
||||
class Keyboard(
|
||||
x: Int,
|
||||
y: Int,
|
||||
firstNote: Int,
|
||||
lastNote: Int,
|
||||
private val controls: KeyboardDevice.Controls,
|
||||
) : Container(x, y) {
|
||||
|
||||
override val children = run {
|
||||
var whiteX = 0
|
||||
List(lastNote - firstNote) { index ->
|
||||
val note = firstNote + index
|
||||
val keyType = octave[note.mod(octave.size)]
|
||||
val keyX = when (keyType) {
|
||||
Key.Type.White -> {
|
||||
val xx = whiteX
|
||||
whiteX += keyType.width - 1
|
||||
xx
|
||||
}
|
||||
Key.Type.Black -> whiteX - keyType.width / 2 - 1
|
||||
}
|
||||
Key(keyX, y = 0, keyType, note.toFloat(), controls)
|
||||
// We want black keys to render after white keys.
|
||||
}.sortedBy { it.type }
|
||||
}
|
||||
|
||||
override val width = children.maxOf { it.x + it.width }
|
||||
override val height = 24
|
||||
|
||||
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
|
||||
if (mouseIsDown) {
|
||||
setPressedKey(context, findPressedKey(event.mouseX.toInt(), event.mouseY.toInt()))
|
||||
} else {
|
||||
setPressedKey(context, null)
|
||||
}
|
||||
return mouseIsDown && pressedKey != null
|
||||
}
|
||||
|
||||
if (event is MouseMove && mouseIsDown) {
|
||||
setPressedKey(context, findPressedKey(event.mouseX.toInt(), event.mouseY.toInt()))
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun findPressedKey(mouseX: Int, mouseY: Int): Key? =
|
||||
children.findLast { it.containsRelativePoint(mouseX - it.x, mouseY - it.y) }
|
||||
|
||||
private fun setPressedKey(context: EventContext, newKey: Key?) {
|
||||
val previousKey = pressedKey
|
||||
pressedKey = newKey
|
||||
if (newKey != previousKey) {
|
||||
previousKey?.triggerUp()
|
||||
if (newKey != null) {
|
||||
newKey.triggerDown()
|
||||
BlockEntityControls.setFloatControlValue(
|
||||
context.blockPosition,
|
||||
controls.pitch,
|
||||
newKey.note
|
||||
)
|
||||
BlockEntityControls.setFloatControlValue(
|
||||
context.blockPosition,
|
||||
controls.trigger,
|
||||
1f
|
||||
)
|
||||
// TODO: Key velocity.
|
||||
BlockEntityControls.setFloatControlValue(
|
||||
context.blockPosition,
|
||||
controls.velocity,
|
||||
1f
|
||||
)
|
||||
} else {
|
||||
BlockEntityControls.setFloatControlValue(
|
||||
context.blockPosition,
|
||||
controls.trigger,
|
||||
0f
|
||||
)
|
||||
BlockEntityControls.setFloatControlValue(
|
||||
context.blockPosition,
|
||||
controls.velocity,
|
||||
0f
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var mouseIsDown = false
|
||||
|
||||
val octave = arrayOf(
|
||||
// For efficiency we start with A, since pitch signals represent it as 0.
|
||||
Key.Type.White, // A
|
||||
Key.Type.Black, // A#
|
||||
Key.Type.White, // B
|
||||
Key.Type.White, // C
|
||||
Key.Type.Black, // C#
|
||||
Key.Type.White, // D
|
||||
Key.Type.Black, // D#
|
||||
Key.Type.White, // E
|
||||
Key.Type.White, // F
|
||||
Key.Type.Black, // F#
|
||||
Key.Type.White, // G
|
||||
Key.Type.Black, // G#
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
"item.dawd3.red_patch_cable": "Red Patch Cable",
|
||||
"item.dawd3.black_patch_cable": "Black Patch Cable",
|
||||
"block.dawd3.amplifier": "Amplifier",
|
||||
"block.dawd3.keyboard": "Keyboard",
|
||||
"block.dawd3.knob": "Knob",
|
||||
"block.dawd3.modulator": "Modulator",
|
||||
"block.dawd3.phase": "Phase",
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 300 B After Width: | Height: | Size: 344 B |
Binary file not shown.
|
Before Width: | Height: | Size: 373 B After Width: | Height: | Size: 480 B |
Reference in a new issue