## To build:

``` <!---sh-->
    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:

``` <!---sh-->
    ./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:

``` <!---sh-->
    ./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:

``` <!---sh-->
    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`:

``` <!---sh-->
    echo "CDEFGABc" | ./endoh3 | padsp tee /dev/dsp > /dev/null
```

If you are using Mac OS X, try [sox](http://sox.sourceforge.net/) like so:

``` <!---sh-->
    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:

``` <!---sh-->
    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:


``` <!---sh-->
    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-->
    (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:

``` <!---c-->
    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.


<!--

    Copyright © %%DATE_RANGE%% by Landon Curt Noll. All Rights Reserved.

    You are free to share and adapt this file under the terms of this license:

        Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)

    For more information, see:

        https://creativecommons.org/licenses/by-sa/4.0/

-->
