    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