Blog-Archiv

Montag, 16. Juni 2025

Should I Use abc Music Notation

I don't know how often I looked at the abc music notation and considered using it. I never did, and the first look was 27 years ago. Not that I did not need it, I have always been using and writing music on paper, and a computer would have offered some valuable features like transposing a score from one key to another in a second. But abc never convinced me. And with every look at it I found new disadvantages.

In 1997, the years when abc evolved, I decided to implement my own music notation language. The goal was to write notes for a single-voiced melody and output it as printable sheet music. I achieved it by using Java/AWT as graphical input user-interface, a self-designed notation language using simple text characters, and a GNU awk script that translated it into into MusixTeX, which is a very mature French TeX package for writing music scores. Together with the C-programming make utility and UNIX shell scripts I wrote and printed over 120 of my pieces on that application. This worked very well for 26 years, across several different LINUX distributions, although I had to manually configure the MusixTeX files and pathes sometimes when changing distros. I would not dare to write MusixTeX source directly, that's not readable. If you have unreadable source, it will be time-consuming and error-prone to maintain, correct and extend your pieces. My own notation language is simple, structured and readable, although more a commandline-language than a context-free grammar.

So how readable is the abc alternative?
By the way, alternative to abc is just musicXML, but this is not readable at all, too big.
The abc language is free open source, and it was well accepted by both musicians and developers. There are online-translators on the web where you can try it out. It even has a grammar definition, but not final, and version-specific. Basically it is a commandline-language, that means every line of an .abc file is interpreted in the context of the header lines read before. Thus the order of lines matters. Another thing is the readability. Not good at all. Not too big like musicXML, to small instead.

  • Spaces:
    If you want "beaming" (eighth notes with a common flag-line), you must do it by leaving out spaces between the notes. The result is really hard to read. What would you expect is this:
    X:1
    L:1/8
    K:C  % end of header lines
    c2G EFG
    Look at the last line. In IPN notation, this is a "C5" quarter note, then a "G4" eighth note, then "E4", "F4" and "G4" eighth notes. The EFG will be beamed together, not the c2G, because a quarter note has no flag that can be written as beam. (Fortunately, for all cases other than beaming, spaces can be used to separate notes.)

  • Newlines:
    If you want the "staff" (note line) to end, you insert a newline. If you don't, the note line will get wider and wider. In other words, you must do the layout of the score manually through newlines. There is no formatter that sizes notes and bars to some formatting parameter, like musixflx provides in MusixTeX - abc source code hard-codes layout:
    X:1
    L:1/4
    K:C
    GBd2|GBd2| 
    a/g/f/e/d2|a/g/f/e/d2|
    This will be rendered in two "staffs" (note lines), each containing two bars. Effect is that whenever you maintain your score and add some fill notes, the overall layout will be affected. The idea behind this may have been to formulate conceptual units, but in fact it was an ignored model-view separation.

  • Numbers:
    There is misleading similarity between IPN notation and abc notation concerning numbers.
    The IPN "C2" means the C in 2nd octave (very low).
    The abc "C2" means an IPN "C4" that is 2 times longer than the standard-length of a note (which is given in header via e.g. "L:1/8", in that case it would be a quarter note).

  • Separators:
    In abc the comma is not a separator. It lowers the octave of the note before. The expression C, (C comma) is one octave lower than C. A single quote is used to put the note one octave higher, c' is one octave higher than c (which surprisingly is one octave higher than C).

Many more cryptographies have been used that make abc scores hardly readable. Not only the author will have problems when coming back to his score years later, maybe also other people would like to be able to maintain some abc source that was written by an author (that unfortunately likes to apply every trick the language offers).

Finally the recommended EasyABC editor - can probably be installed on LINUX, but you should take yourself a day for it. I just threw away my nerves. So much Python documentation and Blogs to read. Everything so outdated (2017), written in so tiny fonts. The editor was implemented in Python, using the wxPython UI toolkit, which is platform-dependent. (Is Python really platform-independent?) The Python package installer (pip) seems to not support LINUX when a package contains platform-dependent binaries. How elegant Java is ....

Summary:
The informatic heresy "Write Less Do More" has done lots of harm, also here in abc. I can understand that shortness was important in 1980 when machines had just 64 KB memory, but since then there is no need for shortness, just the contrary would be needed, as so much unreadable source code blocks the human side of digitalization. Simplicity and accuracy will win in the long run.
Ask yourself:
Will I still be able to understand my abc code in a year?
Will my colleague be able to maintain my abc code when I go on vacation?

Yes, it would be nice to be part of the abc community with nearly a million tunes on its web-repository, but not for the price of having to layout tons of hard-to-read code after every maintenance. So I'll stay on my home-grown solution, will improve it and add an optional "to abc" converter to it. Maybe we all should use MuseScore.

Why is there no better solution for writing music notes? Because this is so complex. It has grown over centuries. It even contains programmatic structures like loops and conditions, an look how complicated programming languages are.

In case you already fell into abc, here is an example how to not write abc code:

....
L:1/4
K:G
GBd2|GBd2| 
a/g/f/e/d2|[Aa]/g/f/e/[Dd]2| 
G,/G/zg2|D/d/z[Aa]2|
z2[Dd]B|[G,G]4|]

(Can anyone read that?) You can achieve the same through more readable code:

....
L:1/1
K:G
G/4 B/4 d/2 | G/4 B/4 d/2 | 
a/8` g/8` f/8` e/8 d/2 | [Aa]/8` g/8` f/8` e/8 [Dd]/2 | 
G,/8` G/8 z/4 g/2 | D/8` d/8 z/4 [Aa]/2 | 
z/2 [Dd]/4 B/4 | [G,G] |]
  • Set the standard note length to the whole bar (1/1), and put the length of the note to every note, else you will have to always calculate their lengths while reading (Write more do more:-)
  • Add spaces wherever it is possible. If impossible due to beaming, you can use back quote ` instead of space to separate the notes.

How do you make your abc code more readable? Leave a comment!


UPDATE 1: didn't take me long to break it, look at following triplet clamps:

X: 1
T: Triplet Clamps Too Short
N: For all of eighth / quarter / half triplets the clamp is too short
M: 4/4
L: 1/1
(3 E/8`F/16`-G/16`A/8 B/4 c/2 |\
(3 D/4 E/8`-F/8 G/4 A/2 |\
(3 C/2 D/4`-E/4 F/2 |

This is not due to the '-' character (slur), you can also leave them out. I tried this abc code on several web translators, was the same everywhere.


UPDATE 2: this may become a longer list of abc bugs, maybe concerning only abcjs. Try to play this tune on some online abc translator:

X: 1
T: Lengthened Notes Play Differently
M: 4/4
L: 1/1
(C | C) | F | C- | C | F |

You will notice that the "(C | C)" expression plays two tones, while the "C- | C" expression correctly just sounds once before the F. The printed notes are the same in both cases, with a slur into next bar.





Donnerstag, 29. Mai 2025

Set Java Swing JSlider Position by Mouse Click

You can set the position of the Java/Swing JSlider knob by dragging it with the left mouse button. But you can not set its position by clicking into the slider's running track, neither by left nor by right click. The left click moves the knob just a little by its increment value, which may require lots of clicks to get to the desired position. But the right mouse click is not used by JSlider, so why not use it for moving the knob to the click location?

Another idea would be to show tooltips according to the current mouse position over the slider. That means if you move the mouse e.g. over the value "2" of the slider, you would like to show a tooltip that says "Mouse is over the value of 2" (or something not so silly:-).

Move Knob to Right Mouse Click Location

All of the following applies to both horizontal and vertical sliders.

    private JSlider createSlider() {
        final JSlider slider = new JSlider();
        
        slider.addMouseListener(new MouseAdapter() {
            /** Moves the slider knob to the given event location when it was a right-mouse click.*/
            @Override
            public void mouseClicked(MouseEvent e) {
                if (((JComponent) e.getSource()).isEnabled() && SwingUtilities.isRightMouseButton(e)) {
                    final int sliderValue = new SliderMouseEventLocator(e).sliderValue;
                    slider.setValue(sliderValue);
                }
            }
        });

        return slider;
    }

So this was the mouse event catching, but what is SliderMouseEventLocator?

public class SliderMouseEventLocator
{
    /** Result of construction. */
    public final Integer sliderValue;
    
    public SliderMouseEventLocator(MouseEvent e) {
        final JSlider slider = (JSlider) e.getSource();
        final BasicSliderUI ui = (BasicSliderUI) slider.getUI();
        final boolean horizontal = (slider.getOrientation() != SwingConstants.VERTICAL);
        this.sliderValue = horizontal ? ui.valueForXPosition(e.getX()) : ui.valueForYPosition(e.getY());
    }
}

This code converts the mouse click location to a slider value. The mouse-event coordinate is relative to the slider, not relative to the window. We can let BasicSliderUI do the work.

You need a new SliderMouseEventLocator for each arriving mouse event. If you want to reuse that object, you would have to implement a mouse-event converter-method instead of the immutable public final sliderValue result field (that must be evaluated at least on constructor execution).

Show Tooltip According to Mouse Location

Having the SliderMouseEventLocator class, it is easy to implement different tooltips according to mouse moves.

        slider.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                final Integer sliderValue = new SliderMouseEventLocator(e).sliderValue;
                final String tooltip = getTextRepresentation(sliderValue);
                // TODO: implement getTextRepresentation
                slider.setToolTipText(tooltip);
            }
        });

Add this snippet to the createSlider() method and implement getTextRepresentation(sliderValue).

Hope this was helpful for the few remaining Swing programmers!




Freitag, 23. Mai 2025

Basic Ubuntu LINUX Firewall Security

LINUX has a built-in firewall called netfilter, configurable through iptables. There is a user friendly Ubuntu command-line tool called ufw to configure this firewall. All three should be already installed in your Ubuntu LINUX. (Probably you don't want to mess with snort!)

By default, the firewall is not turned on!
You must activate it manually. For the purpose of working with your firewall, it may be useful to additionally install its graphical user interface:

  • sudo apt install gufw

And run it:

  • sudo gufw

You will see this:

If you move the "Status" switch to the right, the firewall will be turned on. Now enter this command-line:

  • sudo ufw status

You should see "Status: active". This will survive a reboot. You can reach the gufw graphical user interface without command-line when you enter "firewall" in your application-finder ("Show Apps" button on Ubuntu taskbar). Of course you must enter the superuser password here, as you must do when running any sudo commandline. Remember to read the documentation, especially when you use P2P applications, because ports may be closed now!




Single Web Page Upload to the Internet

Just copied my (self-contained) information page about Austrian mountains to the Internet ("Berge Österreichs mit mindestens 100 m Schartenhöhe"):

This contains lots of information, and why shouldn't it be visible to all?
The Internet provides a free single web-page upload on

Only an accessible e-mail address is required. (Hopefully no ads coming now...)

This page is full of JavaScript (ES6) code that lets you filter and sort table rows, and even collapse and expand table columns. Click onto the column header to try out. It also displays the number of all and that of currently filtered rows on top left.

I published and explained the JavaScript (ES6) code for this type of HTML-table in a series of 4 Blog articles, starting with Sortable Filterable HTML Table with ES6, Part 1. You can use this code for free. Have fun!

Samstag, 10. Mai 2025

HTML Page Reload on Focus

Imagine you need a page that always reloads itself from the server when the user focuses it, that means the according browser tab or window was in background and gets clicked to foreground. For such a page the user would never have to press the "Reload" button when coming back to it, which may make sense e.g. for a wheather-report site (to always show the current temperature).

This is different from updating the page periodically, which can be done via the refresh attribute in a <head> <meta> element. Mind that such would take control away from the user, may consume valuable resources, and is not applicable in all environments.

Code

Following HTML would do a page reload on focus. Mind that this is not recommendable for big expensive pages that need several seconds to render!

<!DOCTYPE HTML>
<html>
  <body onfocus="window.location = window.location;">

    <!-- Here goes the page HTML -->

  </body>
</html>

The technique is to install an event handler for the focus event in the <body> element. The JavaScript code "window.location = window.location;" inside the event handler may look ridiculous, but it actually performs a page reload.

Test

Here is a test-page to verify that behavior. It displays the current time every time it gets loaded, and it has the above mechanism installed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE HTML>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <title>Show Load Time when Focused</title>
  </head>

  <body
    onpageshow="renderTime();"
    onfocus="window.location = window.location;"
  >
    <fieldset>
      <legend>Load Time:</legend>
      <div id="time"></div>
    </fieldset>
	
    <script>
      function renderTime() {
        const date = new Date();
        const timeField = document.getElementById("time");
        timeField.innerHTML = date.getHours()+":"+date.getMinutes()+":"+date.getSeconds();
      }
    </script>
  </body>
</html>

To verify,

  1. load this page in your web-browser,
  2. look at the displayed time, remember it,
  3. then open a new tab or window and focus it (or click onto some already opened),
  4. then change back to this page

→ The displayed time must have changed now.

Resume

I do not know if this is the simplest way to make a page reload itself automatically when it is looked at, but at least it needs very few code. If you need to update just single elements or fields on focus, you will have to use AJAX.




Sonntag, 16. März 2025

Convert Decimal to Fraction in Java

Ever needed to convert a decimal number into a fraction, like 0.5 into 1 / 2 ?
There is a simple method to do this, but it doesn't always work:

    public static long[] toFraction(double decimal) {
        String decimalAsString = String.valueOf(decimal);
        int decimalPlaces = decimalAsString.length() - decimalAsString.indexOf('.') - 1;
        
        long divisor = (long) Math.pow(10, decimalPlaces);
        long dividend = (long) (decimal * divisor);

        long gcd = greatestCommonDivisor(dividend, divisor);

        return new long[] { dividend / gcd, divisor / gcd };
    }

    public static long greatestCommonDivisor(long... numbers) {
        return greatestCommonDivisor(LongStream.of(numbers));
    }
    public static long greatestCommonDivisor(LongStream numbers) {
        return greatestCommonDivisorLong(numbers.boxed());
    }
    public static long greatestCommonDivisorLong(Stream<Long> numbers) {
        return numbers.reduce(0L, (x, y) -> gcd(x, y));
    }
    private static long gcd(long x, long y) {
        return (y == 0L) ? x : gcd(y, x % y);
    }

This works nice as long as you don't pass "periodic" numbers like 1.333333333333333 to that method. It would return 1333333333333333 / 1000000000000000, not 4 / 3 like expected.

Now there are libraries on the web that resolve this problem, the most popular being Apache Commons Math. The only problem for me was that there are so many other solutions in this library (of size 2.2 MB) that I would never need for my very small project. So I decided to go into that source and look if I could adapt some snippet. What I came across was not really understandable code, but trying it out showed that it worked well also for periodic numbers:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
/** Adopted and simplified from apache-commons-math BigFraction. */
public class Fraction
{
    private static final double DEFAULT_EPSILON = 1e-5; // 1.0e-20
    private static final int DEFAULT_ITERATIONS = 100; // 10000

    private final double doubleValue;
    private final BigInteger dividend; // numerator
    private final BigInteger divisor; // denominator

    /**
     * @param dividend numerator, the number above the fraction line.
     * @param divisor denominator, the number below the fraction line.
     */
    public Fraction(long dividend, long divisor) {
        this((double) dividend / (double) divisor);
    }
    
    /**
     * @param value the number to turn into a (reduced) fraction.
     */
    public Fraction(double value) {
        this(value, DEFAULT_EPSILON, Integer.MAX_VALUE, DEFAULT_ITERATIONS);
    }

    private Fraction(double value, double epsilon, int maxDenominator, int maxIterations) {
        this.doubleValue = value;
        
        final long overflow = Long.MAX_VALUE;
        double r0 = value;
        long a0 = (long) Math.floor(r0);

        if (Math.abs(a0) > overflow) {
            throw new RuntimeException("MAX_VALUE overflow!");
        }

        // check for (almost) integer arguments, which should not go to iterations.
        if (Math.abs(a0 - value) < epsilon) {
            dividend = BigInteger.valueOf(a0);
            divisor  = BigInteger.ONE;
            return;
        }

        long p0 = 1;
        long q0 = 0;
        long p1 = a0;
        long q1 = 1;

        long p2 = 0;
        long q2 = 1;

        int n = 0;
        boolean stop = false;
        do {
            ++n;
            final double r1 = 1.0 / (r0 - a0);
            final long a1 = (long) Math.floor(r1);
            p2 = (a1 * p1) + p0;
            q2 = (a1 * q1) + q0;
            if ((p2 > overflow) || (q2 > overflow)) {
                // in maxDenominator mode, if the last fraction was very close to the actual value
                // q2 may overflow in the next iteration; in this case return the last one.
                if (epsilon == 0.0 && Math.abs(q1) < maxDenominator) {
                    break;
                }
                throw new RuntimeException("maxDenominator overflow!");
            }

            final double convergent = (double) p2 / (double) q2;
            if ((n < maxIterations) &&
                (Math.abs(convergent - value) > epsilon) &&
                (q2 < maxDenominator)) {
                p0 = p1;
                p1 = p2;
                q0 = q1;
                q1 = q2;
                a0 = a1;
                r0 = r1;
            } else {
                stop = true;
            }
        } while (!stop);

        if (n >= maxIterations) {
            throw new RuntimeException("maxIterations overflow!");
        }

        if (q2 < maxDenominator) {
            dividend = BigInteger.valueOf(p2);
            divisor  = BigInteger.valueOf(q2);
        } else {
            dividend = BigInteger.valueOf(p1);
            divisor  = BigInteger.valueOf(q1);
        }
    }

    
    /** @return the calculated-by-division or constructor-given value. */
    public double doubleValue() {
        return doubleValue;
    }

    /** @return the reduced dividend (numerator). */
    public BigInteger getDividend() {
        return dividend;
    }
    
    /** @return the reduced divisor (denominator). */
    public BigInteger getDivisor() {
        return divisor;
    }
}

112 lines of code against a 2.2 MB library (that may also change its API in course of time) is not bad. I confess that I don't understand lines 26 to 95, but I also don't understand many other things that I use daily.

Here are two applications for class Fraction, which I have put into MathUtils.java:

    /** 1.5 -> 3/2 */
    public static long[] toFraction(double number) {
        final Fraction fraction = new Fraction(number);
        return new long[] { 
                fraction.getDividend().longValue(), 
                fraction.getDivisor().longValue() 
            };
    }

    /** 10/4 -> 5/2 */
    public static long[] reduceFraction(long dividend, long divisor) {
        final Fraction fraction = new Fraction(dividend, divisor);
        return new long[] { 
                fraction.getDividend().longValue(), 
                fraction.getDivisor().longValue() 
            };
    }

Following JUnit-5 test code in MathUtilsTest.java showed that it works:

    @Test
    void periodicNumberToFraction() {
        long[] fraction;
        
        fraction = MathUtils.toFraction1(1.333333333333333);
        assertEquals(4, fraction[0]);
        assertEquals(3, fraction[1]);
        
        fraction = MathUtils.toFraction(1.666666666666666);
        assertEquals(5, fraction[0]);
        assertEquals(3, fraction[1]);
        
        fraction = MathUtils.toFraction(1.777777777777777);
        assertEquals(16, fraction[0]);
        assertEquals(9, fraction[1]);
        
        fraction = MathUtils.toFraction(0.777777777777777);
        assertEquals(7, fraction[0]);
        assertEquals(9, fraction[1]);
        
        fraction = MathUtils.toFraction(1.599999999999999); // ~ 1.6
        assertEquals(8, fraction[0]);
        assertEquals(5, fraction[1]);
    }

If you can't put a truck onto your bicycle, you may want to use a photo of it:-)
Hope this is helpful to someone!




Freitag, 7. März 2025

Debugging Swing JComboBox Callback Freezes Ubuntu Desktop

Such things happen really rarely. The whole desktop was completely frozen, the mouse still moved but no click caused anything, not even on the Ubuntu status bar. I use Eclipse 2024-09 with Java 21 on Ubuntu LINUX 24.04.1 LTS with Kernel 6.8.0-45-generic on a 64 bit machine.

What I was trying to do is debug a Java Swing JComboBox callback, i.e. trying to follow the source code when I chose an item from that combo box. The combo box was open, my Eclipse debugger correctly jumped to the according source line, but no mouse click or keyboard input was accepted any more by any UI control, not even the operating-system's desktop responded.

On any LINUX you can press Alt-Ctrl-F3 to get a terminal screen, login with your password and then kill the hanging Java process or Eclipse or both. The terminal commands would be:

  $ ps -ef | grep -i java
  # or maybe "ps aux ..."

The number in the second column of the text output would be the PID you need to kill then:

  $ kill PidOfProcessToKill

Mind that killing Eclipse may not remove the Java-process, but I didn't find out which one causes the problem.

With Alt-Ctrl-F2 (or maybe Alt-Ctrl-F7, try F-keys from 2 to 7) you can get back to your graphic desktop, where the input lock should not be present any more then.

But: how to debug now the Java/Swing application? I searched the Internet and found an Ubuntu forum entry from year 2009. Workaround would be to run the Java/Swing aplication with follwing VM-option:

  -Dsun.awt.disablegrab=true

You can enter this on the Eclipse Run/Debug configuration dialog on the right-side "Arguments" tab in the lower "VM arguments" text field. This worked for me. Desktop not locked any more, happy debugging. Very old Java-VM bug, never fixed.




Dienstag, 14. Januar 2025

Obfuscating Names in HTML Pages

Sometimes you want to mention certain dangerous names in your HTML-page, but you don't want search-engines / web-crawlers / HTML-spiders to find them. Let's say you don't want to get shot by Russian agents after having told the truth about Ukraine war. What you could do easily is to obfuscate names using numeric HTML-entities. Here is Java source that does this for you:

public final class NameObfuscator
{
    /**
     * @param name the name to obfuscate for HTML rendering.
     * @return the given name as hexadecimal HTML-entities.
     */
    public static String toHtmlEntities(String name) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < name.length(); i++) {
            char c = name.charAt(i);
            builder.append("&#x"+Integer.toHexString(c)+";");
        }
        return builder.toString();
    }

    private NameObfuscator() {}
}

Mind that this does NOT protect against search-engines that "expand" web-pages before they scan them, that means they render them including execution of JavaScript code and only then read their text.

Here is some test-source for the method above:

    public static void main(String[] args) {
        final String[] names = new String[] {
            "Adolf Hitler",
            "Josef Stalin",
            "Wladimir Putin",
            "Donald Trump",
        };
        for (String name : names)
            System.out.println(NameObfuscator.toHtmlEntities(name));
    }

When you compile this with javac and run it via java, the output you will see is:

&#x41;&#x64;&#x6f;&#x6c;&#x66;&#x20;&#x48;&#x69;&#x74;&#x6c;&#x65;&#x72;
&#x4a;&#x6f;&#x73;&#x65;&#x66;&#x20;&#x53;&#x74;&#x61;&#x6c;&#x69;&#x6e;
&#x57;&#x6c;&#x61;&#x64;&#x69;&#x6d;&#x69;&#x72;&#x20;&#x50;&#x75;&#x74;&#x69;&#x6e;
&#x44;&#x6f;&#x6e;&#x61;&#x6c;&#x64;&#x20;&#x54;&#x72;&#x75;&#x6d;&#x70;

Copy these strings and replace the dangerous names in your HTML source-code by them.
Of course there are much better ways to obfuscate dangerous names, but they are more complicated and may also not protect against sophisticated spiders.