shithub: dumb

ref: 973185f4015df5b8ca89dae9429f1e5d7abfbde5
dir: /src/core/rendduh.c/

View raw version
/*  _______         ____    __         ___    ___
 * \    _  \       \    /  \  /       \   \  /   /       '   '  '
 *  |  | \  \       |  |    ||         |   \/   |         .      .
 *  |  |  |  |      |  |    ||         ||\  /|  |
 *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
 *  |  |  |  |      |  |    ||         ||    |  |         .      .
 *  |  |_/  /        \  \__//          ||    |  |
 * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
 *                                                      /  \
 *                                                     / .  \
 * rendduh.c - Functions for rendering a DUH into     / / \  \
 *             an end-user sample format.            | <  /   \_
 *                                                   |  \/ /\   /
 * By entheh.                                         \_  /  > /
 *                                                      | \ / /
 *                                                      |  ' /
 *                                                       \__/
 */

#include <stdlib.h>
#include <limits.h>

#include "dumb.h"
#include "internal/dumb.h"



/* On the x86, we can use some tricks to speed stuff up */
#if (defined _MSC_VER) || (defined __DJGPP__) || (defined __MINGW__)
// Can't we detect Linux and other x86 platforms here? :/

#define FAST_MID(var, min, max) {                  \
	var -= (min);                                  \
	var &= (~var) >> (sizeof(var) * CHAR_BIT - 1); \
	var += (min);                                  \
	var -= (max);                                  \
	var &= var >> (sizeof(var) * CHAR_BIT - 1);    \
	var += (max);                                  \
}

#define CONVERT8(src, pos, signconv) {       \
	signed int f = (src + 0x8000) >> 16;     \
	FAST_MID(f, -128, 127);                  \
	((char*)sptr)[pos] = (char)f ^ signconv; \
}

#define CONVERT16(src, pos, signconv) {          \
	signed int f = (src + 0x80) >> 8;            \
	FAST_MID(f, -32768, 32767);                  \
	((short*)sptr)[pos] = (short)(f ^ signconv); \
}

#else

#define CONVERT8(src, pos, signconv)		  \
{											  \
	signed int f = (src + 0x8000) >> 16;	  \
	f = MID(-128, f, 127);					  \
	((char *)sptr)[pos] = (char)f ^ signconv; \
}



#define CONVERT16(src, pos, signconv)			  \
{												  \
	signed int f = (src + 0x80) >> 8;			  \
	f = MID(-32768, f, 32767);					  \
	((short *)sptr)[pos] = (short)(f ^ signconv); \
}

#endif

#define CONVERT24(src, pos) {                         \
	signed int f = src;			                      \
	f = MID(-8388608, f, 8388607);				      \
	((unsigned char*)sptr)[pos  ] = (f)       & 0xFF; \
	((unsigned char*)sptr)[pos+1] = (f >> 8)  & 0xFF; \
	((unsigned char*)sptr)[pos+2] = (f >> 16) & 0xFF; \
}

#define CONVERT32F(src, pos) {                                     \
	((float*)sptr)[pos] = (float)((signed int)src) * (1.0f/(float)(0xffffff/2+1)); \
}

#define CONVERT64F(src, pos) {                                     \
	((double*)sptr)[pos] = (double)((signed int)src) * (1.0/(double)(0xffffff/2+1)); \
}



/* This is the only deprecated function in 2.0.0. */
/* DEPRECATED */
long duh_render(
	DUH_SIGRENDERER *sigrenderer,
	int bits, int unsign,
	float volume, float delta,
	long size, void *sptr
)
{
	long n;

	sample_t **sampptr;

	int n_channels;

	ASSERT(bits == 8 || bits == 16);
	ASSERT(sptr);

	if (!sigrenderer)
		return 0;

	n_channels = duh_sigrenderer_get_n_channels(sigrenderer);

	ASSERT(n_channels > 0);
	/* This restriction will be removed when need be. At the moment, tightly
	 * optimised loops exist for exactly one or two channels.
	 */
	ASSERT(n_channels <= 2);

	sampptr = allocate_sample_buffer(n_channels, size);

	if (!sampptr)
		return 0;

	dumb_silence(sampptr[0], n_channels * size);

	size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, sampptr);

	if (bits == 16) {
		int signconv = unsign ? 0x8000 : 0x0000;

		for (n = 0; n < size * n_channels; n++) {
			CONVERT16(sampptr[0][n], n, signconv);
		}
	} else {
		char signconv = unsign ? 0x80 : 0x00;

		for (n = 0; n < size * n_channels; n++) {
			CONVERT8(sampptr[0][n], n, signconv);
		}
	}

	destroy_sample_buffer(sampptr);

	return size;
}


long duh_render_int(
	DUH_SIGRENDERER *sigrenderer,
	sample_t ***sig_samples,
	long *sig_samples_size,
	int bits, int unsign,
	float volume, float delta,
	long size, void *sptr
)
{
	long n;

	sample_t **sampptr;

	int n_channels;

	ASSERT(bits == 8 || bits == 16 || bits == 24);
	ASSERT(sptr);
	ASSERT(sig_samples);
	ASSERT(sig_samples_size);

	if (!sigrenderer)
		return 0;

	n_channels = duh_sigrenderer_get_n_channels(sigrenderer);

	ASSERT(n_channels > 0);
	/* This restriction will be removed when need be. At the moment, tightly
	 * optimised loops exist for exactly one or two channels.
	 */
	ASSERT(n_channels <= 2);

	if ((*sig_samples == NULL) || (*sig_samples_size != size))
	{
		destroy_sample_buffer(*sig_samples);
		*sig_samples = allocate_sample_buffer(n_channels, size);
		*sig_samples_size = size;
	}
	sampptr = *sig_samples;

	if (!sampptr)
		return 0;

	dumb_silence(sampptr[0], n_channels * size);

	size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, sampptr);

	if (bits == 24) {
		long i = 0;
		ASSERT(unsign == 0);

		for (n = 0; n < size * n_channels; n++, i += 3) {
			CONVERT24(sampptr[0][n], i);
		}
	} else
	if (bits == 16) {
		int signconv = unsign ? 0x8000 : 0x0000;

		for (n = 0; n < size * n_channels; n++) {
			CONVERT16(sampptr[0][n], n, signconv);
		}
	} else {
		char signconv = unsign ? 0x80 : 0x00;

		for (n = 0; n < size * n_channels; n++) {
			CONVERT8(sampptr[0][n], n, signconv);
		}
	}

	return size;
}


long duh_render_float(
	DUH_SIGRENDERER *sigrenderer,
	sample_t ***sig_samples,
	long *sig_samples_size,
	int bits,
	float volume, float delta,
	long size, void *sptr
)
{
	long n;

	sample_t **sampptr;

	int n_channels;

	ASSERT(bits == 32 || bits == 64);
	ASSERT(sptr);
	ASSERT(sig_samples);
	ASSERT(sig_samples_size);

	if (!sigrenderer)
		return 0;

	n_channels = duh_sigrenderer_get_n_channels(sigrenderer);

	ASSERT(n_channels > 0);
	/* This restriction will be removed when need be. At the moment, tightly
	 * optimised loops exist for exactly one or two channels.
	 */
	ASSERT(n_channels <= 2);

	if ((*sig_samples == NULL) || (*sig_samples_size != size))
	{
		destroy_sample_buffer(*sig_samples);
		*sig_samples = allocate_sample_buffer(n_channels, size);
		*sig_samples_size = size;
	}
	sampptr = *sig_samples;

	if (!sampptr)
		return 0;

	dumb_silence(sampptr[0], n_channels * size);

	size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, sampptr);

	if (bits == 64) {
		for (n = 0; n < size * n_channels; n++) {
			CONVERT64F(sampptr[0][n], n);
		}
	} else
	if (bits == 32) {
		for (n = 0; n < size * n_channels; n++) {
			CONVERT32F(sampptr[0][n], n);
		}
	}

	return size;
}