pcm/PcmConvert: move code to new class PcmFormatConverter
This commit is contained in:
		| @@ -337,6 +337,7 @@ libpcm_a_SOURCES = \ | ||||
| 	src/pcm/PcmChannels.cxx src/pcm/PcmChannels.hxx \ | ||||
| 	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/PcmResample.cxx src/pcm/PcmResample.hxx \ | ||||
| 	src/pcm/PcmResampleFallback.cxx \ | ||||
| 	src/pcm/PcmResampleInternal.hxx \ | ||||
|   | ||||
							
								
								
									
										104
									
								
								src/pcm/FormatConverter.cxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/pcm/FormatConverter.cxx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| /* | ||||
|  * 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 "FormatConverter.hxx" | ||||
| #include "PcmFormat.hxx" | ||||
| #include "PcmConvert.hxx" | ||||
| #include "util/ConstBuffer.hxx" | ||||
| #include "util/Error.hxx" | ||||
|  | ||||
| #include <assert.h> | ||||
|  | ||||
| bool | ||||
| PcmFormatConverter::Open(SampleFormat _src_format, SampleFormat _dest_format, | ||||
| 			 gcc_unused Error &error) | ||||
| { | ||||
| 	assert(_src_format != SampleFormat::UNDEFINED); | ||||
| 	assert(_dest_format != SampleFormat::UNDEFINED); | ||||
|  | ||||
| 	src_format = _src_format; | ||||
| 	dest_format = _dest_format; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void | ||||
| PcmFormatConverter::Close() | ||||
| { | ||||
| #ifndef NDEBUG | ||||
| 	src_format = SampleFormat::UNDEFINED; | ||||
| 	dest_format = SampleFormat::UNDEFINED; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| ConstBuffer<void> | ||||
| PcmFormatConverter::Convert(ConstBuffer<void> src, Error &error) | ||||
| { | ||||
| 	const void *result = nullptr; | ||||
| 	size_t result_size = 0; | ||||
|  | ||||
| 	switch (dest_format) { | ||||
| 	case SampleFormat::UNDEFINED: | ||||
| 		assert(false); | ||||
| 		gcc_unreachable(); | ||||
|  | ||||
| 	case SampleFormat::S8: | ||||
| 	case SampleFormat::DSD: | ||||
| 		result = nullptr; | ||||
| 		break; | ||||
|  | ||||
| 	case SampleFormat::S16: | ||||
| 		result = pcm_convert_to_16(buffer, dither, | ||||
| 					   src_format, | ||||
| 					   src.data, src.size, | ||||
| 					   &result_size); | ||||
| 		break; | ||||
|  | ||||
| 	case SampleFormat::S24_P32: | ||||
| 		result = pcm_convert_to_24(buffer, | ||||
| 					   src_format, | ||||
| 					   src.data, src.size, | ||||
| 					   &result_size); | ||||
| 		break; | ||||
|  | ||||
| 	case SampleFormat::S32: | ||||
| 		result = pcm_convert_to_32(buffer, | ||||
| 					   src_format, | ||||
| 					   src.data, src.size, | ||||
| 					   &result_size); | ||||
| 		break; | ||||
|  | ||||
| 	case SampleFormat::FLOAT: | ||||
| 		result = pcm_convert_to_float(buffer, | ||||
| 					      src_format, | ||||
| 					      src.data, src.size, | ||||
| 					      &result_size); | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	if (result == nullptr) { | ||||
| 		error.Format(pcm_convert_domain, | ||||
| 			     "PCM conversion from %s to %s is not implemented", | ||||
| 			     sample_format_to_string(src_format), | ||||
| 			     sample_format_to_string(dest_format)); | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	return { result, result_size }; | ||||
| } | ||||
							
								
								
									
										84
									
								
								src/pcm/FormatConverter.hxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/pcm/FormatConverter.hxx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| /* | ||||
|  * 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_FORMAT_CONVERTER_HXX | ||||
| #define MPD_PCM_FORMAT_CONVERTER_HXX | ||||
|  | ||||
| #include "check.h" | ||||
| #include "AudioFormat.hxx" | ||||
| #include "PcmBuffer.hxx" | ||||
| #include "PcmDither.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 PcmFormatConverter { | ||||
| 	SampleFormat src_format, dest_format; | ||||
|  | ||||
| 	PcmBuffer buffer; | ||||
| 	PcmDither dither; | ||||
|  | ||||
| public: | ||||
| #ifndef NDEBUG | ||||
| 	PcmFormatConverter() | ||||
| 		:src_format(SampleFormat::UNDEFINED), | ||||
| 		 dest_format(SampleFormat::UNDEFINED) {} | ||||
|  | ||||
| 	~PcmFormatConverter() { | ||||
| 		assert(src_format == SampleFormat::UNDEFINED); | ||||
| 		assert(dest_format == SampleFormat::UNDEFINED); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	/** | ||||
| 	 * Opens the object, prepare for Convert(). | ||||
| 	 * | ||||
| 	 * @param src_format the sample format of incoming data | ||||
| 	 * @param dest_format the sample format of outgoing data | ||||
| 	 * @param error location to store the error | ||||
| 	 * @return true on success | ||||
| 	 */ | ||||
| 	bool Open(SampleFormat src_format, SampleFormat dest_format, | ||||
| 		  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 | ||||
| @@ -20,11 +20,11 @@ | ||||
| #include "config.h" | ||||
| #include "PcmConvert.hxx" | ||||
| #include "PcmChannels.hxx" | ||||
| #include "PcmFormat.hxx" | ||||
| #include "AudioFormat.hxx" | ||||
| #include "util/ConstBuffer.hxx" | ||||
| #include "util/Error.hxx" | ||||
| #include "util/Domain.hxx" | ||||
| #include "util/ConstBuffer.hxx" | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <math.h> | ||||
| @@ -53,7 +53,7 @@ PcmConvert::~PcmConvert() | ||||
|  | ||||
| bool | ||||
| PcmConvert::Open(AudioFormat _src_format, AudioFormat _dest_format, | ||||
| 		 gcc_unused Error &error) | ||||
| 		 Error &error) | ||||
| { | ||||
| 	assert(!src_format.IsValid()); | ||||
| 	assert(!dest_format.IsValid()); | ||||
| @@ -63,12 +63,24 @@ PcmConvert::Open(AudioFormat _src_format, AudioFormat _dest_format, | ||||
| 	src_format = _src_format; | ||||
| 	dest_format = _dest_format; | ||||
|  | ||||
| 	AudioFormat format = src_format; | ||||
| 	if (format.format == SampleFormat::DSD) | ||||
| 		format.format = SampleFormat::FLOAT; | ||||
|  | ||||
| 	if (format.format != dest_format.format && | ||||
| 	    !format_converter.Open(format.format, dest_format.format, error)) | ||||
| 		return false; | ||||
| 	format.format = dest_format.format; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void | ||||
| PcmConvert::Close() | ||||
| { | ||||
| 	if (src_format.format != dest_format.format) | ||||
| 		format_converter.Close(); | ||||
|  | ||||
| 	dsd.Reset(); | ||||
| 	resampler.Reset(); | ||||
|  | ||||
| @@ -79,23 +91,14 @@ PcmConvert::Close() | ||||
| } | ||||
|  | ||||
| inline ConstBuffer<int16_t> | ||||
| PcmConvert::Convert16(ConstBuffer<void> src, AudioFormat format, Error &error) | ||||
| PcmConvert::Convert16(ConstBuffer<int16_t> src, AudioFormat format, | ||||
| 		      Error &error) | ||||
| { | ||||
| 	const int16_t *buf; | ||||
| 	size_t len; | ||||
|  | ||||
| 	assert(format.format == SampleFormat::S16); | ||||
| 	assert(dest_format.format == SampleFormat::S16); | ||||
|  | ||||
| 	buf = pcm_convert_to_16(format_buffer, dither, | ||||
| 				format.format, | ||||
| 				src.data, src.size, | ||||
| 				&len); | ||||
| 	if (buf == nullptr) { | ||||
| 		error.Format(pcm_convert_domain, | ||||
| 			     "Conversion from %s to 16 bit is not implemented", | ||||
| 			     sample_format_to_string(format.format)); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	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, | ||||
| @@ -125,22 +128,14 @@ PcmConvert::Convert16(ConstBuffer<void> src, AudioFormat format, Error &error) | ||||
| } | ||||
|  | ||||
| inline ConstBuffer<int32_t> | ||||
| PcmConvert::Convert24(ConstBuffer<void> src, AudioFormat format, Error &error) | ||||
| PcmConvert::Convert24(ConstBuffer<int32_t> src, AudioFormat format, | ||||
| 		      Error &error) | ||||
| { | ||||
| 	const int32_t *buf; | ||||
| 	size_t len; | ||||
|  | ||||
| 	assert(format.format == SampleFormat::S24_P32); | ||||
| 	assert(dest_format.format == SampleFormat::S24_P32); | ||||
|  | ||||
| 	buf = pcm_convert_to_24(format_buffer, | ||||
| 				format.format, | ||||
| 				src.data, src.size, &len); | ||||
| 	if (buf == nullptr) { | ||||
| 		error.Format(pcm_convert_domain, | ||||
| 			     "Conversion from %s to 24 bit is not implemented", | ||||
| 			     sample_format_to_string(format.format)); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	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, | ||||
| @@ -170,22 +165,14 @@ PcmConvert::Convert24(ConstBuffer<void> src, AudioFormat format, Error &error) | ||||
| } | ||||
|  | ||||
| inline ConstBuffer<int32_t> | ||||
| PcmConvert::Convert32(ConstBuffer<void> src, AudioFormat format, Error &error) | ||||
| PcmConvert::Convert32(ConstBuffer<int32_t> src, AudioFormat format, | ||||
| 		      Error &error) | ||||
| { | ||||
| 	const int32_t *buf; | ||||
| 	size_t len; | ||||
|  | ||||
| 	assert(format.format == SampleFormat::S32); | ||||
| 	assert(dest_format.format == SampleFormat::S32); | ||||
|  | ||||
| 	buf = pcm_convert_to_32(format_buffer, | ||||
| 				format.format, | ||||
| 				src.data, src.size, &len); | ||||
| 	if (buf == nullptr) { | ||||
| 		error.Format(pcm_convert_domain, | ||||
| 			     "Conversion from %s to 32 bit is not implemented", | ||||
| 			     sample_format_to_string(format.format)); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	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, | ||||
| @@ -215,23 +202,14 @@ PcmConvert::Convert32(ConstBuffer<void> src, AudioFormat format, Error &error) | ||||
| } | ||||
|  | ||||
| inline ConstBuffer<float> | ||||
| PcmConvert::ConvertFloat(ConstBuffer<void> src, AudioFormat format, | ||||
| PcmConvert::ConvertFloat(ConstBuffer<float> src, AudioFormat format, | ||||
| 			 Error &error) | ||||
| { | ||||
| 	assert(format.format == SampleFormat::FLOAT); | ||||
| 	assert(dest_format.format == SampleFormat::FLOAT); | ||||
|  | ||||
| 	/* convert to float now */ | ||||
|  | ||||
| 	size_t size; | ||||
| 	const float *buffer = pcm_convert_to_float(format_buffer, | ||||
| 						   format.format, | ||||
| 						   src.data, src.size, &size); | ||||
| 	if (buffer == nullptr) { | ||||
| 		error.Format(pcm_convert_domain, | ||||
| 			     "Conversion from %s to float is not implemented", | ||||
| 			     sample_format_to_string(format.format)); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	auto buffer = src.data; | ||||
| 	size_t size = src.size * sizeof(*src.data); | ||||
|  | ||||
| 	/* convert channels */ | ||||
|  | ||||
| @@ -288,21 +266,33 @@ PcmConvert::Convert(const void *src, size_t src_size, | ||||
| 		format.format = SampleFormat::FLOAT; | ||||
| 	} | ||||
|  | ||||
| 	if (format.format != dest_format.format) { | ||||
| 		buffer = format_converter.Convert(buffer, error); | ||||
| 		if (buffer.IsNull()) | ||||
| 			return nullptr; | ||||
|  | ||||
| 		format.format = dest_format.format; | ||||
| 	} | ||||
|  | ||||
| 	switch (dest_format.format) { | ||||
| 	case SampleFormat::S16: | ||||
| 		buffer = Convert16(buffer, format, error).ToVoid(); | ||||
| 		buffer = Convert16(ConstBuffer<int16_t>::FromVoid(buffer), | ||||
| 				   format, error).ToVoid(); | ||||
| 		break; | ||||
|  | ||||
| 	case SampleFormat::S24_P32: | ||||
| 		buffer = Convert24(buffer, format, error).ToVoid(); | ||||
| 		buffer = Convert24(ConstBuffer<int32_t>::FromVoid(buffer), | ||||
| 				   format, error).ToVoid(); | ||||
| 		break; | ||||
|  | ||||
| 	case SampleFormat::S32: | ||||
| 		buffer = Convert32(buffer, format, error).ToVoid(); | ||||
| 		buffer = Convert32(ConstBuffer<int32_t>::FromVoid(buffer), | ||||
| 				   format, error).ToVoid(); | ||||
| 		break; | ||||
|  | ||||
| 	case SampleFormat::FLOAT: | ||||
| 		buffer = ConvertFloat(buffer, format, error).ToVoid(); | ||||
| 		buffer = ConvertFloat(ConstBuffer<float>::FromVoid(buffer), | ||||
| 				      format, error).ToVoid(); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
|   | ||||
| @@ -20,10 +20,10 @@ | ||||
| #ifndef PCM_CONVERT_HXX | ||||
| #define PCM_CONVERT_HXX | ||||
|  | ||||
| #include "PcmDither.hxx" | ||||
| #include "PcmDsd.hxx" | ||||
| #include "PcmResample.hxx" | ||||
| #include "PcmBuffer.hxx" | ||||
| #include "FormatConverter.hxx" | ||||
| #include "AudioFormat.hxx" | ||||
|  | ||||
| #include <stddef.h> | ||||
| @@ -42,10 +42,7 @@ class PcmConvert { | ||||
|  | ||||
| 	PcmResampler resampler; | ||||
|  | ||||
| 	PcmDither dither; | ||||
|  | ||||
| 	/** the buffer for converting the sample format */ | ||||
| 	PcmBuffer format_buffer; | ||||
| 	PcmFormatConverter format_converter; | ||||
|  | ||||
| 	/** the buffer for converting the channel count */ | ||||
| 	PcmBuffer channels_buffer; | ||||
| @@ -85,16 +82,16 @@ public: | ||||
| 			    Error &error); | ||||
|  | ||||
| private: | ||||
| 	ConstBuffer<int16_t> Convert16(ConstBuffer<void> src, | ||||
| 	ConstBuffer<int16_t> Convert16(ConstBuffer<int16_t> src, | ||||
| 				       AudioFormat format, | ||||
| 				       Error &error); | ||||
| 	ConstBuffer<int32_t> Convert24(ConstBuffer<void> src, | ||||
| 	ConstBuffer<int32_t> Convert24(ConstBuffer<int32_t> src, | ||||
| 				       AudioFormat format, | ||||
| 				       Error &error); | ||||
| 	ConstBuffer<int32_t> Convert32(ConstBuffer<void> src, | ||||
| 	ConstBuffer<int32_t> Convert32(ConstBuffer<int32_t> src, | ||||
| 				       AudioFormat format, | ||||
| 				       Error &error); | ||||
| 	ConstBuffer<float> ConvertFloat(ConstBuffer<void> src, | ||||
| 	ConstBuffer<float> ConvertFloat(ConstBuffer<float> src, | ||||
| 					AudioFormat format, | ||||
| 					Error &error); | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann