⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rdpsnd_dsp.c

📁 LInux 下的远程桌面工具 Rdesktop
💻 C
字号:
/*   rdesktop: A Remote Desktop Protocol client.   Sound DSP routines   Copyright (C) Michael Gernoth 2006-2007   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., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <strings.h>#include "rdesktop.h"#include "rdpsnd.h"#include "rdpsnd_dsp.h"#ifdef HAVE_LIBSAMPLERATE#include <samplerate.h>#define SRC_CONVERTER SRC_SINC_MEDIUM_QUALITY#endif#define MAX_VOLUME 65535static uint16 softvol_left = MAX_VOLUME;static uint16 softvol_right = MAX_VOLUME;static uint32 resample_to_srate = 44100;static uint16 resample_to_bitspersample = 16;static uint16 resample_to_channels = 2;#ifdef HAVE_LIBSAMPLERATEstatic SRC_STATE *src_converter = NULL;#endifvoidrdpsnd_dsp_softvol_set(uint16 left, uint16 right){	softvol_left = left;	softvol_right = right;	DEBUG(("rdpsnd_dsp_softvol_set: left: %u, right: %u\n", left, right));}voidrdpsnd_dsp_softvol(unsigned char *buffer, unsigned int size, RD_WAVEFORMATEX * format){	unsigned int factor_left, factor_right;	unsigned char *posin = buffer;	unsigned char *posout = buffer;	if ((softvol_left == MAX_VOLUME) && (softvol_right == MAX_VOLUME))		return;	factor_left = (softvol_left * 256) / MAX_VOLUME;	factor_right = (softvol_right * 256) / MAX_VOLUME;	if (format->nChannels == 1)	{		factor_left = factor_right = (factor_left + factor_right) / 2;	}	if (format->wBitsPerSample == 8)	{		sint8 val;		while (posout < buffer + size)		{			/* Left */			val = *posin++;			val = (val * factor_left) >> 8;			*posout++ = val;			/* Right */			val = *posin++;			val = (val * factor_right) >> 8;			*posout++ = val;		}	}	else	{		sint16 val;		while (posout < buffer + size)		{			/* Left */			val = *posin++;			val |= *posin++ << 8;			val = (val * factor_left) >> 8;			*posout++ = val & 0xff;			*posout++ = val >> 8;			/* Right */			val = *posin++;			val |= *posin++ << 8;			val = (val * factor_right) >> 8;			*posout++ = val & 0xff;			*posout++ = val >> 8;		}	}	DEBUG(("using softvol with factors left: %d, right: %d (%d/%d)\n", factor_left,	       factor_right, format->wBitsPerSample, format->nChannels));}voidrdpsnd_dsp_swapbytes(unsigned char *buffer, unsigned int size, RD_WAVEFORMATEX * format){	int i;	uint8 swap;	if (format->wBitsPerSample == 8)		return;	if (size & 0x1)		warning("badly aligned sound data");	for (i = 0; i < (int) size; i += 2)	{		swap = *(buffer + i);		*(buffer + i) = *(buffer + i + 1);		*(buffer + i + 1) = swap;	}}RD_BOOLrdpsnd_dsp_resample_set(uint32 device_srate, uint16 device_bitspersample, uint16 device_channels){#ifdef HAVE_LIBSAMPLERATE	int err;#endif	if (device_bitspersample != 16 && device_bitspersample != 8)		return False;	if (device_channels != 1 && device_channels != 2)		return False;	resample_to_srate = device_srate;	resample_to_bitspersample = device_bitspersample;	resample_to_channels = device_channels;#ifdef HAVE_LIBSAMPLERATE	if (src_converter != NULL)		src_converter = src_delete(src_converter);	if ((src_converter = src_new(SRC_CONVERTER, device_channels, &err)) == NULL)	{		warning("src_new failed: %d!\n", err);		return False;	}#endif	return True;}RD_BOOLrdpsnd_dsp_resample_supported(RD_WAVEFORMATEX * format){	if (format->wFormatTag != WAVE_FORMAT_PCM)		return False;	if ((format->nChannels != 1) && (format->nChannels != 2))		return False;	if ((format->wBitsPerSample != 8) && (format->wBitsPerSample != 16))		return False;	return True;}uint32rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size,		    RD_WAVEFORMATEX * format, RD_BOOL stream_be){#ifdef HAVE_LIBSAMPLERATE	SRC_DATA resample_data;	float *infloat, *outfloat;	int err;#else	int ratio1k = (resample_to_srate * 1000) / format->nSamplesPerSec;#endif	int innum, outnum;	unsigned char *tmpdata = NULL, *tmp = NULL;	int samplewidth = format->wBitsPerSample / 8;	int outsize = 0;	int i;	if ((resample_to_bitspersample == format->wBitsPerSample) &&	    (resample_to_channels == format->nChannels) &&	    (resample_to_srate == format->nSamplesPerSec))		return 0;#ifdef B_ENDIAN	if (!stream_be)		rdpsnd_dsp_swapbytes(in, size, format);#endif	if (resample_to_channels != format->nChannels)	{		int newsize = (size / format->nChannels) * resample_to_channels;		tmpdata = (unsigned char *) xmalloc(newsize);		for (i = 0; i < newsize / samplewidth; i++)		{			if (format->nChannels > resample_to_channels)				memcpy(tmpdata + (i * samplewidth),				       in +				       (((i * format->nChannels) / resample_to_channels) *					samplewidth), samplewidth);			else				memcpy(tmpdata + (i * samplewidth),				       in +				       (((i / resample_to_channels) * format->nChannels +					 (i % format->nChannels)) * samplewidth), samplewidth);		}		in = tmpdata;		size = newsize;	}	/* Expand 8bit input-samples to 16bit */#ifndef HAVE_LIBSAMPLERATE	/* libsamplerate needs 16bit samples */	if (format->wBitsPerSample != resample_to_bitspersample)#endif	{		/* source: 8 bit, dest: 16bit */		if (format->wBitsPerSample == 8)		{			tmp = tmpdata;			tmpdata = (unsigned char *) xmalloc(size * 2);			for (i = 0; i < (int) size; i++)			{				tmpdata[i * 2] = in[i];				tmpdata[(i * 2) + 1] = 0x00;			}			in = tmpdata;			samplewidth = 16 / 2;			size *= 2;			if (tmp != NULL)				xfree(tmp);		}	}	innum = size / samplewidth;	/* Do the resampling */#ifdef HAVE_LIBSAMPLERATE	if (src_converter == NULL)	{		warning("no samplerate converter available!!\n");		return 0;	}	outnum = ((float) innum * ((float) resample_to_srate / (float) format->nSamplesPerSec)) + 1;	infloat = (float *) xmalloc(sizeof(float) * innum);	outfloat = (float *) xmalloc(sizeof(float) * outnum);	src_short_to_float_array((short *) in, infloat, innum);	bzero(&resample_data, sizeof(resample_data));	resample_data.data_in = infloat;	resample_data.data_out = outfloat;	resample_data.input_frames = innum / resample_to_channels;	resample_data.output_frames = outnum / resample_to_channels;	resample_data.src_ratio = (double) resample_to_srate / (double) format->nSamplesPerSec;	resample_data.end_of_input = 0;	if ((err = src_process(src_converter, &resample_data)) != 0)		error("src_process: %s", src_strerror(err));	xfree(infloat);	outsize = resample_data.output_frames_gen * resample_to_channels * samplewidth;	*out = (unsigned char *) xmalloc(outsize);	src_float_to_short_array(outfloat, (short *) *out,				 resample_data.output_frames_gen * resample_to_channels);	xfree(outfloat);#else	/* Michaels simple linear resampler */	if (resample_to_srate < format->nSamplesPerSec)	{		warning("downsampling currently not supported!\n");		return 0;	}	outnum = (innum * ratio1k) / 1000;	outsize = outnum * samplewidth;	*out = (unsigned char *) xmalloc(outsize);	bzero(*out, outsize);	for (i = 0; i < outsize / (resample_to_channels * samplewidth); i++)	{		int source = (i * 1000) / ratio1k;#if 0				/* Partial for linear resampler */		int part = (i * 100000) / ratio1k - source * 100;#endif		int j;		if (source * resample_to_channels + samplewidth > (int) size)			break;#if 0				/* Linear resampling, TODO: soundquality fixes (LP filter) */		if (samplewidth == 1)		{			sint8 cval1, cval2;			for (j = 0; j < resample_to_channels; j++)			{				memcpy(&cval1,				       in + (source * resample_to_channels * samplewidth) +				       (samplewidth * j), samplewidth);				memcpy(&cval2,				       in + ((source + 1) * resample_to_channels * samplewidth) +				       (samplewidth * j), samplewidth);				cval1 += (sint8) (cval2 * part) / 100;				memcpy(*out + (i * resample_to_channels * samplewidth) +				       (samplewidth * j), &cval1, samplewidth);			}		}		else		{			sint16 sval1, sval2;			for (j = 0; j < resample_to_channels; j++)			{				memcpy(&sval1,				       in + (source * resample_to_channels * samplewidth) +				       (samplewidth * j), samplewidth);				memcpy(&sval2,				       in + ((source + 1) * resample_to_channels * samplewidth) +				       (samplewidth * j), samplewidth);				sval1 += (sint16) (sval2 * part) / 100;				memcpy(*out + (i * resample_to_channels * samplewidth) +				       (samplewidth * j), &sval1, samplewidth);			}		}#else /* Nearest neighbor search */		for (j = 0; j < resample_to_channels; j++)		{			memcpy(*out + (i * resample_to_channels * samplewidth) + (samplewidth * j),			       in + (source * resample_to_channels * samplewidth) +			       (samplewidth * j), samplewidth);		}#endif	}	outsize = i * resample_to_channels * samplewidth;#endif	if (tmpdata != NULL)		xfree(tmpdata);	/* Shrink 16bit output-samples to 8bit */#ifndef HAVE_LIBSAMPLERATE	/* libsamplerate produces 16bit samples */	if (format->wBitsPerSample != resample_to_bitspersample)#endif	{		/* source: 16 bit, dest: 8 bit */		if (resample_to_bitspersample == 8)		{			for (i = 0; i < outsize; i++)			{				*out[i] = *out[i * 2];			}			outsize /= 2;		}	}#ifdef B_ENDIAN	if (!stream_be)		rdpsnd_dsp_swapbytes(*out, outsize, format);#endif	return outsize;}STREAMrdpsnd_dsp_process(unsigned char *data, unsigned int size, struct audio_driver * current_driver,		   RD_WAVEFORMATEX * format){	static struct stream out;	RD_BOOL stream_be = False;	/* softvol and byteswap do not change the amount of data they	   return, so they can operate on the input-stream */	if (current_driver->wave_out_volume == rdpsnd_dsp_softvol_set)		rdpsnd_dsp_softvol(data, size, format);#ifdef B_ENDIAN	if (current_driver->need_byteswap_on_be)	{		rdpsnd_dsp_swapbytes(data, size, format);		stream_be = True;	}#endif	out.data = NULL;	if (current_driver->need_resampling)		out.size = rdpsnd_dsp_resample(&out.data, data, size, format, stream_be);	if (out.data == NULL)	{		out.data = (unsigned char *) xmalloc(size);		memcpy(out.data, data, size);		out.size = size;	}	out.p = out.data;	out.end = out.p + out.size;	return &out;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -