001    
002    package ibxm;
003    
004    public class IBXM {
005        public static final String VERSION = "ibxm alpha 51 (c)2008 mumart@gmail.com";
006    
007        public static final int FP_SHIFT = 15;
008        public static final int FP_ONE = 1 << FP_SHIFT;
009        public static final int FP_MASK = FP_ONE - 1;
010    
011        private int sampling_rate, resampling_quality, volume_ramp_length;
012        private int tick_length_samples, current_tick_samples;
013        private int[] mixing_buffer, volume_ramp_buffer;
014    
015        private Module module;
016        private Channel[] channels;
017        private int[] global_volume, note;
018        private int current_sequence_index, next_sequence_index;
019        private int current_row, next_row;
020        private int tick_counter, ticks_per_row;
021        private int pattern_loop_count, pattern_loop_channel;
022    
023        public IBXM( int sample_rate ) {
024            
025    /** MODIFIED 13 Oct 2009 by Paul Lamb **/
026    //      System.out.println( VERSION );
027    /***************************************/
028    
029            if( sample_rate < 8000 ) {
030                sample_rate = 8000;
031            }
032            sampling_rate = sample_rate;
033            volume_ramp_length = sampling_rate >> 10;
034            volume_ramp_buffer = new int[ volume_ramp_length * 2 ];
035            mixing_buffer = new int[ sampling_rate / 6 ];
036            global_volume = new int[ 1 ];
037            note = new int[ 5 ];
038            set_module( new Module() );
039            set_resampling_quality( 1 );
040        }
041        
042        public void set_module( Module m ) {
043            int channel_idx;
044            module = m;
045            channels = new Channel[ module.get_num_channels() ];
046            for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
047                channels[ channel_idx ] = new Channel( module, sampling_rate, global_volume );
048            }
049            set_sequence_index( 0, 0 );
050        }
051    
052        public void set_resampling_quality( int quality ) {
053            resampling_quality = quality;
054        }
055        
056        public int calculate_song_duration() {
057            int song_duration;
058            set_sequence_index( 0, 0 );
059            next_tick();
060            song_duration = tick_length_samples;
061            while( !next_tick() ) {
062                song_duration += tick_length_samples;
063            }
064            set_sequence_index( 0, 0 );
065            return song_duration;
066        }
067        
068        public void set_sequence_index( int sequence_index, int row ) {
069            int channel_idx;
070            global_volume[ 0 ] = 64;
071            for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
072                channels[ channel_idx ].reset();
073                channels[ channel_idx ].set_panning( module.get_initial_panning( channel_idx ) );
074            }
075            set_global_volume( module.global_volume );
076            set_speed( 6 );
077            set_speed( module.default_speed );
078            set_tempo( 125 );
079            set_tempo( module.default_tempo );
080            pattern_loop_count = -1;
081            next_sequence_index = sequence_index;
082            next_row = row;
083            tick_counter = 0;
084            current_tick_samples = tick_length_samples;
085            clear_vol_ramp_buffer();
086        }
087    
088        public void seek( int sample_position ) {
089            int idx;
090            set_sequence_index( 0, 0 );
091            next_tick();
092            while( sample_position > tick_length_samples ) {
093                sample_position -= tick_length_samples;
094                next_tick();
095            }
096            mix_tick();
097            current_tick_samples = sample_position;
098        }
099    
100        public void get_audio( byte[] output_buffer, int frames ) {
101            int output_idx, mix_idx, mix_end, count, amplitude;
102            output_idx = 0;
103            while( frames > 0 ) {
104                count = tick_length_samples - current_tick_samples;
105                if( count > frames ) {
106                    count = frames;
107                }
108                mix_idx = current_tick_samples << 1;
109                mix_end = mix_idx + ( count << 1 ) - 1;
110                while( mix_idx <= mix_end ) {
111                    amplitude = mixing_buffer[ mix_idx ];
112                    if( amplitude > 32767 ) {
113                        amplitude = 32767;
114                    }
115                    if( amplitude < -32768 ) {
116                        amplitude = -32768;
117                    }
118                    output_buffer[ output_idx     ] = ( byte ) ( amplitude >> 8 );
119                    output_buffer[ output_idx + 1 ] = ( byte ) ( amplitude & 0xFF );
120                    output_idx += 2;
121                    mix_idx += 1;
122                }
123                current_tick_samples = mix_idx >> 1;
124                frames -= count;
125                if( frames > 0 ) {
126                    next_tick();
127                    mix_tick();
128                    current_tick_samples = 0;
129                }
130            }
131        }
132    
133        private void mix_tick() {
134            int channel_idx, mix_idx, mix_len;
135            mix_idx = 0;
136            mix_len = tick_length_samples + volume_ramp_length << 1;
137            while( mix_idx < mix_len ) {
138                mixing_buffer[ mix_idx ] = 0;
139                mix_idx += 1;
140            }
141            for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
142                mix_len = tick_length_samples + volume_ramp_length;
143                channels[ channel_idx ].resample( mixing_buffer, 0, mix_len, resampling_quality );
144            }
145            volume_ramp();
146        }
147    
148        private boolean next_tick() {
149            int channel_idx;
150            boolean song_end;
151            for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
152                channels[ channel_idx ].update_sample_idx( tick_length_samples );
153            }
154            tick_counter -= 1;
155            if( tick_counter <= 0 ) {
156                tick_counter = ticks_per_row;
157                song_end = next_row();
158            } else {
159                for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
160                    channels[ channel_idx ].tick();
161                }
162                song_end = false;
163            }
164            return song_end;
165        }
166        
167        private boolean next_row() {
168            int channel_idx, effect, effect_param;
169            boolean song_end;
170            Pattern pattern;
171            song_end = false;
172            if( next_sequence_index < 0 ) {
173                /* Bad next sequence index.*/
174                next_sequence_index = 0;
175                next_row = 0;
176            }
177            if( next_sequence_index >= module.get_sequence_length() ) {
178                /* End of sequence.*/
179                song_end = true;
180                next_sequence_index = module.restart_sequence_index;
181                if( next_sequence_index < 0 ) {
182                    next_sequence_index = 0;
183                }
184                if( next_sequence_index >= module.get_sequence_length() ) {
185                    next_sequence_index = 0;
186                }
187                next_row = 0;
188            }
189            if( next_sequence_index < current_sequence_index ) {
190                /* Jump to previous pattern. */
191                song_end = true;
192            }
193            if( next_sequence_index == current_sequence_index ) {
194                if( next_row <= current_row ) {
195                    if( pattern_loop_count < 0 ) {
196                        /* Jump to previous row in the same pattern, but not a pattern loop. */
197                        song_end = true;
198                    }
199                }
200            }
201            current_sequence_index = next_sequence_index;
202            pattern = module.get_pattern_from_sequence( current_sequence_index );
203            if( next_row < 0 || next_row >= pattern.num_rows ) {
204                /* Bad next row.*/
205                next_row = 0;
206            }
207            current_row = next_row;
208            next_row = current_row + 1;
209            if( next_row >= pattern.num_rows ) {
210                next_sequence_index = current_sequence_index + 1;
211                next_row = 0;
212            }
213            for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
214                pattern.get_note( note, current_row * channels.length + channel_idx );
215                effect = note[ 3 ];
216                effect_param = note[ 4 ];
217                channels[ channel_idx ].row( note[ 0 ], note[ 1 ], note[ 2 ], effect, effect_param );
218                switch( effect ) {
219                    case 0x0B:
220                        /* Pattern Jump.*/
221                        if( pattern_loop_count < 0 ) {
222                            next_sequence_index = effect_param;
223                            next_row = 0;
224                        }
225                        break;
226                    case 0x0D:
227                        /* Pattern Break.*/
228                        if( pattern_loop_count < 0 ) {
229                            next_sequence_index = current_sequence_index + 1;
230                            next_row = ( effect_param >> 4 ) * 10 + ( effect_param & 0x0F );
231                        }
232                        break;
233                    case 0x0E:
234                        /* Extended.*/
235                        switch( effect_param & 0xF0 ) {
236                            case 0x60:
237                                /* Pattern loop.*/
238                                if( ( effect_param & 0x0F ) == 0 ) {
239                                    /* Set loop marker on this channel. */
240                                    channels[ channel_idx ].pattern_loop_row = current_row;
241                                }
242                                if( channels[ channel_idx ].pattern_loop_row < current_row ) {
243                                    /* Marker and parameter are valid. Begin looping. */
244                                    if( pattern_loop_count < 0 ) {
245                                        /* Not already looping, begin. */
246                                        pattern_loop_count = effect_param & 0x0F;
247                                        pattern_loop_channel = channel_idx;
248                                    }
249                                    if( pattern_loop_channel == channel_idx ) {
250                                        /* Loop in progress on this channel. Next iteration. */
251                                        if( pattern_loop_count == 0 ) {
252                                            /* Loop finished. */
253                                            /* Invalidate current marker. */
254                                            channels[ channel_idx ].pattern_loop_row = current_row + 1;
255                                        } else {
256                                            /* Count must be higher than zero. */
257                                            /* Loop and cancel any breaks on this row. */
258                                            next_row = channels[ channel_idx ].pattern_loop_row;
259                                            next_sequence_index = current_sequence_index;
260                                        }
261                                        pattern_loop_count -= 1;
262                                    }
263                                }
264                                break;
265                            case 0xE0:
266                                /* Pattern delay.*/
267                                tick_counter += ticks_per_row * ( effect_param & 0x0F );
268                                break;
269                        }
270                        break;
271                    case 0x0F:
272                        /* Set Speed/Tempo.*/
273                        if( effect_param < 32 ) {
274                            set_speed( effect_param );
275                            tick_counter = ticks_per_row;
276                        } else {
277                            set_tempo( effect_param );
278                        }
279                        break;
280                    case 0x25:
281                        /* S3M Set Speed.*/
282                        set_speed( effect_param );
283                        tick_counter = ticks_per_row;
284                        break;
285                }
286            }
287            return song_end;
288        }
289    
290        private void set_global_volume( int volume ) {
291            if( volume < 0 ) {
292                volume = 0;
293            }
294            if( volume > 64 ) {
295                volume = 64;
296            }
297            global_volume[ 0 ] = volume;
298        }
299    
300        private void set_speed( int speed ) {
301            if( speed > 0 && speed < 256 ) {
302                ticks_per_row = speed;
303            }
304        }
305    
306        private void set_tempo( int bpm ) {
307            if( bpm > 31 && bpm < 256 ) {
308                tick_length_samples = ( sampling_rate * 5 ) / ( bpm * 2 );
309            }
310        }   
311    
312        private void volume_ramp() {
313            int ramp_idx, next_idx, ramp_end;
314            int volume_ramp_delta, volume, sample;
315            sample = 0;
316            volume_ramp_delta = FP_ONE / volume_ramp_length;
317            volume = 0;
318            ramp_idx = 0;
319            next_idx = 2 * tick_length_samples;
320            ramp_end = volume_ramp_length * 2 - 1;
321            while( ramp_idx <= ramp_end ) {
322                sample = volume_ramp_buffer[ ramp_idx ] * ( FP_ONE - volume ) >> FP_SHIFT;
323                mixing_buffer[ ramp_idx ] = sample + ( mixing_buffer[ ramp_idx ] * volume >> FP_SHIFT );
324                volume_ramp_buffer[ ramp_idx ] = mixing_buffer[ next_idx + ramp_idx ];
325                sample = volume_ramp_buffer[ ramp_idx + 1 ] * ( FP_ONE - volume ) >> FP_SHIFT;
326                mixing_buffer[ ramp_idx + 1 ] = sample + ( mixing_buffer[ ramp_idx + 1 ] * volume >> FP_SHIFT );
327                volume_ramp_buffer[ ramp_idx + 1 ] = mixing_buffer[ next_idx + ramp_idx + 1 ];
328                volume += volume_ramp_delta;
329                ramp_idx += 2;
330            }
331        }
332        
333        private void clear_vol_ramp_buffer() {
334            int ramp_idx, ramp_end;
335            ramp_idx = 0;
336            ramp_end = volume_ramp_length * 2 - 1;
337            while( ramp_idx <= ramp_end ) {
338                volume_ramp_buffer[ ramp_idx ] = 0;
339                ramp_idx += 1;
340            }
341        }
342    }
343