// Internal stuff here to keep public header uncluttered // Blip_Buffer $vers #ifndef BLIP_BUFFER_IMPL2_H #define BLIP_BUFFER_IMPL2_H //// Compatibility BLARGG_DEPRECATED( int const blip_low_quality = 8; ) BLARGG_DEPRECATED( int const blip_med_quality = 8; ) BLARGG_DEPRECATED( int const blip_good_quality = 12; ) BLARGG_DEPRECATED( int const blip_high_quality = 16; ) BLARGG_DEPRECATED( int const blip_sample_max = 32767; ) // Number of bits in raw sample that covers normal output range. Less than 32 bits to give // extra amplitude range. That is, // +1 << (blip_sample_bits-1) = +1.0 // -1 << (blip_sample_bits-1) = -1.0 int const blip_sample_bits = 30; //// BLIP_READER_ //// Optimized reading from Blip_Buffer, for use in custom sample buffer or mixer // Begins reading from buffer. Name should be unique to the current {} block. #define BLIP_READER_BEGIN( name, blip_buffer ) \ const Blip_Buffer::delta_t* BLARGG_RESTRICT name##_reader_buf = (blip_buffer).read_pos();\ int name##_reader_accum = (blip_buffer).integrator() // Gets value to pass to BLIP_READER_NEXT() #define BLIP_READER_BASS( blip_buffer ) (blip_buffer).highpass_shift() // Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal // code at the cost of having no bass_freq() functionality int const blip_reader_default_bass = 9; // Current sample as 16-bit signed value #define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16)) // Current raw sample in full internal resolution #define BLIP_READER_READ_RAW( name ) (name##_reader_accum) // Advances to next sample #define BLIP_READER_NEXT( name, bass ) \ (void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass))) // Ends reading samples from buffer. The number of samples read must now be removed // using Blip_Buffer::remove_samples(). #define BLIP_READER_END( name, blip_buffer ) \ (void) ((blip_buffer).set_integrator( name##_reader_accum )) #define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset) int const blip_reader_idx_factor = sizeof (Blip_Buffer::delta_t); #define BLIP_READER_NEXT_IDX_( name, bass, idx ) {\ name##_reader_accum -= name##_reader_accum >> (bass);\ name##_reader_accum += name##_reader_buf [(idx)];\ } #define BLIP_READER_NEXT_RAW_IDX_( name, bass, idx ) {\ name##_reader_accum -= name##_reader_accum >> (bass);\ name##_reader_accum +=\ *(Blip_Buffer::delta_t const*) ((char const*) name##_reader_buf + (idx));\ } //// BLIP_CLAMP #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ defined (__x86_64__) || defined (__ia64__) || defined (__i386__) #define BLIP_X86 1 #define BLIP_CLAMP_( in ) in < -0x8000 || 0x7FFF < in #else #define BLIP_CLAMP_( in ) (blip_sample_t) in != in #endif // Clamp sample to blip_sample_t range #define BLIP_CLAMP( sample, out )\ { if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 31) ^ 0x7FFF; } //// Blip_Synth // (in >> sh & mask) * mul #define BLIP_SH_AND_MUL( in, sh, mask, mul ) \ ((int) (in) / ((1U << (sh)) / (mul)) & (unsigned) ((mask) * (mul))) // (T*) ptr + (off >> sh) #define BLIP_PTR_OFF_SH( T, ptr, off, sh ) \ ((T*) (BLIP_SH_AND_MUL( off, sh, -1, sizeof (T) ) + (char*) (ptr))) template inline void Blip_Synth::offset_resampled( blip_resampled_time_t time, int delta, Blip_Buffer* blip_buf ) const { #if BLIP_BUFFER_FAST int const half_width = 1; #else int const half_width = quality / 2; #endif Blip_Buffer::delta_t* BLARGG_RESTRICT buf = blip_buf->delta_at( time ); delta *= impl.delta_factor; int const phase_shift = BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS; int const phase = (half_width & (half_width - 1)) ? (int) BLIP_SH_AND_MUL( time, phase_shift, blip_res - 1, sizeof (coeff_t) ) * half_width : (int) BLIP_SH_AND_MUL( time, phase_shift, blip_res - 1, sizeof (coeff_t) * half_width ); #if BLIP_BUFFER_FAST int left = buf [0] + delta; // Kind of crappy, but doing shift after multiply results in overflow. // Alternate way of delaying multiply by delta_factor results in worse // sub-sample resolution. int right = (delta >> BLIP_PHASE_BITS) * phase; #if BLIP_BUFFER_NOINTERP // TODO: remove? (just a hack to see how it sounds) right = 0; #endif left -= right; right += buf [1]; buf [0] = left; buf [1] = right; #else int const fwd = -quality / 2; int const rev = fwd + quality - 2; coeff_t const* BLARGG_RESTRICT imp = (coeff_t const*) ((char const*) phases + phase); int const phase2 = phase + phase - (blip_res - 1) * half_width * sizeof (coeff_t); #define BLIP_MID_IMP imp = (coeff_t const*) ((char const*) imp - phase2); #if BLIP_MAX_QUALITY > 16 // General version for any quality if ( quality != 8 && quality != 12 && quality != 16 ) { buf += fwd; // left half for ( int n = half_width / 2; --n >= 0; ) { buf [0] += imp [0] * delta; buf [1] += imp [1] * delta; imp += 2; buf += 2; } // mirrored right half BLIP_MID_IMP for ( int n = half_width / 2; --n >= 0; ) { buf [0] += imp [-1] * delta; buf [1] += *(imp -= 2) * delta; buf += 2; } return; } #endif // Unrolled versions for qualities 8, 12, and 16 #if BLIP_X86 // This gives better code for x86 #define BLIP_ADD( out, in ) \ buf [out] += imp [in] * delta #define BLIP_FWD( i ) {\ BLIP_ADD( fwd + i, i );\ BLIP_ADD( fwd + 1 + i, i + 1 );\ } #define BLIP_REV( r ) {\ BLIP_ADD( rev - r, r + 1 );\ BLIP_ADD( rev + 1 - r, r );\ } BLIP_FWD( 0 ) BLIP_FWD( 2 ) if ( quality > 8 ) BLIP_FWD( 4 ) if ( quality > 12 ) BLIP_FWD( 6 ) BLIP_MID_IMP if ( quality > 12 ) BLIP_REV( 6 ) if ( quality > 8 ) BLIP_REV( 4 ) BLIP_REV( 2 ) BLIP_REV( 0 ) #else // Help RISC processors and simplistic compilers by reading ahead of writes #define BLIP_FWD( i ) {\ int t0 = i0 * delta + buf [fwd + i];\ int t1 = imp [i + 1] * delta + buf [fwd + 1 + i];\ i0 = imp [i + 2];\ buf [fwd + i] = t0;\ buf [fwd + 1 + i] = t1;\ } #define BLIP_REV( r ) {\ int t0 = i0 * delta + buf [rev - r];\ int t1 = imp [r] * delta + buf [rev + 1 - r];\ i0 = imp [r - 1];\ buf [rev - r] = t0;\ buf [rev + 1 - r] = t1;\ } int i0 = *imp; BLIP_FWD( 0 ) if ( quality > 8 ) BLIP_FWD( 2 ) if ( quality > 12 ) BLIP_FWD( 4 ) { int const mid = half_width - 1; int t0 = i0 * delta + buf [fwd + mid - 1]; int t1 = imp [mid] * delta + buf [fwd + mid ]; BLIP_MID_IMP i0 = imp [mid]; buf [fwd + mid - 1] = t0; buf [fwd + mid ] = t1; } if ( quality > 12 ) BLIP_REV( 6 ) if ( quality > 8 ) BLIP_REV( 4 ) BLIP_REV( 2 ) int t0 = i0 * delta + buf [rev ]; int t1 = *imp * delta + buf [rev + 1]; buf [rev ] = t0; buf [rev + 1] = t1; #endif #endif } template #if BLIP_BUFFER_FAST inline #endif void Blip_Synth::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const { offset_resampled( buf->to_fixed( t ), delta, buf ); } template #if BLIP_BUFFER_FAST inline #endif void Blip_Synth::update( blip_time_t t, int amp ) { int delta = amp - impl.last_amp; impl.last_amp = amp; offset_resampled( impl.buf->to_fixed( t ), delta, impl.buf ); } //// blip_eq_t inline blip_eq_t::blip_eq_t( double t ) : treble( t ), kaiser( 5.2 ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { } inline blip_eq_t::blip_eq_t( double t, int rf, int sr, int cf, double k ) : treble( t ), kaiser( k ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { } //// Blip_Buffer inline int Blip_Buffer::length() const { return length_; } inline int Blip_Buffer::samples_avail() const { return (int) (offset_ >> BLIP_BUFFER_ACCURACY); } inline int Blip_Buffer::sample_rate() const { return sample_rate_; } inline int Blip_Buffer::output_latency() const { return BLIP_MAX_QUALITY / 2; } inline int Blip_Buffer::clock_rate() const { return clock_rate_; } inline void Blip_Buffer::clock_rate( int cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); } inline void Blip_Buffer::remove_silence( int count ) { // fails if you try to remove more samples than available assert( count <= samples_avail() ); offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; } #endif