001
002package ibxm;
003
004public class Envelope {
005    public boolean sustain, looped;
006    private int sustain_tick, loop_start_tick, loop_end_tick;
007    private int[] ticks, ampls;
008
009    public Envelope() {
010        set_num_points( 1 );
011    }
012
013    public void set_num_points( int num_points ) {
014        int point;
015        if( num_points <= 0 ) {
016            num_points = 1;
017        }
018        ticks = new int[ num_points ];
019        ampls = new int[ num_points ];
020        set_point( 0, 0, 0, false );
021    }
022
023    /* When you set a point, all subsequent points are reset. */
024    public void set_point( int point, int tick, int ampl, boolean delta ) {
025        if( point >= 0 && point < ticks.length ) {
026            if( point == 0 ) {
027                tick = 0;
028            }
029            if( point > 0 ) {
030                if( delta ) tick += ticks[ point - 1 ];
031                if( tick <= ticks[ point - 1 ] ) {
032                    System.out.println( "Envelope: Point not valid (" + tick + " <= " + ticks[ point - 1 ] + ")");
033                    tick = ticks[ point - 1 ] + 1;
034                }
035            }
036            ticks[ point ] = tick;
037            ampls[ point ] = ampl;
038            point += 1;
039            while( point < ticks.length ) {
040                ticks[ point ] = ticks[ point - 1 ] + 1;
041                ampls[ point ] = 0;
042                point += 1;
043            }
044        }
045    }
046
047    public void set_sustain_point( int point ) {
048        if( point < 0 ) {
049            point = 0;
050        }
051        if( point >= ticks.length ) {
052            point = ticks.length - 1;
053        }
054        sustain_tick = ticks[ point ];
055    }
056
057    public void set_loop_points( int start, int end ) {
058        if( start < 0 ) {
059            start = 0;
060        }
061        if( start >= ticks.length ) {
062            start = ticks.length - 1;
063        }
064        if( end < start || end >= ticks.length ) {
065            end = start;
066        }
067        loop_start_tick = ticks[ start ];
068        loop_end_tick = ticks[ end ];
069    }
070
071    public int next_tick( int tick, boolean key_on ) {
072        tick = tick + 1;
073        if( looped && tick >= loop_end_tick ) {
074            tick = loop_start_tick;
075        }
076        if( sustain && key_on && tick >= sustain_tick ) {
077            tick = sustain_tick;
078        }
079        return tick;
080    }
081
082    public int calculate_ampl( int tick ) {
083        int idx, point, delta_t, delta_a, ampl;
084        ampl = ampls[ ticks.length - 1 ];
085        if( tick < ticks[ ticks.length - 1 ] ) {
086            point = 0;
087            for( idx = 1; idx < ticks.length; idx++ ) {
088                if( ticks[ idx ] <= tick ) {
089                    point = idx;
090                }
091            }
092            delta_t = ticks[ point + 1 ] - ticks[ point ];
093            delta_a = ampls[ point + 1 ] - ampls[ point ];
094            ampl = ( delta_a << IBXM.FP_SHIFT ) / delta_t;
095            ampl = ampl * ( tick - ticks[ point ] ) >> IBXM.FP_SHIFT;
096            ampl = ampl + ampls[ point ];
097        }
098        return ampl;
099    }
100    
101    public void dump() {
102        int idx, tick;
103        for( idx = 0; idx < ticks.length; idx++ ) {
104            System.out.println( ticks[ idx ] + ", " + ampls[ idx ] );
105        }
106        for( tick = 0; tick < 222; tick++ ) {
107            System.out.print( calculate_ampl( tick ) + ", " );
108        }
109    }
110}
111