mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-14 00:21:34 +00:00
Update DUMB to revision 9ac6cf69758fe0db6d6e654f298cd36efdb73366
- Replaced old aliased resampling mode with a 65536x oversampling sinc resampler SVN r4076 (trunk)
This commit is contained in:
parent
13ffa8a1b8
commit
401ee8fafb
10 changed files with 682 additions and 85 deletions
|
@ -36,6 +36,7 @@ add_library( dumb
|
||||||
src/core/rendsig.c
|
src/core/rendsig.c
|
||||||
src/core/unload.c
|
src/core/unload.c
|
||||||
src/helpers/barray.c
|
src/helpers/barray.c
|
||||||
|
src/helpers/blip_buf.c
|
||||||
src/helpers/clickrem.c
|
src/helpers/clickrem.c
|
||||||
src/helpers/memfile.c
|
src/helpers/memfile.c
|
||||||
src/helpers/resample.c
|
src/helpers/resample.c
|
||||||
|
|
|
@ -662,6 +662,8 @@ typedef struct DUMB_VOLUME_RAMP_INFO DUMB_VOLUME_RAMP_INFO;
|
||||||
|
|
||||||
typedef void (*DUMB_RESAMPLE_PICKUP)(DUMB_RESAMPLER *resampler, void *data);
|
typedef void (*DUMB_RESAMPLE_PICKUP)(DUMB_RESAMPLER *resampler, void *data);
|
||||||
|
|
||||||
|
#include "internal/blip_buf.h"
|
||||||
|
|
||||||
struct DUMB_RESAMPLER
|
struct DUMB_RESAMPLER
|
||||||
{
|
{
|
||||||
void *src;
|
void *src;
|
||||||
|
@ -679,6 +681,9 @@ struct DUMB_RESAMPLER
|
||||||
signed char x8[3*2];
|
signed char x8[3*2];
|
||||||
} x;
|
} x;
|
||||||
int overshot;
|
int overshot;
|
||||||
|
int last_clock;
|
||||||
|
int last_amp[2];
|
||||||
|
blip_t* blip_buffer[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DUMB_VOLUME_RAMP_INFO
|
struct DUMB_VOLUME_RAMP_INFO
|
||||||
|
|
77
dumb/include/internal/blip_buf.h
Normal file
77
dumb/include/internal/blip_buf.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/** \file
|
||||||
|
Sample buffer that resamples from input clock rate to output sample rate */
|
||||||
|
|
||||||
|
/* blip_buf 1.1.0 */
|
||||||
|
#ifndef BLIP_BUF_H
|
||||||
|
#define BLIP_BUF_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** First parameter of most functions is blip_t*, or const blip_t* if nothing
|
||||||
|
is changed. */
|
||||||
|
typedef struct blip_t blip_t;
|
||||||
|
|
||||||
|
/** Creates new buffer that can hold at most sample_count samples. Sets rates
|
||||||
|
so that there are blip_max_ratio clocks per sample. Returns pointer to new
|
||||||
|
buffer, or NULL if insufficient memory. */
|
||||||
|
blip_t* blip_new( int sample_count );
|
||||||
|
|
||||||
|
blip_t* blip_dup( blip_t* );
|
||||||
|
|
||||||
|
/** Sets approximate input clock rate and output sample rate. For every
|
||||||
|
clock_rate input clocks, approximately sample_rate samples are generated. */
|
||||||
|
void blip_set_rates( blip_t*, double clock_rate, double sample_rate );
|
||||||
|
|
||||||
|
enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
|
||||||
|
clock_rate must not be greater than sample_rate*blip_max_ratio. */
|
||||||
|
blip_max_ratio = 1 << 20 };
|
||||||
|
|
||||||
|
/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
|
||||||
|
void blip_clear( blip_t* );
|
||||||
|
|
||||||
|
/** Adds positive/negative delta into buffer at specified clock time. */
|
||||||
|
void blip_add_delta( blip_t*, unsigned int clock_time, int delta );
|
||||||
|
|
||||||
|
/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */
|
||||||
|
void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta );
|
||||||
|
|
||||||
|
/** Length of time frame, in clocks, needed to make sample_count additional
|
||||||
|
samples available. */
|
||||||
|
int blip_clocks_needed( const blip_t*, int sample_count );
|
||||||
|
|
||||||
|
enum { /** Maximum number of samples that can be generated from one time frame. */
|
||||||
|
blip_max_frame = 4000 };
|
||||||
|
|
||||||
|
/** Makes input clocks before clock_duration available for reading as output
|
||||||
|
samples. Also begins new time frame at clock_duration, so that clock time 0 in
|
||||||
|
the new time frame specifies the same clock as clock_duration in the old time
|
||||||
|
frame specified. Deltas can have been added slightly past clock_duration (up to
|
||||||
|
however many clocks there are in two output samples). */
|
||||||
|
void blip_end_frame( blip_t*, unsigned int clock_duration );
|
||||||
|
|
||||||
|
/** Number of buffered samples available for reading. */
|
||||||
|
int blip_samples_avail( const blip_t* );
|
||||||
|
|
||||||
|
/** Reads and removes at most 'count' samples and writes them to 'out'. If
|
||||||
|
'stereo' is true, writes output to every other element of 'out', allowing easy
|
||||||
|
interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed
|
||||||
|
samples. Returns number of samples actually read. */
|
||||||
|
int blip_read_samples( blip_t*, int out [], int count );
|
||||||
|
|
||||||
|
/** Reads the current integrator and returns it */
|
||||||
|
int blip_peek_sample( blip_t* );
|
||||||
|
|
||||||
|
/** Frees buffer. No effect if NULL is passed. */
|
||||||
|
void blip_delete( blip_t* );
|
||||||
|
|
||||||
|
|
||||||
|
/* Deprecated */
|
||||||
|
typedef blip_t blip_buffer_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
354
dumb/src/helpers/blip_buf.c
Normal file
354
dumb/src/helpers/blip_buf.c
Normal file
|
@ -0,0 +1,354 @@
|
||||||
|
/* blip_buf 1.1.0. http://www.slack.net/~ant/ */
|
||||||
|
|
||||||
|
#include "internal/blip_buf.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* Library Copyright (C) 2003-2009 Shay Green. This library is free software;
|
||||||
|
you can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||||
|
General Public License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version. This
|
||||||
|
library 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 Lesser General Public License for more
|
||||||
|
details. You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this module; if not, write to the Free Software Foundation,
|
||||||
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||||
|
|
||||||
|
#if defined (BLARGG_TEST) && BLARGG_TEST
|
||||||
|
#include "blargg_test.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Equivalent to ULONG_MAX >= 0xFFFFFFFF00000000.
|
||||||
|
Avoids constants that don't fit in 32 bits. */
|
||||||
|
#if ULONG_MAX/0xFFFFFFFF > 0xFFFFFFFF
|
||||||
|
typedef unsigned long fixed_t;
|
||||||
|
enum { pre_shift = 32 };
|
||||||
|
|
||||||
|
#elif defined(ULLONG_MAX)
|
||||||
|
typedef unsigned long long fixed_t;
|
||||||
|
enum { pre_shift = 32 };
|
||||||
|
|
||||||
|
#else
|
||||||
|
typedef unsigned fixed_t;
|
||||||
|
enum { pre_shift = 0 };
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum { time_bits = pre_shift + 20 };
|
||||||
|
|
||||||
|
static fixed_t const time_unit = (fixed_t) 1 << time_bits;
|
||||||
|
|
||||||
|
enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */
|
||||||
|
enum { end_frame_extra = 2 }; /* allows deltas slightly after frame length */
|
||||||
|
|
||||||
|
enum { half_width = 8 };
|
||||||
|
enum { buf_extra = half_width*2 + end_frame_extra };
|
||||||
|
enum { phase_bits = 5 };
|
||||||
|
enum { phase_count = 1 << phase_bits };
|
||||||
|
enum { delta_bits = 15 };
|
||||||
|
enum { delta_unit = 1 << delta_bits };
|
||||||
|
enum { frac_bits = time_bits - pre_shift };
|
||||||
|
|
||||||
|
/* We could eliminate avail and encode whole samples in offset, but that would
|
||||||
|
limit the total buffered samples to blip_max_frame. That could only be
|
||||||
|
increased by decreasing time_bits, which would reduce resample ratio accuracy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Sample buffer that resamples to output rate and accumulates samples
|
||||||
|
until they're read out */
|
||||||
|
struct blip_t
|
||||||
|
{
|
||||||
|
fixed_t factor;
|
||||||
|
fixed_t offset;
|
||||||
|
int avail;
|
||||||
|
int size;
|
||||||
|
int integrator;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int buf_t;
|
||||||
|
|
||||||
|
/* probably not totally portable */
|
||||||
|
#define SAMPLES( buf ) ((buf_t*) ((buf) + 1))
|
||||||
|
|
||||||
|
/* Arithmetic (sign-preserving) right shift */
|
||||||
|
#define ARITH_SHIFT( n, shift ) \
|
||||||
|
((n) >> (shift))
|
||||||
|
|
||||||
|
enum { max_sample = +32767 };
|
||||||
|
enum { min_sample = -32768 };
|
||||||
|
|
||||||
|
#define CLAMP( n ) \
|
||||||
|
{\
|
||||||
|
if ( (short) n != n )\
|
||||||
|
n = ARITH_SHIFT( n, 16 ) ^ max_sample;\
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_assumptions( void )
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
#if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF
|
||||||
|
#error "int must be at least 32 bits"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert( (-3 >> 1) == -2 ); /* right shift must preserve sign */
|
||||||
|
|
||||||
|
n = max_sample * 2;
|
||||||
|
CLAMP( n );
|
||||||
|
assert( n == max_sample );
|
||||||
|
|
||||||
|
n = min_sample * 2;
|
||||||
|
CLAMP( n );
|
||||||
|
assert( n == min_sample );
|
||||||
|
|
||||||
|
assert( blip_max_ratio <= time_unit );
|
||||||
|
assert( blip_max_frame <= (fixed_t) -1 >> time_bits );
|
||||||
|
}
|
||||||
|
|
||||||
|
blip_t* blip_new( int size )
|
||||||
|
{
|
||||||
|
blip_t* m;
|
||||||
|
assert( size >= 0 );
|
||||||
|
|
||||||
|
m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) );
|
||||||
|
if ( m )
|
||||||
|
{
|
||||||
|
m->factor = time_unit / blip_max_ratio;
|
||||||
|
m->size = size;
|
||||||
|
blip_clear( m );
|
||||||
|
check_assumptions();
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
blip_t* blip_dup( blip_t* m )
|
||||||
|
{
|
||||||
|
size_t size = sizeof *m + (m->size + buf_extra) * sizeof(buf_t);
|
||||||
|
blip_t* r = (blip_t*) malloc( size );
|
||||||
|
if ( r ) memcpy( r, m, size );
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void blip_delete( blip_t* m )
|
||||||
|
{
|
||||||
|
if ( m != NULL )
|
||||||
|
{
|
||||||
|
/* Clear fields in case user tries to use after freeing */
|
||||||
|
memset( m, 0, sizeof *m );
|
||||||
|
free( m );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void blip_set_rates( blip_t* m, double clock_rate, double sample_rate )
|
||||||
|
{
|
||||||
|
double factor = time_unit * sample_rate / clock_rate;
|
||||||
|
m->factor = (fixed_t) factor;
|
||||||
|
|
||||||
|
/* Fails if clock_rate exceeds maximum, relative to sample_rate */
|
||||||
|
assert( 0 <= factor - m->factor && factor - m->factor < 1 );
|
||||||
|
|
||||||
|
/* Avoid requiring math.h. Equivalent to
|
||||||
|
m->factor = (int) ceil( factor ) */
|
||||||
|
if ( m->factor < factor )
|
||||||
|
m->factor++;
|
||||||
|
|
||||||
|
/* At this point, factor is most likely rounded up, but could still
|
||||||
|
have been rounded down in the floating-point calculation. */
|
||||||
|
}
|
||||||
|
|
||||||
|
void blip_clear( blip_t* m )
|
||||||
|
{
|
||||||
|
/* We could set offset to 0, factor/2, or factor-1. 0 is suitable if
|
||||||
|
factor is rounded up. factor-1 is suitable if factor is rounded down.
|
||||||
|
Since we don't know rounding direction, factor/2 accommodates either,
|
||||||
|
with the slight loss of showing an error in half the time. Since for
|
||||||
|
a 64-bit factor this is years, the halving isn't a problem. */
|
||||||
|
|
||||||
|
m->offset = m->factor / 2;
|
||||||
|
m->avail = 0;
|
||||||
|
m->integrator = 0;
|
||||||
|
memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) );
|
||||||
|
}
|
||||||
|
|
||||||
|
int blip_clocks_needed( const blip_t* m, int samples )
|
||||||
|
{
|
||||||
|
fixed_t needed;
|
||||||
|
|
||||||
|
/* Fails if buffer can't hold that many more samples */
|
||||||
|
assert( samples >= 0 && m->avail + samples <= m->size );
|
||||||
|
|
||||||
|
needed = (fixed_t) samples * time_unit;
|
||||||
|
if ( needed < m->offset )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (int)((needed - m->offset + m->factor - 1) / m->factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void blip_end_frame( blip_t* m, unsigned t )
|
||||||
|
{
|
||||||
|
fixed_t off = t * m->factor + m->offset;
|
||||||
|
m->avail += (int)(off >> time_bits);
|
||||||
|
m->offset = off & (time_unit - 1);
|
||||||
|
|
||||||
|
/* Fails if buffer size was exceeded */
|
||||||
|
assert( m->avail <= m->size );
|
||||||
|
}
|
||||||
|
|
||||||
|
int blip_samples_avail( const blip_t* m )
|
||||||
|
{
|
||||||
|
return m->avail;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_samples( blip_t* m, int count )
|
||||||
|
{
|
||||||
|
buf_t* buf = SAMPLES( m );
|
||||||
|
int remain = m->avail + buf_extra - count;
|
||||||
|
m->avail -= count;
|
||||||
|
|
||||||
|
memmove( &buf [0], &buf [count], remain * sizeof buf [0] );
|
||||||
|
memset( &buf [remain], 0, count * sizeof buf [0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
int blip_read_samples( blip_t* m, int out [], int count )
|
||||||
|
{
|
||||||
|
assert( count >= 0 );
|
||||||
|
|
||||||
|
if ( count > m->avail )
|
||||||
|
count = m->avail;
|
||||||
|
|
||||||
|
if ( count )
|
||||||
|
{
|
||||||
|
buf_t const* in = SAMPLES( m );
|
||||||
|
buf_t const* end = in + count;
|
||||||
|
int sum = m->integrator;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Eliminate fraction */
|
||||||
|
int s = ARITH_SHIFT( sum, delta_bits - 8 );
|
||||||
|
|
||||||
|
sum += *in++;
|
||||||
|
|
||||||
|
*out = s;
|
||||||
|
out++;
|
||||||
|
|
||||||
|
/* High-pass filter */
|
||||||
|
sum -= s >> (8 - (delta_bits - bass_shift)); //<< (delta_bits - bass_shift - 8);
|
||||||
|
}
|
||||||
|
while ( in != end );
|
||||||
|
m->integrator = sum;
|
||||||
|
|
||||||
|
remove_samples( m, count );
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int blip_peek_sample( blip_t* m )
|
||||||
|
{
|
||||||
|
return ARITH_SHIFT( m->integrator, delta_bits - 8 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Things that didn't help performance on x86:
|
||||||
|
__attribute__((aligned(128)))
|
||||||
|
#define short int
|
||||||
|
restrict
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Sinc_Generator( 0.9, 0.55, 4.5 ) */
|
||||||
|
static short const bl_step [phase_count + 1] [half_width] =
|
||||||
|
{
|
||||||
|
{ 43, -115, 350, -488, 1136, -914, 5861,21022},
|
||||||
|
{ 44, -118, 348, -473, 1076, -799, 5274,21001},
|
||||||
|
{ 45, -121, 344, -454, 1011, -677, 4706,20936},
|
||||||
|
{ 46, -122, 336, -431, 942, -549, 4156,20829},
|
||||||
|
{ 47, -123, 327, -404, 868, -418, 3629,20679},
|
||||||
|
{ 47, -122, 316, -375, 792, -285, 3124,20488},
|
||||||
|
{ 47, -120, 303, -344, 714, -151, 2644,20256},
|
||||||
|
{ 46, -117, 289, -310, 634, -17, 2188,19985},
|
||||||
|
{ 46, -114, 273, -275, 553, 117, 1758,19675},
|
||||||
|
{ 44, -108, 255, -237, 471, 247, 1356,19327},
|
||||||
|
{ 43, -103, 237, -199, 390, 373, 981,18944},
|
||||||
|
{ 42, -98, 218, -160, 310, 495, 633,18527},
|
||||||
|
{ 40, -91, 198, -121, 231, 611, 314,18078},
|
||||||
|
{ 38, -84, 178, -81, 153, 722, 22,17599},
|
||||||
|
{ 36, -76, 157, -43, 80, 824, -241,17092},
|
||||||
|
{ 34, -68, 135, -3, 8, 919, -476,16558},
|
||||||
|
{ 32, -61, 115, 34, -60, 1006, -683,16001},
|
||||||
|
{ 29, -52, 94, 70, -123, 1083, -862,15422},
|
||||||
|
{ 27, -44, 73, 106, -184, 1152,-1015,14824},
|
||||||
|
{ 25, -36, 53, 139, -239, 1211,-1142,14210},
|
||||||
|
{ 22, -27, 34, 170, -290, 1261,-1244,13582},
|
||||||
|
{ 20, -20, 16, 199, -335, 1301,-1322,12942},
|
||||||
|
{ 18, -12, -3, 226, -375, 1331,-1376,12293},
|
||||||
|
{ 15, -4, -19, 250, -410, 1351,-1408,11638},
|
||||||
|
{ 13, 3, -35, 272, -439, 1361,-1419,10979},
|
||||||
|
{ 11, 9, -49, 292, -464, 1362,-1410,10319},
|
||||||
|
{ 9, 16, -63, 309, -483, 1354,-1383, 9660},
|
||||||
|
{ 7, 22, -75, 322, -496, 1337,-1339, 9005},
|
||||||
|
{ 6, 26, -85, 333, -504, 1312,-1280, 8355},
|
||||||
|
{ 4, 31, -94, 341, -507, 1278,-1205, 7713},
|
||||||
|
{ 3, 35, -102, 347, -506, 1238,-1119, 7082},
|
||||||
|
{ 1, 40, -110, 350, -499, 1190,-1021, 6464},
|
||||||
|
{ 0, 43, -115, 350, -488, 1136, -914, 5861}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Shifting by pre_shift allows calculation using unsigned int rather than
|
||||||
|
possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient.
|
||||||
|
And by having pre_shift 32, a 32-bit platform can easily do the shift by
|
||||||
|
simply ignoring the low half. */
|
||||||
|
|
||||||
|
void blip_add_delta( blip_t* m, unsigned time, int delta )
|
||||||
|
{
|
||||||
|
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
|
||||||
|
buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
|
||||||
|
|
||||||
|
int const phase_shift = frac_bits - phase_bits;
|
||||||
|
int phase = fixed >> phase_shift & (phase_count - 1);
|
||||||
|
short const* in = bl_step [phase];
|
||||||
|
short const* rev = bl_step [phase_count - phase];
|
||||||
|
|
||||||
|
int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1);
|
||||||
|
int delta2 = (delta * interp) >> delta_bits;
|
||||||
|
delta -= delta2;
|
||||||
|
|
||||||
|
/* Fails if buffer size was exceeded */
|
||||||
|
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
|
||||||
|
|
||||||
|
out [0] += in[0]*delta + in[half_width+0]*delta2;
|
||||||
|
out [1] += in[1]*delta + in[half_width+1]*delta2;
|
||||||
|
out [2] += in[2]*delta + in[half_width+2]*delta2;
|
||||||
|
out [3] += in[3]*delta + in[half_width+3]*delta2;
|
||||||
|
out [4] += in[4]*delta + in[half_width+4]*delta2;
|
||||||
|
out [5] += in[5]*delta + in[half_width+5]*delta2;
|
||||||
|
out [6] += in[6]*delta + in[half_width+6]*delta2;
|
||||||
|
out [7] += in[7]*delta + in[half_width+7]*delta2;
|
||||||
|
|
||||||
|
in = rev;
|
||||||
|
out [ 8] += in[7]*delta + in[7-half_width]*delta2;
|
||||||
|
out [ 9] += in[6]*delta + in[6-half_width]*delta2;
|
||||||
|
out [10] += in[5]*delta + in[5-half_width]*delta2;
|
||||||
|
out [11] += in[4]*delta + in[4-half_width]*delta2;
|
||||||
|
out [12] += in[3]*delta + in[3-half_width]*delta2;
|
||||||
|
out [13] += in[2]*delta + in[2-half_width]*delta2;
|
||||||
|
out [14] += in[1]*delta + in[1-half_width]*delta2;
|
||||||
|
out [15] += in[0]*delta + in[0-half_width]*delta2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void blip_add_delta_fast( blip_t* m, unsigned time, int delta )
|
||||||
|
{
|
||||||
|
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
|
||||||
|
buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
|
||||||
|
|
||||||
|
int interp = fixed >> (frac_bits - delta_bits) & (delta_unit - 1);
|
||||||
|
int delta2 = delta * interp;
|
||||||
|
|
||||||
|
/* Fails if buffer size was exceeded */
|
||||||
|
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
|
||||||
|
|
||||||
|
out [7] += delta * delta_unit - delta2;
|
||||||
|
out [8] += delta2;
|
||||||
|
}
|
|
@ -95,7 +95,8 @@ static int process_pickup(DUMB_RESAMPLER *resampler)
|
||||||
#define SET_VOLUME_VARIABLES SET_MONO_DEST_VOLUME_VARIABLES
|
#define SET_VOLUME_VARIABLES SET_MONO_DEST_VOLUME_VARIABLES
|
||||||
#define RETURN_VOLUME_VARIABLES RETURN_MONO_DEST_VOLUME_VARIABLES
|
#define RETURN_VOLUME_VARIABLES RETURN_MONO_DEST_VOLUME_VARIABLES
|
||||||
#define VOLUMES_ARE_ZERO MONO_DEST_VOLUMES_ARE_ZERO
|
#define VOLUMES_ARE_ZERO MONO_DEST_VOLUMES_ARE_ZERO
|
||||||
#define MIX_ALIAS(op, upd, offset) MONO_DEST_MIX_ALIAS(op, upd, offset)
|
#define MIX_ALIAS(count) MONO_DEST_MIX_ALIAS(count)
|
||||||
|
#define PEEK_ALIAS MONO_DEST_PEEK_ALIAS
|
||||||
#define MIX_LINEAR(op, upd, o0, o1) MONO_DEST_MIX_LINEAR(op, upd, o0, o1)
|
#define MIX_LINEAR(op, upd, o0, o1) MONO_DEST_MIX_LINEAR(op, upd, o0, o1)
|
||||||
#define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) MONO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3)
|
#define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) MONO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3)
|
||||||
#define MIX_ZEROS(op) *dst++ op 0
|
#define MIX_ZEROS(op) *dst++ op 0
|
||||||
|
@ -137,7 +138,8 @@ static int process_pickup(DUMB_RESAMPLER *resampler)
|
||||||
if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \
|
if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \
|
||||||
}
|
}
|
||||||
#define VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
|
#define VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
|
||||||
#define MIX_ALIAS(op, upd, offset) STEREO_DEST_MIX_ALIAS(op, upd, offset)
|
#define MIX_ALIAS(count) STEREO_DEST_MIX_ALIAS(count)
|
||||||
|
#define PEEK_ALIAS STEREO_DEST_PEEK_ALIAS
|
||||||
#define MIX_LINEAR(op, upd, o0, o1) STEREO_DEST_MIX_LINEAR(op, upd, o0, o1)
|
#define MIX_LINEAR(op, upd, o0, o1) STEREO_DEST_MIX_LINEAR(op, upd, o0, o1)
|
||||||
#define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3)
|
#define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3)
|
||||||
#define MIX_ZEROS(op) { *dst++ op 0; *dst++ op 0; }
|
#define MIX_ZEROS(op) { *dst++ op 0; *dst++ op 0; }
|
||||||
|
@ -157,6 +159,9 @@ static int process_pickup(DUMB_RESAMPLER *resampler)
|
||||||
#undef MONO_DEST_VOLUME_ZEROS
|
#undef MONO_DEST_VOLUME_ZEROS
|
||||||
#undef MONO_DEST_VOLUME_VARIABLES
|
#undef MONO_DEST_VOLUME_VARIABLES
|
||||||
#undef MONO_DEST_VOLUME_PARAMETERS
|
#undef MONO_DEST_VOLUME_PARAMETERS
|
||||||
|
#undef STEREO_DEST_PEEK_ALIAS
|
||||||
|
#undef MONO_DEST_PEEK_ALIAS
|
||||||
|
#undef POKE_ALIAS
|
||||||
#undef COPYSRC2
|
#undef COPYSRC2
|
||||||
#undef COPYSRC
|
#undef COPYSRC
|
||||||
#undef DIVIDE_BY_SRC_CHANNELS
|
#undef DIVIDE_BY_SRC_CHANNELS
|
||||||
|
|
|
@ -46,12 +46,13 @@
|
||||||
|
|
||||||
int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VOLUME_PARAMETERS, double delta)
|
int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VOLUME_PARAMETERS, double delta)
|
||||||
{
|
{
|
||||||
int dt;
|
int dt, inv_dt;
|
||||||
int VOLUME_VARIABLES;
|
int VOLUME_VARIABLES;
|
||||||
long done;
|
long done;
|
||||||
long todo;
|
long todo;
|
||||||
LONG_LONG todo64;
|
LONG_LONG todo64;
|
||||||
int quality;
|
int quality;
|
||||||
|
int blip_samples[256*SRC_CHANNELS];
|
||||||
|
|
||||||
if (!resampler || resampler->dir == 0) return 0;
|
if (!resampler || resampler->dir == 0) return 0;
|
||||||
ASSERT(resampler->dir == -1 || resampler->dir == 1);
|
ASSERT(resampler->dir == -1 || resampler->dir == 1);
|
||||||
|
@ -59,6 +60,7 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
||||||
done = 0;
|
done = 0;
|
||||||
dt = (int)(delta * 65536.0 + 0.5);
|
dt = (int)(delta * 65536.0 + 0.5);
|
||||||
if (dt == 0 || dt == 0x80000000) return 0;
|
if (dt == 0 || dt == 0x80000000) return 0;
|
||||||
|
inv_dt = (int)(1.0 / delta * 65536.0 + 0.5);
|
||||||
SET_VOLUME_VARIABLES;
|
SET_VOLUME_VARIABLES;
|
||||||
|
|
||||||
if (VOLUMES_ARE_ZERO) dst = NULL;
|
if (VOLUMES_ARE_ZERO) dst = NULL;
|
||||||
|
@ -104,29 +106,34 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
||||||
subpos = (long)new_subpos & 65535;
|
subpos = (long)new_subpos & 65535;
|
||||||
} else if (quality <= DUMB_RQ_ALIASING) {
|
} else if (quality <= DUMB_RQ_ALIASING) {
|
||||||
/* Aliasing, backwards */
|
/* Aliasing, backwards */
|
||||||
|
int todo_clocks = todo << 16, todo_clocks_set = todo_clocks;
|
||||||
SRCTYPE xbuf[2*SRC_CHANNELS];
|
SRCTYPE xbuf[2*SRC_CHANNELS];
|
||||||
SRCTYPE *x = &xbuf[0];
|
SRCTYPE *x = &xbuf[0];
|
||||||
SRCTYPE *xstart;
|
|
||||||
COPYSRC(xbuf, 0, resampler->X, 1);
|
COPYSRC(xbuf, 0, resampler->X, 1);
|
||||||
COPYSRC(xbuf, 1, resampler->X, 2);
|
COPYSRC(xbuf, 1, resampler->X, 2);
|
||||||
while (todo && x < &xbuf[2*SRC_CHANNELS]) {
|
if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536;
|
||||||
|
while (resampler->last_clock < todo_clocks_set && x < &xbuf[2*SRC_CHANNELS]) {
|
||||||
// TODO: check what happens when multiple tempo slides occur per row
|
// TODO: check what happens when multiple tempo slides occur per row
|
||||||
HEAVYASSERT(pos >= resampler->start);
|
HEAVYASSERT(pos >= resampler->start);
|
||||||
MIX_ALIAS(+=, 1, 0);
|
POKE_ALIAS(0);
|
||||||
subpos += dt;
|
pos--;
|
||||||
pos += subpos >> 16;
|
x += SRC_CHANNELS;
|
||||||
x -= (subpos >> 16) * SRC_CHANNELS;
|
|
||||||
subpos &= 65535;
|
|
||||||
todo--;
|
|
||||||
}
|
}
|
||||||
x = xstart = &src[pos*SRC_CHANNELS];
|
x = &src[pos*SRC_CHANNELS];
|
||||||
|
while ( todo_clocks ) {
|
||||||
|
todo_clocks_set = todo_clocks;
|
||||||
|
if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536;
|
||||||
|
todo_clocks -= todo_clocks_set;
|
||||||
|
todo = ( todo_clocks_set - resampler->last_clock + inv_dt - 1 ) / inv_dt;
|
||||||
|
if ( todo < 0 ) todo = 0;
|
||||||
LOOP4(todo,
|
LOOP4(todo,
|
||||||
MIX_ALIAS(+=, 1, 2);
|
POKE_ALIAS(2);
|
||||||
subpos += dt;
|
pos--;
|
||||||
x += (subpos >> 16) * SRC_CHANNELS;
|
x -= SRC_CHANNELS;
|
||||||
subpos &= 65535;
|
|
||||||
);
|
);
|
||||||
pos += DIVIDE_BY_SRC_CHANNELS((long)(x - xstart));
|
todo = todo_clocks_set >> 16;
|
||||||
|
MIX_ALIAS( todo );
|
||||||
|
}
|
||||||
} else if (quality <= DUMB_RQ_LINEAR) {
|
} else if (quality <= DUMB_RQ_LINEAR) {
|
||||||
/* Linear interpolation, backwards */
|
/* Linear interpolation, backwards */
|
||||||
SRCTYPE xbuf[3*SRC_CHANNELS];
|
SRCTYPE xbuf[3*SRC_CHANNELS];
|
||||||
|
@ -205,28 +212,33 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
||||||
subpos = (long)new_subpos & 65535;
|
subpos = (long)new_subpos & 65535;
|
||||||
} else if (quality <= DUMB_RQ_ALIASING) {
|
} else if (quality <= DUMB_RQ_ALIASING) {
|
||||||
/* Aliasing, forwards */
|
/* Aliasing, forwards */
|
||||||
|
int todo_clocks = todo << 16, todo_clocks_set = todo_clocks;
|
||||||
SRCTYPE xbuf[2*SRC_CHANNELS];
|
SRCTYPE xbuf[2*SRC_CHANNELS];
|
||||||
SRCTYPE *x = &xbuf[0];
|
SRCTYPE *x = &xbuf[0];
|
||||||
SRCTYPE *xstart;
|
|
||||||
COPYSRC(xbuf, 0, resampler->X, 1);
|
COPYSRC(xbuf, 0, resampler->X, 1);
|
||||||
COPYSRC(xbuf, 1, resampler->X, 2);
|
COPYSRC(xbuf, 1, resampler->X, 2);
|
||||||
while (todo && x < &xbuf[2*SRC_CHANNELS]) {
|
if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536;
|
||||||
|
while (resampler->last_clock < todo_clocks_set && x < &xbuf[2*SRC_CHANNELS]) {
|
||||||
HEAVYASSERT(pos < resampler->end);
|
HEAVYASSERT(pos < resampler->end);
|
||||||
MIX_ALIAS(+=, 1, 0);
|
POKE_ALIAS(0);
|
||||||
subpos += dt;
|
pos++;
|
||||||
pos += subpos >> 16;
|
x += SRC_CHANNELS;
|
||||||
x += (subpos >> 16) * SRC_CHANNELS;
|
|
||||||
subpos &= 65535;
|
|
||||||
todo--;
|
|
||||||
}
|
}
|
||||||
x = xstart = &src[pos*SRC_CHANNELS];
|
x = &src[pos*SRC_CHANNELS];
|
||||||
|
while ( todo_clocks ) {
|
||||||
|
todo_clocks_set = todo_clocks;
|
||||||
|
if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536;
|
||||||
|
todo_clocks -= todo_clocks_set;
|
||||||
|
todo = ( todo_clocks_set - resampler->last_clock + inv_dt - 1 ) / inv_dt;
|
||||||
|
if ( todo < 0 ) todo = 0;
|
||||||
LOOP4(todo,
|
LOOP4(todo,
|
||||||
MIX_ALIAS(+=, 1, -2);
|
POKE_ALIAS(-2);
|
||||||
subpos += dt;
|
pos++;
|
||||||
x += (subpos >> 16) * SRC_CHANNELS;
|
x += SRC_CHANNELS;
|
||||||
subpos &= 65535;
|
|
||||||
);
|
);
|
||||||
pos += DIVIDE_BY_SRC_CHANNELS((long)(x - xstart));
|
todo = todo_clocks_set >> 16;
|
||||||
|
MIX_ALIAS( todo );
|
||||||
|
}
|
||||||
} else if (quality <= DUMB_RQ_LINEAR) {
|
} else if (quality <= DUMB_RQ_LINEAR) {
|
||||||
/* Linear interpolation, forwards */
|
/* Linear interpolation, forwards */
|
||||||
SRCTYPE xbuf[3*SRC_CHANNELS];
|
SRCTYPE xbuf[3*SRC_CHANNELS];
|
||||||
|
@ -339,7 +351,7 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE
|
||||||
HEAVYASSERT(pos >= resampler->start);
|
HEAVYASSERT(pos >= resampler->start);
|
||||||
if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
|
if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
|
||||||
/* Aliasing, backwards */
|
/* Aliasing, backwards */
|
||||||
MIX_ALIAS(=, 0, 1);
|
PEEK_ALIAS;
|
||||||
} else if (quality <= DUMB_RQ_LINEAR) {
|
} else if (quality <= DUMB_RQ_LINEAR) {
|
||||||
/* Linear interpolation, backwards */
|
/* Linear interpolation, backwards */
|
||||||
MIX_LINEAR(=, 0, 2, 1);
|
MIX_LINEAR(=, 0, 2, 1);
|
||||||
|
@ -351,7 +363,7 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE
|
||||||
HEAVYASSERT(pos < resampler->end);
|
HEAVYASSERT(pos < resampler->end);
|
||||||
if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
|
if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
|
||||||
/* Aliasing */
|
/* Aliasing */
|
||||||
MIX_ALIAS(=, 0, 1);
|
PEEK_ALIAS;
|
||||||
} else if (dumb_resampling_quality <= DUMB_RQ_LINEAR) {
|
} else if (dumb_resampling_quality <= DUMB_RQ_LINEAR) {
|
||||||
/* Linear interpolation, forwards */
|
/* Linear interpolation, forwards */
|
||||||
MIX_LINEAR(=, 0, 1, 2);
|
MIX_LINEAR(=, 0, 1, 2);
|
||||||
|
@ -368,6 +380,7 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE
|
||||||
#undef MIX_CUBIC
|
#undef MIX_CUBIC
|
||||||
#undef MIX_LINEAR
|
#undef MIX_LINEAR
|
||||||
#undef MIX_ALIAS
|
#undef MIX_ALIAS
|
||||||
|
#undef PEEK_ALIAS
|
||||||
#undef VOLUMES_ARE_ZERO
|
#undef VOLUMES_ARE_ZERO
|
||||||
#undef SET_VOLUME_VARIABLES
|
#undef SET_VOLUME_VARIABLES
|
||||||
#undef RETURN_VOLUME_VARIABLES
|
#undef RETURN_VOLUME_VARIABLES
|
||||||
|
|
|
@ -189,7 +189,7 @@ static void init_cubic(void)
|
||||||
|
|
||||||
#define SRCTYPE sample_t
|
#define SRCTYPE sample_t
|
||||||
#define SRCBITS 24
|
#define SRCBITS 24
|
||||||
#define ALIAS(x, vol) MULSC(x, vol)
|
#define ALIAS(x) (x >> 8)
|
||||||
#define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos))
|
#define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos))
|
||||||
/*
|
/*
|
||||||
#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
|
#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
|
||||||
|
@ -225,7 +225,7 @@ static void init_cubic(void)
|
||||||
#define SUFFIX _16
|
#define SUFFIX _16
|
||||||
#define SRCTYPE short
|
#define SRCTYPE short
|
||||||
#define SRCBITS 16
|
#define SRCBITS 16
|
||||||
#define ALIAS(x, vol) (x * vol >> 8)
|
#define ALIAS(x) (x)
|
||||||
#define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos))
|
#define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos))
|
||||||
/*
|
/*
|
||||||
#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
|
#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
|
||||||
|
@ -247,7 +247,7 @@ static void init_cubic(void)
|
||||||
#define SUFFIX _8
|
#define SUFFIX _8
|
||||||
#define SRCTYPE signed char
|
#define SRCTYPE signed char
|
||||||
#define SRCBITS 8
|
#define SRCBITS 8
|
||||||
#define ALIAS(x, vol) (x * vol)
|
#define ALIAS(x) (x << 8)
|
||||||
#define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos)
|
#define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos)
|
||||||
/*
|
/*
|
||||||
#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
|
#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
|
||||||
|
|
|
@ -69,6 +69,11 @@ void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, int src_chann
|
||||||
}
|
}
|
||||||
for (i = 0; i < src_channels*3; i++) resampler->X[i] = 0;
|
for (i = 0; i < src_channels*3; i++) resampler->X[i] = 0;
|
||||||
resampler->overshot = -1;
|
resampler->overshot = -1;
|
||||||
|
resampler->last_clock = 0;
|
||||||
|
resampler->last_amp[0] = 0;
|
||||||
|
resampler->last_amp[1] = 0;
|
||||||
|
blip_clear(resampler->blip_buffer[0]);
|
||||||
|
blip_clear(resampler->blip_buffer[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,6 +82,21 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
||||||
{
|
{
|
||||||
DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler));
|
DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler));
|
||||||
if (!resampler) return NULL;
|
if (!resampler) return NULL;
|
||||||
|
resampler->blip_buffer[0] = blip_new( 256 );
|
||||||
|
if (!resampler->blip_buffer[0])
|
||||||
|
{
|
||||||
|
free(resampler);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
resampler->blip_buffer[1] = blip_new( 256 );
|
||||||
|
if (!resampler->blip_buffer[1])
|
||||||
|
{
|
||||||
|
free(resampler->blip_buffer[0]);
|
||||||
|
free(resampler);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
blip_set_rates(resampler->blip_buffer[0], 65536, 1);
|
||||||
|
blip_set_rates(resampler->blip_buffer[1], 65536, 1);
|
||||||
dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality);
|
dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality);
|
||||||
return resampler;
|
return resampler;
|
||||||
}
|
}
|
||||||
|
@ -123,16 +143,41 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
||||||
}
|
}
|
||||||
#define RETURN_MONO_DEST_VOLUME_VARIABLES if ( volume ) volume->volume = (float)volr / 16777216.0f
|
#define RETURN_MONO_DEST_VOLUME_VARIABLES if ( volume ) volume->volume = (float)volr / 16777216.0f
|
||||||
#define MONO_DEST_VOLUMES_ARE_ZERO (vol == 0 && volt == 0)
|
#define MONO_DEST_VOLUMES_ARE_ZERO (vol == 0 && volt == 0)
|
||||||
#define MONO_DEST_MIX_ALIAS(op, upd, offset) { \
|
#define POKE_ALIAS(offset) { \
|
||||||
*dst++ op ALIAS(x[offset], vol); \
|
int delta = ALIAS(x[offset]) - resampler->last_amp[0]; \
|
||||||
if ( upd ) UPDATE_VOLUME( volume, vol ); \
|
resampler->last_amp[0] += delta; \
|
||||||
|
if ( delta ) blip_add_delta( resampler->blip_buffer[0], resampler->last_clock, delta ); \
|
||||||
|
resampler->last_clock += inv_dt; \
|
||||||
}
|
}
|
||||||
#define STEREO_DEST_MIX_ALIAS(op, upd, offset) { \
|
#define MONO_DEST_PEEK_ALIAS *dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), vol )
|
||||||
int xm = x[offset]; \
|
#define MONO_DEST_MIX_ALIAS(count) { \
|
||||||
*dst++ op ALIAS(xm, lvol); \
|
int n = 0; \
|
||||||
*dst++ op ALIAS(xm, rvol); \
|
resampler->last_clock -= count * 65536; \
|
||||||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \
|
||||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \
|
||||||
|
LOOP4( count, \
|
||||||
|
*dst++ += MULSC( blip_samples[n], vol ); \
|
||||||
|
n++; \
|
||||||
|
UPDATE_VOLUME( volume, vol ); \
|
||||||
|
); \
|
||||||
|
}
|
||||||
|
#define STEREO_DEST_PEEK_ALIAS { \
|
||||||
|
int sample = blip_peek_sample( resampler->blip_buffer[0] ); \
|
||||||
|
*dst++ = MULSC( sample, lvol ); \
|
||||||
|
*dst++ = MULSC( sample, rvol ); \
|
||||||
|
}
|
||||||
|
#define STEREO_DEST_MIX_ALIAS(count) { \
|
||||||
|
int sample, n = 0; \
|
||||||
|
resampler->last_clock -= count * 65536; \
|
||||||
|
blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \
|
||||||
|
blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \
|
||||||
|
LOOP4( count, \
|
||||||
|
sample = blip_samples[n++]; \
|
||||||
|
*dst++ += MULSC( sample, lvol ); \
|
||||||
|
*dst++ += MULSC( sample, rvol ); \
|
||||||
|
UPDATE_VOLUME( volume_left, lvol ); \
|
||||||
|
UPDATE_VOLUME( volume_right, rvol ); \
|
||||||
|
); \
|
||||||
}
|
}
|
||||||
#define MONO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
|
#define MONO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
|
||||||
*dst++ op MULSC(LINEAR(x[o0], x[o1]), vol); \
|
*dst++ op MULSC(LINEAR(x[o0], x[o1]), vol); \
|
||||||
|
@ -208,16 +253,51 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
||||||
if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \
|
if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \
|
||||||
}
|
}
|
||||||
#define MONO_DEST_VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
|
#define MONO_DEST_VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
|
||||||
#define MONO_DEST_MIX_ALIAS(op, upd, offset) { \
|
#define POKE_ALIAS(offset) { \
|
||||||
*dst++ op ALIAS(x[(offset)*2], lvol) + ALIAS(x[(offset)*2+1], rvol); \
|
int deltal = ALIAS(x[(offset)*2+0]) - resampler->last_amp[0]; \
|
||||||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
int deltar = ALIAS(x[(offset)*2+1]) - resampler->last_amp[1]; \
|
||||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
resampler->last_amp[0] += deltal; \
|
||||||
|
resampler->last_amp[1] += deltar; \
|
||||||
|
if ( deltal ) blip_add_delta( resampler->blip_buffer[0], resampler->last_clock, deltal ); \
|
||||||
|
if ( deltar ) blip_add_delta( resampler->blip_buffer[1], resampler->last_clock, deltar ); \
|
||||||
|
resampler->last_clock += inv_dt; \
|
||||||
}
|
}
|
||||||
#define STEREO_DEST_MIX_ALIAS(op, upd, offset) { \
|
#define MONO_DEST_PEEK_ALIAS { \
|
||||||
*dst++ op ALIAS(x[(offset)*2], lvol); \
|
*dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ) + \
|
||||||
*dst++ op ALIAS(x[(offset)*2+1], rvol); \
|
MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \
|
||||||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
}
|
||||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
#define MONO_DEST_MIX_ALIAS(count) { \
|
||||||
|
int n = 0; \
|
||||||
|
resampler->last_clock -= count * 65536; \
|
||||||
|
blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \
|
||||||
|
blip_end_frame( resampler->blip_buffer[1], count * 65536 ); \
|
||||||
|
blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \
|
||||||
|
blip_read_samples( resampler->blip_buffer[1], blip_samples + 256, count ); \
|
||||||
|
LOOP4( count, \
|
||||||
|
*dst++ += MULSC( blip_samples[n], lvol ) + MULSC( blip_samples[256+n], rvol ); \
|
||||||
|
n++; \
|
||||||
|
UPDATE_VOLUME( volume_left, lvol ); \
|
||||||
|
UPDATE_VOLUME( volume_right, rvol ); \
|
||||||
|
); \
|
||||||
|
}
|
||||||
|
#define STEREO_DEST_PEEK_ALIAS { \
|
||||||
|
*dst++ = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ); \
|
||||||
|
*dst++ = MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \
|
||||||
|
}
|
||||||
|
#define STEREO_DEST_MIX_ALIAS(count) { \
|
||||||
|
int n = 0; \
|
||||||
|
resampler->last_clock -= count * 65536; \
|
||||||
|
blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \
|
||||||
|
blip_end_frame( resampler->blip_buffer[1], count * 65536 ); \
|
||||||
|
blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \
|
||||||
|
blip_read_samples( resampler->blip_buffer[1], blip_samples + 256, count ); \
|
||||||
|
LOOP4( count, \
|
||||||
|
*dst++ += MULSC( blip_samples[n], lvol); \
|
||||||
|
*dst++ += MULSC( blip_samples[256+n], rvol); \
|
||||||
|
n++; \
|
||||||
|
UPDATE_VOLUME( volume_left, lvol ); \
|
||||||
|
UPDATE_VOLUME( volume_right, rvol ); \
|
||||||
|
); \
|
||||||
}
|
}
|
||||||
#define MONO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
|
#define MONO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
|
||||||
*dst++ op MULSC(LINEAR(x[(o0)*2], x[(o1)*2]), lvol) + MULSC(LINEAR(x[(o0)*2+1], x[(o1)*2+1]), rvol); \
|
*dst++ op MULSC(LINEAR(x[(o0)*2], x[(o1)*2]), lvol) + MULSC(LINEAR(x[(o0)*2+1], x[(o1)*2+1]), rvol); \
|
||||||
|
|
|
@ -29,15 +29,38 @@
|
||||||
#define END_RAMPING
|
#define END_RAMPING
|
||||||
#define RAMP_DOWN
|
#define RAMP_DOWN
|
||||||
|
|
||||||
static IT_PLAYING *alloc_playing(DUMB_IT_SIGRENDERER *itsr)
|
static IT_PLAYING *new_playing(DUMB_IT_SIGRENDERER *itsr)
|
||||||
{
|
{
|
||||||
|
IT_PLAYING *r;
|
||||||
|
|
||||||
if (itsr->free_playing != NULL)
|
if (itsr->free_playing != NULL)
|
||||||
{
|
{
|
||||||
IT_PLAYING *pl = itsr->free_playing;
|
r = itsr->free_playing;
|
||||||
itsr->free_playing = pl->next;
|
itsr->free_playing = r->next;
|
||||||
return pl;
|
blip_clear(r->resampler.blip_buffer[0]);
|
||||||
|
blip_clear(r->resampler.blip_buffer[1]);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
return (IT_PLAYING *)malloc(sizeof(IT_PLAYING));
|
r = (IT_PLAYING *)malloc(sizeof(IT_PLAYING));
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
r->resampler.blip_buffer[0] = blip_new( 256 );
|
||||||
|
if ( !r->resampler.blip_buffer[0] )
|
||||||
|
{
|
||||||
|
free( r );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
r->resampler.blip_buffer[1] = blip_new( 256 );
|
||||||
|
if ( !r->resampler.blip_buffer[1] )
|
||||||
|
{
|
||||||
|
free( r->resampler.blip_buffer[0] );
|
||||||
|
free( r );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
blip_set_rates(r->resampler.blip_buffer[0], 65536, 1);
|
||||||
|
blip_set_rates(r->resampler.blip_buffer[1], 65536, 1);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_playing(DUMB_IT_SIGRENDERER *itsr, IT_PLAYING *playing)
|
static void free_playing(DUMB_IT_SIGRENDERER *itsr, IT_PLAYING *playing)
|
||||||
|
@ -46,6 +69,13 @@ static void free_playing(DUMB_IT_SIGRENDERER *itsr, IT_PLAYING *playing)
|
||||||
itsr->free_playing = playing;
|
itsr->free_playing = playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_playing_orig(IT_PLAYING * r)
|
||||||
|
{
|
||||||
|
blip_delete( r->resampler.blip_buffer[1] );
|
||||||
|
blip_delete( r->resampler.blip_buffer[0] );
|
||||||
|
free( r );
|
||||||
|
}
|
||||||
|
|
||||||
static IT_PLAYING *dup_playing(IT_PLAYING *src, IT_CHANNEL *dstchannel, IT_CHANNEL *srcchannel)
|
static IT_PLAYING *dup_playing(IT_PLAYING *src, IT_CHANNEL *dstchannel, IT_CHANNEL *srcchannel)
|
||||||
{
|
{
|
||||||
IT_PLAYING *dst;
|
IT_PLAYING *dst;
|
||||||
|
@ -135,6 +165,19 @@ static IT_PLAYING *dup_playing(IT_PLAYING *src, IT_CHANNEL *dstchannel, IT_CHANN
|
||||||
|
|
||||||
dst->resampler = src->resampler;
|
dst->resampler = src->resampler;
|
||||||
dst->resampler.pickup_data = dst;
|
dst->resampler.pickup_data = dst;
|
||||||
|
dst->resampler.blip_buffer[0] = blip_dup( dst->resampler.blip_buffer[0] );
|
||||||
|
if ( !dst->resampler.blip_buffer[0] )
|
||||||
|
{
|
||||||
|
free( dst );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
dst->resampler.blip_buffer[1] = blip_dup( dst->resampler.blip_buffer[1] );
|
||||||
|
if ( !dst->resampler.blip_buffer[1] )
|
||||||
|
{
|
||||||
|
blip_delete( dst->resampler.blip_buffer[0] );
|
||||||
|
free( dst );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
dst->time_lost = src->time_lost;
|
dst->time_lost = src->time_lost;
|
||||||
|
|
||||||
//dst->output = src->output;
|
//dst->output = src->output;
|
||||||
|
@ -1582,7 +1625,7 @@ static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *chan
|
||||||
if (channel->playing)
|
if (channel->playing)
|
||||||
free_playing(sigrenderer, channel->playing);
|
free_playing(sigrenderer, channel->playing);
|
||||||
|
|
||||||
channel->playing = alloc_playing(sigrenderer);
|
channel->playing = new_playing(sigrenderer);
|
||||||
|
|
||||||
if (!channel->playing)
|
if (!channel->playing)
|
||||||
return;
|
return;
|
||||||
|
@ -2889,9 +2932,7 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent
|
||||||
{
|
{
|
||||||
DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
|
DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
|
||||||
IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
|
IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
|
||||||
IT_PLAYING playing;
|
IT_PLAYING * playing = NULL;
|
||||||
|
|
||||||
playing.sample = 0;
|
|
||||||
|
|
||||||
if (entry->mask & IT_ENTRY_INSTRUMENT) {
|
if (entry->mask & IT_ENTRY_INSTRUMENT) {
|
||||||
int oldsample = channel->sample;
|
int oldsample = channel->sample;
|
||||||
|
@ -2901,7 +2942,8 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent
|
||||||
if (channel->playing &&
|
if (channel->playing &&
|
||||||
!((entry->mask & IT_ENTRY_NOTE) && entry->note >= 120) &&
|
!((entry->mask & IT_ENTRY_NOTE) && entry->note >= 120) &&
|
||||||
!((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_XM_KEY_OFF && entry->effectvalue == 0)) {
|
!((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_XM_KEY_OFF && entry->effectvalue == 0)) {
|
||||||
playing = *channel->playing;
|
playing = dup_playing(channel->playing, channel, channel);
|
||||||
|
if (!playing) return;
|
||||||
if (!(sigdata->flags & IT_WAS_A_MOD)) {
|
if (!(sigdata->flags & IT_WAS_A_MOD)) {
|
||||||
/* Retrigger vol/pan envelopes if enabled, and cancel fadeout.
|
/* Retrigger vol/pan envelopes if enabled, and cancel fadeout.
|
||||||
* Also reset vol/pan to that of _original_ instrument.
|
* Also reset vol/pan to that of _original_ instrument.
|
||||||
|
@ -2934,12 +2976,11 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent
|
||||||
channel->playing = NULL;
|
channel->playing = NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!channel->playing) {
|
if (channel->playing) {
|
||||||
channel->playing = alloc_playing(sigrenderer);
|
free_playing(sigrenderer, channel->playing);
|
||||||
if (!channel->playing) return;
|
|
||||||
}
|
}
|
||||||
*channel->playing = playing;
|
channel->playing = playing;
|
||||||
playing.sample = (IT_SAMPLE *)-1;
|
playing = NULL;
|
||||||
channel->playing->declick_stage = 0;
|
channel->playing->declick_stage = 0;
|
||||||
channel->playing->declick_volume = 1.f / 256.f;
|
channel->playing->declick_volume = 1.f / 256.f;
|
||||||
#else
|
#else
|
||||||
|
@ -2985,7 +3026,11 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent
|
||||||
if (channel->playing) {
|
if (channel->playing) {
|
||||||
#ifdef RAMP_DOWN
|
#ifdef RAMP_DOWN
|
||||||
int i;
|
int i;
|
||||||
if (playing.sample) *channel->playing = playing;
|
if (playing) {
|
||||||
|
free_playing(sigrenderer, channel->playing);
|
||||||
|
channel->playing = playing;
|
||||||
|
playing = NULL;
|
||||||
|
}
|
||||||
for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
|
for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
|
||||||
if (!sigrenderer->playing[i]) {
|
if (!sigrenderer->playing[i]) {
|
||||||
channel->playing->declick_stage = 2;
|
channel->playing->declick_stage = 2;
|
||||||
|
@ -3003,6 +3048,7 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent
|
||||||
channel->playing = NULL;
|
channel->playing = NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
if (playing) free_playing(sigrenderer, playing);
|
||||||
return;
|
return;
|
||||||
} else if (channel->playing && (entry->mask & IT_ENTRY_VOLPAN) && ((entry->volpan>>4) == 0xF)) {
|
} else if (channel->playing && (entry->mask & IT_ENTRY_VOLPAN) && ((entry->volpan>>4) == 0xF)) {
|
||||||
/* Don't retrigger note; portamento in the volume column. */
|
/* Don't retrigger note; portamento in the volume column. */
|
||||||
|
@ -3015,20 +3061,26 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent
|
||||||
channel->destnote = IT_NOTE_OFF;
|
channel->destnote = IT_NOTE_OFF;
|
||||||
|
|
||||||
if (!channel->playing) {
|
if (!channel->playing) {
|
||||||
channel->playing = alloc_playing(sigrenderer);
|
channel->playing = new_playing(sigrenderer);
|
||||||
if (!channel->playing)
|
if (!channel->playing) {
|
||||||
|
if (playing) free_playing(sigrenderer, playing);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
// Adding the following seems to do the trick for the case where a piece starts with an instrument alone and then some notes alone.
|
// Adding the following seems to do the trick for the case where a piece starts with an instrument alone and then some notes alone.
|
||||||
retrigger_xm_envelopes(channel->playing);
|
retrigger_xm_envelopes(channel->playing);
|
||||||
}
|
}
|
||||||
#ifdef RAMP_DOWN
|
#ifdef RAMP_DOWN
|
||||||
else if (playing.sample != (IT_SAMPLE *)-1) {
|
else if (playing) {
|
||||||
/* volume rampy stuff! move note to NNA */
|
/* volume rampy stuff! move note to NNA */
|
||||||
int i;
|
int i;
|
||||||
IT_PLAYING * ptemp = alloc_playing(sigrenderer);
|
IT_PLAYING * ptemp;
|
||||||
if (!ptemp) return;
|
if (playing->sample) ptemp = playing;
|
||||||
if (playing.sample) *ptemp = playing;
|
else ptemp = channel->playing;
|
||||||
else *ptemp = *channel->playing;
|
if (!ptemp) {
|
||||||
|
if (playing) free_playing(sigrenderer, playing);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
playing = NULL;
|
||||||
for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
|
for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
|
||||||
if (!sigrenderer->playing[i]) {
|
if (!sigrenderer->playing[i]) {
|
||||||
ptemp->declick_stage = 2;
|
ptemp->declick_stage = 2;
|
||||||
|
@ -3189,6 +3241,8 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (playing) free_playing(sigrenderer, playing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5165,7 +5219,7 @@ void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer)
|
||||||
|
|
||||||
for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
|
for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
|
||||||
if (sigrenderer->channel[i].playing)
|
if (sigrenderer->channel[i].playing)
|
||||||
free(sigrenderer->channel[i].playing);
|
free_playing_orig(sigrenderer->channel[i].playing);
|
||||||
#ifdef BIT_ARRAY_BULLSHIT
|
#ifdef BIT_ARRAY_BULLSHIT
|
||||||
bit_array_destroy(sigrenderer->channel[i].played_patjump);
|
bit_array_destroy(sigrenderer->channel[i].played_patjump);
|
||||||
#endif
|
#endif
|
||||||
|
@ -5173,12 +5227,12 @@ void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer)
|
||||||
|
|
||||||
for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++)
|
for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++)
|
||||||
if (sigrenderer->playing[i])
|
if (sigrenderer->playing[i])
|
||||||
free(sigrenderer->playing[i]);
|
free_playing_orig(sigrenderer->playing[i]);
|
||||||
|
|
||||||
for (playing = sigrenderer->free_playing; playing != NULL; playing = next)
|
for (playing = sigrenderer->free_playing; playing != NULL; playing = next)
|
||||||
{
|
{
|
||||||
next = playing->next;
|
next = playing->next;
|
||||||
free(playing);
|
free_playing_orig(playing);
|
||||||
}
|
}
|
||||||
|
|
||||||
dumb_destroy_click_remover_array(sigrenderer->n_channels, sigrenderer->click_remover);
|
dumb_destroy_click_remover_array(sigrenderer->n_channels, sigrenderer->click_remover);
|
||||||
|
|
|
@ -877,6 +877,10 @@
|
||||||
RelativePath="..\..\src\helpers\barray.c"
|
RelativePath="..\..\src\helpers\barray.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\helpers\blip_buf.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\helpers\clickrem.c"
|
RelativePath="..\..\src\helpers\clickrem.c"
|
||||||
>
|
>
|
||||||
|
@ -1960,6 +1964,10 @@
|
||||||
<Filter
|
<Filter
|
||||||
Name="internal"
|
Name="internal"
|
||||||
>
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\include\internal\blip_buf.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\include\internal\dumb.h"
|
RelativePath="..\..\include\internal\dumb.h"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in a new issue