Open SArpnt opened 2 years ago
I made some reorganization in library: https://github.com/SthephanShinkufag/bytebeat-composer/commit/7763d1ad49323bf408e80c7454d45ea4ef88c4c1#commitcomment-63084572
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.
Ok, I will check all the formulas from the [Non-JS] section with C compiler, and move invalid ones to [Compat JS].
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...
(((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
"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...
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]
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.
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.
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.
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.
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.
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
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?
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...
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.
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
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
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.
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
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...
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
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
&&
with *
has a buzzing noise...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.
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!
@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.
i think you can change x&&y
to x?y:0
to make it have the same behavior in c
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.
edit: in case it's unclear, these problems don't appear on the JS website, only when i put them in the C code.
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?
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.
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)
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.