alt.hn

2/19/2026 at 10:54:28 PM

Show HN: A small, simple music theory library in C99

https://github.com/thelowsunoverthemoon/mahler.c

by lowsun

2/20/2026 at 2:09:23 AM

As someone who only has used C in conjunction with Rust...

Given that it is 2026, what are some of the thoughts that go into choosing C99 vs C23, which I presume has more quality-of-life features?

by OptionOfT

2/20/2026 at 3:29:52 AM

Requiring C23 for a library header is a great way to guarantee nobody will use your code for long time.

I still write nearly ANSI compliant C for simple embedded things. Because somebody might need to figure out how to rebuild it in twenty years, and making that person's life harder for some syntactic sugar isn't worth it.

Even C99 can be a problem: for example, C99 designated initializers are not supported in C++. If your header needs to support C++ you can't use them (C++ forces you to initialize every field in the structure in order if you do it that way).

by jcalvinowens

2/20/2026 at 4:34:33 PM

> C99 designated initializers are not supported in C++.

They are, finally, part of C++20.

by onedognight

2/20/2026 at 2:45:24 AM

Very few people are using C for `quality-of-life features`. I'm fairly certain I've never even seen any C23 code, is it supported by many compilers or C tooling? One of the great things about C is that it is fairly easy to write code that runs everywhere and for a library that is especially important. There are many who just stick to C89.

by rabf

2/20/2026 at 9:07:48 PM

The quality of life is “it compiles nearly everywhere with the first toolchain you can get your hands on”.

by nxobject

2/20/2026 at 1:22:26 PM

As usual, clang and gcc have great support, intel ok, msvc no.

C11 is probably the newest that’s widely adopted.

by TingPing

2/20/2026 at 2:37:35 AM

known quantity. UBs well understood. tooling.

by fallingmeat

2/20/2026 at 12:35:50 PM

Yes, you sit at that piano every Sunday morning and play Mahler for Maris. But you hate Mahler. Besides Maris, who doesn't?

by firmretention

2/20/2026 at 7:19:16 AM

What is the purpose of this and how would I use it (as someone who actually knows a lot about music theory and C programming)?

by randomNumber7

2/20/2026 at 7:31:19 AM

Well, this library provides the core functions for classical, Western music theory (scales, keys, intervals, etc.). So any ideas that needs to understand or generate these structures could use them. Some examples off the top of my head:

- Music theory education tools - Music generation (and the outputs could be transformed to MIDI format for example) - Piano chord finder

and similar.

by lowsun

2/20/2026 at 7:42:19 AM

So you can generate the d dorian scale and it outputs d e f g a b c d?

Whats the target audience? A good musician knows the scales by heart (and also how they sound/feel) and for the others it's unclear to me what they would do with music theory they don't really understand.

by randomNumber7

2/20/2026 at 10:59:58 AM

I think you're looking at this the wrong way around. A human might know the notes of a D Dorian scale, but a computer doesn't. If you've ever selected the key of D major in any music creation software and it's shown you a stave with two sharps then the computer was using a library like this.

by Hasnep

2/20/2026 at 7:54:41 AM

There is a function for that, yes.

For your second thought, I'm not really sure I understand the point.

Since this is a library, it can power any application that needs to understand or generate these abstractions. So to expand on some options I gave above:

- You can create a program that generates a piece in the style of a Bach cantata for example, using this library as the backbone.

- If a teacher wanted to create a tool to educate kids about scales for example, it can use this library as a backbone.

by lowsun

2/20/2026 at 10:10:35 AM

The question is: what is the use case?

If you don't have a practical use case, the probability that there is one AND that it will use your library (instead of building its own, adjusted to their needs) is next to zero.

(I have been there more than once a long time ago)

Edit to add: and it's not to blame. Just there are more and more libraries popping up these days, without a clear use case, even their own. Which is totally fine as long as they are clear about not having one.

by Juliate

2/20/2026 at 8:06:15 AM

>So you can generate the d dorian scale and it outputs d e f g a b c d?

lmao

by pipeline_peak

2/20/2026 at 12:38:40 PM

Love the point of 100% test coverage.

by saivishwak

2/20/2026 at 5:19:29 AM

Nitpicking:

https://github.com/thelowsunoverthemoon/mahler.c/blob/4ebfe8...

Should that type have been mah_acci instead of int? mah_acci doesn't seem to be used anywhere.

Also, have you considered using (edit) designated initializer syntax for some of the function calls that take in structs as arguments?

https://cppreference.com/w/c/language/struct_initialization....

    struct mah_scale scale = mah_get_scale(
        (struct mah_note) {
            .tone=MAH_C,
            .acci=MAH_NATURAL,
            .pitch=4
        },
        &MAH_BLUES_SCALE, notes,
        MAH_ASCEND,
        NULL
    );

by ceteia

2/20/2026 at 5:43:28 AM

Ah yes, that is by design. This is because it supports more than a double sharp / double flat (eg triple sharp, quad sharp, etc). The enums are there just for the most common values so it's easier to read.

As for second, that's a good point! Would definitely make readability better, thanks.

by lowsun