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 }