001
002package ibxm;
003
004public class Sample {
005    public String name;
006    public boolean set_panning;
007    public int volume, panning;
008    public int transpose;
009    
010    private int loop_start, loop_length;
011    private short[] sample_data;
012
013    /* For the sinc interpolator.*/
014    private static final int POINT_SHIFT = 4;
015    private static final int POINTS = 1 << POINT_SHIFT;
016    private static final int OVERLAP = POINTS >> 1;
017    private static final int INTERP_SHIFT = IBXM.FP_SHIFT - 4;
018    private static final int INTERP_BITMASK = ( 1 << INTERP_SHIFT ) - 1;
019    private static final short[] sinc_table = {
020         0, -7,  27, -71,  142, -227,  299,  32439,   299,  -227,  142,  -71,  27,  -7,  0,  0,
021         0,  0,  -5,  36, -142,  450, -1439, 32224,  2302,  -974,  455, -190,  64, -15,  2,  0,
022         0,  6, -33, 128, -391, 1042, -2894, 31584,  4540, -1765,  786, -318, 105, -25,  3,  0,
023         0, 10, -55, 204, -597, 1533, -4056, 30535,  6977, -2573, 1121, -449, 148, -36,  5,  0,
024        -1, 13, -71, 261, -757, 1916, -4922, 29105,  9568, -3366, 1448, -578, 191, -47,  7,  0,
025        -1, 15, -81, 300, -870, 2185, -5498, 27328, 12263, -4109, 1749, -698, 232, -58,  9,  0,
026        -1, 15, -86, 322, -936, 2343, -5800, 25249, 15006, -4765, 2011, -802, 269, -68, 10,  0,
027        -1, 15, -87, 328, -957, 2394, -5849, 22920, 17738, -5298, 2215, -885, 299, -77, 12,  0,
028         0, 14, -83, 319, -938, 2347, -5671, 20396, 20396, -5671, 2347, -938, 319, -83, 14,  0,
029         0, 12, -77, 299, -885, 2215, -5298, 17738, 22920, -5849, 2394, -957, 328, -87, 15, -1,
030         0, 10, -68, 269, -802, 2011, -4765, 15006, 25249, -5800, 2343, -936, 322, -86, 15, -1,
031         0,  9, -58, 232, -698, 1749, -4109, 12263, 27328, -5498, 2185, -870, 300, -81, 15, -1,
032         0,  7, -47, 191, -578, 1448, -3366,  9568, 29105, -4922, 1916, -757, 261, -71, 13, -1,
033         0,  5, -36, 148, -449, 1121, -2573,  6977, 30535, -4056, 1533, -597, 204, -55, 10,  0,
034         0,  3, -25, 105, -318,  786, -1765,  4540, 31584, -2894, 1042, -391, 128, -33,  6,  0,
035         0,  2, -15,  64, -190,  455,  -974,  2302, 32224, -1439,  450, -142,  36,  -5,  0,  0,
036         0,  0,  -7,  27,  -71,  142,  -227,   299, 32439,   299, -227,  142, -71,  27, -7,  0
037    };
038    
039    public Sample() {
040        name = "";
041        set_sample_data( new short[ 0 ], 0, 0, false );
042    }
043    
044    public void set_sample_data( short[] data, int loop_start, int loop_length, boolean ping_pong ) {
045        int offset;
046        short sample;       
047        if( loop_start < 0 ) {
048            loop_start = 0;
049        }
050        if( loop_start >= data.length ) {
051            loop_start = data.length - 1;
052        }
053        if( loop_start + loop_length > data.length ) {
054            loop_length = data.length - loop_start;
055        }
056        if( loop_length <= 1 ) {
057            sample_data = new short[ OVERLAP + data.length + OVERLAP * 3 ];
058            System.arraycopy( data, 0, sample_data, OVERLAP, data.length );
059            offset = 0;
060            while( offset < OVERLAP ) {
061                sample = sample_data[ OVERLAP + data.length - 1 ];
062                sample = ( short ) ( sample * ( OVERLAP - offset ) / OVERLAP );
063                sample_data[ OVERLAP + data.length + offset ] = sample;
064                offset += 1;
065            }
066            loop_start = OVERLAP + data.length + OVERLAP;
067            loop_length = 1;
068        } else {
069            if( ping_pong ) {
070                sample_data = new short[ OVERLAP + loop_start + loop_length * 2 + OVERLAP * 2 ];
071                System.arraycopy( data, 0, sample_data, OVERLAP, loop_start + loop_length );
072                offset = 0;
073                while( offset < loop_length ) {
074                    sample = data[ loop_start + loop_length - offset - 1 ];
075                    sample_data[ OVERLAP + loop_start + loop_length + offset ] = sample;
076                    offset += 1;
077                }
078                loop_start = loop_start + OVERLAP;
079                loop_length = loop_length * 2;
080            } else {
081                sample_data = new short[ OVERLAP + loop_start + loop_length + OVERLAP * 2 ];
082                System.arraycopy( data, 0, sample_data, OVERLAP, loop_start + loop_length );
083                loop_start = loop_start + OVERLAP;
084            }
085            offset = 0;
086            while( offset < OVERLAP * 2 ) {
087                sample = sample_data[ loop_start + offset ];
088                sample_data[ loop_start + loop_length + offset ] = sample;
089                offset += 1;
090            }
091        }
092        this.loop_start = loop_start;
093        this.loop_length = loop_length;
094    }
095
096    public void resample_nearest(
097            int sample_idx, int sample_frac, int step, int left_gain, int right_gain,
098            int[] mix_buffer, int frame_offset, int frames ) {
099        int loop_end, offset, end, max_sample_idx;
100        sample_idx += OVERLAP;
101        loop_end = loop_start + loop_length - 1;
102        offset = frame_offset << 1;
103        end = ( frame_offset + frames - 1 ) << 1;
104        while( frames > 0 ) {
105            if( sample_idx > loop_end ) {
106                if( loop_length <= 1 ) {
107                    break;
108                }
109                sample_idx = loop_start + ( sample_idx - loop_start ) % loop_length;
110            }
111            max_sample_idx = sample_idx + ( ( sample_frac + ( frames - 1 ) * step ) >> IBXM.FP_SHIFT );
112            if( max_sample_idx > loop_end ) {
113                while( sample_idx <= loop_end ) {
114                    mix_buffer[ offset++ ] += sample_data[ sample_idx ] * left_gain >> IBXM.FP_SHIFT;
115                    mix_buffer[ offset++ ] += sample_data[ sample_idx ] * right_gain >> IBXM.FP_SHIFT;
116                    sample_frac += step;
117                    sample_idx += sample_frac >> IBXM.FP_SHIFT;
118                    sample_frac &= IBXM.FP_MASK;
119                }
120            } else {
121                while( offset <= end ) {
122                    mix_buffer[ offset++ ] += sample_data[ sample_idx ] * left_gain >> IBXM.FP_SHIFT;
123                    mix_buffer[ offset++ ] += sample_data[ sample_idx ] * right_gain >> IBXM.FP_SHIFT;
124                    sample_frac += step;
125                    sample_idx += sample_frac >> IBXM.FP_SHIFT;
126                    sample_frac &= IBXM.FP_MASK;
127                }
128            }
129            frames = ( end - offset + 2 ) >> 1;
130        }
131    }
132
133    public void resample_linear(
134            int sample_idx, int sample_frac, int step, int left_gain, int right_gain,
135            int[] mix_buffer, int frame_offset, int frames ) {
136        int loop_end, offset, end, max_sample_idx, amplitude;
137        sample_idx += OVERLAP;
138        loop_end = loop_start + loop_length - 1;
139        offset = frame_offset << 1;
140        end = ( frame_offset + frames - 1 ) << 1;
141        while( frames > 0 ) {
142            if( sample_idx > loop_end ) {
143                if( loop_length <= 1 ) {
144                    break;
145                }
146                sample_idx = loop_start + ( sample_idx - loop_start ) % loop_length;
147            }
148            max_sample_idx = sample_idx + ( ( sample_frac + ( frames - 1 ) * step ) >> IBXM.FP_SHIFT );
149            if( max_sample_idx > loop_end ) {
150                while( sample_idx <= loop_end ) {
151                    amplitude = sample_data[ sample_idx ];
152                    amplitude += ( sample_data[ sample_idx + 1 ] - amplitude ) * sample_frac >> IBXM.FP_SHIFT;
153                    mix_buffer[ offset++ ] += amplitude * left_gain >> IBXM.FP_SHIFT;
154                    mix_buffer[ offset++ ] += amplitude * right_gain >> IBXM.FP_SHIFT;
155                    sample_frac += step;
156                    sample_idx += sample_frac >> IBXM.FP_SHIFT;
157                    sample_frac &= IBXM.FP_MASK;
158                }
159            } else {
160                while( offset <= end ) {
161                    amplitude = sample_data[ sample_idx ];
162                    amplitude += ( sample_data[ sample_idx + 1 ] - amplitude ) * sample_frac >> IBXM.FP_SHIFT;
163                    mix_buffer[ offset++ ] += amplitude * left_gain >> IBXM.FP_SHIFT;
164                    mix_buffer[ offset++ ] += amplitude * right_gain >> IBXM.FP_SHIFT;
165                    sample_frac += step;
166                    sample_idx += sample_frac >> IBXM.FP_SHIFT;
167                    sample_frac &= IBXM.FP_MASK;
168                }
169            }
170            frames = ( end - offset + 2 ) >> 1;
171        }
172    }
173
174    public void resample_sinc(
175            int sample_idx, int sample_frac, int step, int left_gain, int right_gain,
176            int[] mix_buffer, int frame_offset, int frames ) {
177        int offset, end, loop_end, table_idx, a1, a2, amplitude;
178        loop_end = loop_start + loop_length - 1;
179        offset = frame_offset << 1;
180        end = ( frame_offset + frames - 1 ) << 1;
181        while( offset <= end ) {
182            if( sample_idx > loop_end ) {
183                if( loop_length <= 1 ) {
184                    break;
185                }
186                sample_idx = loop_start + ( sample_idx - loop_start ) % loop_length;
187            }
188            table_idx = ( sample_frac >> INTERP_SHIFT ) << POINT_SHIFT;
189            a1  = sinc_table[ table_idx + 0  ] * sample_data[ sample_idx + 0  ] >> 15;
190            a1 += sinc_table[ table_idx + 1  ] * sample_data[ sample_idx + 1  ] >> 15;
191            a1 += sinc_table[ table_idx + 2  ] * sample_data[ sample_idx + 2  ] >> 15;
192            a1 += sinc_table[ table_idx + 3  ] * sample_data[ sample_idx + 3  ] >> 15;
193            a1 += sinc_table[ table_idx + 4  ] * sample_data[ sample_idx + 4  ] >> 15;
194            a1 += sinc_table[ table_idx + 5  ] * sample_data[ sample_idx + 5  ] >> 15;
195            a1 += sinc_table[ table_idx + 6  ] * sample_data[ sample_idx + 6  ] >> 15;
196            a1 += sinc_table[ table_idx + 7  ] * sample_data[ sample_idx + 7  ] >> 15;
197            a1 += sinc_table[ table_idx + 8  ] * sample_data[ sample_idx + 8  ] >> 15;
198            a1 += sinc_table[ table_idx + 9  ] * sample_data[ sample_idx + 9  ] >> 15;
199            a1 += sinc_table[ table_idx + 10 ] * sample_data[ sample_idx + 10 ] >> 15;
200            a1 += sinc_table[ table_idx + 11 ] * sample_data[ sample_idx + 11 ] >> 15;
201            a1 += sinc_table[ table_idx + 12 ] * sample_data[ sample_idx + 12 ] >> 15;
202            a1 += sinc_table[ table_idx + 13 ] * sample_data[ sample_idx + 13 ] >> 15;
203            a1 += sinc_table[ table_idx + 14 ] * sample_data[ sample_idx + 14 ] >> 15;
204            a1 += sinc_table[ table_idx + 15 ] * sample_data[ sample_idx + 15 ] >> 15;
205            a2  = sinc_table[ table_idx + 16 ] * sample_data[ sample_idx + 0  ] >> 15;
206            a2 += sinc_table[ table_idx + 17 ] * sample_data[ sample_idx + 1  ] >> 15;
207            a2 += sinc_table[ table_idx + 18 ] * sample_data[ sample_idx + 2  ] >> 15;
208            a2 += sinc_table[ table_idx + 19 ] * sample_data[ sample_idx + 3  ] >> 15;
209            a2 += sinc_table[ table_idx + 20 ] * sample_data[ sample_idx + 4  ] >> 15;
210            a2 += sinc_table[ table_idx + 21 ] * sample_data[ sample_idx + 5  ] >> 15;
211            a2 += sinc_table[ table_idx + 22 ] * sample_data[ sample_idx + 6  ] >> 15;
212            a2 += sinc_table[ table_idx + 23 ] * sample_data[ sample_idx + 7  ] >> 15;
213            a2 += sinc_table[ table_idx + 24 ] * sample_data[ sample_idx + 8  ] >> 15;
214            a2 += sinc_table[ table_idx + 25 ] * sample_data[ sample_idx + 9  ] >> 15;
215            a2 += sinc_table[ table_idx + 26 ] * sample_data[ sample_idx + 10 ] >> 15;
216            a2 += sinc_table[ table_idx + 27 ] * sample_data[ sample_idx + 11 ] >> 15;
217            a2 += sinc_table[ table_idx + 28 ] * sample_data[ sample_idx + 12 ] >> 15;
218            a2 += sinc_table[ table_idx + 29 ] * sample_data[ sample_idx + 13 ] >> 15;
219            a2 += sinc_table[ table_idx + 30 ] * sample_data[ sample_idx + 14 ] >> 15;
220            a2 += sinc_table[ table_idx + 31 ] * sample_data[ sample_idx + 15 ] >> 15;            
221            amplitude = a1 + ( ( a2 - a1 ) * ( sample_frac & INTERP_BITMASK ) >> INTERP_SHIFT );
222            mix_buffer[ offset ] += amplitude * left_gain >> IBXM.FP_SHIFT;
223            mix_buffer[ offset + 1 ] += amplitude * right_gain >> IBXM.FP_SHIFT;
224            offset += 2;
225            sample_frac += step;
226            sample_idx += sample_frac >> IBXM.FP_SHIFT;
227            sample_frac &= IBXM.FP_MASK;
228        }
229    }
230
231    public boolean has_finished( int sample_idx ) {
232        boolean finished;
233        finished = false;
234        if( loop_length <= 1 && sample_idx > loop_start ) {
235            finished = true;
236        }
237        return finished;
238    }
239}