biquad filters

This commit is contained in:
りき萌 2023-05-04 12:46:55 +02:00
parent c682d69a3e
commit 81ada8fd9b
42 changed files with 1145 additions and 141 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,6 +1,9 @@
// 1.19.2 2023-05-03T22:15:16.62168443 Models
// 1.19.2 2023-05-04T12:05:42.735576298 Models
ab1820dba3bfcb2fd52b83a3938b7664deae61fc assets/dawd3/models/item/biquad_high_pass.json
5919f5e0f79620a682f481a8e02995f95724b2ce assets/dawd3/models/block/amplifier.json
92eda96dc509faf070a1900ef9a28de92e5a2759 assets/dawd3/models/item/biquad_notch.json
c3ea3e310d8fe7796b5b055d34db712cb8c7ac5a assets/dawd3/blockstates/triangle_oscillator.json
559aa36552662b42fb817f73b72c2b963d6bda88 assets/dawd3/blockstates/biquad_notch.json
97f0b7f5e19cd8c92915c4dfdedcee0e0b2a4b7f assets/dawd3/models/item/amplifier.json
0fb5cd695c2a82a2353809529dc8b5086ee2c87d assets/dawd3/blockstates/phase.json
5ed33e9ec3c70e8cc027eea6425951d51487437f assets/dawd3/models/item/blue_patch_cable.json
@ -11,20 +14,25 @@ fe4987cffd1253462cc8440c90ff2341ac3026a4 assets/dawd3/models/block/triangle_osci
d1e691559156bd4bf0ec0d488d1a28ac193f4967 assets/dawd3/blockstates/adsr.json
123ed8aa83a77b4714cee4dfc6747832cf72c75c assets/dawd3/blockstates/mixer.json
becb814a10bcf2d3e071a6479e9b2289165d0059 assets/dawd3/models/item/modulator.json
90bea21dbe4feeaff17d3a16487d4a8a0f459329 assets/dawd3/blockstates/biquad_low_pass.json
f69a4acfdf715c64f64830ce0a79aa452ad4760a assets/dawd3/models/item/saw_oscillator.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
019bcf77479bfc64a04555f9864e2cbac2055b9f assets/dawd3/models/block/phase.json
d34f7c647d354526a32588ce859fb7fc39bf3fb5 assets/dawd3/models/block/phase.json
292685c025f28911bca9252da3e4ac72998b3c7a assets/dawd3/blockstates/pulse_oscillator.json
9324c53b8d96635804d363f8e27f8dfea138e25b assets/dawd3/models/item/biquad_low_pass.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
21bbd95c32540ade970a960697cec0a2a977322d assets/dawd3/models/block/biquad_notch.json
b86fca103cf1e781c373131cc748f223ce785993 assets/dawd3/blockstates/biquad_band_pass.json
0afd7ba8d87444961a33cb87bba122fca5ebef8e assets/dawd3/models/block/saw_oscillator.json
67ff4ae22c5f716f1aa2b6e2dac31d12be2336d1 assets/dawd3/blockstates/modulator.json
64c9ff6a94721f17a823c9d253559e5b9e73662a assets/dawd3/models/block/sine_oscillator.json
012ae6bec3490e1e4f4b8a4677ce46600e1a501c assets/dawd3/models/block/mixer.json
50023b9cff64844a4001e3e78d3f0ac828f2724a assets/dawd3/models/block/sine_oscillator.json
f4979bec00279f57ee706c17210147cbc8412a4e assets/dawd3/models/block/mixer.json
e94f02b2105c4d89cf963651121582e4dc3ba7d0 assets/dawd3/blockstates/biquad_high_pass.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
@ -34,19 +42,23 @@ bf0e322e33123cb6873c2da4e8c6ab85688deb4e assets/dawd3/models/item/gray_patch_cab
8ba890b28c5ac57c59f19ccc8c72825caac10677 assets/dawd3/models/item/magenta_patch_cable.json
e34001d3c974aecfa347d435beb6bc0b9d325897 assets/dawd3/models/item/cyan_patch_cable.json
550c0b15996732cc81c5871290b7fc2e6608c060 assets/dawd3/models/block/adsr.json
df50baa0409cf07eb789f731588995342e9f0c0c assets/dawd3/models/block/biquad_high_pass.json
f7b47538f17992177e97e06842c0039ae5096b2b assets/dawd3/blockstates/speaker.json
9cf2cff42345ec60a944d7399b5047323aa8e88c assets/dawd3/models/item/red_patch_cable.json
8c6f0307320980a66c70622b0b7c72c8cfe78dc3 assets/dawd3/models/item/light_gray_patch_cable.json
0d899dc2bd693c95d582231a00faf40bf1d67a47 assets/dawd3/blockstates/saw_oscillator.json
8c4b8147bfea2bdb8c1d348bc332a60d2cd82d68 assets/dawd3/models/item/phase.json
8aa966337109315240614d5257eb72f959eba5d8 assets/dawd3/models/item/orange_patch_cable.json
0b8f2a8c456a65c5dd415fc6ad3459dd8b43f954 assets/dawd3/models/block/pulse_oscillator.json
3bbd395ae432b4df11d3029de946e4ac10226b32 assets/dawd3/models/block/biquad_low_pass.json
ddb6c2275b0c671144c2a2fdff0f58f171851a11 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
fcdf84d35d87e83ca2401d78a4867abf05933ea5 assets/dawd3/models/item/biquad_band_pass.json
4be49e87d036188e4c9d5285d7fcebbb25954dfe assets/dawd3/models/block/keyboard.json
2adb4f854a9f13090dffaf8ab9dfe0553cc59a80 assets/dawd3/models/item/triangle_oscillator.json
0138d252653a513ed398ddf55f00cafefc577298 assets/dawd3/models/block/biquad_band_pass.json
3b1811bab3ba394ba03b67ac2efc72cb35316dc8 assets/dawd3/blockstates/sine_oscillator.json
8688de3eadb6579cac89522683c394f18733e614 assets/dawd3/models/block/knob.json
88b188e4e2b4354de87a0d57bdc0260881438bdd assets/dawd3/models/item/adsr.json

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=east": {
"model": "dawd3:block/biquad_band_pass",
"y": 90
},
"facing=north": {
"model": "dawd3:block/biquad_band_pass"
},
"facing=south": {
"model": "dawd3:block/biquad_band_pass",
"y": 180
},
"facing=west": {
"model": "dawd3:block/biquad_band_pass",
"y": 270
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=east": {
"model": "dawd3:block/biquad_high_pass",
"y": 90
},
"facing=north": {
"model": "dawd3:block/biquad_high_pass"
},
"facing=south": {
"model": "dawd3:block/biquad_high_pass",
"y": 180
},
"facing=west": {
"model": "dawd3:block/biquad_high_pass",
"y": 270
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=east": {
"model": "dawd3:block/biquad_low_pass",
"y": 90
},
"facing=north": {
"model": "dawd3:block/biquad_low_pass"
},
"facing=south": {
"model": "dawd3:block/biquad_low_pass",
"y": 180
},
"facing=west": {
"model": "dawd3:block/biquad_low_pass",
"y": 270
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=east": {
"model": "dawd3:block/biquad_notch",
"y": 90
},
"facing=north": {
"model": "dawd3:block/biquad_notch"
},
"facing=south": {
"model": "dawd3:block/biquad_notch",
"y": 180
},
"facing=west": {
"model": "dawd3:block/biquad_notch",
"y": 270
}
}
}

View file

@ -0,0 +1,150 @@
{
"parent": "block/block",
"elements": [
{
"faces": {
"down": {
"cullface": "down",
"texture": "#bottom"
},
"east": {
"cullface": "east",
"texture": "#right"
},
"north": {
"cullface": "north",
"texture": "#front"
},
"south": {
"cullface": "south",
"texture": "#back"
},
"up": {
"cullface": "up",
"rotation": 180,
"texture": "#top"
},
"west": {
"cullface": "west",
"texture": "#left"
}
},
"from": [
0.0,
0.0,
0.0
],
"to": [
16.0,
16.0,
16.0
]
},
{
"faces": {
"north": {
"cullface": "north",
"texture": "#port",
"uv": [
0.0,
0.0,
4.0,
4.0
]
}
},
"from": [
9.0,
9.0,
-0.01
],
"to": [
13.0,
13.0,
0.01
]
},
{
"faces": {
"north": {
"cullface": "north",
"texture": "#port",
"uv": [
0.0,
0.0,
4.0,
4.0
]
}
},
"from": [
3.0,
9.0,
-0.01
],
"to": [
7.0,
13.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
]
},
{
"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": {
"back": "dawd3:block/biquad_band_pass_side",
"bottom": "dawd3:block/biquad_band_pass_side",
"front": "dawd3:block/biquad_band_pass_front",
"left": "dawd3:block/biquad_band_pass_side",
"particle": "dawd3:block/biquad_band_pass_side",
"port": "dawd3:device/port",
"right": "dawd3:block/biquad_band_pass_side",
"top": "dawd3:block/biquad_band_pass_side"
}
}

View file

@ -0,0 +1,150 @@
{
"parent": "block/block",
"elements": [
{
"faces": {
"down": {
"cullface": "down",
"texture": "#bottom"
},
"east": {
"cullface": "east",
"texture": "#right"
},
"north": {
"cullface": "north",
"texture": "#front"
},
"south": {
"cullface": "south",
"texture": "#back"
},
"up": {
"cullface": "up",
"rotation": 180,
"texture": "#top"
},
"west": {
"cullface": "west",
"texture": "#left"
}
},
"from": [
0.0,
0.0,
0.0
],
"to": [
16.0,
16.0,
16.0
]
},
{
"faces": {
"north": {
"cullface": "north",
"texture": "#port",
"uv": [
0.0,
0.0,
4.0,
4.0
]
}
},
"from": [
9.0,
9.0,
-0.01
],
"to": [
13.0,
13.0,
0.01
]
},
{
"faces": {
"north": {
"cullface": "north",
"texture": "#port",
"uv": [
0.0,
0.0,
4.0,
4.0
]
}
},
"from": [
3.0,
9.0,
-0.01
],
"to": [
7.0,
13.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
]
},
{
"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": {
"back": "dawd3:block/biquad_high_pass_side",
"bottom": "dawd3:block/biquad_high_pass_side",
"front": "dawd3:block/biquad_high_pass_front",
"left": "dawd3:block/biquad_high_pass_side",
"particle": "dawd3:block/biquad_high_pass_side",
"port": "dawd3:device/port",
"right": "dawd3:block/biquad_high_pass_side",
"top": "dawd3:block/biquad_high_pass_side"
}
}

View file

@ -0,0 +1,150 @@
{
"parent": "block/block",
"elements": [
{
"faces": {
"down": {
"cullface": "down",
"texture": "#bottom"
},
"east": {
"cullface": "east",
"texture": "#right"
},
"north": {
"cullface": "north",
"texture": "#front"
},
"south": {
"cullface": "south",
"texture": "#back"
},
"up": {
"cullface": "up",
"rotation": 180,
"texture": "#top"
},
"west": {
"cullface": "west",
"texture": "#left"
}
},
"from": [
0.0,
0.0,
0.0
],
"to": [
16.0,
16.0,
16.0
]
},
{
"faces": {
"north": {
"cullface": "north",
"texture": "#port",
"uv": [
0.0,
0.0,
4.0,
4.0
]
}
},
"from": [
9.0,
9.0,
-0.01
],
"to": [
13.0,
13.0,
0.01
]
},
{
"faces": {
"north": {
"cullface": "north",
"texture": "#port",
"uv": [
0.0,
0.0,
4.0,
4.0
]
}
},
"from": [
3.0,
9.0,
-0.01
],
"to": [
7.0,
13.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
]
},
{
"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": {
"back": "dawd3:block/biquad_low_pass_side",
"bottom": "dawd3:block/biquad_low_pass_side",
"front": "dawd3:block/biquad_low_pass_front",
"left": "dawd3:block/biquad_low_pass_side",
"particle": "dawd3:block/biquad_low_pass_side",
"port": "dawd3:device/port",
"right": "dawd3:block/biquad_low_pass_side",
"top": "dawd3:block/biquad_low_pass_side"
}
}

View file

@ -0,0 +1,150 @@
{
"parent": "block/block",
"elements": [
{
"faces": {
"down": {
"cullface": "down",
"texture": "#bottom"
},
"east": {
"cullface": "east",
"texture": "#right"
},
"north": {
"cullface": "north",
"texture": "#front"
},
"south": {
"cullface": "south",
"texture": "#back"
},
"up": {
"cullface": "up",
"rotation": 180,
"texture": "#top"
},
"west": {
"cullface": "west",
"texture": "#left"
}
},
"from": [
0.0,
0.0,
0.0
],
"to": [
16.0,
16.0,
16.0
]
},
{
"faces": {
"north": {
"cullface": "north",
"texture": "#port",
"uv": [
0.0,
0.0,
4.0,
4.0
]
}
},
"from": [
9.0,
9.0,
-0.01
],
"to": [
13.0,
13.0,
0.01
]
},
{
"faces": {
"north": {
"cullface": "north",
"texture": "#port",
"uv": [
0.0,
0.0,
4.0,
4.0
]
}
},
"from": [
3.0,
9.0,
-0.01
],
"to": [
7.0,
13.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
]
},
{
"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": {
"back": "dawd3:block/biquad_notch_side",
"bottom": "dawd3:block/biquad_notch_side",
"front": "dawd3:block/biquad_notch_front",
"left": "dawd3:block/biquad_notch_side",
"particle": "dawd3:block/biquad_notch_side",
"port": "dawd3:device/port",
"right": "dawd3:block/biquad_notch_side",
"top": "dawd3:block/biquad_notch_side"
}
}

View file

@ -40,6 +40,54 @@
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": {
"cullface": "north",
"texture": "#port",
"uv": [
0.0,
0.0,
4.0,
4.0
]
}
},
"from": [
9.0,
9.0,
-0.01
],
"to": [
13.0,
13.0,
0.01
]
},
{
"faces": {
"north": {
@ -63,54 +111,6 @@
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
]
},
{
"faces": {
"north": {
"cullface": "north",
"texture": "#port",
"uv": [
0.0,
0.0,
4.0,
4.0
]
}
},
"from": [
9.0,
9.0,
-0.01
],
"to": [
13.0,
13.0,
0.01
]
}
],
"textures": {

View file

@ -40,30 +40,6 @@
16.0
]
},
{
"faces": {
"north": {
"cullface": "north",
"texture": "#port",
"uv": [
0.0,
0.0,
4.0,
4.0
]
}
},
"from": [
9.0,
9.0,
-0.01
],
"to": [
13.0,
13.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,
9.0,
-0.01
],
"to": [
13.0,
13.0,
0.01
]
},
{
"faces": {
"north": {

View file

@ -40,30 +40,6 @@
16.0
]
},
{
"faces": {
"north": {
"cullface": "north",
"texture": "#port",
"uv": [
0.0,
0.0,
4.0,
4.0
]
}
},
"from": [
9.0,
9.0,
-0.01
],
"to": [
13.0,
13.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,
9.0,
-0.01
],
"to": [
13.0,
13.0,
0.01
]
},
{
"faces": {
"north": {

View file

@ -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": {

View file

@ -0,0 +1,3 @@
{
"parent": "dawd3:block/biquad_band_pass"
}

View file

@ -0,0 +1,3 @@
{
"parent": "dawd3:block/biquad_high_pass"
}

View file

@ -0,0 +1,3 @@
{
"parent": "dawd3:block/biquad_low_pass"
}

View file

@ -0,0 +1,3 @@
{
"parent": "dawd3:block/biquad_notch"
}

View file

@ -0,0 +1,167 @@
package net.liquidev.dawd3.audio.devices.filter
import net.liquidev.dawd3.Mod
import net.liquidev.dawd3.audio.Audio
import net.liquidev.dawd3.audio.device.*
import net.liquidev.dawd3.common.clamp
import net.minecraft.util.Identifier
import kotlin.math.cos
import kotlin.math.max
import kotlin.math.sin
class BiquadDevice(val type: Type) : Device<BiquadDevice.Controls> {
companion object : DeviceDescriptor {
override val id = Identifier(Mod.id, "biquad")
val inputPort = InputPortName(id, "input")
val frequencyCVPort = InputPortName(id, "frequency_cv")
val resonanceCVPort = InputPortName(id, "resonance_cv")
val outputPort = OutputPortName(id, "output")
val frequencyControl = ControlDescriptor(id, "frequency", 8000f)
val frequencyCVControl = ControlDescriptor(id, "frequency_cv", 16000f)
val resonanceControl = ControlDescriptor(id, "resonance", 0.5f)
val resonanceCVControl = ControlDescriptor(id, "resonance_cv", 0.5f)
}
class Controls : ControlSet {
val frequency = FloatControl(frequencyControl)
val frequencyCV = FloatControl(frequencyCVControl)
val resonance = FloatControl(resonanceControl)
val resonanceCV = FloatControl(resonanceCVControl)
override fun visitControls(visit: (ControlName, Control) -> Unit) {
visit(frequencyControl.name, frequency)
visit(frequencyCVControl.name, frequencyCV)
visit(resonanceControl.name, resonance)
visit(resonanceCVControl.name, resonanceCV)
}
}
enum class Type {
LowPass,
HighPass,
BandPass,
Notch,
}
val input = InputPort()
val frequencyCV = InputPort()
val resonanceCV = InputPort()
val output = OutputPort(bufferCount = 1)
private var firstSample = true
private var x1 = 0f
private var x2 = 0f
private var y1 = 0f
private var y2 = 0f
private var b0a0 = 0f
private var b1a0 = 0f
private var b2a0 = 0f
private var a1a0 = 0f
private var a2a0 = 0f
private var frequency: Float? = null
private var resonance: Float? = null
private fun updateCoefficients(frequency: Float, resonance: Float) {
if (frequency == this.frequency && resonance == this.resonance) {
return
}
this.frequency = frequency
this.resonance = resonance
// Need to clamp the frequency to 1Hz here because if it reaches 0 we get division by 0,
// which explodes the entire state. Similar thing with resonance.
val f = max(1f, frequency) * Audio.sampleRateFInv
val r = clamp(resonance, 0f, 1f)
val alpha = sin(f) * (1f - r)
val cosW0 = cos(f)
val a0 = 1f + alpha
val a1 = -2f * cosW0
val a2 = 1f - alpha
var b0 = 0f
var b1 = 0f
var b2 = 0f
when (type) {
Type.LowPass -> {
b0 = (1f - cosW0) * 0.5f
b1 = 1f - cosW0
b2 = (1f - cosW0) * 0.5f
}
Type.HighPass -> {
b0 = (1f + cosW0) * 0.5f
b1 = -1f - cosW0
b2 = (1f + cosW0) * 0.5f
}
Type.BandPass -> {
b0 = r * alpha
b1 = 0f
b2 = -r * alpha
}
Type.Notch -> {
b0 = 1f
b1 = -2f * cosW0
b2 = 1f
}
}
b0a0 = b0 / a0
b1a0 = b1 / a0
b2a0 = b2 / a0
a1a0 = a1 / a0
a2a0 = a2 / a0
}
override fun process(sampleCount: Int, controls: Controls) {
val inputBuffer = input.getConnectedOutputBuffer(0, sampleCount)
val frequencyCVBuffer = frequencyCV.getConnectedOutputBuffer(0, sampleCount)
val resonanceCVBuffer = resonanceCV.getConnectedOutputBuffer(0, sampleCount)
val outputBuffer = output.buffers[0].getOrReallocate(sampleCount)
val frequencyCenter = controls.frequency.value
val frequencyCV = controls.frequencyCV.value
val resonanceCenter = controls.resonance.value
val resonanceCV = controls.resonanceCV.value
for (i in 0 until sampleCount) {
val x0 = inputBuffer[i]
if (firstSample) {
y1 = x0
y2 = x0
x1 = x0
x2 = x0
firstSample = false
}
val frequency = frequencyCenter + frequencyCVBuffer[i] * frequencyCV
val resonance = resonanceCenter + resonanceCVBuffer[i] * resonanceCV
updateCoefficients(frequency, resonance)
val y0 = b0a0 * x0 + b1a0 * x1 + b2a0 * x2 - a1a0 * y1 - a2a0 * y2
x2 = x1
x1 = x0
y2 = y1
y1 = y0
outputBuffer[i] = y0
}
}
override fun visitInputPorts(visit: (InputPortName, InputPort) -> Unit) {
visit(inputPort, input)
visit(frequencyCVPort, frequencyCV)
visit(resonanceCVPort, resonanceCV)
}
override fun visitOutputPorts(visit: (OutputPortName, OutputPort) -> Unit) {
visit(outputPort, output)
}
}

View file

@ -12,6 +12,7 @@ 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.envelope.AdsrBlockDescriptor
import net.liquidev.dawd3.block.devices.filter.BiquadBlockDescriptor
import net.liquidev.dawd3.block.devices.io.KeyboardBlockDescriptor
import net.liquidev.dawd3.block.devices.io.KnobBlockDescriptor
import net.liquidev.dawd3.block.devices.math.AmplifierBlockDescriptor
@ -63,11 +64,18 @@ object Blocks {
Block(FabricBlockSettings.of(Material.METAL))
)!!
//
// Device blocks
//
// NOTE: The order here matters, as it defines the order in which the items appear in the
// creative tab. Generally we want to group devices of similar function together.
//
val speaker = registerDeviceBlock(SpeakerBlockDescriptor)
val knob = registerDeviceBlock(KnobBlockDescriptor)
val keyboard = registerDeviceBlock(KeyboardBlockDescriptor)
val amplifier = registerDeviceBlock(AmplifierBlockDescriptor)
val modulator = registerDeviceBlock(ModulatorBlockDescriptor)
val mixer = registerDeviceBlock(MixerBlockDescriptor)
@ -78,6 +86,11 @@ object Blocks {
val sawOscillator = registerDeviceBlock(SawOscillatorBlockDescriptor)
val triangleOscillator = registerDeviceBlock(TriangleOscillatorBlockDescriptor)
val biquadLowPass = registerDeviceBlock(BiquadBlockDescriptor.lowPass)
val biquadHighPass = registerDeviceBlock(BiquadBlockDescriptor.highPass)
val biquadBandPass = registerDeviceBlock(BiquadBlockDescriptor.bandPass)
val biquadNotch = registerDeviceBlock(BiquadBlockDescriptor.notch)
val adsr = registerDeviceBlock(AdsrBlockDescriptor)
fun initialize() {}

View file

@ -0,0 +1,101 @@
package net.liquidev.dawd3.block.devices.filter
import net.liquidev.dawd3.Mod
import net.liquidev.dawd3.audio.device.DeviceInstance
import net.liquidev.dawd3.audio.devices.filter.BiquadDevice
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.units.SiValue
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
class BiquadBlockDescriptor(
override val id: Identifier,
private val type: BiquadDevice.Type,
) : DeviceBlockDescriptor<BiquadBlockDescriptor.ClientState, BiquadDevice.Controls> {
companion object {
val lowPass =
BiquadBlockDescriptor(Identifier(Mod.id, "biquad_low_pass"), BiquadDevice.Type.LowPass)
val highPass = BiquadBlockDescriptor(
Identifier(Mod.id, "biquad_high_pass"),
BiquadDevice.Type.HighPass
)
val bandPass = BiquadBlockDescriptor(
Identifier(Mod.id, "biquad_band_pass"),
BiquadDevice.Type.BandPass
)
val notch =
BiquadBlockDescriptor(Identifier(Mod.id, "biquad_notch"), BiquadDevice.Type.Notch)
}
override val portLayout = PhysicalPort.layout {
port(BiquadDevice.inputPort, position = Vec2f(0.25f, 0.25f), PhysicalPort.Side.Front)
port(BiquadDevice.frequencyCVPort, position = Vec2f(0.75f, 0.25f), PhysicalPort.Side.Front)
port(BiquadDevice.resonanceCVPort, position = Vec2f(0.25f, 0.75f), PhysicalPort.Side.Front)
port(BiquadDevice.outputPort, position = Vec2f(0.75f, 0.75f), PhysicalPort.Side.Front)
}
class ClientState(type: BiquadDevice.Type, controls: BiquadDevice.Controls) :
DeviceBlockDescriptor.ClientState {
override val logicalDevice =
DeviceInstance.create(BiquadDevice(type), controls)
}
override fun initControls() = BiquadDevice.Controls()
override fun onClientLoad(controls: BiquadDevice.Controls, world: ClientWorld) =
ClientState(type, controls)
override val ui = object : DeviceBlockDescriptor.UI<BiquadDevice.Controls> {
override fun open(controls: BiquadDevice.Controls, x: Int, y: Int) =
Window(
x,
y,
width = 121,
height = 48,
Text.translatable(id.toTranslationKey("block"))
).apply {
children.add(
Knob(
x = 8, y = 18,
controls.frequency,
min = 1f, max = 25000f,
Knob.Color.Orange,
unit = SiValue.frequency,
)
)
children.add(
Knob(
x = 36, y = 18,
controls.frequencyCV,
min = -20000f, max = 20000f,
Knob.Color.Orange,
unit = SiValue.frequency,
)
)
children.add(
Knob(
x = 64, y = 18,
controls.resonance,
min = 0f, max = 1f,
Knob.Color.Blue,
unit = PercentageValue
)
)
children.add(
Knob(
x = 92, y = 18,
controls.resonanceCV,
min = -1f, max = 1f,
Knob.Color.Blue,
unit = PercentageValue,
)
)
}
}
}

View file

@ -1,6 +1,7 @@
package net.liquidev.dawd3.ui.units
import net.liquidev.dawd3.audio.unit.Amplitude
import kotlin.math.abs
import kotlin.math.roundToInt
interface FloatUnit {
@ -29,24 +30,26 @@ object PercentageValue : FloatUnit {
class SiValue(val unit: String) : FloatUnit {
override fun display(value: Float): String {
val abs = abs(value)
val divided: Float =
if (value > 1_000_000_000_000) value / 1_000_000_000_000
else if (value > 1_000_000_000) value / 1_000_000_000
else if (value > 1_000_000) value / 1_000_000
else if (value > 1_000) value / 1_000
else if (value < 1) value * 1_000
if (abs >= 1_000_000_000_000) value / 1_000_000_000_000
else if (abs >= 1_000_000_000) value / 1_000_000_000
else if (abs >= 1_000_000) value / 1_000_000
else if (abs >= 1_000) value / 1_000
else if (abs < 1) value * 1_000
else value
val prefix =
if (value > 1_000_000_000_000) "T"
else if (value > 1_000_000_000) "G"
else if (value > 1_000_000) "M"
else if (value > 1_000) "k"
else if (value < 1) "m"
if (abs >= 1_000_000_000_000) "T"
else if (abs >= 1_000_000_000) "G"
else if (abs >= 1_000_000) "M"
else if (abs >= 1_000) "k"
else if (abs < 1) "m"
else ""
return String.format("%.01f %s%s", divided, prefix, unit)
}
companion object {
val time = SiValue("s")
val frequency = SiValue("Hz")
}
}

View file

@ -1,6 +1,6 @@
package net.liquidev.dawd3.ui.widget.keyboard
import net.liquidev.dawd3.audio.devices.io.KeyboardDevice
import net.liquidev.dawd3.audio.device.FloatControl
import net.liquidev.dawd3.render.Render
import net.liquidev.dawd3.render.Sprite
import net.liquidev.dawd3.ui.Event
@ -14,7 +14,7 @@ class Key(
y: Int,
val type: Type,
val note: Float,
val controls: KeyboardDevice.Controls,
val pitchControl: FloatControl,
) : Widget(x, y) {
enum class Type(
@ -22,18 +22,21 @@ class Key(
val height: Int,
val idleSprite: Sprite,
val pressedSprite: Sprite,
val currentPitchSprite: 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),
currentPitchSprite = Sprite(u = 59, v = 16, width = 4, height = 4),
),
Black(
width = 5,
width = 7,
height = 20,
idleSprite = Sprite(u = 52, v = 16, width = 7, height = 20),
pressedSprite = Sprite(u = 52, v = 36, width = 7, height = 20)
pressedSprite = Sprite(u = 52, v = 36, width = 7, height = 20),
currentPitchSprite = Sprite(u = 59, v = 20, width = 3, height = 3),
),
}
@ -50,6 +53,15 @@ class Key(
Rack.atlas,
if (isPressed) type.pressedSprite else type.idleSprite
)
if (pitchControl.value == note) {
Render.sprite(
matrices,
x = (width / 2f - type.currentPitchSprite.width / 2f).toInt(),
y = height - type.currentPitchSprite.height - 2,
Rack.atlas,
type.currentPitchSprite
)
}
}
override fun event(context: EventContext, event: Event) = false

View file

@ -25,9 +25,9 @@ class Keyboard(
whiteX += keyType.width - 1
xx
}
Key.Type.Black -> whiteX - keyType.width / 2 - 1
Key.Type.Black -> whiteX - keyType.width / 2
}
Key(keyX, y = 0, keyType, note.toFloat(), controls)
Key(keyX, y = 0, keyType, note.toFloat(), controls.pitch)
// We want black keys to render after white keys.
}.sortedBy { it.type }
}

View file

@ -18,6 +18,10 @@
"item.dawd3.black_patch_cable": "Black Patch Cable",
"block.dawd3.adsr": "ADSR",
"block.dawd3.amplifier": "Amplifier",
"block.dawd3.biquad_low_pass": "Low-Pass Filter (2P)",
"block.dawd3.biquad_high_pass": "High-Pass Filter (2P)",
"block.dawd3.biquad_band_pass": "Band-Pass Filter (2P)",
"block.dawd3.biquad_notch": "Notch Filter (2P)",
"block.dawd3.keyboard": "Keyboard",
"block.dawd3.knob": "Knob",
"block.dawd3.mixer": "Mixer",
@ -35,6 +39,10 @@
"dawd3.control.dawd3.adsr.release": "REL",
"dawd3.control.dawd3.amplifier.amplitude": "AMP",
"dawd3.control.dawd3.amplifier.amplitude_cv": "CV",
"dawd3.control.dawd3.biquad.frequency": "FRQ",
"dawd3.control.dawd3.biquad.frequency_cv": "Fcv",
"dawd3.control.dawd3.biquad.resonance": "RES",
"dawd3.control.dawd3.biquad.resonance_cv": "Rcv",
"dawd3.control.dawd3.constant.value": "",
"dawd3.control.dawd3.fma.add": "ADD",
"dawd3.control.dawd3.fma.multiply": "MUL",

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 480 B

After

Width:  |  Height:  |  Size: 510 B

Before After
Before After