## 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](../../bugs.html#2013_endoh3). ## To use: ``` ./endoh3 ``` This program plays sound. See the FAQ on "[compile with sound](../../faq.html#sox)" 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](%%REPO_URL%%/2013/endoh3/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](http://en.wikipedia.org/wiki/ABC_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](http://sox.sourceforge.net/) 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](https://en.wikipedia.org/wiki/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. ### Legal 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"](http://en.wikipedia.org/wiki/4%E2%80%B233%E2%80%B3). ### 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](http://en.wikipedia.org/wiki/Stern%E2%80%93Brocot_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.