Added support for stacked guitar pickups

This commit is contained in:
Bane Stojkovic
2026-08-21 12:52:31 +02:00
parent 8d506b21c4
commit 18b6bfb1db
5 changed files with 193 additions and 20 deletions
@@ -397,6 +397,10 @@
<releaseDate>2026-08-06 00:00:00.000 CET</releaseDate>
<name></name>
<changes>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added support for stacked guitar pickups: 'Stacked - North' and 'Stacked - South' are two new options to pick in the Coil(s) property of Single Coil, P-90, P-Bass and Jazz Bass pickups</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added 'Node Name Tooltips' feature that can be toggled in the Config menu; when enabled a tooltip is shown next to the cursor with names of component nodes under the cursor</description>
@@ -294,8 +294,13 @@ public abstract class AbstractGuitarPickup extends AbstractLabeledComponent<Stri
return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin);
}
public boolean isStacked() {
return getPolarity() == Polarity.StackedNorth || getPolarity() == Polarity.StackedSouth;
}
public enum Polarity {
North("Single - North"), South("Single - South"), Humbucking("Humbucking - 4 leads");
North("Single - North"), South("Single - South"), Humbucking("Humbucking - 4 leads"),
StackedNorth("Stacked - North"), StackedSouth("Stacked - South");
private String label;
@@ -60,8 +60,10 @@ public abstract class AbstractSingleOrHumbuckerPickup extends AbstractGuitarPick
break;
}
if (getPolarity() == Polarity.North || getPolarity() == Polarity.South) {
StringUtils.drawCenteredText(g2d, getPolarity().name().substring(0, 1), (points[1].getX() + points[2].getX()) / 2 + dx, (points[1].getY() + points[2].getY()) / 2 + dy, HorizontalAlignment.CENTER,
if (getPolarity() == Polarity.North || getPolarity() == Polarity.South
|| getPolarity() == Polarity.StackedNorth || getPolarity() == Polarity.StackedSouth) {
String label = (getPolarity() == Polarity.North || getPolarity() == Polarity.StackedNorth) ? "N" : "S";
StringUtils.drawCenteredText(g2d, label, (points[1].getX() + points[2].getX()) / 2 + dx, (points[1].getY() + points[2].getY()) / 2 + dy, HorizontalAlignment.CENTER,
VerticalAlignment.CENTER);
} else {
StringUtils.drawCenteredText(g2d, "N", (points[0].getX() + points[1].getX()) / 2 + dx, (points[0].getY() + points[1].getY()) / 2 + dy, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
@@ -91,15 +93,15 @@ public abstract class AbstractSingleOrHumbuckerPickup extends AbstractGuitarPick
return null;
return"North Start";
case 1:
if (getPolarity() == Polarity.South)
if (getPolarity() == Polarity.South || getPolarity() == Polarity.StackedSouth)
return "South Start";
if (getPolarity() == Polarity.North)
if (getPolarity() == Polarity.North || getPolarity() == Polarity.StackedNorth)
return "North Start";
return "North Finish";
case 2:
if (getPolarity() == Polarity.South)
if (getPolarity() == Polarity.South || getPolarity() == Polarity.StackedSouth)
return "South Finish";
if (getPolarity() == Polarity.North)
if (getPolarity() == Polarity.North || getPolarity() == Polarity.StackedNorth)
return "North Finish";
return "South Finish";
case 3:
@@ -125,6 +127,8 @@ public abstract class AbstractSingleOrHumbuckerPickup extends AbstractGuitarPick
break;
case North:
case South:
case StackedNorth:
case StackedSouth:
if (index1 == 1 && index2 == 2)
return getPolarity().name() + "->";
else if (index1 == 2 && index2 == 1)
@@ -182,20 +182,25 @@ public class GuitarDiagramAnalyzer extends AbstractNetlistAnalyzer implements IN
@Override
public void visit(TreeLeaf l) {
if ((l.toString().toLowerCase().contains("north")
&& (l.toString().toLowerCase().contains("->")))
|| (l.toString().toLowerCase().contains("south")
&& (l.toString().toLowerCase().contains("<-"))))
noiseCount++;
if ((l.toString().toLowerCase().contains("north")
&& (l.toString().toLowerCase().contains("<-")))
|| (l.toString().toLowerCase().contains("south")
&& (l.toString().toLowerCase().contains("->"))))
noiseCount--;
String s = l.toString().toLowerCase();
boolean isStacked = s.contains("stacked");
if (l.toString().toLowerCase().contains("->"))
if (!isStacked) {
if ((s.contains("north")
&& (s.contains("->")))
|| (s.contains("south")
&& (s.contains("<-"))))
noiseCount++;
if ((s.contains("north")
&& (s.contains("<-")))
|| (s.contains("south")
&& (s.contains("->"))))
noiseCount--;
}
if (s.contains("->"))
positiveCount++;
if (l.toString().toLowerCase().contains("<-"))
if (s.contains("<-"))
negativeCount++;
}
});
@@ -224,8 +229,9 @@ public class GuitarDiagramAnalyzer extends AbstractNetlistAnalyzer implements IN
} else {
TreeLeaf leaf = new TreeLeaf(pickup, 1, 2);
Tree t = tree.locate(leaf, false);
if (t != null)
if (t != null) {
pickupRoots.put(pickup, t);
}
}
}
}
@@ -19,13 +19,16 @@
package org.diylc.netlist;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.List;
import org.diylc.components.passive.AxialFilmCapacitor;
import org.diylc.components.passive.Resistor;
import org.junit.Test;
import org.diylc.components.electromechanical.OpenJack1_4;
import org.diylc.components.guitar.AbstractGuitarPickup.Polarity;
import org.diylc.components.guitar.HumbuckerPickup;
import org.diylc.components.guitar.SingleCoilPickup;
import org.diylc.components.passive.PotentiometerPanel;
@@ -328,4 +331,155 @@ public class GuitarDiagramAnalyzerTests {
"((Volume.3-2 + ((Pickup1.North<- + Pickup1.South<-) || (Pickup2.North<- + Pickup2.South<-) || (Tone1.2-1 + Cap1) || (Tone2.2-1 + Cap2))) || Volume.2-1)",
s);
}
@Test
public void testOneStackedNorthPickup() throws TreeException {
OpenJack1_4 jack = new OpenJack1_4();
SingleCoilPickup pickup = new SingleCoilPickup();
pickup.setName("Pickup");
pickup.setPolarity(Polarity.StackedNorth);
Netlist netlist = new Netlist(Arrays.asList(jack, pickup));
Group tipGroup = new Group().connect(jack, 0).connect(pickup, 1);
Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 2);
netlist.add(tipGroup).add(sleeveGroup);
GuitarDiagramAnalyzer analyzer = new GuitarDiagramAnalyzer();
Tree tree = analyzer.constructTree(netlist);
String s = tree.toString();
assertEquals("Pickup.StackedNorth<-", s);
List<String> notes = analyzer.collectNotes(netlist);
assertTrue(notes.contains("This configuration is hum-cancelling"));
assertTrue(notes.contains("'Pickup' is the only engaged pickup"));
}
@Test
public void testOneStackedSouthPickup() throws TreeException {
OpenJack1_4 jack = new OpenJack1_4();
SingleCoilPickup pickup = new SingleCoilPickup();
pickup.setName("Pickup");
pickup.setPolarity(Polarity.StackedSouth);
Netlist netlist = new Netlist(Arrays.asList(jack, pickup));
Group tipGroup = new Group().connect(jack, 0).connect(pickup, 1);
Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 2);
netlist.add(tipGroup).add(sleeveGroup);
GuitarDiagramAnalyzer analyzer = new GuitarDiagramAnalyzer();
Tree tree = analyzer.constructTree(netlist);
String s = tree.toString();
assertEquals("Pickup.StackedSouth<-", s);
List<String> notes = analyzer.collectNotes(netlist);
assertTrue(notes.contains("This configuration is hum-cancelling"));
}
@Test
public void testOneStackedPickupReverse() throws TreeException {
OpenJack1_4 jack = new OpenJack1_4();
SingleCoilPickup pickup = new SingleCoilPickup();
pickup.setName("Pickup");
pickup.setPolarity(Polarity.StackedNorth);
Netlist netlist = new Netlist(Arrays.asList(jack, pickup));
Group tipGroup = new Group().connect(jack, 0).connect(pickup, 2);
Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 1);
netlist.add(tipGroup).add(sleeveGroup);
GuitarDiagramAnalyzer analyzer = new GuitarDiagramAnalyzer();
Tree tree = analyzer.constructTree(netlist);
String s = tree.toString();
assertEquals("Pickup.StackedNorth->", s);
List<String> notes = analyzer.collectNotes(netlist);
assertTrue(notes.contains("This configuration is hum-cancelling"));
}
@Test
public void testTwoStackedPickupsParallel() throws TreeException {
OpenJack1_4 jack = new OpenJack1_4();
SingleCoilPickup pickup1 = new SingleCoilPickup();
pickup1.setName("Pickup1");
pickup1.setPolarity(Polarity.StackedNorth);
SingleCoilPickup pickup2 = new SingleCoilPickup();
pickup2.setName("Pickup2");
pickup2.setPolarity(Polarity.StackedSouth);
Netlist netlist = new Netlist(Arrays.asList(jack, pickup1, pickup2));
Group tipGroup = new Group().connect(jack, 0).connect(pickup1, 1).connect(pickup2, 1);
Group sleeveGroup = new Group().connect(jack, 1).connect(pickup1, 2).connect(pickup2, 2);
netlist.add(tipGroup).add(sleeveGroup);
GuitarDiagramAnalyzer analyzer = new GuitarDiagramAnalyzer();
Tree tree = analyzer.constructTree(netlist);
String s = tree.toString();
assertEquals("(Pickup1.StackedNorth<- || Pickup2.StackedSouth<-)", s);
List<String> notes = analyzer.collectNotes(netlist);
assertTrue(notes.contains("This configuration is hum-cancelling"));
assertTrue(notes.contains("All pickup coils are wired in-phase"));
}
@Test
public void testTwoStackedPickupsParallelOutOfPhase() throws TreeException {
OpenJack1_4 jack = new OpenJack1_4();
SingleCoilPickup pickup1 = new SingleCoilPickup();
pickup1.setName("Pickup1");
pickup1.setPolarity(Polarity.StackedNorth);
SingleCoilPickup pickup2 = new SingleCoilPickup();
pickup2.setName("Pickup2");
pickup2.setPolarity(Polarity.StackedSouth);
Netlist netlist = new Netlist(Arrays.asList(jack, pickup1, pickup2));
Group tipGroup = new Group().connect(jack, 0).connect(pickup1, 1).connect(pickup2, 2);
Group sleeveGroup = new Group().connect(jack, 1).connect(pickup1, 2).connect(pickup2, 1);
netlist.add(tipGroup).add(sleeveGroup);
GuitarDiagramAnalyzer analyzer = new GuitarDiagramAnalyzer();
Tree tree = analyzer.constructTree(netlist);
String s = tree.toString();
assertEquals("(Pickup1.StackedNorth<- || Pickup2.StackedSouth->)", s);
List<String> notes = analyzer.collectNotes(netlist);
assertTrue(notes.contains("This configuration is hum-cancelling"));
assertTrue(notes.contains("Some pickup coils are wired OUT-of-phase"));
}
@Test
public void testStackedPickupAndSingleCoilParallel() throws TreeException {
OpenJack1_4 jack = new OpenJack1_4();
SingleCoilPickup pickup1 = new SingleCoilPickup();
pickup1.setName("Pickup1");
pickup1.setPolarity(Polarity.StackedNorth);
SingleCoilPickup pickup2 = new SingleCoilPickup();
pickup2.setName("Pickup2");
pickup2.setPolarity(Polarity.North);
Netlist netlist = new Netlist(Arrays.asList(jack, pickup1, pickup2));
Group tipGroup = new Group().connect(jack, 0).connect(pickup1, 1).connect(pickup2, 1);
Group sleeveGroup = new Group().connect(jack, 1).connect(pickup1, 2).connect(pickup2, 2);
netlist.add(tipGroup).add(sleeveGroup);
GuitarDiagramAnalyzer analyzer = new GuitarDiagramAnalyzer();
Tree tree = analyzer.constructTree(netlist);
String s = tree.toString();
assertEquals("(Pickup1.StackedNorth<- || Pickup2.North<-)", s);
List<String> notes = analyzer.collectNotes(netlist);
assertTrue(notes.contains("This configuration is NOT hum-cancelling"));
assertTrue(notes.contains("All pickup coils are wired in-phase"));
}
@Test
public void testStackedPickupAndHumbuckerParallel() throws TreeException {
OpenJack1_4 jack = new OpenJack1_4();
SingleCoilPickup pickup1 = new SingleCoilPickup();
pickup1.setName("Pickup1");
pickup1.setPolarity(Polarity.StackedNorth);
HumbuckerPickup pickup2 = new HumbuckerPickup();
pickup2.setName("Pickup2");
Netlist netlist = new Netlist(Arrays.asList(jack, pickup1, pickup2));
Group tipGroup = new Group().connect(jack, 0).connect(pickup1, 1).connect(pickup2, 0);
Group coilTapGroup = new Group().connect(pickup2, 1).connect(pickup2, 2);
Group sleeveGroup = new Group().connect(jack, 1).connect(pickup1, 2).connect(pickup2, 3);
netlist.add(tipGroup).add(coilTapGroup).add(sleeveGroup);
GuitarDiagramAnalyzer analyzer = new GuitarDiagramAnalyzer();
Tree tree = analyzer.constructTree(netlist);
String s = tree.toString();
assertEquals("((Pickup2.North<- + Pickup2.South<-) || Pickup1.StackedNorth<-)", s);
List<String> notes = analyzer.collectNotes(netlist);
assertTrue(notes.contains("'Pickup2' pickup wired in humbucking mode with series coils"));
assertTrue(notes.contains("This configuration is hum-cancelling"));
assertTrue(notes.contains("All pickup coils are wired in-phase"));
}
}