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