Files
ioccc/2013/endoh3
Landon Curt Noll f29b37e49a improve HTML menus, add social.html, prep for IOCCC28 winners
Prepare for the winners of **IOCCC28**.

> However these are not the 2024 droids you are looking for.  :-)

The HTML menu (both JavaScript and non-JavaScript) has been updated.

The `Status -> Rules and guidelines' have been replaced with two
separate menus `Status -> IOCCC rules` and `Status -> IOCCC guidelines`.

Added a new top level `social.html` page: built from a new `social.md`.

Sorted rules for building specific web pages in the top level `Makefile`.
Added `make social` to make the `social.html` page from `social.md`.

The `bin/gen-top-html.sh` now is able to process a argument of **social**
to process the new top level `social.html` page.

Changed `bin/gen-top-html.sh` VERSION from "2.0.0 2025-03-13"
to "2.0.1 2025-07-25".

Below `About -> Home page` a new `About -> IOCCC social media` menu item
as added.

Because the menu change touched every HTML file, we changed the general
copyright date range for HTML files from "1984-2024" to "1984-2025"
due to the extensive changes made for **IOCCC28**.

Those markdown files that were modified in 2025 had their copyright date
range also changed from "1984-2024" to "1984-2025".

Rebuilt tarballs and sitemap due to the extensive HTML rebuilding.

Ran `make update` to perform the above.
2025-07-26 13:06:29 -07:00
..
2024-01-27 10:29:47 -08:00
2023-07-06 21:49:38 -07:00
2020-12-30 16:57:03 -08:00
2020-12-30 16:57:03 -08:00
2020-12-30 16:57:03 -08:00
2024-05-30 11:17:04 -07:00
2020-12-30 16:57:03 -08:00
2020-12-30 16:57:03 -08:00
2020-12-30 16:57:03 -08:00

To build:

    make

Bugs and (Mis)features:

The current status of this entry is:

STATUS: INABIAF - please DO NOT fix

For more detailed information see 2013/endoh3 in bugs.html.

To use:

    ./endoh3

This program plays sound. See the FAQ on "compile with sound" if you do not know how to set your system up for this or if you want to verify that everything is oky.

Try:

    ./try.sh

    ./try.sh ABC

    ./try.sh test.abc yankee.abc

    ./try.sh *.abc

The script will check for SoX first and next padsp from PulseAudio and finally if neither are found if you have ruby(1) installed it'll use the included ruby script to convert it to a WAV file for you to play.

If no args are passed to the script it will play twinkle.abc and the string ABC. Otherwise while there's a remaining arg if it's a file it will run the program on the file. If it's not a file it'll run it as a string.

The *.abc files are provided as music samples.

Judges' remarks:

This program can toot out a tune that is small enough to posted to most social media platforms that have small message length limits.

This endoh3ram can toot out a tune that is small enough.

A modern day (2023) note about the award 'Most tweetable 1-liner' and twitter:

The IOCCC no longer endorses the use of what was once twitter, or whatever it might be called today. We recommend that you pick a responsible social media platform to post the program's output on. Nevertheless the award of this entry will remain the same for historical purposes.

Author's remarks:

Remarks

This is a sound synthesizer for a subset of ABC music notation.

Try:

    cc -o endoh3 endoh3.c
    echo "CDEFGABc" | ./endoh3 > /dev/dsp

If /dev/dsp is not available on your system, use an OSS sound wrapper such as padsp or aoss:

    echo "CDEFGABc" | ./endoh3 | padsp tee /dev/dsp > /dev/null

If you are using Mac OS X, try sox like so:

    echo "CDEFGABc" | ./endoh3 | sox -q -traw -r8000 -b8 -e unsigned-integer - -tcoreaudio

If that does not work, use the attached script to convert the output into a wave file format:

    echo "CDEFGABc" | ./endoh3 | ruby wavify.rb > cde.wav

and play cde.wav.

You can also enjoy some music scores that I attached. With /dev/dsp you can do so like:

    cat twinkle.abc | ./endoh3 > /dev/dsp
    cat menuet.abc | ./endoh3 > /dev/dsp

but you should be able to modify it a way to meet your system requirements as described above.

Obfuscation

The following sequence of questions may be helpful to understand the endoh3ram program:

  • How does it convert ABC notes into the frequency?
  • What is 89/84.? I found it by using the Stern-Brocot tree.
  • How does it generate a wave? Hint: it generates a saw wave.

Limitation

The following features are supported:

  • Notes:
    • C D E F G A B (in low octave)
    • c d e f g a b (in high octave)
  • Rests: z
  • Note lengths:
    • A (an eighth note)
    • A2 (a quarter note)
    • A3 (a dotted quarter note)
    • A4 (a half note)

The following features are NOT supported:

  • Sharp and flat: ^C _C
    • But it is possible to emit the half tones. Do you see how?
  • Shorter note lengths than 1: C1/2
    • But you can use C0.5 instead.
  • Higher and lower notes: c' C,
  • Any meta fields: T:title L:1/4
  • Bar line, repeat, ties and slurs, and everything else.

Known Bugs

You can NOT write a note length immediately followed by a note E, such as C2E2.

Can you figure out why?

A workaround is inserting a whitespace: C2 E2.

Portability

I tested it on:

  • Ubuntu 13.10 with gcc 4.7.3, clang 3.2, and tcc 0.9.25.
  • Mac OS X 10.6 with gcc 4.2.1 and clang 1.7.

I believe that all the scores that I attached are out-of-copyright.

I did write a score of the Happy Birthday song too. (It does not matter because the song is out-of-copyright in my country.) But I do not attach it to protect you from W****r.

For the same reason, do not post a score that contains only z1092. You know, it is "the famous song".

NOTICE to those who wish for a greater challenge:

If you want a greater challenge, don't read any further: just try to understand the program via the source.

If you get stuck, come back and read below for additional hints and information.

How this entry works:

Here is a magical expression which I found by brute-force:

    (c % 32 + 5) * 9 / 5 % 13 + n / 32 * 12 - 22

Interestingly, it converts an ASCII number of ABC notes to the corresponding tone number.

    'C' (ASCII  67) =>  3
    'D' (ASCII  68) =>  5
    'E' (ASCII  69) =>  7
    'F' (ASCII  70) =>  9
    'G' (ASCII  71) => 10
    'A' (ASCII  65) => 12
    'B' (ASCII  66) => 14
    'c' (ASCII  99) => 15
    'd' (ASCII 100) => 17
    'e' (ASCII 101) => 19
    'f' (ASCII 102) => 20
    'g' (ASCII 103) => 22
    'a' (ASCII  97) => 24
    'b' (ASCII  98) => 26

By the way, you can write a half-tone by the following characters.

    'K' =>  4 (= C#)
    'L' =>  6 (= D#)
    'U' =>  8 (= F#)
    'V' => 11 (= G#)
    'P' => 13 (= A#)

Note that the tone numbers simply enumerate the semi-tone steps. So we can calculate the frequency easily: pow(2, n / 12.0). Then, how can we calculate pow without math.h? pow(2, 1.0 / 12.0) is approximated by 89/84.. (I found this approximation by using the Stern-Brocot tree.) We can gain the frequency by multiplying the value by n times.

Finally, the following code generates a saw wave:

    for(c = 0; c < len; c++) putchar(a = n * D);

where D is a frequency and a is a variable whose type is char. By assigning float to char variable, the implicit type conversion is performed from float to char (modulo 256).

(Strictly speaking, this behavior is undefined according to 6.3.1.4 in C99; you can replace it with (long)(n*D) if you are pedantic.)

All that was left was to combine and condense the components. The key is squashing them into just one for-loop.