SthephanShinkufag / bytebeat-composer

Bytebeat player with a collection of many formulas from around the internet.
https://dollchan.net/bytebeat/
MIT License
84 stars 25 forks source link

some "classic" bytebeats are js only #23

Open SArpnt opened 2 years ago

SArpnt commented 2 years ago

classic seems to imply c expressions, however many songs mix ints and doubles in ways that aren't valid in c for example fanfare doesn't work in c because it applies a bitwise operator to doubles.

SthephanShinkufag commented 2 years ago

I made some reorganization in library: https://github.com/SthephanShinkufag/bytebeat-composer/commit/7763d1ad49323bf408e80c7454d45ea4ef88c4c1#commitcomment-63084572

SthephanShinkufag commented 2 years ago

Fanfare test

mix ints and doubles in ways that aren't valid in c

I did not check "Non-JS" formulas with the C compiler, sorting only visually by used functions such as sin etc.

SthephanShinkufag commented 2 years ago

Ok, I will check all the formulas from the [Non-JS] section with C compiler, and move invalid ones to [Compat JS].

SthephanShinkufag commented 2 years ago

Also, there some things that are not obvious at first glance:

song by yehar

t>>4+!(-t>>13&7)+2*!(t>>17)|t*t*(t>>(t>>12^t>>11)%3+10)/(7+(t>>10&t>>14&3))*!(t&512)<<3+(t>>14&1)

Warning: overflow is possible in 16 bit addition, casting to 'long' may be required Warning: overflow is possible in 16 bit multiplication, casting to 'long' may be required

must be rewrited for C as

t>>4+(unsigned long)(!(-t>>13&7))+(2*(unsigned long)(!(t>>17)))|t*t*(t>>(t>>12^t>>11)%3+10)/(7+(t>>10&t>>14&3))*!(t&512)<<3+(t>>14&1)

So, it moves to JS formulas too...

SthephanShinkufag commented 2 years ago
(((1<t/16E3%2?3*t|16*t:2*t|16*t)|123)+(1<t/32E3%2?500>t%1E3?18.3*t:0:500>t%1E3?18.9*t:0)|t/1E3<<4)-128+(50>t%1E3?t<<t/3:0)

operand types 'unsigned long' and 'int' are incompatible with the '%' or '%=' operator

SthephanShinkufag commented 2 years ago

"non-javascript 8khz song, turned out pretty good (2021-10-11)" (t>>4>>(t&t>>11))*(t>>4>>(t&t>>11)&128?-1:1)+(t>>t/(t&65536?2:3)&63)+(3E4/(t&4095)&100)

operand types '' and 'int' are incompatible with the '&' or '&=' operator

called "non-javascript"

haha, what an irony...

SthephanShinkufag commented 2 years ago

OK, next step is to rename [Compact JS] into [JS multivar] and move all its one-(t)-variable code (with used sin, arrays, strings, etc) into [JS one-var]

SArpnt commented 2 years ago

i'm noticing some code like remix of "I hear the long meowing of a cat :)" by SthephanShi in the C section even though it uses division. just because an expression compiles in c doesn't mean it'll actually behave the same. i assume C would use integer division which truncates.

there also could potentially be expressions that only compile if t starts as a double instead of an int, or work if t is an unsigned int but not a signed int.

SthephanShinkufag commented 2 years ago

Yes, the code compiles and I leave it in the Classic section because it's a very vague task. I was not so strict, for this you need to implement the player in C and reproduce each formula in order to listen.

if t starts as a double instead of an int

then you got a ton of errors like "operand type incompatible with the '>>' or '>>=' operator".

Some songs can be modified to be reproduced in C, but according to this logic, almost any code can be modified and ported to C, one way or another. Then the question arises as to what category it should be assigned to, because the original remains incompatible.

SthephanShinkufag commented 2 years ago

Moreover, as I remember, some formulas had playback problems on 8-bit microcontroller with a clock rate of 16MHz, because the calculations take too many clocks, hehe. But these are hardware problems. I will build a player in C for a PC (sorry, I'm not a Linux user, it would be easier), and listen to all the remaining formulas, then everything will be strict.

SArpnt commented 2 years ago

when i test bytebeat formulas in c i generally just run the program and pipe it to aplay on linux testing it on windows needs the player though which is pretty annoying

i think the best option would be to not worry about playing them and instead create an automated script that runs the bytebeat in nodejs with a "player" that just outputs as chars to stdout, then compile a few possible c players (different types for t) and see if they give the same result.

SthephanShinkufag commented 2 years ago

At first I splitted all JS formulas in two sections: [JS one-var] and [JS multi-var], but decided finally to keep all JS code in one section.

SArpnt commented 2 years ago

as an example of code that compiles but doesn't run, the first bytebeat with division doesn't work because of a division by 0 at the start t%(t/(t>>9|t>>13))

trill is currently in the js section, but actually kinda with c when including the math library 64*sin(sin(t/100)-t/(2+(t>>10&t>>12)%9))+128 sin is carefully used here and doesn't ever throw an error an issue with it though is that t gets divided by other numbers and ends up rounded because it's an integer

SthephanShinkufag commented 2 years ago

If you start t from 1, not 0, or timer-counter on hardware changes faster than calculations, 0 can be skipped. My AVR microcontroller plays that fine at beginning, but after a second it starts to change to something different. Its strange... Maybe behavior is not the same because of integer division which truncates, as you said.

Yes, some of sin formulas compiles in C, but it so happened historically I called "classical" formulas that don't use anything other than operators. That is, they don't use the math.h library. But according to new logic, if I called the section "[Classic] — valid C code with one variable (t)", I must include here everything that compiles. How do you think? Rename to "[Classic] — valid C code with one variable (t), no math.h", or include sin and other valid?

SthephanShinkufag commented 2 years ago

Hmmm. "Glissando" t*t/(t>>13^t>>8) plays normally, "Waiver" (t/91&t^t/90&t)-1 too, "Everything is broken" t*t/(1+(t>>9&t>>8))&128 plays good. But t%(t/(t>>9|t>>13)) plays different...

SArpnt commented 2 years ago

i would still go with the approach i recommended before, of using an automated script to compare the outputs (js, c with int32_t t, c with uint32_t t, c with double t) i would recommend int32 based types because that's what javascript uses for bitwise operations, whereas types like int are implementation dependent.

oddly enough (int)(3.2) is both valid js and c and could probably be abused to create compatible expressions, although in js it floors and in c it truncates (i assume it floors in js because of some legacy mistake). it also makes it somewhat confusing what is and isn't a valid minification.

Butterroach commented 1 year ago

oddly enough (int)(3.2) is both valid js and c and could probably be abused to create compatible expressions, although in js it floors and in c it truncates (i assume it floors in js because of some legacy mistake). it also makes it somewhat confusing what is and isn't a valid minification.

actually (int)(3.2) isn't valid js (if you don't have int defined, at least), the only reason it works in the player is because the player defines int as an alias to Math.floor

Chasyxx commented 1 year ago

I decicded i'g do find for songs that have typing issues and/or sound different in C (using gcc -o a c.c && ./a | aplay --interactive -f U8 --duration=10 --rate=(smth here) and

int main() {
    for(int t=0;;t++){
        putchar(
            ...
            );
    }
    return 0;
}

gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04). I'll post the classic codes that have this issues shortly

Chasyxx commented 1 year ago

I decided to do this because i was noticing a lot of songs (for example, bongo) that were having this issue at the bottom of the section... Also, sarpnt was saying that fanfare should be in the js secton due to typing issues, so everything else should get the same treatment.

  1. Not a compiler or song issue, but for some reason aplay is giving a read error with https://chipmusic.org/forums/post/79378/#p79378 . i cant check this code right now due to this reason. (12. PSYCHEDELIC too. strange!)
  2. https://battleofthebits.com/arena/Entry/son+of+a+glitch.txt/17660/
    c.c:15:75: error: invalid operands to binary | (have ‘double’ and ‘int’)
    15 | 0&44)%32>>1)+((t>>9&44)%32>>1))*(32768>t%65536?1:.8)*t|t>>3)*(t|t>>8|t>>6)
      | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
      |                                                     |   |
      |                                                     |   int
      |                                                     double
  3. https://www.reddit.com/r/bytebeat/comments/govfve/rhythmic_thing/
    c.c:15:24: error: invalid operands to binary >> (have ‘double’ and ‘int’)
    15 |             t*2>>(t*4.5>>4)
      |                   ~~~~~^~
      |                    |
      |                    double

    I feel like sarpnt's buzzy grindy beat could have issues too, but aplay once again gets a read error...

  4. https://www.reddit.com/r/bytebeat/comments/qjmy4v/no_array_array_song/ : something sounds a bit off with the bash command i'm using (using the 44100hz rate ofc).
  5. https://www.reddit.com/r/bytebeat/comments/rirrir/combination_fanfare_ca98/ : it's very subtle, but it's different right at the end of each loop
  6. https://demozoo.org/music/305278/ : Everything is one note, only changing octaves. that's not how it is normally
  7. https://dollchan.net/btb/res/44.html#61 : Almost silent in C...
  8. https://dollchan.net/btb/res/44.html#69 : same as 5.
  9. https://www.reddit.com/r/bytebeat/comments/14do1q3/hydrogen_fucker/
    c.c:15:63: error: invalid operands to binary | (have ‘double’ and ‘int’)
    15 |           (t/2/(4+(t>>13&3))*128|t>>(t>>12&15))+4E5/(t&4095)|t>>4
      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
      |                                                |              |
      |                                                double         int
  10. https://dollchan.net/btb/res/204.html#932 . Bongo, the example i gave from earlier!
    c.c:15:45: error: invalid operands to binary >> (have ‘double’ and ‘int’)
    15 |             ((t*(t&131072?t&65536?1.5:4/3:1)>>(1&~t>>13)&128)*(-t>>5<<(1&t>>15)&255)>>7)+(t>>5<<(1&t>>15)&255)/2
      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
      |                |                                |
      |                double                           int
  11. https://www.reddit.com/r/bytebeat/comments/122rwfc/h_ypn0t1z3/ : sounds different!
  12. https://www.reddit.com/r/bytebeat/comments/15383dn/atari_sound_discovered/ : completely silent initiall, replacing && with * has a buzzing noise...
  13. https://www.reddit.com/r/bytebeat/comments/155inp4/times_new_music/ : s i l e n t ! at least, just barely heard...;
  14. https://www.reddit.com/r/bytebeat/comments/1567oiq/omg_teh_bytebeatness/ : This and it's pwm version have pitching issues, similar to 5 and 7.
Chasyxx commented 1 year ago

would recommend int32 based types because that's what javascript uses for bitwise operations, whereas types like int are implementation dependent. -Sarpnt

maybe keep this in mind when it comes to my tests then.

Chasyxx commented 1 year ago

on 12, 11, and 6, maybe it's just for me, but the && seems to actually evaluate both sides and output 1 or 0 in C, which is different fro what is does in js (outputting the right side unless the left side is falsy). huh!

SthephanShinkufag commented 9 months ago

@Chasyxx 1 "son of a glitch" by Xaser - replaced .8 to 4/5 in minified version 2 "rhythmic thing" by SArpnt - replaced 4.5 to 9/2 in minified version 6 "Logics, and?" by lhphr - moved to Compact JS because of different && behavior. 8 "hydrogen fucker" by psubscirbe - replaced 4E5 to 400000, see this issue 9 "bongo" by Zackx - replaced 1.5 to 3/2 in minified version 11 "Atari sound discovered?"by BSquareIsBack - moved to Compact JS because of different && behavior. 12 "times new music" by hcdphobe - moved to Compact JS because of different && behavior.

3, 4, 5, 7, 10, 13 still unsolved.

Butterroach commented 9 months ago

i think you can change x&&y to x?y:0 to make it have the same behavior in c

Chasyxx commented 9 months ago

Truncation in C due to integer division causes issues now. Arch linux with gcc (GCC) 13.2.1 20230801. command is echo -e "#include <stdio.h>\nint main(void){for(int i=0; i<44; i++) putchar(0); for(int t=0;;t++) putchar( /*bytebeat code*/ ); return 0;}" | gcc -xc -&&./a.out | aplay (sh) I. "hydrogen fucker" - Not a truncation issue, but still a division one. There's a division by 0 that causes the program to crash for me. "floating point exception (core dumped)" when not piped to aplay. I don't really know if this should count, but it is notable.

  1. "Son of a glitch" - broken 2nd half
  2. "bongo" - Now there's only one note playing (aside form the octave changes).

edit: in case it's unclear, these problems don't appear on the JS website, only when i put them in the C code.

SthephanShinkufag commented 9 months ago

This song sparked a discussion - is it worth moving songs with one t and with C library functions like sin() into C code section?

UPD: Do such songs even exist?

SthephanShinkufag commented 9 months ago

6 "Logics, and?" by lhphr - turned to t&165&t%255?t/256*(t&t>>12):0 and moved back to C compatible. 11 "Atari sound discovered?"by BSquareIsBack - turned to t*(0xAFEDC320>>t/(6-(t>>10&13))&1)?128:0 and moved back. 12 "times new music" by hcdphobe - turned to (0b1011101101>>(t>>13&7|-t>>12&11|-t>>14&5)/3)*t/3520&1?(-t>>5)*((t>>15&3)==2?1/4:t>>7&128?t>>15&3?1/2:2:1):0 and moved back.

Chasyxx commented 9 months ago

I think 3, 4, 5, 7, 10, and 13 are also caused by C integer division (truncating numbers and messing with pitches), just like in my last comment. You'd have to maybe change the division to use floats, and then make some parts an int using a cast to avoid compiler type errors.

Bongo example: (((int)(t*(t&131072?t&65536?3.0/2.0:4.0/3.0:1.0))>>(1&~t>>13)&128)*(-t>>5<<(1&t>>15)&255)>>7)+(t>>5<<(1&t>>15)&255)/2 (This code works with the command I used before; as in it compiles and sounds like bongo)