output/alsa: add option "stop_dsd_silence" to work around DSD DAC noise
This commit is contained in:
parent
ee270f9b00
commit
c8121176b3
2
NEWS
2
NEWS
@ -1,4 +1,6 @@
|
|||||||
ver 0.23.3 (not yet released)
|
ver 0.23.3 (not yet released)
|
||||||
|
* output
|
||||||
|
- alsa: add option "stop_dsd_silence" to work around DSD DAC noise
|
||||||
* macOS: fix libfmt related build failure
|
* macOS: fix libfmt related build failure
|
||||||
|
|
||||||
ver 0.23.2 (2021/10/22)
|
ver 0.23.2 (2021/10/22)
|
||||||
|
@ -836,6 +836,11 @@ The `Advanced Linux Sound Architecture (ALSA) <http://www.alsa-project.org/>`_ p
|
|||||||
- If set to no, then libasound will not attempt to convert between different sample formats (16 bit, 24 bit, floating point, ...).
|
- If set to no, then libasound will not attempt to convert between different sample formats (16 bit, 24 bit, floating point, ...).
|
||||||
* - **dop yes|no**
|
* - **dop yes|no**
|
||||||
- If set to yes, then DSD over PCM according to the `DoP standard <http://dsd-guide.com/dop-open-standard>`_ is enabled. This wraps DSD samples in fake 24 bit PCM, and is understood by some DSD capable products, but may be harmful to other hardware. Therefore, the default is no and you can enable the option at your own risk.
|
- If set to yes, then DSD over PCM according to the `DoP standard <http://dsd-guide.com/dop-open-standard>`_ is enabled. This wraps DSD samples in fake 24 bit PCM, and is understood by some DSD capable products, but may be harmful to other hardware. Therefore, the default is no and you can enable the option at your own risk.
|
||||||
|
* - **stop_dsd_silence yes|no**
|
||||||
|
- If enabled, silence is played before manually stopping playback
|
||||||
|
("stop" or "pause") in DSD mode (native DSD or DoP). This is a
|
||||||
|
workaround for some DACs which emit noise when stopping DSD
|
||||||
|
playback.
|
||||||
* - **allowed_formats F1 F2 ...**
|
* - **allowed_formats F1 F2 ...**
|
||||||
- Specifies a list of allowed audio formats, separated by a space. All items may contain asterisks as a wild card, and may be followed by "=dop" to enable DoP (DSD over PCM) for this particular format. The first matching format is used, and if none matches, MPD chooses the best fallback of this list.
|
- Specifies a list of allowed audio formats, separated by a space. All items may contain asterisks as a wild card, and may be followed by "=dop" to enable DoP (DSD over PCM) for this particular format. The first matching format is used, and if none matches, MPD chooses the best fallback of this list.
|
||||||
|
|
||||||
|
@ -84,6 +84,23 @@ class AlsaOutput final
|
|||||||
* @see http://dsd-guide.com/dop-open-standard
|
* @see http://dsd-guide.com/dop-open-standard
|
||||||
*/
|
*/
|
||||||
bool dop_setting;
|
bool dop_setting;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Are we currently playing DSD? (Native DSD or DoP)
|
||||||
|
*/
|
||||||
|
bool use_dsd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play some silence before closing the output in DSD mode?
|
||||||
|
* This is a workaround for some DACs which emit noise when
|
||||||
|
* stopping DSD playback.
|
||||||
|
*/
|
||||||
|
const bool stop_dsd_silence;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Are we currently draining with #stop_dsd_silence?
|
||||||
|
*/
|
||||||
|
bool in_stop_dsd_silence;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** libasound's buffer_time setting (in microseconds) */
|
/** libasound's buffer_time setting (in microseconds) */
|
||||||
@ -355,6 +372,9 @@ private:
|
|||||||
error = std::current_exception();
|
error = std::current_exception();
|
||||||
active = false;
|
active = false;
|
||||||
waiting = false;
|
waiting = false;
|
||||||
|
#ifdef ENABLE_DSD
|
||||||
|
in_stop_dsd_silence = false;
|
||||||
|
#endif
|
||||||
cond.notify_one();
|
cond.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,6 +431,7 @@ AlsaOutput::AlsaOutput(EventLoop &_loop, const ConfigBlock &block)
|
|||||||
dop_setting(block.GetBlockValue("dop", false) ||
|
dop_setting(block.GetBlockValue("dop", false) ||
|
||||||
/* legacy name from MPD 0.18 and older: */
|
/* legacy name from MPD 0.18 and older: */
|
||||||
block.GetBlockValue("dsd_usb", false)),
|
block.GetBlockValue("dsd_usb", false)),
|
||||||
|
stop_dsd_silence(block.GetBlockValue("stop_dsd_silence", false)),
|
||||||
#endif
|
#endif
|
||||||
buffer_time(block.GetPositiveValue("buffer_time",
|
buffer_time(block.GetPositiveValue("buffer_time",
|
||||||
MPD_ALSA_BUFFER_TIME_US)),
|
MPD_ALSA_BUFFER_TIME_US)),
|
||||||
@ -711,6 +732,9 @@ AlsaOutput::Open(AudioFormat &audio_format)
|
|||||||
snd_pcm_nonblock(pcm, 1);
|
snd_pcm_nonblock(pcm, 1);
|
||||||
|
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
|
use_dsd = audio_format.format == SampleFormat::DSD;
|
||||||
|
in_stop_dsd_silence = false;
|
||||||
|
|
||||||
if (params.dsd_mode == PcmExport::DsdMode::DOP)
|
if (params.dsd_mode == PcmExport::DsdMode::DOP)
|
||||||
LogDebug(alsa_output_domain, "DoP (DSD over PCM) enabled");
|
LogDebug(alsa_output_domain, "DoP (DSD over PCM) enabled");
|
||||||
#endif
|
#endif
|
||||||
@ -844,6 +868,18 @@ AlsaOutput::WriteFromPeriodBuffer() noexcept
|
|||||||
inline bool
|
inline bool
|
||||||
AlsaOutput::DrainInternal()
|
AlsaOutput::DrainInternal()
|
||||||
{
|
{
|
||||||
|
#ifdef ENABLE_DSD
|
||||||
|
if (in_stop_dsd_silence) {
|
||||||
|
/* "stop_dsd_silence" is in progress: clear internal
|
||||||
|
buffers and instead, fill the period buffer with
|
||||||
|
silence */
|
||||||
|
in_stop_dsd_silence = false;
|
||||||
|
ring_buffer->reset();
|
||||||
|
period_buffer.Clear();
|
||||||
|
period_buffer.FillWithSilence(silence, out_frame_size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* drain ring_buffer */
|
/* drain ring_buffer */
|
||||||
CopyRingToPeriodBuffer();
|
CopyRingToPeriodBuffer();
|
||||||
|
|
||||||
@ -974,6 +1010,17 @@ AlsaOutput::Cancel() noexcept
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_DSD
|
||||||
|
if (stop_dsd_silence && use_dsd) {
|
||||||
|
/* play some DSD silence instead of snd_pcm_drop() */
|
||||||
|
std::unique_lock<Mutex> lock(mutex);
|
||||||
|
in_stop_dsd_silence = true;
|
||||||
|
drain = true;
|
||||||
|
cond.wait(lock, [this]{ return !drain || !active; });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
BlockingCall(GetEventLoop(), [this](){
|
BlockingCall(GetEventLoop(), [this](){
|
||||||
CancelInternal();
|
CancelInternal();
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user