More > JRiver Media Center 22 for Windows
Bit-perfect problem found, proposed fix
GreenMan:
Executive summary:
When I converted 24-bit and 16-bit WAV files to 64-bit floating-point in a Python script, MC playback sounds more accurate. I propose MC uses the ldexp() function from the standard C++ library to convert PCM/integer to 64-bit floating-point in a bit-perfect way.
Details:
I found the same problem and confirmed the same fix in both MC v21.0.83 and MC v22.0.13. I run 64-bit Windows 8.1.
For a 24-bit WAV file, I used the Maria 24/192 sample (Windows version) at http://www.soundkeeperrecordings.com/format.htm
For a 16-bit WAV file, I used the Maria 16/44 sample from the same link.
I use a Lynx Hilo external 24-bit DAC for audio playback, which has an analog volume control after the DAC. Therefore, I disable the volume control in MC to minimize distortion. I observe that the Lynx Hilo sounds better with WASAPI exclusive than ASIO in MC and other applications, so I used WASAPI exclusive. The Lynx ASIO driver has a mixer for sharing audio from multiple apps, so this could be why WASAPI exclusive sounds better. Here are the options I used in an attempt to make MC bit-perfect for 24-bit and 16-bit WAV playback:
Tools > Options > Audio:
- Audio Device = Lynx Hilo [WASAPI]
- Audio Device ... Device settings... check "Open device for exclusive access", Bitdepth = 24-bit integer, Buffering = 100 msec
- Settings ... DSP & output format... uncheck all checkboxes at left (no changes made by DSP Studio)
- Settings > Bitstreaming = none
- Track Change > Switch tracks = Gapless
- Track Change > check "Do not play silence (leading and trailing)"
- Track Change > check "Use gapless for sequential album tracks"
- Track Change > check "Use gapless for manual track changes"
- Stop, Seek & Skip > Seek = Gapless
- Stop, Seek & Skip > Stop = Immediate
- Stop, Seek & Skip > Pause = Immediate
- Volume > Volume mode = Disabled Volume
- Advanced > Dither Mode (not zone-specific) = No Dithering
- Advanced > Live playback latency = 50 msec (recommended)
As a side note, disabling dithering in MC turned out to be important to get the best sound quality.
Here is a Python script named wav_to_64b.py that I used to convert the 24-bit and 16-bit WAV files to 64-bit floating-point:
--- Code: ---# -*- coding: utf-8 -*-
"""WAV file reformat to 64b
Supports mono and stereo.
Usage:
Install NumPy and SciPy packages in Python. See www.scipy.org/install.html
Download wavio.py from https://gist.github.com/WarrenWeckesser/7461781
Put wavio.py in the same folder as this script.
In a Python console:
>>> os.chdir(r'path of folder containing this script')
>>> from wav_to_64b import wav_reformat
>>> in_file = r'D:\Music\input file.wav'
>>> out_file = r'D:\Music\output file.wav'
>>> wav_reformat(in_file, out_file)
"""
import numpy
import scipy.io.wavfile
import wavio
def wav_reformat(in_file, out_file):
# wavio supports only PCM/integer WAV files, with 8, 16, 24 or 32 bits.
# in_array has one column per channel.
sample_rate, bytes_per_mono_sample, in_array = wavio.readwav(in_file)
# Convert integer to float64 dtype
out_array = numpy.float64(in_array)
# Scale to fractional format.
if bytes_per_mono_sample == 2:
out_array = numpy.ldexp(out_array, -15)
elif bytes_per_mono_sample == 3:
out_array = numpy.ldexp(out_array, -23)
elif bytes_per_mono_sample == 4:
out_array = numpy.ldexp(out_array, -31)
else:
raise ValueError('8-bit WAV files are not supported.')
# Write to floating-point WAV file
scipy.io.wavfile.write(out_file, sample_rate, out_array)
--- End code ---
My listening tests showed that the 64-bit floating-point versions:
- Had deeper bass
- Had better clarity
- Had better 3D imaging
- Had more impact
- Were more emotionally involving and fun to listen to
If MC was bit-perfect, the original 24-bit and 16-bit WAV files would sound identical or better.
To summarize, all I did in Python was recast the PCM/integer values to floating-point (double type in C++) and use NumPy's ldexp() function to scale the data to the standard [-1, 1] fractional range for floating-point audio. The same improvement in sound quality and realization of bit-perfect playback is achievable in MC by using the ldexp() standard library function in C++:
http://en.cppreference.com/w/cpp/numeric/math/ldexp
Enjoy!
Hendrik:
MCs audio processing is bit-perfect as it is today, and this is exactly the math it uses as well, just in a more optimized form, but with the same accuracy.
GreenMan:
I documented my test conditions so JRiver and other users could replicate. I invite all to try my test.
Is it possible that MC was tested to be bit-perfect with 24-bit WAV file input and 24-bit WASAPI exclusive output at one point in time, and that a bug has crept in since then? How do you capture 24-bit WASAPI exclusive output to a file for an objective comparison with the 24-bit WAV file input?
GreenMan:
A lot of developers copy code from the open-source libsndfile project, which uses 32767 as a scaler for 16-bit PCM and 8388607 as a scaler for 24-bit PCM conversion. See http://www.mega-nerd.com/libsndfile/FAQ.html#Q010
Note that the developer admits that bit-perfect conversion is not achieved.
Since the convention used by WAV files and the ADC/DAC industry is to interpret the binary data as two's complement, 32768 (2**15) and 8388608 (2**23) are the correct scalers to use for PCM-to-floating-point conversion for 16-bit and 24-bit, respectively. This applies in both directions of conversion!
The ldexp() function is ideal because it only modifies the exponent, not the mantissa. This guarantees bit-perfect.
Hendrik:
Like I said, this is the exact math MC uses.
The Disk Writer output plugin can write audio data straight from the audio engine into a file (at the same point it would usually be handed of to WASAPI etc). The bitdepth it writes in is not configurable however, but it should match the input file in most cases, as far as I can tell.
A quick test I ran on a single 24-bit file confirmed that both the input 24-bit file (a FLAC in this case) and the output WAV written by Disk Writer contain perfectly identical audio.
Please note that for this test its advised to disable "Do not play silence (leading and trailing)", otherwise a bit of audio can be cut off, screwing with the result when comparing entire files.
Please note that listening tests, especially without double-blind conditions, are usually tainted by expectation bias, and as such any results from those shall be taken with a grain of salt.
Navigation
[0] Message Index
[#] Next page
Go to full version