Filter löschen
Filter löschen

why does audiowrite cast int16 different than the cast function?

3 Ansichten (letzte 30 Tage)
Hello all,
If we use the function audiowrite with a double as an input the audio array is cast to int16 and written in the .wav file.
If we use the cast function to convert the audio array to int16 the resulting array is not the same as the array imported using the audioread function.
An example to illustrate this:
>> y = [-1:0.2:1]
y =
-1.0000 -0.8000 -0.6000 -0.4000 -0.2000 0 0.2000 0.4000 0.6000 0.8000 1.0000
>> cast(y * 2^15, 'int16')
ans =
1×11 int16 row vector
-32768 -26214 -19661 -13107 -6554 0 6554 13107 19661 26214 32767
>> audiowrite('y.wav',y,44100)
>> y_test = audioread('y.wav','native')
y_test =
1×11 int16 row vector
-32768 -26215 -19661 -13108 -6554 0 6553 13107 19660 26214 32767
Notice how the second, fourth, seventh and ninth values are different by one.
What is interesting is that if we cast the array before we write it, the problem goes away. e.g. :
>> audiowrite('y_int16.wav',cast(y * 2^15,'int16'),44100)
>> y_int16_test = audioread('y_int16.wav','native')
y_int16_test =
1×11 int16 row vector
-32768 -26214 -19661 -13107 -6554 0 6554 13107 19661 26214 32767
Notice how the values are no longer different.
It would appear that the casting operation internal to the audiowrite function is different than the cast function. What is causing this difference when we audiowrite a double array? Is it a different rounding/truncation operation?
Thank you in advance,
A.

Akzeptierte Antwort

Guillaume
Guillaume am 29 Nov. 2018
Bearbeitet: Guillaume am 29 Nov. 2018
If you follow the code of audiowrite, the floating point array is never converted and is passed as is to asyncioimpl.OutputStream.write. That latter method, you can't see the code so it must be compiled code, not m-file, probably as part of audiofilesndfilewriterplugin.dll. Most likely, it's C code or similar and follow C rules for conversions from float to integer. The C rule truncates floating point values (rounds towards 0).
Your cast on the other hand uses matlab float to integer rules which is rule to nearest. Hence the discrepancy.
You can emulate the C rules if you wish (for audio, matlab rules are probably better) using fix.
audiowrite('y.wav', int16(fix(y * 2^15)), 44100) %has the same conversion rule as
audiowrite('y.wave', y, 44100)
Bottom line, matlab and C (and many other languages) don't follow the same rules when dealing with integer types. There's similar unexpected behaviour (for a C programmer) when dealing with integer division (matlab rounds by default, C truncates).
Note that you don't need to use cast to do the conversion to integer.
yint = int16(y); %simpler than cast(y, 'int16')
  2 Kommentare
Andreas Prokopiou
Andreas Prokopiou am 29 Nov. 2018
Bearbeitet: Andreas Prokopiou am 29 Nov. 2018
Thank you for your reply!
I did follow the function in order to find the casting call and saw that it goes into asyncio and so I assumed this is getting more involved than I can crack just by following the m file.
Your suggestion does indeed truncate towards zero, however it does not give the same conversion as the audiowrite function. e.g. :
>> int16(fix(y * 2^15))
ans =
1×11 int16 row vector
-32768 -26214 -19660 -13107 -6553 0 6553 13107 19660 26214 32767
versus
>> audioread('y.wav','native')'
ans =
1×11 int16 row vector
-32768 -26215 -19661 -13108 -6554 0 6553 13107 19660 26214 32767
It would actually seem that its the floor function used instead of the fix function:
>> int16(floor(y * 2^15))
ans =
1×11 int16 row vector
-32768 -26215 -19661 -13108 -6554 0 6553 13107 19660 26214 32767
Guillaume
Guillaume am 29 Nov. 2018
Bearbeitet: Guillaume am 29 Nov. 2018
Then it looks like audiowrite rounds towards -Inf. In which case:
>>int16(floor(y * 2^15))
ans =
1×11 int16 row vector
-32768 -26215 -19661 -13108 -6554 0 6553 13107 19660 26214 32767
or maybe it has a different way of scaling -1:1 to the int16 range. It's a bit unusual to round towards -Inf when converting from float to int.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (0)

Kategorien

Mehr zu MATLAB finden Sie in Help Center und File Exchange

Produkte


Version

R2018b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by