Skip to content

Commit 8d9947d

Browse files
committed
Massively simplify blocks
1 parent b3ebaaa commit 8d9947d

13 files changed

Lines changed: 181 additions & 515 deletions

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>sh.ball</groupId>
88
<artifactId>patchable</artifactId>
9-
<version>1.2.0</version>
9+
<version>1.2.1</version>
1010

1111
<name>patchable</name>
1212

src/main/java/sh/ball/graph/GraphController.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import java.util.ArrayList;
2828
import java.util.List;
29+
import sh.ball.graph.blocks.BlockInput;
2930
import sh.ball.graph.blocks.types.AddBlock;
3031
import sh.ball.graph.blocks.types.MultiplyBlock;
3132
import sh.ball.graph.blocks.types.SineBlock;
@@ -46,6 +47,7 @@ public class GraphController {
4647
private int blockIndex = -1;
4748
private Line cable;
4849
private Block returnBlock;
50+
private int outputIndex = -1;
4951

5052

5153
public GraphController(Group group, ContextMenu contextMenu, AudioEngine audioEngine) {
@@ -101,14 +103,18 @@ public void addBlock(Block block) {
101103
for (int i = 0; i < blocks.size(); i++) {
102104
Block other = blocks.get(i);
103105
List<Node> outputs = other.getOutputNodes();
104-
for (Node output : outputs) {
106+
for (int j = 0; j < outputs.size(); j++) {
107+
Node output = outputs.get(j);
105108
Point2D mouse = output.sceneToLocal(event.getSceneX(), event.getSceneY());
106109
if (output.contains(mouse)) {
107110
Bounds bounds = output.getBoundsInParent();
108111
blockIndex = i;
112+
outputIndex = j;
109113
cable = new Line(0, 0, event.getSceneX(), event.getSceneY());
110-
cable.startXProperty().bind(output.getParent().layoutXProperty().add(bounds.getCenterX()));
111-
cable.startYProperty().bind(output.getParent().layoutYProperty().add(bounds.getCenterY()));
114+
cable.startXProperty()
115+
.bind(output.getParent().layoutXProperty().add(bounds.getCenterX()));
116+
cable.startYProperty()
117+
.bind(output.getParent().layoutYProperty().add(bounds.getCenterY()));
112118
group.getChildren().add(cable);
113119
break;
114120
}
@@ -155,11 +161,12 @@ public void addBlock(Block block) {
155161
Block startBlock = blocks.get(blockIndex);
156162
Block endBlock = blocks.get(i);
157163
if (endBlock.currentInputs() < endBlock.totalInputs()) {
158-
endBlock.setInput(startBlock, j);
164+
endBlock.setInput(new BlockInput(startBlock, outputIndex), j);
159165
connected = true;
160166
inputToCableMap.put(input, cable);
161167
cable = null;
162168
blockIndex = -1;
169+
outputIndex = -1;
163170
}
164171
} else {
165172
// remove the input from the block

src/main/java/sh/ball/graph/blocks/Block.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
public interface Block extends AudioDeviceListener {
99
double process(int sampleNumber, int index);
10-
List<Block> getInputs();
11-
void setInput(Block block, int index);
10+
List<BlockInput> getInputs();
11+
void setInput(BlockInput input, int index);
1212
void removeInput(int index);
1313
int totalInputs();
1414
int totalOutputs();
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package sh.ball.graph.blocks;
2+
3+
public record BlockInput(Block block, int index) {}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package sh.ball.graph.blocks;
2+
3+
public interface BlockProcessor {
4+
5+
void process(double[] inputs, double[] outputs);
6+
}
Lines changed: 2 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,10 @@
11
package sh.ball.graph.blocks.types;
22

3-
import java.util.List;
4-
import java.util.stream.Stream;
5-
import javafx.scene.Node;
63
import javafx.scene.paint.Paint;
7-
import sh.ball.audio.engine.AudioDevice;
8-
import sh.ball.graph.blocks.Block;
9-
import sh.ball.graph.blocks.BlockDesigner;
104

11-
public class AddBlock implements Block {
12-
13-
private Block leftInput = null;
14-
private Block rightInput = null;
15-
16-
private final List<Node> inputNodes;
17-
private final List<Node> outputNodes;
18-
19-
private int previousSampleNumber = -1;
20-
private double buffer = 0;
5+
public class AddBlock extends BasicBlock {
216

227
public AddBlock() {
23-
inputNodes = BlockDesigner.inputNodes(totalInputs());
24-
outputNodes = BlockDesigner.outputNodes(totalOutputs());
25-
}
26-
27-
@Override
28-
public double process(int sampleNumber, int index) {
29-
if (sampleNumber != previousSampleNumber) {
30-
previousSampleNumber = sampleNumber;
31-
if (leftInput != null) {
32-
buffer = leftInput.process(sampleNumber, 0);
33-
} else {
34-
buffer = 0;
35-
}
36-
if (rightInput != null) {
37-
buffer += rightInput.process(sampleNumber, 0);
38-
}
39-
}
40-
41-
return buffer;
42-
}
43-
44-
@Override
45-
public List<Block> getInputs() {
46-
return List.of();
47-
}
48-
49-
@Override
50-
public void setInput(Block block, int index) {
51-
if (leftInput != null && rightInput != null) {
52-
throw new IllegalStateException("AddBlock already has an input");
53-
}
54-
if (index >= totalInputs()) {
55-
throw new IllegalArgumentException("AddBlock only has " + totalInputs() + " inputs");
56-
}
57-
if (index == 0) {
58-
leftInput = block;
59-
} else {
60-
rightInput = block;
61-
}
62-
}
63-
64-
@Override
65-
public void removeInput(int index) {
66-
if (index >= totalInputs()) {
67-
throw new IllegalArgumentException("AddBlock only has " + totalInputs() + " inputs");
68-
}
69-
if (index == 0) {
70-
leftInput = null;
71-
} else {
72-
rightInput = null;
73-
}
74-
}
75-
76-
@Override
77-
public int totalInputs() {
78-
return 2;
79-
}
80-
81-
@Override
82-
public int totalOutputs() {
83-
return 1;
84-
}
85-
86-
@Override
87-
public int currentInputs() {
88-
return (leftInput == null ? 0 : 1) + (rightInput == null ? 0 : 1);
89-
}
90-
91-
@Override
92-
public Node getNode() {
93-
return BlockDesigner.createNode(Paint.valueOf("green"), "Add", 70, 20, Stream.concat(inputNodes.stream(), outputNodes.stream()).toList());
94-
}
95-
96-
@Override
97-
public List<Node> getInputNodes() {
98-
return inputNodes;
99-
}
100-
101-
@Override
102-
public List<Node> getOutputNodes() {
103-
return outputNodes;
104-
}
105-
106-
@Override
107-
public void audioDeviceChanged(AudioDevice audioDevice) {
108-
// do nothing
8+
super((inputs, outputs) -> outputs[0] = inputs[0] + inputs[1], 2, 1, Paint.valueOf("#ff0000"), "Add");
1099
}
11010
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package sh.ball.graph.blocks.types;
2+
3+
import com.sun.glass.ui.Clipboard;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
import java.util.Objects;
7+
import java.util.stream.Stream;
8+
import javafx.scene.Node;
9+
import javafx.scene.paint.Paint;
10+
import sh.ball.audio.engine.AudioDevice;
11+
import sh.ball.graph.blocks.Block;
12+
import sh.ball.graph.blocks.BlockDesigner;
13+
import sh.ball.graph.blocks.BlockInput;
14+
import sh.ball.graph.blocks.BlockProcessor;
15+
16+
public abstract class BasicBlock implements Block {
17+
18+
private final BlockInput[] inputs;
19+
private final List<Node> inputNodes;
20+
private final List<Node> outputNodes;
21+
private final int totalInputs;
22+
private final int totalOutputs;
23+
private final double[] inputBuffer;
24+
private final double[] outputBuffer;
25+
private final Paint color;
26+
private final String name;
27+
private final List<Node> nodes = new ArrayList<>();
28+
29+
private BlockProcessor processor;
30+
private int previousSampleNumber = -1;
31+
protected AudioDevice device;
32+
33+
public BasicBlock(BlockProcessor processor, int totalInputs, int totalOutputs, Paint color, String name) {
34+
this.processor = processor;
35+
this.totalInputs = totalInputs;
36+
this.totalOutputs = totalOutputs;
37+
this.color = color;
38+
this.name = name;
39+
this.inputNodes = BlockDesigner.inputNodes(totalInputs);
40+
this.outputNodes = BlockDesigner.outputNodes(totalOutputs);
41+
this.inputs = new BlockInput[totalInputs];
42+
this.inputBuffer = new double[totalInputs];
43+
this.outputBuffer = new double[totalOutputs];
44+
}
45+
46+
public BasicBlock(int totalInputs, int totalOutputs, Paint color, String name) {
47+
this(null, totalInputs, totalOutputs, color, name);
48+
}
49+
50+
public void setProcessor(BlockProcessor processor) {
51+
this.processor = processor;
52+
}
53+
54+
public void addNode(Node node) {
55+
nodes.add(node);
56+
}
57+
58+
@Override
59+
public double process(int sampleNumber, int index) {
60+
if (sampleNumber != previousSampleNumber) {
61+
previousSampleNumber = sampleNumber;
62+
for (int i = 0; i < totalInputs(); i++) {
63+
if (inputs[i] != null) {
64+
inputBuffer[i] = inputs[i].block().process(sampleNumber, inputs[i].index());
65+
} else {
66+
inputBuffer[i] = 0;
67+
}
68+
}
69+
processor.process(inputBuffer, outputBuffer);
70+
}
71+
72+
return outputBuffer[index];
73+
}
74+
75+
@Override
76+
public List<BlockInput> getInputs() {
77+
return List.of(inputs);
78+
}
79+
80+
@Override
81+
public void setInput(BlockInput input, int index) {
82+
if (index >= totalInputs()) {
83+
throw new IllegalArgumentException("Block only has " + totalInputs() + " inputs");
84+
}
85+
if (inputs[index] != null) {
86+
throw new IllegalStateException("Block already has an input at index " + index);
87+
}
88+
inputs[index] = input;
89+
}
90+
91+
@Override
92+
public void removeInput(int index) {
93+
if (index >= totalInputs()) {
94+
throw new IllegalArgumentException("AddBlock only has " + totalInputs() + " inputs");
95+
}
96+
inputs[index] = null;
97+
}
98+
99+
@Override
100+
public int totalInputs() {
101+
return totalInputs;
102+
}
103+
104+
@Override
105+
public int totalOutputs() {
106+
return totalOutputs;
107+
}
108+
109+
@Override
110+
public int currentInputs() {
111+
return (int) Stream.of(inputs).filter(Objects::nonNull).count();
112+
}
113+
114+
@Override
115+
public Node getNode() {
116+
Stream<Node> nodeStream = Stream.concat(Stream.concat(getInputNodes().stream(), getOutputNodes().stream()), nodes.stream());
117+
return BlockDesigner.createNode(color, name, 70, 20, nodeStream.toList());
118+
}
119+
120+
@Override
121+
public List<Node> getInputNodes() {
122+
return inputNodes;
123+
}
124+
125+
@Override
126+
public List<Node> getOutputNodes() {
127+
return outputNodes;
128+
}
129+
130+
@Override
131+
public void audioDeviceChanged(AudioDevice audioDevice) {
132+
this.device = audioDevice;
133+
}
134+
}

0 commit comments

Comments
 (0)