diff --git a/Frameworks/Dumb/Dumb.xcodeproj/project.pbxproj b/Frameworks/Dumb/Dumb.xcodeproj/project.pbxproj index f0a289fff..792ca95d1 100644 --- a/Frameworks/Dumb/Dumb.xcodeproj/project.pbxproj +++ b/Frameworks/Dumb/Dumb.xcodeproj/project.pbxproj @@ -102,6 +102,8 @@ 8370B68A17F61038001A4D7A /* readstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B66117F61038001A4D7A /* readstm.c */; }; 8370B68B17F61038001A4D7A /* readstm2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B66217F61038001A4D7A /* readstm2.c */; }; 8370B7EA17F62A40001A4D7A /* lanczos_resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 8370B7E817F62A40001A4D7A /* lanczos_resampler.h */; }; + 83C8DF1D18C6B31400750AF7 /* blip_buf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8DF1C18C6B31400750AF7 /* blip_buf.c */; }; + 83C8DF1F18C6B32100750AF7 /* blip_buf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8DF1E18C6B32100750AF7 /* blip_buf.h */; }; 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; }; /* End PBXBuildFile section */ @@ -209,6 +211,8 @@ 8370B66117F61038001A4D7A /* readstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = readstm.c; sourceTree = ""; }; 8370B66217F61038001A4D7A /* readstm2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = readstm2.c; sourceTree = ""; }; 8370B7E817F62A40001A4D7A /* lanczos_resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lanczos_resampler.h; sourceTree = ""; }; + 83C8DF1C18C6B31400750AF7 /* blip_buf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blip_buf.c; sourceTree = ""; }; + 83C8DF1E18C6B32100750AF7 /* blip_buf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blip_buf.h; sourceTree = ""; }; 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 8DC2EF5B0486A6940098B216 /* Dumb.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dumb.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D2F7E79907B2D74100F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; @@ -303,6 +307,7 @@ 17C8F60D0CBEE797008D969D /* internal */ = { isa = PBXGroup; children = ( + 83C8DF1E18C6B32100750AF7 /* blip_buf.h */, 8370B7E817F62A40001A4D7A /* lanczos_resampler.h */, 8370B61E17F60FE2001A4D7A /* barray.h */, 8370B62017F60FE2001A4D7A /* dumbfile.h */, @@ -349,6 +354,7 @@ 17C8F61E0CBEE797008D969D /* helpers */ = { isa = PBXGroup; children = ( + 83C8DF1C18C6B31400750AF7 /* blip_buf.c */, 8370B62E17F61001001A4D7A /* barray.c */, 8370B63017F61001001A4D7A /* lanczos_resampler.c */, 8370B63117F61001001A4D7A /* lpc.c */, @@ -444,6 +450,7 @@ buildActionMask = 2147483647; files = ( 8370B62D17F60FE2001A4D7A /* tarray.h in Headers */, + 83C8DF1F18C6B32100750AF7 /* blip_buf.h in Headers */, 8370B62617F60FE2001A4D7A /* barray.h in Headers */, 17C8F63E0CBEE797008D969D /* dumb.h in Headers */, 17C8F6400CBEE797008D969D /* it.h in Headers */, @@ -581,6 +588,7 @@ 17C8F6620CBEE797008D969D /* loadxm.c in Sources */, 17C8F6630CBEE797008D969D /* loadxm2.c in Sources */, 8370B67117F61038001A4D7A /* loadpsm.c in Sources */, + 83C8DF1D18C6B31400750AF7 /* blip_buf.c in Sources */, 8370B67617F61038001A4D7A /* loadriff2.c in Sources */, 8370B66C17F61038001A4D7A /* loadmtm2.c in Sources */, 8370B67A17F61038001A4D7A /* read669.c in Sources */, diff --git a/Frameworks/Dumb/dumb/include/dumb.h b/Frameworks/Dumb/dumb/include/dumb.h index c952d8b8a..32274ba5f 100644 --- a/Frameworks/Dumb/dumb/include/dumb.h +++ b/Frameworks/Dumb/dumb/include/dumb.h @@ -679,6 +679,11 @@ typedef struct DUMB_VOLUME_RAMP_INFO DUMB_VOLUME_RAMP_INFO; typedef void (*DUMB_RESAMPLE_PICKUP)(DUMB_RESAMPLER *resampler, void *data); +#ifndef BLIP_T_DEFINED +#define BLIP_T_DEFINED +typedef struct blip_t blip_t; +#endif + struct DUMB_RESAMPLER { void *src; @@ -696,6 +701,9 @@ struct DUMB_RESAMPLER signed char x8[3*2]; } x; int overshot; + int last_clock; + int last_amp[2]; + blip_t* blip_buffer[2]; double fir_resampler_ratio; void* fir_resampler[2]; }; diff --git a/Frameworks/Dumb/dumb/include/internal/blip_buf.h b/Frameworks/Dumb/dumb/include/internal/blip_buf.h new file mode 100644 index 000000000..6bf37836e --- /dev/null +++ b/Frameworks/Dumb/dumb/include/internal/blip_buf.h @@ -0,0 +1,80 @@ +/** \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. */ +#ifndef BLIP_T_DEFINED +#define BLIP_T_DEFINED +typedef struct blip_t blip_t; +#endif + +/** 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 diff --git a/Frameworks/Dumb/dumb/src/helpers/blip_buf.c b/Frameworks/Dumb/dumb/src/helpers/blip_buf.c new file mode 100644 index 000000000..9f26f71cb --- /dev/null +++ b/Frameworks/Dumb/dumb/src/helpers/blip_buf.c @@ -0,0 +1,354 @@ +/* blip_buf 1.1.0. http://www.slack.net/~ant/ */ + +#include "internal/blip_buf.h" + +#include +#include +#include +#include + +/* 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 (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 += 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; +} diff --git a/Frameworks/Dumb/dumb/src/helpers/resamp2.inc b/Frameworks/Dumb/dumb/src/helpers/resamp2.inc index c032ba160..b343d23b2 100644 --- a/Frameworks/Dumb/dumb/src/helpers/resamp2.inc +++ b/Frameworks/Dumb/dumb/src/helpers/resamp2.inc @@ -94,6 +94,8 @@ static int process_pickup(DUMB_RESAMPLER *resampler) #define SET_VOLUME_VARIABLES SET_MONO_DEST_VOLUME_VARIABLES #define RETURN_VOLUME_VARIABLES RETURN_MONO_DEST_VOLUME_VARIABLES #define VOLUMES_ARE_ZERO MONO_DEST_VOLUMES_ARE_ZERO +#define MIX_ALIAS(count) MONO_DEST_MIX_ALIAS(count) +#define PEEK_ALIAS MONO_DEST_PEEK_ALIAS #define PEEK_FIR MONO_DEST_PEEK_FIR #define MIX_FIR MONO_DEST_MIX_FIR #define MIX_LINEAR(op, upd, o0, o1) MONO_DEST_MIX_LINEAR(op, upd, o0, o1) @@ -138,6 +140,8 @@ static int process_pickup(DUMB_RESAMPLER *resampler) if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \ } #define VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0) +#define MIX_ALIAS(count) STEREO_DEST_MIX_ALIAS(count) +#define PEEK_ALIAS STEREO_DEST_PEEK_ALIAS #define PEEK_FIR STEREO_DEST_PEEK_FIR #define MIX_FIR STEREO_DEST_MIX_FIR #define MIX_LINEAR(op, upd, o0, o1) STEREO_DEST_MIX_LINEAR(op, upd, o0, o1) @@ -151,12 +155,17 @@ static int process_pickup(DUMB_RESAMPLER *resampler) #undef MONO_DEST_MIX_CUBIC #undef STEREO_DEST_MIX_LINEAR #undef MONO_DEST_MIX_LINEAR +#undef STEREO_DEST_MIX_ALIAS +#undef MONO_DEST_MIX_ALIAS #undef MONO_DEST_VOLUMES_ARE_ZERO #undef SET_MONO_DEST_VOLUME_VARIABLES #undef RETURN_MONO_DEST_VOLUME_VARIABLES #undef MONO_DEST_VOLUME_ZEROS #undef MONO_DEST_VOLUME_VARIABLES #undef MONO_DEST_VOLUME_PARAMETERS +#undef STEREO_DEST_PEEK_ALIAS +#undef MONO_DEST_PEEK_ALIAS +#undef POKE_ALIAS #undef MONO_DEST_PEEK_FIR #undef STEREO_DEST_PEEK_FIR #undef MONO_DEST_MIX_FIR diff --git a/Frameworks/Dumb/dumb/src/helpers/resamp3.inc b/Frameworks/Dumb/dumb/src/helpers/resamp3.inc index 199cb57b5..a60ed131f 100644 --- a/Frameworks/Dumb/dumb/src/helpers/resamp3.inc +++ b/Frameworks/Dumb/dumb/src/helpers/resamp3.inc @@ -52,6 +52,8 @@ long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLU long todo; LONG_LONG todo64; int quality; + int blip_samples[256*SRC_CHANNELS]; + int check; if (!resampler || resampler->dir == 0) return 0; ASSERT(resampler->dir == -1 || resampler->dir == 1); @@ -105,29 +107,39 @@ long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLU subpos = (long)new_subpos & 65535; } else if (quality <= DUMB_RQ_ALIASING) { /* Aliasing, backwards */ - SRCTYPE *x; - if ( resampler->fir_resampler_ratio != delta ) { - lanczos_resampler_set_rate( resampler->fir_resampler[0], delta * 32.0 ); - lanczos_resampler_set_rate( resampler->fir_resampler[1], delta * 32.0 ); - resampler->fir_resampler_ratio = delta; + int todo_clocks = todo << 16, todo_clocks_set = todo_clocks; + SRCTYPE xbuf[2*SRC_CHANNELS]; + SRCTYPE *x = &xbuf[0]; + check = resampler->start; + COPYSRC(xbuf, 0, resampler->X, 1); + COPYSRC(xbuf, 1, resampler->X, 2); + 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 + HEAVYASSERT(pos >= resampler->start); + POKE_ALIAS(0); + pos--; + x += SRC_CHANNELS; } x = &src[pos*SRC_CHANNELS]; - while ( todo ) { - while ( lanczos_resampler_get_free_count( resampler->fir_resampler[0] ) && - pos >= resampler->start ) { - POKE_FIR(0); - if ( ( subpos -= 2048 ) < 0 ) { - pos--; - x -= SRC_CHANNELS; - subpos += 65536; - } + while ( todo_clocks ) { + todo_clocks_set = todo_clocks; + if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536; + todo_clocks -= todo_clocks_set; + while ( resampler->last_clock < todo_clocks_set && pos >= check ) { + POKE_ALIAS(2); + pos--; + x -= SRC_CHANNELS; } - if ( !lanczos_resampler_get_sample_count( resampler->fir_resampler[0] ) ) break; - MIX_FIR; - ADVANCE_FIR; - --todo; + todo = todo_clocks_set >> 16; + check = 0; + if ( resampler->last_clock < todo_clocks_set ) { + check = ( todo_clocks_set - resampler->last_clock + 65535 ) >> 16; + } + todo -= check; + MIX_ALIAS( todo ); + done -= check; } - done -= todo; } else if (quality <= DUMB_RQ_LINEAR) { /* Linear interpolation, backwards */ SRCTYPE xbuf[3*SRC_CHANNELS]; @@ -182,29 +194,30 @@ long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLU x += (subpos >> 16) * SRC_CHANNELS; subpos &= 65535; ); - } else { - /* FIR resampling, backwards */ - SRCTYPE *x; - if ( resampler->fir_resampler_ratio != delta ) { - lanczos_resampler_set_rate( resampler->fir_resampler[0], delta ); - lanczos_resampler_set_rate( resampler->fir_resampler[1], delta ); - resampler->fir_resampler_ratio = delta; - } - x = &src[pos*SRC_CHANNELS]; - while ( todo ) { - while ( lanczos_resampler_get_free_count( resampler->fir_resampler[0] ) && - pos >= resampler->start ) { - POKE_FIR(0); - pos--; - x -= SRC_CHANNELS; - } - if ( !lanczos_resampler_get_sample_count( resampler->fir_resampler[0] ) ) break; - MIX_FIR; - ADVANCE_FIR; - --todo; - } - done -= todo; - } + } else { + /* FIR resampling, backwards */ + SRCTYPE *x; + if ( resampler->fir_resampler_ratio != delta ) { + lanczos_resampler_set_rate( resampler->fir_resampler[0], delta ); + lanczos_resampler_set_rate( resampler->fir_resampler[1], delta ); + resampler->fir_resampler_ratio = delta; + } + x = &src[pos*SRC_CHANNELS]; + while ( todo ) { + while ( lanczos_resampler_get_free_count( resampler->fir_resampler[0] ) && + pos >= resampler->start ) + { + POKE_FIR(0); + pos--; + x -= SRC_CHANNELS; + } + if ( !lanczos_resampler_get_sample_count( resampler->fir_resampler[0] ) ) break; + MIX_FIR; + ADVANCE_FIR; + --todo; + } + done -= todo; + } diff = diff - pos; overshot = resampler->start - pos - 1; if (diff >= 3) { @@ -228,29 +241,38 @@ long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLU subpos = (long)new_subpos & 65535; } else if (quality <= DUMB_RQ_ALIASING) { /* Aliasing, forwards */ - SRCTYPE *x; - if ( resampler->fir_resampler_ratio != delta ) { - lanczos_resampler_set_rate( resampler->fir_resampler[0], delta * 32.0 ); - lanczos_resampler_set_rate( resampler->fir_resampler[1], delta * 32.0 ); - resampler->fir_resampler_ratio = delta; + int todo_clocks = todo << 16, todo_clocks_set = todo_clocks; + SRCTYPE xbuf[2*SRC_CHANNELS]; + SRCTYPE *x = &xbuf[0]; + check = resampler->end; + COPYSRC(xbuf, 0, resampler->X, 1); + COPYSRC(xbuf, 1, resampler->X, 2); + 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); + POKE_ALIAS(0); + pos++; + x += SRC_CHANNELS; } x = &src[pos*SRC_CHANNELS]; - while ( todo ) { - while ( lanczos_resampler_get_free_count( resampler->fir_resampler[0] ) && - pos < resampler->end ) { - POKE_FIR(0); - if ( ( subpos += 2048 ) >= 65536 ) { - pos++; - x += SRC_CHANNELS; - subpos -= 65536; - } + while ( todo_clocks ) { + todo_clocks_set = todo_clocks; + if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536; + todo_clocks -= todo_clocks_set; + while ( resampler->last_clock < todo_clocks_set && pos < check ) { + POKE_ALIAS(-2); + pos++; + x += SRC_CHANNELS; } - if ( !lanczos_resampler_get_sample_count( resampler->fir_resampler[0] ) ) break; - MIX_FIR; - ADVANCE_FIR; - --todo; + todo = todo_clocks_set >> 16; + check = 0; + if ( resampler->last_clock < todo_clocks_set ) { + check = ( todo_clocks_set - resampler->last_clock + 65535 ) >> 16; + } + todo -= check; + MIX_ALIAS( todo ); + done -= check; } - done -= todo; } else if (quality <= DUMB_RQ_LINEAR) { /* Linear interpolation, forwards */ SRCTYPE xbuf[3*SRC_CHANNELS]; @@ -304,29 +326,30 @@ long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLU x += (subpos >> 16) * SRC_CHANNELS; subpos &= 65535; ); - } else { - /* FIR resampling, forwards */ - SRCTYPE *x; - if ( resampler->fir_resampler_ratio != delta ) { - lanczos_resampler_set_rate( resampler->fir_resampler[0], delta ); - lanczos_resampler_set_rate( resampler->fir_resampler[1], delta ); - resampler->fir_resampler_ratio = delta; - } - x = &src[pos*SRC_CHANNELS]; - while ( todo ) { - while ( lanczos_resampler_get_free_count( resampler->fir_resampler[0] ) && - pos < resampler->end ) { - POKE_FIR(0); - pos++; - x += SRC_CHANNELS; - } - if ( !lanczos_resampler_get_sample_count( resampler->fir_resampler[0] ) ) break; - MIX_FIR; - ADVANCE_FIR; - --todo; - } - done -= todo; - } + } else { + /* FIR resampling, forwards */ + SRCTYPE *x; + if ( resampler->fir_resampler_ratio != delta ) { + lanczos_resampler_set_rate( resampler->fir_resampler[0], delta ); + lanczos_resampler_set_rate( resampler->fir_resampler[1], delta ); + resampler->fir_resampler_ratio = delta; + } + x = &src[pos*SRC_CHANNELS]; + while ( todo ) { + while ( lanczos_resampler_get_free_count( resampler->fir_resampler[0] ) && + pos < resampler->end ) + { + POKE_FIR(0); + pos++; + x += SRC_CHANNELS; + } + if ( !lanczos_resampler_get_sample_count( resampler->fir_resampler[0] ) ) break; + MIX_FIR; + ADVANCE_FIR; + --todo; + } + done -= todo; + } diff = pos - diff; overshot = pos - resampler->end; if (diff >= 3) { @@ -385,32 +408,32 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE HEAVYASSERT(pos >= resampler->start); if (quality <= DUMB_RQ_ALIASING) { /* Aliasing, backwards */ - PEEK_FIR; + PEEK_ALIAS; } else if (quality <= DUMB_RQ_LINEAR) { /* Linear interpolation, backwards */ MIX_LINEAR(=, 0, 2, 1); - } else if (quality <= DUMB_RQ_CUBIC) { + } else if (quality <= DUMB_RQ_CUBIC) { /* Cubic interpolation, backwards */ MIX_CUBIC(=, 0, src, x, pos, 2, 1, 0); - } else { - /* FIR resampling, backwards */ - PEEK_FIR; - } + } else { + /* FIR resampling, backwards */ + PEEK_FIR; + } } else { HEAVYASSERT(pos < resampler->end); if (quality <= DUMB_RQ_ALIASING) { /* Aliasing */ - PEEK_FIR; + PEEK_ALIAS; } else if (quality <= DUMB_RQ_LINEAR) { /* Linear interpolation, forwards */ MIX_LINEAR(=, 0, 1, 2); - } else if (quality <= DUMB_RQ_CUBIC) { + } else if (quality <= DUMB_RQ_CUBIC) { /* Cubic interpolation, forwards */ MIX_CUBIC(=, 0, x, src, 0, 1, 2, pos); - } else { - /* FIR resampling, forwards */ - PEEK_FIR; - } + } else { + /* FIR resampling, forwards */ + PEEK_FIR; + } } } @@ -419,7 +442,9 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE #undef MIX_ZEROS #undef MIX_CUBIC #undef MIX_LINEAR +#undef MIX_ALIAS #undef MIX_FIR +#undef PEEK_ALIAS #undef PEEK_FIR #undef VOLUMES_ARE_ZERO #undef SET_VOLUME_VARIABLES diff --git a/Frameworks/Dumb/dumb/src/helpers/resample.c b/Frameworks/Dumb/dumb/src/helpers/resample.c index 0bf573509..7c7ecb363 100644 --- a/Frameworks/Dumb/dumb/src/helpers/resample.c +++ b/Frameworks/Dumb/dumb/src/helpers/resample.c @@ -45,6 +45,7 @@ #include #include "dumb.h" +#include "internal/blip_buf.h" #include "internal/lanczos_resampler.h" @@ -190,6 +191,7 @@ void _dumb_init_cubic(void) #define SRCTYPE sample_t #define SRCBITS 24 +#define ALIAS(x) (x >> 8) #define FIR(x) (x >> 8) #define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos)) /* @@ -226,6 +228,7 @@ void _dumb_init_cubic(void) #define SUFFIX _16 #define SRCTYPE short #define SRCBITS 16 +#define ALIAS(x) (x) #define FIR(x) (x) #define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos)) /* @@ -248,6 +251,7 @@ void _dumb_init_cubic(void) #define SUFFIX _8 #define SRCTYPE signed char #define SRCBITS 8 +#define ALIAS(x) (x << 8) #define FIR(x) (x << 8) #define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos) /* diff --git a/Frameworks/Dumb/dumb/src/helpers/resample.inc b/Frameworks/Dumb/dumb/src/helpers/resample.inc index d15df7fb8..bf520559d 100644 --- a/Frameworks/Dumb/dumb/src/helpers/resample.inc +++ b/Frameworks/Dumb/dumb/src/helpers/resample.inc @@ -69,9 +69,14 @@ void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, int src_chann } for (i = 0; i < src_channels*3; i++) resampler->X[i] = 0; resampler->overshot = -1; - resampler->fir_resampler_ratio = 0; - lanczos_resampler_clear(resampler->fir_resampler[0]); - lanczos_resampler_clear(resampler->fir_resampler[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]); + resampler->fir_resampler_ratio = 0; + lanczos_resampler_clear(resampler->fir_resampler[0]); + lanczos_resampler_clear(resampler->fir_resampler[1]); } @@ -80,6 +85,21 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, l { DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler)); 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); return resampler; } @@ -128,15 +148,38 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, l } #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 POKE_ALIAS(offset) { \ + int delta = ALIAS(x[offset]) - resampler->last_amp[0]; \ + resampler->last_amp[0] += delta; \ + if ( delta ) blip_add_delta( resampler->blip_buffer[0], resampler->last_clock, delta ); \ + resampler->last_clock += inv_dt; \ +} #define POKE_FIR(offset) { \ lanczos_resampler_write_sample( resampler->fir_resampler[0], FIR(x[offset]) ); \ } +#define MONO_DEST_PEEK_ALIAS *dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), vol ) #define MONO_DEST_PEEK_FIR *dst = MULSC( lanczos_resampler_get_sample( resampler->fir_resampler[0] ), vol ) #define MONO_DEST_MIX_FIR { \ *dst++ += MULSC( lanczos_resampler_get_sample( resampler->fir_resampler[0] ), vol ); \ UPDATE_VOLUME( volume, vol ); \ } #define ADVANCE_FIR lanczos_resampler_remove_sample( resampler->fir_resampler[0] ) +#define MONO_DEST_MIX_ALIAS(count) { \ + int 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, \ + *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_PEEK_FIR { \ int sample = lanczos_resampler_get_sample( resampler->fir_resampler[0] ); \ *dst++ = MULSC( sample, lvol ); \ @@ -149,6 +192,19 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, l UPDATE_VOLUME( volume_left, lvol ); \ UPDATE_VOLUME( volume_right, 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) { \ *dst++ op MULSC(LINEAR(x[o0], x[o1]), vol); \ if ( upd ) UPDATE_VOLUME( volume, vol ); \ @@ -227,10 +283,23 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, l 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 POKE_ALIAS(offset) { \ + int deltal = ALIAS(x[(offset)*2+0]) - resampler->last_amp[0]; \ + int deltar = ALIAS(x[(offset)*2+1]) - resampler->last_amp[1]; \ + 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 POKE_FIR(offset) { \ lanczos_resampler_write_sample( resampler->fir_resampler[0], FIR(x[(offset)*2+0]) ); \ lanczos_resampler_write_sample( resampler->fir_resampler[1], FIR(x[(offset)*2+1]) ); \ } +#define MONO_DEST_PEEK_ALIAS { \ + *dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ) + \ + MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \ +} #define MONO_DEST_PEEK_FIR { \ *dst = MULSC( lanczos_resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \ MULSC( lanczos_resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ @@ -245,6 +314,24 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, l lanczos_resampler_remove_sample( resampler->fir_resampler[0] ); \ lanczos_resampler_remove_sample( resampler->fir_resampler[1] ); \ } +#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_PEEK_FIR { \ *dst++ = MULSC( lanczos_resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \ *dst++ = MULSC( lanczos_resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ @@ -255,6 +342,21 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, l UPDATE_VOLUME( volume_left, lvol ); \ UPDATE_VOLUME( volume_right, 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) { \ *dst++ op MULSC(LINEAR(x[(o0)*2], x[(o1)*2]), lvol) + MULSC(LINEAR(x[(o0)*2+1], x[(o1)*2+1]), rvol); \ if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \ @@ -294,6 +396,7 @@ void dumb_end_resampler(DUMB_RESAMPLER *resampler) #undef CUBICVOL #undef CUBIC #undef LINEAR +#undef ALIAS #undef FIR #undef SRCBITS #undef SRCTYPE diff --git a/Frameworks/Dumb/dumb/src/it/itrender.c b/Frameworks/Dumb/dumb/src/it/itrender.c index dcb894528..4dc304e3f 100644 --- a/Frameworks/Dumb/dumb/src/it/itrender.c +++ b/Frameworks/Dumb/dumb/src/it/itrender.c @@ -26,6 +26,7 @@ #include "internal/it.h" #include "internal/lpc.h" +#include "internal/blip_buf.h" #include "internal/lanczos_resampler.h" // #define BIT_ARRAY_BULLSHIT @@ -38,15 +39,34 @@ static IT_PLAYING *new_playing() IT_PLAYING * r = (IT_PLAYING*) malloc(sizeof(*r)); 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); r->resampler.fir_resampler_ratio = 0.0; r->resampler.fir_resampler[0] = lanczos_resampler_create(); if ( !r->resampler.fir_resampler[0] ) { + free( r->resampler.blip_buffer[1] ); + free( r->resampler.blip_buffer[0] ); free( r ); return NULL; } r->resampler.fir_resampler[1] = lanczos_resampler_create(); if ( !r->resampler.fir_resampler[1] ) { lanczos_resampler_delete( r->resampler.fir_resampler[0] ); + free( r->resampler.blip_buffer[1] ); + free( r->resampler.blip_buffer[0] ); free( r ); return NULL; } @@ -58,6 +78,8 @@ static void free_playing(IT_PLAYING * r) { lanczos_resampler_delete( r->resampler.fir_resampler[1] ); lanczos_resampler_delete( r->resampler.fir_resampler[0] ); + blip_delete( r->resampler.blip_buffer[1] ); + blip_delete( r->resampler.blip_buffer[0] ); free( r ); } @@ -150,15 +172,32 @@ static IT_PLAYING *dup_playing(IT_PLAYING *src, IT_CHANNEL *dstchannel, IT_CHANN dst->resampler = src->resampler; dst->resampler.pickup_data = dst; + dst->resampler.blip_buffer[0] = blip_dup( src->resampler.blip_buffer[0] ); + if ( !dst->resampler.blip_buffer[0] ) + { + free( dst ); + return NULL; + } + dst->resampler.blip_buffer[1] = blip_dup( src->resampler.blip_buffer[1] ); + if ( !dst->resampler.blip_buffer[1] ) + { + blip_delete( dst->resampler.blip_buffer[0] ); + free( dst ); + return NULL; + } dst->resampler.fir_resampler_ratio = src->resampler.fir_resampler_ratio; dst->resampler.fir_resampler[0] = lanczos_resampler_dup( src->resampler.fir_resampler[0] ); if ( !dst->resampler.fir_resampler[0] ) { + blip_delete( dst->resampler.blip_buffer[1] ); + blip_delete( dst->resampler.blip_buffer[0] ); free( dst ); return NULL; } dst->resampler.fir_resampler[1] = lanczos_resampler_dup( src->resampler.fir_resampler[1] ); if ( !dst->resampler.fir_resampler[1] ) { lanczos_resampler_delete( dst->resampler.fir_resampler[0] ); + blip_delete( dst->resampler.blip_buffer[1] ); + blip_delete( dst->resampler.blip_buffer[0] ); free( dst ); return NULL; } @@ -2569,8 +2608,11 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than end = sample->sus_loop_end; else if (sample->flags & IT_SAMPLE_LOOP) end = sample->loop_end; - else + else { end = sample->length; + if ( sigdata->flags & IT_WAS_PROCESSED && end > 64 ) // XXX bah damn LPC and edge case modules + end -= 64; + } if ((sigdata->flags & IT_WAS_A_PTM) && (sample->flags & IT_SAMPLE_16BIT)) offset >>= 1; if (offset < end) { @@ -3847,14 +3889,14 @@ static int update_it_envelope(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLA if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) { if (pe->tick > envelope->node_t[envelope->sus_loop_end]) { pe->next_node = envelope->sus_loop_start + 1; - ASSERT(pe->next_node < envelope->n_nodes); + ASSERT(pe->next_node <= envelope->n_nodes); pe->tick = envelope->node_t[envelope->sus_loop_start]; return 0; } } else if (envelope->flags & IT_ENVELOPE_LOOP_ON) { if (pe->tick > envelope->node_t[envelope->loop_end]) { pe->next_node = envelope->loop_start + 1; - ASSERT(pe->next_node < envelope->n_nodes); + ASSERT(pe->next_node <= envelope->n_nodes); pe->tick = envelope->node_t[envelope->loop_start]; return 0; }