ref: 87219e8c7135c5d54ae37d8f9cbae9eba67dde4b
dir: /src/core/rendduh.c/
/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/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)); \ } /* DEPRECATED */ DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos) { return duh_start_sigrenderer(duh, 0, n_channels, pos); } /* 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; } /* DEPRECATED */ int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr) { return duh_sigrenderer_get_n_channels(dr); } /* DEPRECATED */ long duh_renderer_get_position(DUH_SIGRENDERER *dr) { return duh_sigrenderer_get_position(dr); } /* DEPRECATED */ void duh_end_renderer(DUH_SIGRENDERER *dr) { duh_end_sigrenderer(dr); } /* DEPRECATED */ DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer) { return sigrenderer; } /* DEPRECATED */ DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr) { return dr; } /* DEPRECATED */ DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr) { return dr; }