LoudPizza shenanigans

should be pretty easy to get a simple audio instance going, if you want to ask me make a thread
637 Replies
Lyris the Kitori
i made a thread
TechPizza
TechPizza2y ago
my tiny sample project will be accessible tomorrow for now we have to just yolo
Lyris the Kitori
im assuming i should do a raw export of bad apple into stereo 16bit short data? because you can only use bad apple for test songs no other songs
Nitrous
Nitrous2y ago
the painful part about this is .NET's lack of audio libraries don't mention NAudio or I'll shoot
Lyris the Kitori
ManagedBass is quite good, but not OSS
Nitrous
Nitrous2y ago
yeahhhhhh bit of a stretch really when I want something OSS
TechPizza
TechPizza2y ago
feel free to port miniaudio to c# kekw while i enjoy my LoudPizza i prefer 32bit float
Lyris the Kitori
makes sense
TechPizza
TechPizza2y ago
i have yet to write a "AudioBufferInstance" class that transcode on the fly
Lyris the Kitori
oh OpenAL only supports 16bit signed integers
TechPizza
TechPizza2y ago
there is a flag for 32bit float
Nitrous
Nitrous2y ago
surely someone already did that right?
TechPizza
TechPizza2y ago
i doubt it's literally a 3MB header file it's hell
Lyris the Kitori
its an extension iirc, and i dont want to deal with extensions more than i already am having to given they are just borked
Nitrous
Nitrous2y ago
3MB header file what so much for being called "mini"
Lyris the Kitori
thats a perfectly reasonable size for an audio engine? not all of that is going to be compiled, compiler wont put what isnt used
Nitrous
Nitrous2y ago
I hope we can just slap this to cppsharp and call it a day
Lyris the Kitori
yeah no LMAO
Nitrous
Nitrous2y ago
yeah it would've been TOO easy
TechPizza
TechPizza2y ago
it takes literally ages for any compiler to chew through it though not having it in multiple headers also kills IDEs
Lyris the Kitori
audacity refuses to work so time to get some fork of audacity :^)
TechPizza
TechPizza2y ago
and the maintainer REFUSES to change it "bECAuase My SinGle HeaDEr"
Nitrous
Nitrous2y ago
gotta keep the "mini" moniker true 😛
TechPizza
TechPizza2y ago
audacity went to shit recently they le fucking git made applying effects awful you can't preview any part you want instantly you need to select the whole thing and only do 5s of preview on the beginning like what in the everliving fuck
Lyris the Kitori
time to heat my room compiling from source
TechPizza
TechPizza2y ago
keep in mind that the ogg streamer works
Lyris the Kitori
oh
Nitrous
Nitrous2y ago
👀
TechPizza
TechPizza2y ago
so if you got any ogg just slap it on VorbisReader
Lyris the Kitori
making badapple.ogg as we speak its making a theora video god dAMN you ffmpeg
Aqua
Aqua2y ago
remember the bad apple midi files
Lyris the Kitori
okay i went from mp4 -> mp3 -> ogg and it made an ACTUAL vorbis audio file
TechPizza
TechPizza2y ago
feel free to try setting up the async streamer yourself and come back if you struggle (should be like 3 lines)
Nitrous
Nitrous2y ago
wake me up if someone makes a decent audio decoder library for C#
Lyris the Kitori
ffmpeg when use any of the multiple shitty bindings
Nitrous
Nitrous2y ago
I don't want to die
Aqua
Aqua2y ago
create your own ffmpeg bindings, ez ffmpeg bindings in silk when?
Lyris the Kitori
tried, no
Aqua
Aqua2y ago
shame
Nitrous
Nitrous2y ago
the bindings available are autogenerated from cppsharp
Aqua
Aqua2y ago
cppsharp surely that must be limited to good old .net framework right
TechPizza
TechPizza2y ago
there is one ffmpeg bindings library that i like
Lyris the Kitori
am i on the right track
No description
TechPizza
TechPizza2y ago
that is not the streamer but kinda yes otherwise you can do vorbisReader.TotalSamples and LoadRawWave is not what you want at least not in the loop
Lyris the Kitori
HOLG SHIT ITS DOING SOMETHIng speed is wrong the 2 ears are out of sync BUT ITS DOING SOMETHING let me record this shit
Lyris the Kitori
the right ear seems to be half way through the song and the left ear right at the start oddly @grifon.petre would you happen to have experienced this when working with OpenAL? and/or might have an idea of whats wrong
Aqua
Aqua2y ago
uh oh this might be an incorrect pcm format some pcm formats (crap ones) put the left channel first, and then the right channel having said that usually the left channel will completely cut out before the right channel starts playing I can't really hear the video, it's quiet and I'm on my phone, but this could either be an incorrect format, or incorrect output from the buffer
TechPizza
TechPizza2y ago
use reader.ReadSamples(span, reader.TotalSamples, reader.TotalSamples) and new float[reader.TotalSamples * reader.Channels]
Lyris the Kitori
what is channelstride o
TechPizza
TechPizza2y ago
that ReadSamples overload reads 11112222 instead of 12121212
Aqua
Aqua2y ago
yeah to me this sounds like incorrect translation from the buffer to openal openal expects pcm data [l, l, r, r]
TechPizza
TechPizza2y ago
AudioBuffer wants 11112222 i think loudpizza mixes into that the actual vorbis is the poblem
Lyris the Kitori
YOOOOOO
Aqua
Aqua2y ago
it's the typical pcm format so it should
Lyris the Kitori
THAT WORKED BAD APPLE PLAYING
Aqua
Aqua2y ago
nice
Lyris the Kitori
time to listen to the entirety of bad apple for TESTING REASONS
TechPizza
TechPizza2y ago
tldr: NVorbis interleaved 11112222 into 12121212
Aqua
Aqua2y ago
eeeesh
TechPizza
TechPizza2y ago
so i just added an overload that gives me the raw data because loudpizza also likes raw data
Aqua
Aqua2y ago
what is it with things using crappy nonstandard pcm formats
TechPizza
TechPizza2y ago
it was a significant speedup i vectorized the interleaving though 😉
Lyris the Kitori
i mean logically i can see why 1212121212 makes sense
Aqua
Aqua2y ago
don't even get me started with tracker files JEEZ
Lyris the Kitori
one chunk of [12][12][12] is a single 'metasample' of audio like logically thats how i thought it was layed out i didnt know it was 11112222
Aqua
Aqua2y ago
typical 16 bit pcm is
TechPizza
TechPizza2y ago
ehh 12121212 is good in streaming 11112222 is good for processing
Aqua
Aqua2y ago
[Left lower byte, Left upper byte, Right lower byte, Right upper byte] which is what most things expect
TechPizza
TechPizza2y ago
conclusion: both are useful
Lyris the Kitori
流れてく 時の中ででも 気だるさが ほらグルグル廻って 私から 離れる心も 見えないわ そう知らない? oh i should make sure 3d audio works after this loop of bad apple
Aqua
Aqua2y ago
first time I discovered bad apple was a Minecraft version like 6 years ago lmao it was awesome tho, the actual video in Minecraft
TechPizza
TechPizza2y ago
if it's broken i blame openal lol
Lyris the Kitori
i know it will 95% chance of working, i just want to make bad apple spin around me in 3d audio
TechPizza
TechPizza2y ago
i hate youtube videos that say 8D but i can't seem to download any audiostream that actually has more than 2 channels >;(
Lyris the Kitori
i have a feeling i fucked up
No description
Aqua
Aqua2y ago
holy shit I found it https://youtu.be/i1udDC-XLCQ
NiceMarkMC
YouTube
Bad Apple!! but it's in Minecraft Blocks
Bad Apple!! - a Touhou video recreated with Minecraft blocks and note blocks. I guess you could call it a Minecraft stop motion animation. More information is available below! Read the full description :) Note block song (+ song download) - https://www.youtube.com/watch?v=3Sf064dkVeY * There are 6585 frames in this video, it runs at 30 frames...
Lyris the Kitori
its not doing anything
TechPizza
TechPizza2y ago
you need to enable 3d on the instance and on the soloud handle i think
Lyris the Kitori
i just switched from play to play3d OH update3dAudio
Lyris the Kitori
ITS BEAUTIFUL
TechPizza
TechPizza2y ago
it's so good that even the buttons are jamming
Lyris the Kitori
oh yeah rider just kinda does that
TechPizza
TechPizza2y ago
it's the icon next to Debug disappearing isn't it curseed
Lyris the Kitori
yup that menu hasnt been updated to the new UI yet so its buggy
TechPizza
TechPizza2y ago
@baebey if you plan to use loudpizza don't be afraid to message me about anything
Lyris the Kitori
makes sense i'll be writing an SDL one next, then PR these sample apps in how would i do async streaming by the way?
TechPizza
TechPizza2y ago
tldr:
AudioStreamer streamer = new();
streamer.Start();

VorbisStream vorbisStream = new(...);
StreamedAudioStream streamedStream = new(streamer, vorbisStream);
streamer.RegisterStream(streamedStream);
AudioStreamer streamer = new();
streamer.Start();

VorbisStream vorbisStream = new(...);
StreamedAudioStream streamedStream = new(streamer, vorbisStream);
streamer.RegisterStream(streamedStream);
and use streamedStream as an AudioInstance (disposing StreamedAudioStream automatically calls streamer.UnregisterStream)
Lyris the Kitori
wait i got this far how do i actually play it
No description
TechPizza
TechPizza2y ago
oh right, StreamedAudioStream is an AudioSource not an AudioInstance
Lyris the Kitori
play wants an AudioSource
TechPizza
TechPizza2y ago
hol on
Lyris the Kitori
StreamedAudioStream is IAudioStream
TechPizza
TechPizza2y ago
i am clowning create an AudioStream audioSource = new(soloud, streamedStream); i think i need to rename some types somehow having IAudioStream and AudioStream is... confusing
TechPizza
TechPizza2y ago
you didn't initialize the nested VorbisReader
Lyris the Kitori
i have brain damage
TechPizza
TechPizza2y ago
i thought i had a better exception than a NRE for using an uninitialized VorbisReader 🙄
Lyris the Kitori
now its playing too slow with slightly lower pitch
TechPizza
TechPizza2y ago
uhoh
Lyris the Kitori
i think theres a mismatch of sample rates 41000 vs 48000
Lyris the Kitori
code so far
No description
TechPizza
TechPizza2y ago
weird, i thought i set the sample rate correctly
Lyris the Kitori
if you want i can send you the ogg file, and push my code so far to a repo
TechPizza
TechPizza2y ago
oh so i can build it? sure sure
Lyris the Kitori
cool one min and ill get a github repo up
Lyris the Kitori
GitHub
GitHub - Beyley/LoudPizza: Port of SoLoud for .NET
Port of SoLoud for .NET. Contribute to Beyley/LoudPizza development by creating an account on GitHub.
Lyris the Kitori
ogg file there just clone it and run the LoudPizza.Test application
TechPizza
TechPizza2y ago
'Could not find or load the native library: openal32.dll
panik
Lyris the Kitori
oh you can install the openal soft native package i have it system-wide so i forgot Silk.NET.OpenAL.Soft.Native its possible its too old to have the extension though, in that case you will have to build from source
Aqua
Aqua2y ago
make sure you enable soft in the GetApi calls or it won't find the output dll from the nuget package
Lyris the Kitori
oh
TechPizza
TechPizza2y ago
so like you are just setting sample rate to 48000 and channels to 2 and not reading what openal gives you and you're not asking openal for specific sample rate or channels
Lyris the Kitori
oh do you have to?
TechPizza
TechPizza2y ago
... it gives you whatever it wants
Lyris the Kitori
aside from forgetting to pass the right format into BufferCallback i do give it a sample rate tho
TechPizza
TechPizza2y ago
not to mention that silk doesn't even expose the GetIntegerv enum for frequency or channels 🤔 only to BufferData, not when you open a device ... can you even ask openal for a specific samplerate or is SoftCallbackBuffer a buffer that manages device rates ugghhhh why is openal literally 7x worse than i remember it being
Lyris the Kitori
specification for the extension here https://openal-soft.org/openal-extensions/SOFT_callback_buffer.txt "with <freq> being the base sample rate the samples will play at" if it is an OpenAL problem, then its odd it works when i dont stream it
TechPizza
TechPizza2y ago
No description
TechPizza
TechPizza2y ago
i hate openal i hate openal i hate openal uhh no clue actually
Lyris the Kitori
are you sure you have to query that? the Silk WavePlayer example doesnt do that it just reads the sample rate from the file and passes that directly into the buffer
TechPizza
TechPizza2y ago
i mean you don't have to ugh, it plays at low pitch at 44100 sus
Lyris the Kitori
thats why im thinking LoudPizza is resampling it wrong, even if i tell OpenAL to play at 44100 it still is wrong
TechPizza
TechPizza2y ago
you are already telling the openal buffer what frequency your data is at, it's just an optimization for creating hardware device yup, i'm investigating found the problem i think the buffer callback is trolling you
Lyris the Kitori
oh no?
TechPizza
TechPizza2y ago
numBytes is 3936 while the buffer size is 8192 bytes and 3936 happens to not align on the 8192 buffer length
Lyris the Kitori
its ALMOST half the size
No description
Lyris the Kitori
i dont understand why its doing that
TechPizza
TechPizza2y ago
because the buffer got set to pretty big so it requests often but not for full refills i have a simple fix though i think
Lyris the Kitori
oh was (int)(bufferSize * channels * sizeof(ushort)) too big? i tried to match what i thought SDL was doing
TechPizza
TechPizza2y ago
it's not too big openal is just being clever
Lyris the Kitori
WHAT SINCE WHEN
TechPizza
TechPizza2y ago
never
Lyris the Kitori
damn
TechPizza
TechPizza2y ago
it was all an elaborate L
Lyris the Kitori
same
TechPizza
TechPizza2y ago
If the return value is less than <numbytes>, it's treated as the end of the buffer and the source will play any complete samples before stopping.
you are actually fucking kidding me
Lyris the Kitori
solution: always return numBytes
TechPizza
TechPizza2y ago
i refuse
Lyris the Kitori
but it w o r k s
TechPizza
TechPizza2y ago
if you call silence between buffer refills correct then sure!
Lyris the Kitori
what if return value is MORE than numbytes does it just stab you really hard with a knife
TechPizza
TechPizza2y ago
.... it changed nothing how bloody cursed oh damn i need to expose the actual scratch buffer size why does openal take so god damn long to initialize anyways
Lyris the Kitori
is it slow? it didnt seem to be for me 111ms on my machine
TechPizza
TechPizza2y ago
idk, feels like seconds to me
Lyris the Kitori
yeah about 110ms on average for me, which isnt that bad
long timestamp = Stopwatch.GetTimestamp();
backend.Init();
timestamp = Stopwatch.GetTimestamp() - timestamp;
Console.WriteLine($"Backend init took {timestamp / (double)Stopwatch.Frequency * 1000}ms");
long timestamp = Stopwatch.GetTimestamp();
backend.Init();
timestamp = Stopwatch.GetTimestamp() - timestamp;
Console.WriteLine($"Backend init took {timestamp / (double)Stopwatch.Frequency * 1000}ms");
replace the init with that
TechPizza
TechPizza2y ago
oh shit i align a pointer in the wrong direction
Lyris the Kitori
thats not healthy
TechPizza
TechPizza2y ago
guess what it quits immediately if you return less than numBytes
Lyris the Kitori
lmao chad "oh you are done sending data, alright then DONE"
TechPizza
TechPizza2y ago
ok i am confused what format does this take it in because mixSigned16 outputs 12121212
Lyris the Kitori
5.3.4 seems to be about buffer content https://www.openal.org/documentation/openal-1.1-specification.pdf IT DOES WANT INTERLEAVED 121212121212 openal is weird i hate it Stereo data is expressed in an interleaved format, left channel sample followed by the right channel sample.
TechPizza
TechPizza2y ago
ok wait i think everything is fine in soloud hold the fuckety up
Lyris the Kitori
i am implementing SDL2 support as we speak to see
TechPizza
TechPizza2y ago
i'm just tired SDL2 audio is godly compared to openshital
Lyris the Kitori
OpenShitAll
TechPizza
TechPizza2y ago
i am offended
No description
TechPizza
TechPizza2y ago
Init is called as Init() btw
Lyris the Kitori
maybe try a rebuild? because the interface definition is uint channels = 2
TechPizza
TechPizza2y ago
ah
Lyris the Kitori
better than your old one which defaulted to 0 channels and that broke all the math
TechPizza
TechPizza2y ago
0 meant take platform default 🙃 there is a reason to calling SoLoud.postinit_internal
Lyris the Kitori
oh i see thats an SDL thing
TechPizza
TechPizza2y ago
no, that's a backend thing SDL just does that by default as well
Lyris the Kitori
i meant what is actually setting it from 0 to something else
TechPizza
TechPizza2y ago
SDL in the SDL backend
Lyris the Kitori
the desired vs obtained audio spec
TechPizza
TechPizza2y ago
yes, any other soloud backend should set it to something sane as well
Lyris the Kitori
i think its possible to get the highest supported one in OpenAL but i havent bothered :^)
TechPizza
TechPizza2y ago
i think i want to burn openal
Lyris the Kitori
valid
TechPizza
TechPizza2y ago
i also need to fix resampling apparently alright i found the bug fuck you did help in uncovering a new resampling bug though
Lyris the Kitori
sick currently just finishing up the SDL2 backend yup SDL2 provides the same behaviour, but importantly works
TechPizza
TechPizza2y ago
i need to revamp how audio instances work as a whole this OOP shit is killing me ECS time
Lyris the Kitori
based i may go against my own and perksey's advice and use the silk sdl2 bindings here since it would let someone pass in their own get proc address function for whatever SDL2 binding they use
TechPizza
TechPizza2y ago
pull upstream for a fix btw
TechPizza
TechPizza2y ago
hold on i forgot about the resampling bug
Lyris the Kitori
both backends work flawlessly with that commit
TechPizza
TechPizza2y ago
there, fixed the new bugger as well also not to be annoying but i don't think i'll merge any PR from your fork it would be too much code style cleanup 😅
Lyris the Kitori
fair, the code style of the rest of loudpizza is like night and day with mine lmao
TechPizza
TechPizza2y ago
it's a bit on me for not having a .editorconfig
Lyris the Kitori
i mean feel free to export one and ill try to match the rest best i can
TechPizza
TechPizza2y ago
but i can easily fix up code styles manually if i decide to merge
Lyris the Kitori
one thing about your original implementation is that it would break on net framework(im fairly certain)/mono(i think?) due to accessing instance fields from a native callback, which is why i use GCHandles no matter how much i hate them
TechPizza
TechPizza2y ago
sounds like you didn't leave the instance rooted?
Lyris the Kitori
but its not like its netstandard in the first place :^)
TechPizza
TechPizza2y ago
but yes, GCHandle good
Lyris the Kitori
i got no idea what that means, but i was yelled at by people for not using it in my video decoder FFmpeg callback since it would break on framework
TechPizza
TechPizza2y ago
rooting means having either a GC.KeepAlive so the object lives long enough in a method or putting it in a field into another object that is alive
Lyris the Kitori
oh, thats not why i was yelled at, it was something about instance fields being just fucking cursed on framework in native callbacks
TechPizza
TechPizza2y ago
so it would not only break on netframework ... well then i would rather not support that then :)
Lyris the Kitori
specifically instance fields when using this inside a native callback, no idea why
TechPizza
TechPizza2y ago
i rather not know the real issue, anyways i'm going to bed
Lyris the Kitori
fair
Lyris the Kitori
oh you cant get an accurate exact timestamp, it seems to be updated infrequently hmm
No description
Lyris the Kitori
ah i see, its only updated when you mix i wonder if i can use a Stopwatch here to interpolate the values and get a much much more accurate value
TechPizza
TechPizza2y ago
ok so like what do you want to do with stream time because if you're getting the stream position, that will not practically be the current stream position
Lyris the Kitori
i want to know exactly what position in the song is playing
TechPizza
TechPizza2y ago
because mixing moves time
Lyris the Kitori
down to the milisecond
TechPizza
TechPizza2y ago
so every time your mix is called, record the current time stamp and then do currentTime - mixTimestamp + streamTimeBeforeMix :yeehaw:
Lyris the Kitori
ye im working on basically that rn
TechPizza
TechPizza2y ago
hmm i have an idea instead of tracking the time of every stream nvm wait you can track the timestamp of a mix, and how much that mix mixed and then do streamTimeAfterMix - mixAmount to get streamTimeBeforeMix 🧠 alright i think i ironed out every wrinkle in my brain for today tldr: it's a solvable problem
Lyris the Kitori
solved i got an interpolated time position working
TechPizza
TechPizza2y ago
but in the future, when i have a more ECS-based approach, i will probably have plenty of "events" (not c# events but fast ECS events) for implementing custom logic stuff
Lyris the Kitori
i basically track how long its been in real time since the last mix, then add that time to the last mix time when the song is paused, i pause the time
TechPizza
TechPizza2y ago
hmm if you only wanted the soloud time and not the position of an individual stream then sure lmfao it's just that pitch and stuff affects streams so uhh have fun 👍
Lyris the Kitori
i do it per voice er the var is called voice but the actual class is AudioSourceInstance each AudioSourceInstance stores its own time since the last mix and i make sure that i take into account speed being different
TechPizza
TechPizza2y ago
i'm not merging that
Lyris the Kitori
yeah having 80 instances of stopwatch is dumb, but i wanted to see if it worked and it does, would just using Stopwatch.GetTimestamp be fine? er wait no that wouldnt work
TechPizza
TechPizza2y ago
i am on the other hand fine with implementing this myself some day just keep your fork somewhat tidy so i can read it in a month lollllll
Lyris the Kitori
makes sense, feel free to not merge any of my stuff, im just modifying it to suit the needs of my engine i try to keep commits mostly clean
TechPizza
TechPizza2y ago
forks good (you committed Silk.NET.OpenAL.Extensions.Soft.dll into the repo lol)
Lyris the Kitori
thats because i use an extension i havent opened a PR for yet ill be opening one soon then once its merged the nuget will work fine
TechPizza
TechPizza2y ago
but why is it committed into the repo angryturtle
Lyris the Kitori
to make your life easier when building it locally to test :^)
TechPizza
TechPizza2y ago
how dare you bloat my git objects when
Lyris the Kitori
i can just remove the commit from the history i know enough git-fu
TechPizza
TechPizza2y ago
good because git-fu kicked my ass earlier
Lyris the Kitori
The Modern Coder
YouTube
Learn how to rewrite Git history - Amend, Reword, Delete, Reorder, ...
In this video I'll dive into some of the ways Git allows us to rewrite commit history. Specifically I cover: amending commits, rewording commit messages, deleting commits, reordering commits, squashing commits and splitting commits. FULL WRITEUP: https://www.themoderncoder.com/rewriting-git-history/ MORE GIT VIDEOS: https://youtube.com/playlist...
Lyris the Kitori
since its a fork and im not scared of force pushes since im the only consumer of my fork, if you need the history cleaned up when you do get around to looking at the changes im making, i can do that
TechPizza
TechPizza2y ago
sounds good to me
Lyris the Kitori
cool
TechPizza
TechPizza2y ago
now i'm going for real 🛏️
Lyris the Kitori
have a good sleep i have streaming from MP3 files partially working i can play it at half speed from a single channel and at full speed with constant tiny dropouts its also pitched down? i believe the dropouts are due to the fact that NLayer reads things in an interleaved format, ive tried to hack it to not-do-that but ive been unsuccessful i also patched NLayer to be net 6.0 and use spans in more places rather than arrays oh apparently you already had a fork to do exactly that im dumb DAMNIT its playing correctly now but only in the left ear
Lyris the Kitori
i dont really understand this code i changed it and i can no longer get it back to this state ive gotten close to it multiple times
Nitrous
Nitrous2y ago
was NAudio made back in the net framework days?
Lyris the Kitori
NAudio is kinda old and windows only, so i generally dont consider it i pushed my one-ear-only MP3 implementation
TechPizza
TechPizza2y ago
i am pretty sure i have a vectorized deinterleave helper exposed in soloud, have fun finding that
Lyris the Kitori
you have a function to interlace them yeah im not seeing a deinterlace in your old WIP mp3 code it used basically that exact same func
Lyris the Kitori
this is what i have so far, i dont understand why it would only be in the left ear
No description
Lyris the Kitori
because i stepped through in a debugger and it all seems to be correct i am going to SCREECH
Lyris the Kitori
SPOT THE CODE DIFFERENCE THAT MADE IT WORK
No description
Lyris the Kitori
cool so now i have audio streaming for both mp3 and ogg i am currently listening to the sound of VICTORY aka bad apple in glorious stereo audio looping works too i was worried i messed up EOF stuff works on both OpenAL and SDL too awesome currently vibing HARD to bad apple in the maintainers VC because i have achieved success time to fix seeking as currently its just hacked together code
TechPizza
TechPizza2y ago
hol on hmm maybe you're right i thought i had one somewhere though i can't seem to find it, pain and i am 99% certain that localBuffer is not needed
Lyris the Kitori
i think you do to be able to deinterlace(?) maybe theres some magic deinterlace alg that works on a single buffer or smthn but i dont know it
TechPizza
TechPizza2y ago
i'll figure it out and put it in a vectorized helper
Lyris the Kitori
cool, im not good with algs so im probably missing something obvious lol
TechPizza
TechPizza2y ago
i meant to do that as a utility for AudioBuffer anyways
Lyris the Kitori
okay i thought i had gotten seeking good but i have not, it seems to be seeking to some rando part of the song am i stupid how do you even seek to a specific second timestamp tried samplerate * channels * secondToSeekTo also tried samplerate * secondToSeekTo both on vorbis and mp3 neither seem to be producing the correct results oh im fucking STUPID what the hell i was using the WRONG FILE as reference okay vorbis seeking works perfectly doing sampleRate * secondToSeekTo okay it still is going absolutely in the wrong place but i commit my current work and now im going to BED because im TIRED of MP3 and its BS and also i have coffee and code in 9.5 hours :) 7 hours of sleep EH ill be fine lets hope my breakfast arrives early enough so i can eat it fully :^) i got mp3 SO FUCKING CLOSE i can seek ALMOST i can seek to half the position i am supposed to seek to if i multiply that position by 2 it seeks to way further than 2x in the song so seeking ALMOST works
TechPizza
TechPizza2y ago
concern
Lyris the Kitori
yeah i got seeking almost working but i have given up for now i tried using Mp3Sharp but its bad and i gave up i was going to begin writing a WAV decoder but then i got distracted for the next 11 hours alright im 90% sure i narrowed the mp3 seeking down more MpegFile has a way to directly seek to a particular TIMESTAMP instead of sample i tell it to seek to exactly 60 seconds and its wrong so i think im able to open an issue here
Lyris the Kitori
oh wait i should probably make sure this isnt a bug with your fork, it shouldnt be but i dont know for sure im looking at your changes and i dont see anything out of the ordinary at least nothing that should break seeking
Lyris the Kitori
liar vvvv
No description
Lyris the Kitori
(yes i know there is a way to get the sample position directly im just testing) oh hmmmm thats really weird Cytoid creates a new MpegFile every time they seek
Lyris the Kitori
i wonder if there is a reason that didnt fix the problem it would have been very weird if it did tbh im seeing a SUSPICIOUS / sizeof(float) in a lot of things consuming NLayer relating to length and position not only that but a lot of unity projects using NLayer do something odd
var clip = AudioClip.Create(path,
(int) mp3Clip.Length/sizeof(float)/mp3Clip.Channels, mp3Clip.Channels,
mp3Clip.SampleRate, true,
data => { mp3Clip.ReadSamples(data, 0, data.Length); },
position => {
mp3Clip = new MpegFile(path);
});
var clip = AudioClip.Create(path,
(int) mp3Clip.Length/sizeof(float)/mp3Clip.Channels, mp3Clip.Channels,
mp3Clip.SampleRate, true,
data => { mp3Clip.ReadSamples(data, 0, data.Length); },
position => {
mp3Clip = new MpegFile(path);
});
in the 'set position' callback they all just create a new clip thats it cytus is the only one that ever actually SETS the time i am so confused at why ths doesnt work i am pouring over NAudio and NLayer issues and documentation nothing makes sense
Lyris the Kitori
theres MAYBE a relavent PR https://github.com/naudio/NAudio/pull/10
GitHub
Add sample-exact seeking to Mp3FileReader by protyposis · Pull Requ...
This changeset adds frame-exact seek capabilities to the Mp3FileReader as explained in this blogpost. It also fixes frame-granular repositioning, position reporting, and handles the decoder warmup ...
Lyris the Kitori
did you ever have mp3 seeking fully working? or was your seeking code that you did have a WIP
TechPizza
TechPizza2y ago
seeking was indeed a joke and my NLayer fork is WIP
Lyris the Kitori
i was going to implement WAV with a custom WAV decoder then i realized id have to implement seeking and i got distracted thinking of how to do sample accurate seeking
TechPizza
TechPizza2y ago
seeking? in a WAV? how could this be any harder than a += would be nice to support WAV in the same manner as audacity does (talking about the amount of data formats) including ADPCM
Lyris the Kitori
JUNK is a random identifier that appears between data identifiers to align things also getting sample accurate seeking with streaming is the part im not sure how to properly do i think ill store a dictionary of the sample start index of each data identifier -> byte position
TechPizza
TechPizza2y ago
i will align someone with a gun WAV was just too easy to not fuck up huh
Lyris the Kitori
then basically go to the right data identifier, and then add the remaining samples i need to go to the sample read position
TechPizza
TechPizza2y ago
sounds fine, i do that dance in vorbis as well
Lyris the Kitori
cool, yeah thats a lot simpler than my brain was initially things laying it out in text helped understand it this would be quite easy to do and sounds like a fun coding challenge :) ive never written a streaming audio format decoder only a 'read the entire wav beforehand' decoder
TechPizza
TechPizza2y ago
it's easier when the encoder doesn't lie and breaks the format spec
Lyris the Kitori
wav is simple enough in concept where i dont think many encoders will break spec
TechPizza
TechPizza2y ago
i will be forever salty for ogg encoders being broken for years
Lyris the Kitori
just for clarification, if leaveOpen is false that means close the stream if the reader is disposed? i just realized i dont actually know for certain
TechPizza
TechPizza2y ago
ya leaveOpen==false => close on dispose
Lyris the Kitori
cool oh god theres sub-specifications of WAV forks of it to fix problems RF64, uses a 64bit file size marker rather than a 32bit one that the original spec used theres also the W64 format which does the same thing but is a different format okay ill figure that out another time, im just going to target base spec WAV for now wow i forgot how quickly parsers balloon into large files lmao wikipedia literally just shits on the spec and says 'the spec is confused here, heres how the spec SHOULD have been written' IAudioStream.Seek 100% is being passed in a sample count ignorant of the number of channels for samplePosition, right? like when SoLoud calls IAudioStream.Seek, samplePosition is the number of samples (divided by the number of channels)? okay so the WAV files by FFmpeg are just a single data chunk i think i will craft my own wav file in a hex editor that has JUNK identifiers and multiple data chunks to stress test the seeking
Aqua
Aqua2y ago
tmk wav file data chunks don't have any headers after it. data is always the last chunk and it always contains the pcm data
Lyris the Kitori
then whats the point of JUNK
Aqua
Aqua2y ago
it goes before the data header to provide crap bits of metadata iirc i used to have a file with a junk chunk but i can't find it anymore
Lyris the Kitori
okay so apparently theres something called a "wave list chunk" wavl that can contain multiple
Lyris the Kitori
https://sites.google.com/site/musicgapi/technical-documents/wav-file-format according to some old site which has quite helpful listings of the chunks
Lyris the Kitori
but apparently its almost a hack but with how i was planning on implementing the wav sample reading, this is trivial to support so i dont see why not im sure theres 1 wav file from 2003 that uses it that someone is going to complain doesnt work
Aqua
Aqua2y ago
for a wav file the only chunks you are interested in are fmt and data you can ignore the rest, that's what i do my reader just checks chunks until it finds fmt and data and then it just stops searching (unless ofc you need other metadata)
Lyris the Kitori
yea but thats no fun i like writing parsers
Aqua
Aqua2y ago
wdym by parser tho? there isn't anything to parse?
Lyris the Kitori
im fairly certain im parsing the wav file any binary reading of data structures is parsing :^)
Aqua
Aqua2y ago
ah. i always just considered that loading but i suppose you are right but yea creating a spec compliant wav loader is really simple. at the point though that the format identifier is not 1 or 3 though is the point you start panicking cause that's when the data becomes not PCM (1 = integer pcm, 3 = floating point. i discovered this by staring at wav files with various different sample formats)
TechPizza
TechPizza2y ago
i try to keep the sample count definition to "one sample = all values for channels at one time"
Lyris the Kitori
cool, thats what i thought ill stick with that internally in the parser oh apparently the WavePlayer in the silk repo doesnt follow spec "One tricky thing about RIFF file chunks is that they must be word aligned. This means that their total size must be a multiple of 2 bytes (ie. 2, 4, 6, 8, and so on). If a chunk contains an odd number of data bytes, causing it not to be word aligned, an extra padding byte with a value of zero must follow the last data byte. This extra padding byte is not counted in the chunk size, therefor a program must always word align a chunk headers size value in order to calculate the offset of the following chunk."
Lyris the Kitori
simple fix tho
No description
Lyris the Kitori
@techpizza is there an optimized codepath already for u8/s16 -> float already somewhere?
TechPizza
TechPizza2y ago
this is what soloud did for loadRawWave8
for (i = 0; i < aLength; i++)
mData[i] = ((signed)aMem[i] - 128) / (float)0x80;
for (i = 0; i < aLength; i++)
mData[i] = ((signed)aMem[i] - 128) / (float)0x80;
lol i have not made optimized helpers for that yet
Lyris the Kitori
ah wait what the fuck is (signed)
TechPizza
TechPizza2y ago
didn't know you can just do signed it seems to cast the integer from unsigned to signed (surprise)
Lyris the Kitori
i didnt know that was a thing
TechPizza
TechPizza2y ago
feels like something you'd whip up on an interview
Lyris the Kitori
i like writing this kind of stuff this is fun im enjoying this so far clueless ^^^
TechPizza
TechPizza2y ago
i do enjoy data transformations quite a lot
Lyris the Kitori
slowly getting this read samples func down (yes i know this wont work if you cant seek but for my specific needs i dont care about non-seekable streams)
No description
Lyris the Kitori
MemoryMarshal for the win
No description
Lyris the Kitori
im going to combine de-interlacing and converting formats into one for loop and pray to the JIT gods that it gets vectorized
Aqua
Aqua2y ago
ohh i see what you mean now. you are literally streaming directly from the file
Lyris the Kitori
yup going to support some extensions to the format too, like W64, and the weird 'silent chunk' stuff
Aqua
Aqua2y ago
nice!
Lyris the Kitori
silent chunks are an interesting way to compress
Aqua
Aqua2y ago
not seen them before, what are they?
TechPizza
TechPizza2y ago
compression? in my WAV?!
Lyris the Kitori
its a chunk that only contains a single i32, which is just how many silent samples combine tha with multiple data chunks and you cut down a TON of data
Aqua
Aqua2y ago
ohh okay thats cool
TechPizza
TechPizza2y ago
i can't wait to write a WAV parser myself that doesn't allocate
Lyris the Kitori
all the allocations are due to my unknowledge of deinterlacing and conversions :^) im TRYING to keep it down to a single array allocation for code simplicity i know i could do this differently by reading and converting directly from the stream that would be allocation-less but not right now actually wait is that what you were going to do? thats really simple i may just do that right now since i dont actually have any of the conversion code written yet
Lyris the Kitori
hows something like this then, this cuts out the allocations
No description
TechPizza
TechPizza2y ago
now i'm going to bitch about an inefficient loop my unhealthly high standards are a pain
Lyris the Kitori
i dont know how to write an effecient one here, im not good with that kind of stuff, what would be better? is this some memory cache thing i dont understand where i am writing to alternating points in a buffer, instead of contiguously?
TechPizza
TechPizza2y ago
there are many points and i'm tired rn
Lyris the Kitori
ah
TechPizza
TechPizza2y ago
i will just a write WAV helper and buffer and streamer later
Lyris the Kitori
fair this is good enough for my current uses
TechPizza
TechPizza2y ago
you using loudpizza does me happy tho
Lyris the Kitori
oh god wait this is not good enough for my use cases its taking 1.6ms to read 1000 samples tf taking that long profiler time
TechPizza
TechPizza2y ago
that can't be right uhuhhh do you increase read?
Lyris the Kitori
oh i dont do that but i dont use it either
TechPizza
TechPizza2y ago
you return it also, why not keep a BinaryReader field on your class
Lyris the Kitori
i do, i just forgot to increase it :^)
TechPizza
TechPizza2y ago
1. you need to warm up le code 2. there is Stopwatch.GetElapsedTime Console.WriteLine(Stopwatch.GetElapsedTime(l)); 👌
Lyris the Kitori
what no there isnt is this a net7 thing
TechPizza
TechPizza2y ago
net7 gang
Lyris the Kitori
ah loudpizza is still on net6 so thats what the test project is on :^)
TechPizza
TechPizza2y ago
i'm surprised it took them so long
Lyris the Kitori
okay that is MUCH more reasonable
No description
No description
Lyris the Kitori
it just had to warm up
TechPizza
TechPizza2y ago
Tier0 code is bleh it is basically debug codegen
Lyris the Kitori
ouch i forget the JIT tiers exist
TechPizza
TechPizza2y ago
i feel bad for monogame devs that got indoctrinated to turn off TieredCompilation "because of hitches" the upgrade from tier0 to tier1 is asynchronous angryturtle
Lyris the Kitori
oh god wait i hope that monogame curse isnt still in my engines project file ONE MIN IT IS NOOO i didnt know what it meant back then i just read 'causes hitches, disable it' so i did
Lyris the Kitori
fixing immediately
TechPizza
TechPizza2y ago
we have JIT magic, might as well use it the tier0 to tier1 is 100% worth it
Lyris the Kitori
tiered compilation off:
No description
Lyris the Kitori
tiered compilation on:
No description
Lyris the Kitori
halves draw time
TechPizza
TechPizza2y ago
when
Lyris the Kitori
makes updates like 5x faster and inputs seem unaffected oh wait no those are 50% faster too, that screenshot just happened to be at an unfortanate time
TechPizza
TechPizza2y ago
i mean, it turns static readonly fields into JIT constants it can eliminate huge chunks of code and stuff
Lyris the Kitori
thank you for gaining me 1.1k fps i would have never known i had that disabled
TechPizza
TechPizza2y ago
obscure java tricks be like pretty sure this makes tiered PGO better as well soooo 5000 fps when when
Lyris the Kitori
the biggest bottleneck seems to be the Draw() function, which makes sense since its quite hefty
TechPizza
TechPizza2y ago
the jit is smart when compiling tier0 code; it gathers inlining metrics and stuff at that point so if you cut your draw method up into smaller pieces and stuff, i'm sure you can get a bit faster won't really matter when you start drawing actual content because drivers boohoo
Lyris the Kitori
it is split up quite well
No description
Lyris the Kitori
that highlighted code is it complaining about allocations which is a problem i have yet to solve oh right its complaining about a debug assert allocating i have no idea how it is but apparently it is but yeah it the top level draw function calls down into here eventually https://github.com/Furball-Engine/Furball/blob/4a9a43517dcf7daa94fb673e4a4fb301cab17cd4/Furball.Engine/Engine/Graphics/Drawables/Managers/DrawableManager.cs#L63 and this calls into every single drawable in the scene the drawable draw method is virtual :^) either way, ill dig into whats causing Draw() to take so long later, back to wav stuff lmao ALRIGHT first test of playing a wav file and its pure silence OH i know whats happening im not increasing the read position oops wait WHAt ITS WORKING I HEAR BAD APPLE NO DISTORTION
Aqua
Aqua2y ago
nice
Lyris the Kitori
literally the only bug was i was just reading the first chunk of the song over and over
Lyris the Kitori
cool so i now just need to do this for 8bit PCM, then for floats i only need to deinterlace
No description
Lyris the Kitori
is WAV 8bit PCM data signed or unsigned i cant find much on google
Aqua
Aqua2y ago
unsigned
Lyris the Kitori
midpoint of 128?
Aqua
Aqua2y ago
ye
Lyris the Kitori
cool
Aqua
Aqua2y ago
i just do sbyte.MaxValue and i have no issues but 128 should make no difference either
Lyris the Kitori
if this was zig i believe i could do some shenanigans there to support ANY bit count, since zig can have shit like a 13bit unsigned integer and it just works okay i just listened to the entirety of bad apple 'for testing' back to actually coding eyyyy 8bit PCM works now too is there such thing as 16bit float PCM data or is that too cursed for any encoder to have implemented
Aqua
Aqua2y ago
not seen anything with 16-bit floats, only 32 there is also 32 bit integer format too which is just cursed
Lyris the Kitori
audacity doesnt have 16bit float exports i wonder if FFmpeg does FFmpeg doesnt either
Aqua
Aqua2y ago
the formats im aware of are: 8 bit unsigned 16 bit signed (There are also signed 8 and 16 bit unsigned but we don't talk about those because I've never seen anything use them except tracker formats) 24 bit integer 32 bit integer and floats and i think that's the "main" formats used that's what mixr supports anyway (except 24 bit integers, they can go die in a hole)
Lyris the Kitori
f32 works and so does f64 now wouldnt 16bit unsigned sound the exact same, just phase-shifted 180 degrees? if parsed as 16bit signed
Aqua
Aqua2y ago
nope, it sounds like garbage (try it, but turn down your volume lmao) you have to subtract short.MaxValue to convert it to signed
Lyris the Kitori
would the midpoint of 16-bit unsigned not be short.MaxValue?
Aqua
Aqua2y ago
it is yea
Aqua
Aqua2y ago
yeah this is the difference between signed and unsigned lmfao
No description
No description
Lyris the Kitori
that logically doesnt make sense in my brain, let me try to write down what im thinking lets pretend its 4 bit PCM for clarity in the signed representation 1000 would equal 0000 (as that would be negative 0) but unsigned 1000 is also the midpoint (but off by one?) so any other numbers should just parse out and be the same (but with signed-ness flipped), no?
Aqua
Aqua2y ago
part of the problem is that pcm data is big endian so it kinda doesn't know what to do with it
Lyris the Kitori
OH yeah BE vs LE will be a bigger problem but signed vs unsigned at its worst will be 1 number off what it should be since 1000 != 0111 which is imperceptible to hear (assuming this is 16bit)
Aqua
Aqua2y ago
yea ive not tried converting from big to little endian and then casting to signed, wonder if that would work don't see why it wouldn't
Lyris the Kitori
yeah thats my thinking, if the endianness is the same it should just sound the same if maybe phase shifted 180 degrees with peaks becoming troughs and vice versa
Aqua
Aqua2y ago
yea id be interested to see the result of that cause yeah typical unsigned-signed conversion on pcm audio just completely rips your eardrums apart lmao
Lyris the Kitori
you are probably getting trolled by endianness there lmao
Aqua
Aqua2y ago
ye
Lyris the Kitori
how the fuck do i read a 24 bit integer from a stream
Aqua
Aqua2y ago
i have no idea i've tried and failed so i just kinda gave up for the moment
Lyris the Kitori
actually wait i know exactly how
Aqua
Aqua2y ago
what you gotta do is strip out the sign bit and convert the result to a 32 bit integer iirc but i failed miserably oh wait nvm
Lyris the Kitori
this would work, right?
No description
Lyris the Kitori
although i may get trolled by endianness
Aqua
Aqua2y ago
reading from a stream should be much easier than trying whatevertheheck i was doing to convert it to listenable audio, soloud should handle that for you
Lyris the Kitori
nah i have to give it float data
Aqua
Aqua2y ago
oh
Lyris the Kitori
from -1 to 1 so i need to convert to that format
Aqua
Aqua2y ago
yeah thats not gonna work cause if you cast it to int, it will lose the signing
Lyris the Kitori
no it wont im using a pointer
Aqua
Aqua2y ago
oh ok
Lyris the Kitori
oh wait but yeah the sign will be in the wrong place
Aqua
Aqua2y ago
yea
Lyris the Kitori
thats a simple fix one sec
Aqua
Aqua2y ago
thats the issue i was having nothing i did fixed it so if you can work it out lemme know lmao
Lyris the Kitori
this should work, right?
Aqua
Aqua2y ago
maybe, only one way to find out
Lyris the Kitori
i need 24bit pcm data first :^) oh audacity has an export for it
TechPizza
TechPizza2y ago
just do bitshifts dammit
Lyris the Kitori
the runtime should be smart enough
TechPizza
TechPizza2y ago
it is absolutely not not to mention that endianness issues will be real bad here *you're also doing a stackalloc in a loop lol 💥
Aqua
Aqua2y ago
is that bad?
Lyris the Kitori
fuck right stack is cleared at function end not scope end
Aqua
Aqua2y ago
a h
TechPizza
TechPizza2y ago
i am pretty sure that stackalloc underline is a warning for the loop
Lyris the Kitori
what is the little endian order of u24 it is a warning for it im just blind
TechPizza
TechPizza2y ago
little endian is little endian
Lyris the Kitori
yes well IM stupid
TechPizza
TechPizza2y ago
first byte comes first, second byte comes second, etc
Lyris the Kitori
oh wait then this should work fine
TechPizza
TechPizza2y ago
no because in big endian your integer will be flipped
Lyris the Kitori
unless the PCM data is BE
TechPizza
TechPizza2y ago
*unless your CPU is BE tldr just
Aqua
Aqua2y ago
pcm data is big endian
TechPizza
TechPizza2y ago
byte b0, b1, b2; uint sample = b0 | (b1 << 8) | (b2 << 16);
Aqua
Aqua2y ago
^^^^^^^^^^^^^
TechPizza
TechPizza2y ago
reality can be whatever i want also
FYI for WAV file format, a RIFF header requires little endian byte order, and a RIFX header requires big endian byte order. See this.
fuck RIFX amirite
Lyris the Kitori
this just causes everything to be XTREME BASS BOOSTED 3 MILLION VIEWS
No description
Aqua
Aqua2y ago
yep, that's cause the sign is missing, so it's just processing unsigned audio
Lyris the Kitori
o rite
Aqua
Aqua2y ago
i did try to extract the sign but uh
No description
Aqua
Aqua2y ago
something no worky
Lyris the Kitori
this still causes the same problem i feel like im missing something obvious
No description
Aqua
Aqua2y ago
yea im not sure, i tried doing that and it didnt work either
TechPizza
TechPizza2y ago
my sign bit in christ have you considered just subtracting
Lyris the Kitori
no i would never subtract thats a crime in america we only need to make things bigger more money more nukes more obesity rates yea subtracting didnt work
TechPizza
TechPizza2y ago
without the bränch
Lyris the Kitori
yea that didnt work either i dont see why it would
No description
TechPizza
TechPizza2y ago
alright i give up maybe divide by 2 to the pow of 24?
Aqua
Aqua2y ago
i tried this but no
No description
Aqua
Aqua2y ago
just static
Lyris the Kitori
static?
Aqua
Aqua2y ago
yep
Lyris the Kitori
im getting the music just bass boosted
TechPizza
TechPizza2y ago
commit the division
Lyris the Kitori
me?
Aqua
Aqua2y ago
yeah if i get rid of the weird shit i did then i get the same bass boosted result
TechPizza
TechPizza2y ago
yes, div by 0xffffff idk
Lyris the Kitori
i think we are all may be the stupid
Lyris the Kitori
this works
No description
Lyris the Kitori
i told copilot "convert the signed 24 bit int to a signed 32bit int" and it did
TechPizza
TechPizza2y ago
do you need that branch?
Aqua
Aqua2y ago
LMAO trying that now
Lyris the Kitori
i dont know lemme remove the if
TechPizza
TechPizza2y ago
🤡
Lyris the Kitori
removing the if returns it to bass boosted state oh wait i should go full AI mode here, im going to ask ChatGPT why the previous solution didnt work, and why the current one does lets see if it can keep up with my incredible stupidity and misunderstanding of math
Aqua
Aqua2y ago
yea i tried all this stuff and it never worked either lmao
TechPizza
TechPizza2y ago
i am really weirded out by that OR with 0xff000000
Lyris the Kitori
same
TechPizza
TechPizza2y ago
i will have to try this myself tomorrow
Lyris the Kitori
"This code reads three bytes (b0, b1, b2) from a data stream and converts them into a 24-bit signed integer sample. The first code block correctly converts the 24-bit signed integer to a 32-bit signed integer by extending the sign bit if the 24th bit is set. This is achieved by using the binary OR operator (|) to set the high-order 8 bits to 1. If the 24th bit is not set, the high-order 8 bits remain 0, and the result is still a valid 32-bit signed integer with the same value as the original 24-bit integer. The second code block, on the other hand, first extends the sign bit by using the binary OR operator to set the high-order 8 bits to 1. Then it subtracts 0x00800000, which would remove the sign bit, but this operation is unnecessary and could cause unintended consequences. Finally, both code blocks divide the resulting integer by 0x00FFFFFF to obtain a floating-point value between -1 and 1, which can be used as a sample in audio processing." -chatgpt i dont understand like it explained the code but it didnt really explain why one worked and why one didnt okay i clarified my question
TechPizza
TechPizza2y ago
the sign bit is 1 bit, and setting 8 bits on a 32bit register wont keep it a 24bit int what kind of bullshit is this
Lyris the Kitori
"The first code snippet works fine because it is converting a 24-bit signed integer to a 32-bit signed integer. First, the three bytes are read from the reader and then combined into a 24-bit integer using the bitwise OR operator (|). Next, if the 24th bit (0x00800000) is set, then the 32-bit signed integer is extended by ORing it with 0xFF000000. This extends the sign to the 32nd bit, making it a signed 32-bit integer. Finally, the 32-bit integer is divided by 0x00FFFFFF, which normalizes the value to the range of -1 to 1, which is the range of a 32-bit float. The second code snippet does not work because it is trying to convert a 24-bit signed integer to a 32-bit signed integer, but it is not correctly extending the sign bit. First, the three bytes are read and combined into a 24-bit integer as in the first code snippet. Then, if the 24th bit is set (indicating a negative number), the code tries to extend the sign by ORing the integer with 0x80000000. However, this is not correct because 0x80000000 is a positive number, not a negative number. The correct value to OR with to extend the sign is 0xFF000000, as in the first code snippet. The code also tries to remove the sign from the 24th bit by subtracting 0x00800000, which is incorrect and will produce a heavily boosted result."
TechPizza
TechPizza2y ago
is it retarded?
Lyris the Kitori
maybe?
TechPizza
TechPizza2y ago
or did i finally lose my brain at uni today
Lyris the Kitori
i dont understand why 0xFF000000 works and why thats the proper way okay i entirely removed the working code snippet and only gave it the broken one
TechPizza
TechPizza2y ago
i have a feeling like you're getting lucky
Lyris the Kitori
"The code above is attempting to convert 24-bit signed PCM data into 32-bit float audio data in the range of -1 to 1. However, the code is incorrect because it is not properly handling the sign extension for negative numbers. In the first part of the code, the bytes are read from the RIFF WAVE file and concatenated into a 24-bit sample using the bitwise OR operator. Then, the code checks if the 24th bit is set, which indicates a negative number. If it is, the code attempts to extend the sign by OR-ing with 0x80000000 and subtracting 0x00800000. The issue with this approach is that the subtraction operation is removing the sign from the 24th bit, which is incorrect. This results in the negative samples being boosted significantly and the positive samples being boosted slightly, leading to a heavily boosted result. To fix this issue, the sign extension should be done by simply OR-ing with 0xff000000 instead of subtracting. Additionally, the code is dividing the final result by 0x00ffffff, which is not the correct maximum value for 24-bit PCM data. The correct maximum value is 0x007fffff, which should be used instead." -ChatGPT
TechPizza
TechPizza2y ago
anyways, does soloud take 0.0-1.0 samples or -1.0-1.0 samples 😹
Lyris the Kitori
-1 -> 1 i believe? thats what has been working this whole time
Aqua
Aqua2y ago
it should be -1 to 1
Lyris the Kitori
yeah -1 -> 1 makes the most sense uses the float better are we stupid? it is HELL BENT on that bitwise OR with 0xFF000000 and it works
TechPizza
TechPizza2y ago
alright it's -1 to 1
Aqua
Aqua2y ago
im trying a different method
TechPizza
TechPizza2y ago
ok i get it it is turning the 32bit integer into ffffffff makes sense i left my brain at uni afterall i can write that sign extension without a branch though hehe
Lyris the Kitori
are ternary operations not branches????
No description
TechPizza
TechPizza2y ago
i see it's biased to C compilers emitting cmov
Aqua
Aqua2y ago
yeah they can be converted to math sometimes i believe depends on the situation
TechPizza
TechPizza2y ago
or that
Lyris the Kitori
okay its spitting out some code thats branchless
Lyris the Kitori
MY EARS YOU BITCH ASS AI
TechPizza
TechPizza2y ago
i love how that sample >> 24 will always be zero very useful
TechPizza
TechPizza2y ago
yeah no
Lyris the Kitori
oh hey that works
TechPizza
TechPizza2y ago
what how
Lyris the Kitori
idk they are ANDing it with ff000000 so it should be 0???
TechPizza
TechPizza2y ago
unless the garbage top bits are getting divided into oblivion AI will replace programmers for sure when
Aqua
Aqua2y ago
for some reason none of this shit works at all for me
TechPizza
TechPizza2y ago
learn to read
Lyris the Kitori
am i just deaf or smthn am i hearing 8 bit audio and just cant tell the difference im not an audiophile it seems to work
TechPizza
TechPizza2y ago
ok after closer inspection, this should work
Lyris the Kitori
wait why
TechPizza
TechPizza2y ago
by shifting by 8 turn it into a real 32bit int
Lyris the Kitori
but then you discard most of the data with the AND i wonder if it will work if i and by 0xffffff00 instead
TechPizza
TechPizza2y ago
oh right, you can fix the discard
Lyris the Kitori
oh hey that works, but i dont hear a difference
TechPizza
TechPizza2y ago
i mean, the top bits of a 24bit int are probably enough to make good audio mask with 0xf0_00_00_00 and enjoy 4bit audio lol
Lyris the Kitori
TRUE
Aqua
Aqua2y ago
mmmmmm
Lyris the Kitori
oh yeah i can hear that now THATs quality 3 bit audio next
TechPizza
TechPizza2y ago
0b1100_0000_0000_0000 my beloved imagine if getting old reduced the amount of bits you can hear
Lyris the Kitori
OH YEAH 3 BIT AUDIO IS THE SHIT
TechPizza
TechPizza2y ago
send it over sir hint: make a soloud backend that outputs a pcm data into a file just dump floats into a file at full blast and import in idk audacity
Lyris the Kitori
heres the main verse and the beginning at 3bits
Lyris the Kitori
i am too lazy to make a file soloud backend ffmpeg -i recordingfromobs.mp4 output.mp3
Aqua
Aqua2y ago
BEAUTIFUL 1 bit audio when?
Lyris the Kitori
loud warning
Aqua
Aqua2y ago
lmao it just sounds like unsigned audio at this point
TechPizza
TechPizza2y ago
surprisingly audible
Lyris the Kitori
yeah its still a sine wine just a very poor one and the change from up to down is what makes the sound so even if its just full tilt or no tilt it still makes audible noise
TechPizza
TechPizza2y ago
deepfry with one simple bit
Lyris the Kitori
thats why only having the single upper byte was indistinguishable
TechPizza
TechPizza2y ago
i love how it crashes VLC
Lyris the Kitori
thats 255 states between on and off lmao what how
TechPizza
TechPizza2y ago
ask android
Lyris the Kitori
that is processed from FFmpeg
TechPizza
TechPizza2y ago
it stops at 10s even tho file is 23s
Lyris the Kitori
oh yeah it just like does that time to stop being side tracked and do 32bit ints
TechPizza
TechPizza2y ago
¯\_(ツ)_/¯ i am going to bed
Lyris the Kitori
good night bam that works
Aqua
Aqua2y ago
yeah 32 bit stuff is easy in comparison lmao
Lyris the Kitori
cool so now i handle u8, s16, s24, s32, f32, f64
Aqua
Aqua2y ago
nice what was your code for converting 24 bit stuff in the end?
Lyris the Kitori
the conversion is branchless
Aqua
Aqua2y ago
nice, gonna try it now nope, still borked af probably thanks to rust being really fucking strict on conversions 🙃
Lyris the Kitori
given the second audio format in WAVE is ADPCM i wonder how common it is
Aqua
Aqua2y ago
adpcm is still quite common i think no idea what its used in anymore but
Lyris the Kitori
hmm so then i probably want to be able to read it oh apparently seeking/looping is harder with ADPCM since you need to decode the full block of data to get any singular sample
Aqua
Aqua2y ago
yeah what you could do is work out which block you need, decode it and work out the sample from there
Lyris the Kitori
yeah
Aqua
Aqua2y ago
adpcm is cheap so it shouldn't be too bad
Aqua
Aqua2y ago
how many adpcm formats are there tf
Lyris the Kitori
like 3 or smthn 4
Aqua
Aqua2y ago
jeez
Lyris the Kitori
this is an incomplete list too
Aqua
Aqua2y ago
mpeg 👀
Lyris the Kitori
i hate SO much that mpeg is there
Aqua
Aqua2y ago
yeah lmao
Lyris the Kitori
use a FUCKING mp3 file PLEASE i will personally stab any people putting MPEG data into WAV files
Aqua
Aqua2y ago
lmfao understandable
Lyris the Kitori
oh dear god theres more to WAV i didnt know about "There are 3 variants of the Format chunk for sampled data" is the scariest thing ever to read
Lyris the Kitori
so i need to check the length of it
Aqua
Aqua2y ago
where are you looking for this? my source is a site that is literally 300 years old
Lyris the Kitori
if the length of the fmt header is longer than the normal size, then i need to read ANOTHER size and thas the size of the extension data the fuck is VALID BITS per sample speaker position mask??? SUB FORMAT? ITS A GUID
Aqua
Aqua2y ago
aaaaaaand this is why most wav players can only support bog standard PCM and ADPCM cause fuck this rabbit hole
Lyris the Kitori
i wouldnt be surprised if the cursed 2 decade old japanese wav files i have to work with are some shitty annoying format that hasnt been seen by humanity since 2005 I SHOULD PROBABLY CHECK ONE MINUTE
Aqua
Aqua2y ago
lmao time to stick it in a hex editor and check
Lyris the Kitori
im just gonna try and load them
Lyris the Kitori
why pack both a wav and ogg file? I DONT KNOW
No description
Lyris the Kitori
IT DOESNT EVEN USE THE WAV FILE THATS SO WASTEFUL
Aqua
Aqua2y ago
ah yes, numbers
Lyris the Kitori
okay so its ONLY a decade old
No description
Lyris the Kitori
oh thank fuck its a normal file 16bit pcm data
Aqua
Aqua2y ago
yeah anything from like year 2000s onwards i would be surprised if it used some weird nonstandard format
Lyris the Kitori
those are beat line bars and beat line beats (direct translation)
Aqua
Aqua2y ago
ahhh ok
Lyris the Kitori
what do you mean ok that means nothing the dev used non-standard terms everywhere
Aqua
Aqua2y ago
i kinda just assumed bars and beats were like the things on a musical score they're not?
Lyris the Kitori
nah
Aqua
Aqua2y ago
a h
Lyris the Kitori
its some random division of the BPM i think its 1/4th or something horrible
Aqua
Aqua2y ago
lmao i see anyways id best be off to sleep also, good night
Lyris the Kitori
good night oh boy the decode thread just spins forever when you reach the end of the song :^) i need to set an EOF flag and actually exit out of the while seeking works OOTB too sick
Lyris the Kitori
GitHub
Wav: Implement full Async WAV player · Beyley/LoudPizza@1b047b0
Supports PCM and Float data of the formats F32, F64, u8, s16, s24, s32, all major PCM and Float formats
Lyris the Kitori
if anyone wants to judge my WAV reader 4hrs 45mins to make a full WAV reader ill take that https://www.aelius.com/njh/wavemetatools/doc/riffmci.pdf oh apparently slnt chunks are part of the main spec not a weird extension okay so to handle slnt i need to know whether i seeked to the position im playing at or whether some other sample was used previously, the best way i think i can handle this is to constantly keep track of the last sample to have been played from a data chunk, and maintain that value for the rest of the slnt chunk but if you seek reset that to 0 thats what the spec suggests
Lyris the Kitori
i also love when the SPECIFICation says the word 'might' i just dug through every reference to wavl on github NO ENCODERS OR DECODERS implement wavl or slnt NONE
TechPizza
TechPizza2y ago
i don't think you need the 0xffffff00 you're shifting in zeros anyway
Lyris the Kitori
ah yeah probably how do i fix the pops when you seek vorbis doesnt have this problem but both wav and mp3 have it is there some interpolation smoothing thing you are supposed to do
TechPizza
TechPizza2y ago
lol what pops vorbis just seeks to a specific sample, no magic
Lyris the Kitori
if i seek to some point in the middle of the song, theres a loud audible pop for some reason it dont happen on vorbis or maybe i was getting lucky idk oh wait no its happening now, ig i was just getting lucky with my seek position with my other ogg
TechPizza
TechPizza2y ago
that is a suspiciously loud pop
Lyris the Kitori
yeah im really not sure whats happening there tbh im assuming its samples going from 0 -> some high value THE PLOT THICKENS it doesnt happen with OpenAL only SDL2
Lyris the Kitori
im doing basically exactly what you did in the VoxelPizza audio test
No description
TechPizza
TechPizza2y ago
ugh idk, log the samples to a file or something i never had any loud pops on windows at least and i seeked a lot
Lyris the Kitori
weird, mayhaps a linux thing then, ill log to a file and see what comes out
Lyris the Kitori
copilot you are the have stupid
No description
TechPizza
TechPizza2y ago
hehe
Lyris the Kitori
(i did try forcing s16 mixing to be used, to see if f32 was maybe the problem (OpenAL uses s16 always right now), but that didnt help) lemme finish writing to a file rq
TechPizza
TechPizza2y ago
copilot ingested too many builder patterns
Lyris the Kitori
true alright its going to be slow as BALLS but thats all i need
TechPizza
TechPizza2y ago
whatafak
Lyris the Kitori
i forgot the newline
TechPizza
TechPizza2y ago
using StreamWriter writer = new("samples.txt"); i beg
Lyris the Kitori
i mean the audio plays at full speed still SOMEHOW i crashed my text editor lmao
TechPizza
TechPizza2y ago
c# good
Lyris the Kitori
full text file incase you want to take a look
Lyris the Kitori
nothing looks out of the ordinary OH i should compare it to what the audio looks like normally with no seeking okay yeah looking at what it looks like NORMALLY this is super out of the ordinary normall the audio goes from like 2.8672945E-05 to numbers like 0.2 over a long period of time i think that jump from 0 -> 0.2 is the cause of the pop
TechPizza
TechPizza2y ago
uuuh going from 0 to 0.0678 is quite a jump yes maybe certain audio backends smooth out harsh transitions? not xlue
Lyris the Kitori
hmm yeah this definitely seems like something SDL related if i tell SDL to use alsa directly the pop is very loud but if i tell it to use pulseaudio the pop is quieter i cant tell whether this is a bug that i should report to SDL (given OpenAL doesnt have the problem) or whether i should try to fix this SoLoud side by fading for like maybe 100 samples from the last sample before seek, to the 100th sample after seek 100 samples is enough to probably not cause a pop, but short enough to not be noticable especially if i just directly interpolate for 100 samples from the last sample pre-seek to the 100th sample after seek
TechPizza
TechPizza2y ago
just multiply the first couple samples you read after seeking with 0.1f 0.2f 0.3f etc
Lyris the Kitori
makes sense er wait that wont work, what if the seek operation happens while audio is playing and it jumps from like 0.2 -> -0.2 ill try a little interpolation see if that helps
TechPizza
TechPizza2y ago
right, so storing e.g. the last samples read into a buffer and lerping between that and currently read data sounds interesting
Lyris the Kitori
yup thats what im working on rn
TechPizza
TechPizza2y ago
er... it would not be last samples, it would be current sample playing
Lyris the Kitori
the pop is basically eliminated with 2000 interpolated samples i think i could interpolate this smarter by basically weighting the real samples by the interpolated value that should remove the quiet little 'static' i hear hmm that doesnt fix the static
Lyris the Kitori
you can see what the 'static' is here its minimal though and a lot better than a pop
Lyris the Kitori
YES i know this code is bad and does silly allocations i am just testing
No description
Lyris the Kitori
oh i think im interpolating the WRONG WAY oops
TechPizza
TechPizza2y ago
you hear static? i'm concerned
Lyris the Kitori
its like <10ms of 'static' i dont think its static but i cant describe it any other way oh god i know why its hitting static im stupid i basically am creating static by accident my interp code assumes that the getaudio is greater than the amount of samples i want to interpolate so its basically interpolating from 0 to a bunch of random positions later in the buffer over and over i know how to solve this but im too tired to tbh its 00:30 i think im heading to bed lmao actually wait i dont know how to solve this how do i interpolate to a value i dont know yet do i just like guess and check? cus 512 samples of interp doesnt seem like enough i think it has to be at least 2k eh ill think more about how to structure this nightmare tomorrow idk maybe you have an idea of how to do this
Kai
Kai2y ago
you don't what you can't interpolerate to a future unknown
Lyris the Kitori
i can if i try really hard
Kai
Kai2y ago
not really and you don't really need to either
Lyris the Kitori
i can interpolate by a small value until the final 512 then i can properly interpolate the rest or smthn
Kai
Kai2y ago
yeah you just interpolerate what you have
Lyris the Kitori
if it's too far thats probably fine
Kai
Kai2y ago
and then the next once you get more
Lyris the Kitori
i just wish all the hard problems could be solved for me by unknown magic forces like how OpenAL works perfectly fine
Kai
Kai2y ago
haha
Lyris the Kitori
it's a rare OpenAL W
Aqua
Aqua2y ago
popping when seeking is just something that happens. if you want to eliminate it, fade the audio out over the span of about 50 samples, and back in over the span of another 20 samples or so this is how openmpt does it and it basically eliminates popping ofc this does assume there's not a period of silence or static in the middle
TechPizza
TechPizza2y ago
yeah, multiplying a negative or positive number by a less-than-one factor should still have the desired outcome and reduces the amount of tracking you have to do
Lyris the Kitori
okay ive janked together a null backend
No description
Lyris the Kitori
since how often i call mix effects playback speed, im using a combination of Thread.Sleep and SpinWait to wait for exactly the right amount of time inb4 theres some simple magic solution in soloud to solve this :^) ooo soloud has so many backends to implement in c# time to get distracted with that jack also expects samples in non-interlaced format it to be specific: each channel is a separate buffer
Lyris the Kitori
(which makes sense given the main purpose of it is to be able to re-route your audio around :^)
No description
Lyris the Kitori
man the INTRUSIVE THOUGHTS to call it the "Jack Black-end"
No description
Lyris the Kitori
bruh the only jack bindings for c# is a stupid wrapper time to run buildtools over the header and make my own after "lunch" the fuck is a .dll.a i sure do love my STATIC DYNAMIC libraries ah buildtools chokes on it for some reason its not handling the opaque structs oh i forgot traverse oops okay Jack bindings created time to actually continue porting
Lyris the Kitori
Solound
No description
Lyris the Kitori
for performance, i added a mix_single_channel function, which basically just copies directly from the internal scratch buffer to the given buffer
Lyris the Kitori
basically removes the whole de-interlaced -> interlaced -> de-interlaced ring-around that SoLoud itself does well its playing at 2x speed but its not actually fucked holy shit i found a fucking RELIC http://linux-audio.com/ okay this didnt work since i was mixing twice, thats why it was 2x speed
Lyris the Kitori
solution was to create a mix_without_copy then a copy_deinterlaced_channel_samples
No description
Lyris the Kitori
and now it seems to 'just work' cool so now Jack, OpenAL, Null, and SDL2 backends work oh im really stupid null backend is meant to not progress play head i just accidentally created the nosound backend the main problem is fading out the stream i dont know enough about how SoLoud is structured to be able to do that ill leave the popping fix for later what platforms/usecases am i missing at this point i have Jack, SDL2, and OpenAL Jack for ultra-low-latency and more music-production based tasks, SDL2 for basically all platforms, and OpenAL for something idk ideally id port the raw Alsa and XAudio2 backends over too so that i dont have to go through SDL for any unix-likes or windows on linux Jack is available in most places that have pipewire, but for pulseaudio systems its likely not available i also need to write some code to auto-detect the best backend to try to use i think right now i would go the path of try Jack -> OpenAL with the buffer_callback extension -> SDL2 -> OpenAL with the thread strategy since OpenAL with buffer_callback is much less to dynamically load than the entirety of SDL2 but OpenAL without the buffer callback extension is less reliable than SDL2 with Alsa and XAudio2, itd be Jack -> Alsa -> XAudio2 -> OpenAL (buffer_callback) -> SDL2 -> OpenAL (raw) jack always first, since Jack is super low latency on linux pipewire it doesnt matter too much, but on windows, Jack is probably the lowest latency option but its only going to be available on 1/100000 of windows systems which is sad
TechPizza
TechPizza2y ago
i'll probably add something like this since i like speeeeed there are ways to have reasonable latency on windows
Kai
Kai2y ago
:( pipewire my beloved
Lyris the Kitori
it's a tiny thing im surprised SoLoud never did tbh all of the soloud backends are really half baked like the soloud jack backend completely breaks if the server uses a weird sample rate (which is fixed in my version :^) pipewire has similar latency no matter if you talk to it directly, or through jack, or through pulse
TechPizza
TechPizza2y ago
i wish this poor soul good luck
No description
TechPizza
TechPizza2y ago
they even made the fork private
Aqua
Aqua2y ago
doesn't unity already have like fmod
TechPizza
TechPizza2y ago
discord weird
Lyris the Kitori
GitHub
GitHub - phoboslab/qoa: The “Quite OK Audio Format” for fast, lossy...
The “Quite OK Audio Format” for fast, lossy audio compression - GitHub - phoboslab/qoa: The “Quite OK Audio Format” for fast, lossy audio compression
Want results from more Discord servers?
Add your server