    001
    002    package ibxm;
    003
    004    public 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    }