0x55 0x53 0x20 0x24
sox --encoding unsigned-integer --bits 8 --endian big --channels 1 --rate 22050 test.raw --encoding unsigned-integer --bits 16 --endian big --channels 1 --rate 22050 test16.raw
0x5500 0x5300 0x2000 0x2400
But it is wrong. You're using the wrong formula.
Look. For example, we have a sample 0xFF:
0xFF=255
255/256=0.99609375
0.99609375*65536=65280
65280=0xFF00
Initial value had maximum possible amplitude, but after conversion we have a bit lower volume of the sound.
The right calculations are:
0xFF=255
255/255=1.0
1.0*65535=65535
65535=0xFFFF
It will work for every value. Generally, we have to do x << 8 + x for conversion from 8 to 16 bit. Why 255 and 65535 instead of 256 and 65536? Just imagine a line between 0 and 255 (maximum possible value for 8 bit integer). You will have 256 dots on this line (number of possible values), but only 255 of them will have a segment on this line.
For example:
0_1_2_3_4_5
There are 6 numbers, but only five segments (underscores).
The existing method is reversible using the normal narrowing conversion. This is more important than utilising the entire 16-bit range.
But the proposed method is also reversible by using usual narrowing conversion. And it produces much more logical result. Imagine conversion to FLOAT32. When you convert uint8 255 to float, you get 1.0. When you convert uint16 65535 to float, you get 1.0. But when you convert uint8 255 to uint16 uisng your method, and then convert it to float, you will get wrong value. It is unexpected.
Last edit: Evgeny Vrublevsky 2020-08-03
Converting back after using your method gives different results for negative values.
There is no loss of information, so I don't see what the problem is.
But there is loss of information. uint8 -> float and uint8 -> uint16 -> float will give you different results, but it shouldn't. The maximum amplitude will be a bit smaller.
Actually, I created this ticket exactly because I proposed to my friend to use SoX to convert stream of 8-bit samples to 16-bit, and then he complained me that it affected the sound somehow. It was confusing, but later we understood what was the reason. Conversion from 8-bit to 16-bit shouldn't cause any difference to the signal. Now, when you convert uint8 to uint16, and when you play the original file, and the new file, you will have a bit different results.
The same thing can be implemented for signed samples also. The simplest approach is to make int8 -> uint8 -> uint16 -> int16 implicitly, if you want to use the
(x << 8) + xformula. Conversion from signed to unsigned and back is lossless.Last edit: Evgeny Vrublevsky 2020-08-03
The process is reversible, so there can be no loss of information.
You're losing about 0.03 dB of volume (256 / 257). Nobody can hear that.
There is loss of information. Yeah, if you convert uint8 -> uint16 -> uint8 using current buggy method, you will get the same result. But it will happen just because conversion from uint16 to uint8 is lossy, and the new precision is not enough to represent the difference which was caused by current buggy conversion from uint8 to uint16.
float32 has enough precision to represent the difference. When you use current method, uint8 -> uint16 -> float32 will have measurable difference from uint8 -> float32.
When I reported it, I considered it as a bug which is not so hard to fix. It would make the tool a bit better than it is. Don't know why you object against this improvement so much. I do agree, that the difference is small, but it is there. It is always better to be more precise and less lax if there are no other drawbacks.
Last edit: Evgeny Vrublevsky 2020-08-03
You consider it a bug. I don't. You say it's easy to "fix." It isn't. I am the maintainer. You are not. End of story.
As far as I can see in the code, you just need to fix a few macros:
It seems quite easy to fix, I don't see any issues with it. The fact that the
sox_sample_tis signed is not an issue at all, it requires just an additional bit operation and that's it. If I make a patch, will you accept it?Last edit: Evgeny Vrublevsky 2020-08-04
I am interested in this as I've had a suspicion that it's rounding towards zero instead of in the same direction. https://codeberg.org/sox_ng/sox_ng/issues/564