Path: blob/a-new-beginning/Cherry/Core/include/audio/Blip_Synth.h
2 views
1// Blip_Synth and Blip_Wave are waveform transition synthesizers for adding2// waveforms to a Blip_Buffer.34// Blip_Buffer 0.3.4. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.56#ifndef BLIP_SYNTH_H7#define BLIP_SYNTH_H89#ifndef BLIP_BUFFER_H10#include "Blip_Buffer.h"11#endif1213// Quality level. Higher levels are slower, and worse in a few cases.14// Use blip_good_quality as a starting point.15const int blip_low_quality = 1;16const int blip_med_quality = 2;17const int blip_good_quality = 3;18const int blip_high_quality = 4;1920// Blip_Synth is a transition waveform synthesizer which adds band-limited21// offsets (transitions) into a Blip_Buffer. For a simpler interface, use22// Blip_Wave (below).23//24// Range specifies the greatest expected offset that will occur. For a25// waveform that goes between +amp and -amp, range should be amp * 2 (half26// that if it only goes between +amp and 0). When range is large, a higher27// accuracy scheme is used; to force this even when range is small, pass28// the negative of range (i.e. -range).29template<int quality,int range>30class Blip_Synth {31BOOST_STATIC_ASSERT( 1 <= quality && quality <= 5 );32BOOST_STATIC_ASSERT( -32768 <= range && range <= 32767 );33enum {34abs_range = (range < 0) ? -range : range,35fine_mode = (range > 512 || range < 0),36width = (quality < 5 ? quality * 4 : Blip_Buffer::widest_impulse_),37res = 1 << blip_res_bits_,38impulse_size = width / 2 * (fine_mode + 1),39base_impulses_size = width / 2 * (res / 2 + 1),40fine_bits = (fine_mode ? (abs_range <= 64 ? 2 : abs_range <= 128 ? 3 :41abs_range <= 256 ? 4 : abs_range <= 512 ? 5 : abs_range <= 1024 ? 6 :42abs_range <= 2048 ? 7 : 8) : 0)43};44blip_pair_t_ impulses [impulse_size * res * 2 + base_impulses_size];45Blip_Impulse_ impulse;46void init() { impulse.init( impulses, width, res, fine_bits ); }47public:48Blip_Synth() { init(); }49Blip_Synth( double volume ) { init(); this->volume( volume ); }5051// Configure low-pass filter (see notes.txt). Not optimized for real-time control52void treble_eq( const blip_eq_t& eq ) { impulse.treble_eq( eq ); }5354// Set volume of a transition at amplitude 'range' by setting volume_unit55// to v / range56void volume( double v ) { impulse.volume_unit( v * (1.0 / abs_range) ); }5758// Set base volume unit of transitions, where 1.0 is a full swing between the59// positive and negative extremes. Not optimized for real-time control.60void volume_unit( double unit ) { impulse.volume_unit( unit ); }6162// Default Blip_Buffer used for output when none is specified for a given call63Blip_Buffer* output() const { return impulse.buf; }64void output( Blip_Buffer* b ) { impulse.buf = b; }6566// Add an amplitude offset (transition) with a magnitude of delta * volume_unit67// into the specified buffer (default buffer if none specified) at the68// specified source time. Delta can be positive or negative. To increase69// performance by inlining code at the call site, use offset_inline().70void offset( blip_time_t, int delta, Blip_Buffer* ) const;7172void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;73void offset_resampled( blip_resampled_time_t t, int o ) const {74offset_resampled( t, o, impulse.buf );75}76void offset( blip_time_t t, int delta ) const {77offset( t, delta, impulse.buf );78}79void offset_inline( blip_time_t time, int delta, Blip_Buffer* buf ) const {80offset_resampled( time * buf->factor_ + buf->offset_, delta, buf );81}82void offset_inline( blip_time_t time, int delta ) const {83offset_inline( time, delta, impulse.buf );84}85};8687// Blip_Wave is a synthesizer for adding a *single* waveform to a Blip_Buffer.88// A wave is built from a series of delays and new amplitudes. This provides a89// simpler interface than Blip_Synth, nothing more.90template<int quality,int range>91class Blip_Wave {92Blip_Synth<quality,range> synth;93blip_time_t time_;94int last_amp;95void init() { time_ = 0; last_amp = 0; }96public:97// Start wave at time 0 and amplitude 098Blip_Wave() { init(); }99Blip_Wave( double volume ) { init(); this->volume( volume ); }100101// See Blip_Synth for description102void volume( double v ) { synth.volume( v ); }103void volume_unit( double v ) { synth.volume_unit( v ); }104void treble_eq( const blip_eq_t& eq){ synth.treble_eq( eq ); }105Blip_Buffer* output() const { return synth.output(); }106void output( Blip_Buffer* b ) { synth.output( b ); if ( !b ) time_ = last_amp = 0; }107108// Current time in frame109blip_time_t time() const { return time_; }110void time( blip_time_t t ) { time_ = t; }111112// Current amplitude of wave113int amplitude() const { return last_amp; }114void amplitude( int );115116// Move forward by 't' time units117void delay( blip_time_t t ) { time_ += t; }118119// End time frame of specified duration. Localize time to new frame.120// If wave hadn't been run to end of frame, start it at beginning of new frame.121void end_frame( blip_time_t duration )122{123time_ -= duration;124if ( time_ < 0 )125time_ = 0;126}127};128129// End of public interface130131template<int quality,int range>132void Blip_Wave<quality,range>::amplitude( int amp ) {133int delta = amp - last_amp;134last_amp = amp;135synth.offset_inline( time_, delta );136}137138template<int quality,int range>139inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,140int delta, Blip_Buffer* blip_buf ) const141{142typedef blip_pair_t_ pair_t;143144unsigned sample_index = (time >> BLIP_BUFFER_ACCURACY) & ~1;145assert(( (void)"Blip_Synth/Blip_wave: Went past end of buffer",146sample_index < blip_buf->buffer_size_ ));147enum { const_offset = Blip_Buffer::widest_impulse_ / 2 - width / 2 };148pair_t* buf = (pair_t*) &blip_buf->buffer_ [const_offset + sample_index];149150enum { shift = BLIP_BUFFER_ACCURACY - blip_res_bits_ };151enum { mask = res * 2 - 1 };152const pair_t* imp = &impulses [((time >> shift) & mask) * impulse_size];153154pair_t offset = impulse.offset * delta;155156if ( !fine_bits )157{158// normal mode159for ( int n = width / 4; n; --n )160{161pair_t t0 = buf [0] - offset;162pair_t t1 = buf [1] - offset;163164t0 += imp [0] * delta;165t1 += imp [1] * delta;166imp += 2;167168buf [0] = t0;169buf [1] = t1;170buf += 2;171}172}173else174{175// fine mode176enum { sub_range = 1 << fine_bits };177delta += sub_range / 2;178int delta2 = (delta & (sub_range - 1)) - sub_range / 2;179delta >>= fine_bits;180181for ( int n = width / 4; n; --n )182{183pair_t t0 = buf [0] - offset;184pair_t t1 = buf [1] - offset;185186t0 += imp [0] * delta2;187t0 += imp [1] * delta;188189t1 += imp [2] * delta2;190t1 += imp [3] * delta;191192imp += 4;193194buf [0] = t0;195buf [1] = t1;196buf += 2;197}198}199}200201template<int quality,int range>202void Blip_Synth<quality,range>::offset( blip_time_t time, int delta, Blip_Buffer* buf ) const {203offset_resampled( time * buf->factor_ + buf->offset_, delta, buf );204}205206#endif207208209210