    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