pcm/PcmConvert: move code to new class PcmChannelsConverter
This commit is contained in:
		@@ -338,6 +338,7 @@ libpcm_a_SOURCES = \
 | 
			
		||||
	src/pcm/PcmPack.cxx src/pcm/PcmPack.hxx \
 | 
			
		||||
	src/pcm/PcmFormat.cxx src/pcm/PcmFormat.hxx \
 | 
			
		||||
	src/pcm/FormatConverter.cxx src/pcm/FormatConverter.hxx \
 | 
			
		||||
	src/pcm/ChannelsConverter.cxx src/pcm/ChannelsConverter.hxx \
 | 
			
		||||
	src/pcm/PcmResample.cxx src/pcm/PcmResample.hxx \
 | 
			
		||||
	src/pcm/PcmResampleFallback.cxx \
 | 
			
		||||
	src/pcm/PcmResampleInternal.hxx \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										115
									
								
								src/pcm/ChannelsConverter.cxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								src/pcm/ChannelsConverter.cxx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,115 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2003-2013 The Music Player Daemon Project
 | 
			
		||||
 * http://www.musicpd.org
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License along
 | 
			
		||||
 * with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "ChannelsConverter.hxx"
 | 
			
		||||
#include "PcmChannels.hxx"
 | 
			
		||||
#include "PcmConvert.hxx"
 | 
			
		||||
#include "util/ConstBuffer.hxx"
 | 
			
		||||
#include "util/Error.hxx"
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
PcmChannelsConverter::Open(SampleFormat _format,
 | 
			
		||||
			   unsigned _src_channels, unsigned _dest_channels,
 | 
			
		||||
			   gcc_unused Error &error)
 | 
			
		||||
{
 | 
			
		||||
	assert(_format != SampleFormat::UNDEFINED);
 | 
			
		||||
 | 
			
		||||
	switch (_format) {
 | 
			
		||||
	case SampleFormat::S16:
 | 
			
		||||
	case SampleFormat::S24_P32:
 | 
			
		||||
	case SampleFormat::S32:
 | 
			
		||||
	case SampleFormat::FLOAT:
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		error.Format(pcm_convert_domain,
 | 
			
		||||
			     "PCM channel conversion for %s is not implemented",
 | 
			
		||||
			     sample_format_to_string(format));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	format = _format;
 | 
			
		||||
	src_channels = _src_channels;
 | 
			
		||||
	dest_channels = _dest_channels;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
PcmChannelsConverter::Close()
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
	format = SampleFormat::UNDEFINED;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConstBuffer<void>
 | 
			
		||||
PcmChannelsConverter::Convert(ConstBuffer<void> src, Error &error)
 | 
			
		||||
{
 | 
			
		||||
	const void *result = nullptr;
 | 
			
		||||
	size_t result_size = 0;
 | 
			
		||||
 | 
			
		||||
	switch (format) {
 | 
			
		||||
	case SampleFormat::UNDEFINED:
 | 
			
		||||
	case SampleFormat::S8:
 | 
			
		||||
	case SampleFormat::DSD:
 | 
			
		||||
		assert(false);
 | 
			
		||||
		gcc_unreachable();
 | 
			
		||||
 | 
			
		||||
	case SampleFormat::S16:
 | 
			
		||||
		result = pcm_convert_channels_16(buffer, dest_channels,
 | 
			
		||||
						 src_channels,
 | 
			
		||||
						 (const int16_t *)src.data,
 | 
			
		||||
						 src.size, &result_size);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case SampleFormat::S24_P32:
 | 
			
		||||
		result = pcm_convert_channels_24(buffer, dest_channels,
 | 
			
		||||
						 src_channels,
 | 
			
		||||
						 (const int32_t *)src.data,
 | 
			
		||||
						 src.size, &result_size);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case SampleFormat::S32:
 | 
			
		||||
		result = pcm_convert_channels_32(buffer, dest_channels,
 | 
			
		||||
						 src_channels,
 | 
			
		||||
						 (const int32_t *)src.data,
 | 
			
		||||
						 src.size, &result_size);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case SampleFormat::FLOAT:
 | 
			
		||||
		result = pcm_convert_channels_float(buffer, dest_channels,
 | 
			
		||||
						    src_channels,
 | 
			
		||||
						    (const float *)src.data,
 | 
			
		||||
						    src.size, &result_size);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (result == nullptr) {
 | 
			
		||||
		error.Format(pcm_convert_domain,
 | 
			
		||||
			     "Conversion from %u to %u channels "
 | 
			
		||||
			     "is not implemented",
 | 
			
		||||
			     src_channels, dest_channels);
 | 
			
		||||
		return nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return { result, result_size };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								src/pcm/ChannelsConverter.hxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/pcm/ChannelsConverter.hxx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2003-2013 The Music Player Daemon Project
 | 
			
		||||
 * http://www.musicpd.org
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License along
 | 
			
		||||
 * with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef MPD_PCM_CHANNELS_CONVERTER_HXX
 | 
			
		||||
#define MPD_PCM_CHANNELS_CONVERTER_HXX
 | 
			
		||||
 | 
			
		||||
#include "check.h"
 | 
			
		||||
#include "AudioFormat.hxx"
 | 
			
		||||
#include "PcmBuffer.hxx"
 | 
			
		||||
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
class Error;
 | 
			
		||||
template<typename T> struct ConstBuffer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A class that converts samples from one format to another.
 | 
			
		||||
 */
 | 
			
		||||
class PcmChannelsConverter {
 | 
			
		||||
	SampleFormat format;
 | 
			
		||||
	unsigned src_channels, dest_channels;
 | 
			
		||||
 | 
			
		||||
	PcmBuffer buffer;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
	PcmChannelsConverter()
 | 
			
		||||
		:format(SampleFormat::UNDEFINED) {}
 | 
			
		||||
 | 
			
		||||
	~PcmChannelsConverter() {
 | 
			
		||||
		assert(format == SampleFormat::UNDEFINED);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Opens the object, prepare for Convert().
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param format the sample format
 | 
			
		||||
	 * @param src_channels the number of source channels
 | 
			
		||||
	 * @param dest_channels the number of destination channels
 | 
			
		||||
	 * @param error location to store the error
 | 
			
		||||
	 * @return true on success
 | 
			
		||||
	 */
 | 
			
		||||
	bool Open(SampleFormat format,
 | 
			
		||||
		  unsigned src_channels, unsigned dest_channels,
 | 
			
		||||
		  Error &error);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Closes the object.  After that, you may call Open() again.
 | 
			
		||||
	 */
 | 
			
		||||
	void Close();
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Convert a block of PCM data.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param src the input buffer
 | 
			
		||||
	 * @param error location to store the error
 | 
			
		||||
	 * @return the destination buffer on success,
 | 
			
		||||
	 * ConstBuffer::Null() on error
 | 
			
		||||
	 */
 | 
			
		||||
	gcc_pure
 | 
			
		||||
	ConstBuffer<void> Convert(ConstBuffer<void> src, Error &error);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -19,7 +19,6 @@
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "PcmConvert.hxx"
 | 
			
		||||
#include "PcmChannels.hxx"
 | 
			
		||||
#include "AudioFormat.hxx"
 | 
			
		||||
#include "util/ConstBuffer.hxx"
 | 
			
		||||
#include "util/Error.hxx"
 | 
			
		||||
@@ -72,12 +71,22 @@ PcmConvert::Open(AudioFormat _src_format, AudioFormat _dest_format,
 | 
			
		||||
		return false;
 | 
			
		||||
	format.format = dest_format.format;
 | 
			
		||||
 | 
			
		||||
	if (format.channels != dest_format.channels &&
 | 
			
		||||
	    !channels_converter.Open(format.format, format.channels,
 | 
			
		||||
				     dest_format.channels, error)) {
 | 
			
		||||
		format_converter.Close();
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
PcmConvert::Close()
 | 
			
		||||
{
 | 
			
		||||
	if (src_format.channels != dest_format.channels)
 | 
			
		||||
		channels_converter.Close();
 | 
			
		||||
 | 
			
		||||
	if (src_format.format != dest_format.format)
 | 
			
		||||
		format_converter.Close();
 | 
			
		||||
 | 
			
		||||
@@ -96,25 +105,11 @@ PcmConvert::Convert16(ConstBuffer<int16_t> src, AudioFormat format,
 | 
			
		||||
{
 | 
			
		||||
	assert(format.format == SampleFormat::S16);
 | 
			
		||||
	assert(dest_format.format == SampleFormat::S16);
 | 
			
		||||
	assert(format.channels == dest_format.channels);
 | 
			
		||||
 | 
			
		||||
	auto buf = src.data;
 | 
			
		||||
	size_t len = src.size * sizeof(*src.data);
 | 
			
		||||
 | 
			
		||||
	if (format.channels != dest_format.channels) {
 | 
			
		||||
		buf = pcm_convert_channels_16(channels_buffer,
 | 
			
		||||
					      dest_format.channels,
 | 
			
		||||
					      format.channels,
 | 
			
		||||
					      buf, len, &len);
 | 
			
		||||
		if (buf == nullptr) {
 | 
			
		||||
			error.Format(pcm_convert_domain,
 | 
			
		||||
				     "Conversion from %u to %u channels "
 | 
			
		||||
				     "is not implemented",
 | 
			
		||||
				     format.channels,
 | 
			
		||||
				     dest_format.channels);
 | 
			
		||||
			return nullptr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (format.sample_rate != dest_format.sample_rate) {
 | 
			
		||||
		buf = resampler.Resample16(dest_format.channels,
 | 
			
		||||
					   format.sample_rate, buf, len,
 | 
			
		||||
@@ -133,25 +128,11 @@ PcmConvert::Convert24(ConstBuffer<int32_t> src, AudioFormat format,
 | 
			
		||||
{
 | 
			
		||||
	assert(format.format == SampleFormat::S24_P32);
 | 
			
		||||
	assert(dest_format.format == SampleFormat::S24_P32);
 | 
			
		||||
	assert(format.channels == dest_format.channels);
 | 
			
		||||
 | 
			
		||||
	auto buf = src.data;
 | 
			
		||||
	size_t len = src.size * sizeof(*src.data);
 | 
			
		||||
 | 
			
		||||
	if (format.channels != dest_format.channels) {
 | 
			
		||||
		buf = pcm_convert_channels_24(channels_buffer,
 | 
			
		||||
					      dest_format.channels,
 | 
			
		||||
					      format.channels,
 | 
			
		||||
					      buf, len, &len);
 | 
			
		||||
		if (buf == nullptr) {
 | 
			
		||||
			error.Format(pcm_convert_domain,
 | 
			
		||||
				     "Conversion from %u to %u channels "
 | 
			
		||||
				     "is not implemented",
 | 
			
		||||
				     format.channels,
 | 
			
		||||
				     dest_format.channels);
 | 
			
		||||
			return nullptr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (format.sample_rate != dest_format.sample_rate) {
 | 
			
		||||
		buf = resampler.Resample24(dest_format.channels,
 | 
			
		||||
					   format.sample_rate, buf, len,
 | 
			
		||||
@@ -170,25 +151,11 @@ PcmConvert::Convert32(ConstBuffer<int32_t> src, AudioFormat format,
 | 
			
		||||
{
 | 
			
		||||
	assert(format.format == SampleFormat::S32);
 | 
			
		||||
	assert(dest_format.format == SampleFormat::S32);
 | 
			
		||||
	assert(format.channels == dest_format.channels);
 | 
			
		||||
 | 
			
		||||
	auto buf = src.data;
 | 
			
		||||
	size_t len = src.size * sizeof(*src.data);
 | 
			
		||||
 | 
			
		||||
	if (format.channels != dest_format.channels) {
 | 
			
		||||
		buf = pcm_convert_channels_32(channels_buffer,
 | 
			
		||||
					      dest_format.channels,
 | 
			
		||||
					      format.channels,
 | 
			
		||||
					      buf, len, &len);
 | 
			
		||||
		if (buf == nullptr) {
 | 
			
		||||
			error.Format(pcm_convert_domain,
 | 
			
		||||
				     "Conversion from %u to %u channels "
 | 
			
		||||
				     "is not implemented",
 | 
			
		||||
				     format.channels,
 | 
			
		||||
				     dest_format.channels);
 | 
			
		||||
			return nullptr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (format.sample_rate != dest_format.sample_rate) {
 | 
			
		||||
		buf = resampler.Resample32(dest_format.channels,
 | 
			
		||||
					   format.sample_rate, buf, len,
 | 
			
		||||
@@ -207,27 +174,11 @@ PcmConvert::ConvertFloat(ConstBuffer<float> src, AudioFormat format,
 | 
			
		||||
{
 | 
			
		||||
	assert(format.format == SampleFormat::FLOAT);
 | 
			
		||||
	assert(dest_format.format == SampleFormat::FLOAT);
 | 
			
		||||
	assert(format.channels == dest_format.channels);
 | 
			
		||||
 | 
			
		||||
	auto buffer = src.data;
 | 
			
		||||
	size_t size = src.size * sizeof(*src.data);
 | 
			
		||||
 | 
			
		||||
	/* convert channels */
 | 
			
		||||
 | 
			
		||||
	if (format.channels != dest_format.channels) {
 | 
			
		||||
		buffer = pcm_convert_channels_float(channels_buffer,
 | 
			
		||||
						    dest_format.channels,
 | 
			
		||||
						    format.channels,
 | 
			
		||||
						    buffer, size, &size);
 | 
			
		||||
		if (buffer == nullptr) {
 | 
			
		||||
			error.Format(pcm_convert_domain,
 | 
			
		||||
				     "Conversion from %u to %u channels "
 | 
			
		||||
				     "is not implemented",
 | 
			
		||||
				     format.channels,
 | 
			
		||||
				     dest_format.channels);
 | 
			
		||||
			return nullptr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* resample with float, because this is the best format for
 | 
			
		||||
	   libsamplerate */
 | 
			
		||||
 | 
			
		||||
@@ -274,6 +225,14 @@ PcmConvert::Convert(const void *src, size_t src_size,
 | 
			
		||||
		format.format = dest_format.format;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (format.channels != dest_format.channels) {
 | 
			
		||||
		buffer = channels_converter.Convert(buffer, error);
 | 
			
		||||
		if (buffer.IsNull())
 | 
			
		||||
			return nullptr;
 | 
			
		||||
 | 
			
		||||
		format.channels = dest_format.channels;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (dest_format.format) {
 | 
			
		||||
	case SampleFormat::S16:
 | 
			
		||||
		buffer = Convert16(ConstBuffer<int16_t>::FromVoid(buffer),
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include "PcmResample.hxx"
 | 
			
		||||
#include "PcmBuffer.hxx"
 | 
			
		||||
#include "FormatConverter.hxx"
 | 
			
		||||
#include "ChannelsConverter.hxx"
 | 
			
		||||
#include "AudioFormat.hxx"
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
@@ -43,9 +44,7 @@ class PcmConvert {
 | 
			
		||||
	PcmResampler resampler;
 | 
			
		||||
 | 
			
		||||
	PcmFormatConverter format_converter;
 | 
			
		||||
 | 
			
		||||
	/** the buffer for converting the channel count */
 | 
			
		||||
	PcmBuffer channels_buffer;
 | 
			
		||||
	PcmChannelsConverter channels_converter;
 | 
			
		||||
 | 
			
		||||
	AudioFormat src_format, dest_format;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user