MemSound has a deficiency :)
#1
Hello,

I just released a new version of SaveSound in my thread. It can also do something that hasn't been here before - save sound in 24 bit Wav format. On that occasion, I discovered that both SndOpen and SndPlay can play the created 24-bit WAV file, but unfortunately, MemSound cannot handle it. This also follows from the help for MemSound, where only 8, 16, 32 bit formats are written about. I recently found out how to create a 24 bit format very easily and I'm assuming you didn't know about this option and that's why it wasn't known.


Reply
#2
(04-24-2023, 06:37 PM)Petr Wrote: Hello,

I just released a new version of SaveSound in my thread. It can also do something that hasn't been here before - save sound in 24 bit Wav format. On that occasion, I discovered that both SndOpen and SndPlay can play the created 24-bit WAV file, but unfortunately, MemSound cannot handle it. This also follows from the help for MemSound, where only 8, 16, 32 bit formats are written about. I recently found out how to create a 24 bit format very easily and I'm assuming you didn't know about this option and that's why it wasn't known.

Well, there is a reason for that. _MEMSOUND uses the ELEMENTSIZE and TYPE members of _MEM to describe the audio data format. Unfortunately, there is nothing for 24-bits as you can see here (under TYPE values): _MEM - QB64 Phoenix Edition Wiki. It's the same reason _SNDNEW - QB64 Phoenix Edition Wiki is limited to 8, 16 and 32.

It is actually super easy to expose 24-bit audio data using _MEMSOUND, but we'll need to come up with a solution on how to expose this correctly. Probably we could just return 11000 or 0x18 in the TYPE member and 3, 6... for the ELEMENTSIZE (depending on the channels).

@DSMan195276, @RhoSigma, @SMcNeill thoughts?
Reply
#3
Maybe "downgrade" to 16-bit or "upscale" to 32-bit?

Could turn into 32-bit internally but then it would be a pain or a hinderance to performance to disregard the extra byte from every packet.
Reply
#4
(04-25-2023, 08:35 AM)a740g Wrote: It is actually super easy to expose 24-bit audio data using _MEMSOUND, but we'll need to come up with a solution on how to expose this correctly. Probably we could just return 11000 or 0x18 in the TYPE member and 3, 6... for the ELEMENTSIZE (depending on the channels).

I like the 11000 (0x18) idea, it follows the regular binary logic building each possible number by combining the respective bits. Hence combining bit 3 (for 8 bit data) and bit 4 (for 16 bit data) to specify 24 bit data is absolutly legitimate from my POV.
Reply
#5
(04-25-2023, 08:35 AM)a740g Wrote: It is actually super easy to expose 24-bit audio data using _MEMSOUND, but we'll need to come up with a solution on how to expose this correctly. Probably we could just return 11000 or 0x18 in the TYPE member and 3, 6... for the ELEMENTSIZE (depending on the channels).

I'm not against the idea, but I could see it breaking some existing code. The catch is that right now the documentation implies that all the .TYPE bitflags for size are exclusive, so you're free to assume that if one of them is set then the other ones are not. That's further backed up by the note on that page basically saying we won't do what you're suggesting:

Quote:If a future integer, float or other type doesn't have a size that is 1,2,4,8,16,32,64,128 or 256 it won't have a size-bit set.

For me, that tells me I could use an
AND
to easily check for the size, such as
.TYPE AND &h08
to check for an 8-byte size (4th bit set), which is a nice way to do it if all the other information is irrelevant to me. The issue is that the check still passes if you introduce a 24-bit type with two bits set in .TYPE, that code would think it's the correct size when it's actually not. This can be fixed by changing the code to
(.TYPE AND &h3F) = &H08
so that it checks all the bit-size bits, but that doesn't help any existing code.

I suppose the other weird aspect is that the .TYPE flags are supposed to indicate a type that actually exists in QB64, or a flag indicating it's a UDT or etc. A 24-bit integer doesn't really fit into that, this doesn't matter much to me but I could see it being a bit confusing. It's only necessary to set it to 24-bits because you have to use it together with .ELEMENTSIZE to differentiate between mono and stereo, so perhaps it'd be simpler to just introduce a new
_SND
command to get the number of channels (I feel like we talked about this before Big Grin I don't remember the outcome though) - then we could leave the .TYPE size bits blank for 24-bit and .ELEMENTSIZE would be used along with the channel count.

In practice I mostly see people just doing a straight
=
comparison with a specific
.TYPE
value, and when you do that it doesn't matter, so that's why I'm not super bothered by it if we do want to just use two bit flags.
Reply
#6
Honestly, I wouldn't want to see it implemented as a double-bit type just for the havoc that it could put on already existing code.  

IF m.TYPE AND 1 THEN 'It's one byte
...
ELSEIF m.TYPE AND 2 THEN 'It's two bytes
...
ELSEIF...  'check the other types

You'll see a lot of code written in the above syntax, and a Type 3 type would fall into both categories, throwing that existing code off.  Instead, I'd rather stick to the documentation that has existed for mem's syntax since the swap from SDL to GL, and honor the "Note: If a future integer, float or other type doesn't have a size that is 1,2,4,8,16,32,64,128 or 256 it won't have a size-bit set."  

I'd give it a TYPE value of 0 for size (undefined by our existing syntax rules), but then mem.ELEMENTSIZE could still easily define it as being 3 bytes in size.   Such a change then shouldn't break anything that exists now, I wouldn't think, and if it did, it would probably be the smallest of changes needed to update the user's code so that the end of their code doesn't end in ELSE .... 'It's a float (or whatever other else logic that have which didn't take in a 0 value return as a possibility for size).
Reply
#7
(04-25-2023, 04:16 PM)SMcNeill Wrote: I'd give it a TYPE value of 0 for size (undefined by our existing syntax rules), but then mem.ELEMENTSIZE could still easily define it as being 3 bytes in size.   Such a change then shouldn't break anything that exists now, I wouldn't think, and if it did, it would probably be the smallest of changes needed to update the user's code so that the end of their code doesn't end in ELSE .... 'It's a float (or whatever other else logic that have which didn't take in a 0 value return as a possibility for size).

Donno if you read my comment Tongue But the underlying issue is that the ELEMENTSIZE is dependent on both the sample size and the number of channels. The 24-bit audio could have an ELEMENTSIZE of 3, 6, 9, 12, etc. depending on the number of channels in the audio, and those numbers can overlap with other possibilities. In this case, 24-bit is weird enough you could probably differentiate it for 1 and 2 channels, but it may not remain that way if more formats are added. A theoretical 4-channel 24-bit audio would have 12 byte elements, which is the same as 3-channel 32-bit audio.
Reply
#8
(04-25-2023, 06:09 PM)DSMan195276 Wrote:
(04-25-2023, 04:16 PM)SMcNeill Wrote: I'd give it a TYPE value of 0 for size (undefined by our existing syntax rules), but then mem.ELEMENTSIZE could still easily define it as being 3 bytes in size.   Such a change then shouldn't break anything that exists now, I wouldn't think, and if it did, it would probably be the smallest of changes needed to update the user's code so that the end of their code doesn't end in ELSE .... 'It's a float (or whatever other else logic that have which didn't take in a 0 value return as a possibility for size).

Donno if you read my comment Tongue But the underlying issue is that the ELEMENTSIZE is dependent on both the sample size and the number of channels. The 24-bit audio could have an ELEMENTSIZE of 3, 6, 9, 12, etc. depending on the number of channels in the audio, and those numbers can overlap with other possibilities. In this case, 24-bit is weird enough you could probably differentiate it for 1 and 2 channels, but it may not remain that way if more formats are added. A theoretical 4-channel 24-bit audio would have 12 byte elements, which is the same as 3-channel 32-bit audio.

Gotcha.

What might be needed is to add a few parameters to the mem type for sound.

m.SoundChannels
m.ChannelSize

Then you could tell if it was 4x12 or 3x16 or even 2x24 which made up the 48 bits.
Reply
#9
Yeah. We cannot do this using ELEMENTSIZE alone. And I too agree that passing 0x18 in TYPE is not a satisfactory solution as those are related to the sizes of QB64 base data type.

I did not really pay attention to the note:
Quote:If a future integer, float or other type doesn't have a size that is 1,2,4,8,16,32,64,128 or 256 it won't have a size-bit set.

But I notice that TYPE is an _OFFSET and the remaining bits above 16 are unused.

So, we can use say bit 17 like:
  • [bit 17] 131072 = 24-bit audio data usually from _MEMSOUND and _SNDNEW

This is kinda like what bit 11 is doing.

The idea of just adding a new _SND command is tempting. We did talk about it before, but I too do not remember the outcome. Big Grin  I think we decided to use the ELEMENTSIZE and TYPE fields then. Not sure.
Reply
#10
(04-25-2023, 06:42 PM)SMcNeill Wrote: What might be needed is to add a few parameters to the mem type for sound.

m.SoundChannels
m.ChannelSize

Then you could tell if it was 4x12 or 3x16 or even 2x24 which made up the 48 bits.

I support this. However the field name should be "generic." What if in the future there's something to do with images? In the distant future support for video... or something like that, but since video also has sound... (facepalm)

So must look for something else that could require a _MEM variable which is not multimedia...

But how many WAV files exist which have more than two channels? Which might have the Surround 5.1 arrangement? Not as many as 24-bit stereo that came with music technology magazines, that's for sure.
Reply




Users browsing this thread: 2 Guest(s)