    001
    002package ibxm;
    003
    004import java.io.*;
    005
    006public class ScreamTracker3 {
    007    private static final int[] effect_map = new int[] {
    008        0xFF,
    009        0x25, /* A: Set Speed.*/
    010        0x0B, /* B: Pattern Jump.*/
    011        0x0D, /* C: Pattern Break.*/
    012        0x0A, /* D: Volume Slide.*/
    013        0x02, /* E: Portamento Down.*/
    014        0x01, /* F: Portamento Up.*/
    015        0x03, /* G: Tone Portamento.*/
    016        0x04, /* H: Vibrato.*/
    017        0x1D, /* I: Tremor.*/
    018        0x00, /* J: Arpeggio.*/
    019        0x06, /* K: Vibrato + Volume Slide.*/
    020        0x05, /* L: Tone Portamento + Volume Slide.*/
    021        0xFF, /* M: */
    022        0xFF, /* N: */
    023        0x09, /* O: Sample Offset.*/
    024        0xFF, /* P: */
    025        0x1B, /* Q: Retrig + Volume Slide.*/
    026        0x07, /* R: Tremolo.*/
    027        0x0E, /* S: Extended Effects.*/
    028        0x0F, /* T: Set Tempo.*/
    029        0x24, /* U: Fine Vibrato.*/
    030        0x10, /* V: Set Global Volume. */
    031        0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    032        0xFF, 0xFF, 0xFF, 0xFF
    033    };
    034
    035    private static final int[] effect_s_map = new int[] {
    036        0x00, /* 0: Set Filter.*/
    037        0x03, /* 1: Glissando.*/
    038        0x05, /* 2: Set Fine Tune.*/
    039        0x04, /* 3: Set Vibrato Waveform.*/
    040        0x07, /* 4: Set Tremolo Waveform.*/
    041        0xFF, /* 5: */
    042        0xFF, /* 6: */
    043        0xFF, /* 7: */
    044        0x08, /* 8: Set Panning.*/
    045        0xFF, /* 9: */
    046        0x09, /* A: Stereo Control.*/
    047        0x06, /* B: Pattern Loop.*/
    048        0x0C, /* C: Note Cut.*/
    049        0x0D, /* D: Note Delay.*/
    050        0x0E, /* E: Pattern Delay.*/
    051        0x0F  /* F: Invert Loop.*/
    052    };
    053
    054    public static boolean is_s3m( byte[] header_96_bytes ) {
    055        String s3m_identifier;
    056        s3m_identifier = ascii_text( header_96_bytes, 44, 4 );
    057        return s3m_identifier.equals( "SCRM" );
    058    }
    059
    060    public static Module load_s3m( byte[] header_96_bytes, DataInput data_input ) throws IOException {
    061        int num_pattern_orders, num_instruments, num_patterns, num_channels;
    062        int flags, tracker_version, master_volume, panning, channel_config, sequence_length;
    063        int instrument_idx, pattern_idx, channel_idx, order_idx, panning_offset;
    064        boolean signed_samples, stereo_mode, default_panning;
    065        int[] channel_map, sequence;
    066        byte[] s3m_file;
    067        Module module;
    068        Instrument instrument;
    069        s3m_file = read_s3m_file( header_96_bytes, data_input );
    070        module = new Module();
    071        module.song_title = ascii_text( s3m_file, 0, 28 );
    072        num_pattern_orders = get_num_pattern_orders( s3m_file );
    073        num_instruments = get_num_instruments( s3m_file );
    074        num_patterns = get_num_patterns( s3m_file );
    075        flags = unsigned_short_le( s3m_file, 38 );
    076        tracker_version = unsigned_short_le( s3m_file, 40 );
    077        if( ( flags & 0x40 ) == 0x40 || tracker_version == 0x1300 ) {
    078            module.fast_volume_slides = true;
    079        }
    080        signed_samples = false;
    081        if( unsigned_short_le( s3m_file, 42 ) == 0x01 ) {
    082            signed_samples = true;
    083        }
    084        module.global_volume = s3m_file[ 48 ] & 0xFF;
    085        module.default_speed = s3m_file[ 49 ] & 0xFF;
    086        module.default_tempo = s3m_file[ 50 ] & 0xFF;
    087        master_volume = s3m_file[ 51 ] & 0x7F;
    088        module.channel_gain = ( master_volume << IBXM.FP_SHIFT ) >> 7;
    089        stereo_mode = ( s3m_file[ 51 ] & 0x80 ) == 0x80;
    090        default_panning = ( s3m_file[ 53 ] & 0xFF ) == 0xFC;
    091        channel_map = new int[ 32 ];
    092        num_channels = 0;
    093        for( channel_idx = 0; channel_idx < 32; channel_idx++ ) {
    094            channel_config = s3m_file[ 64 + channel_idx ] & 0xFF;
    095            channel_map[ channel_idx ] = -1;
    096            if( channel_config < 16 ) {
    097                channel_map[ channel_idx ] = num_channels;
    098                num_channels += 1;
    099            }
    100        }
    101        module.set_num_channels( num_channels );
    102        panning_offset = 96 + num_pattern_orders + num_instruments * 2 + num_patterns * 2;
    103        for( channel_idx = 0; channel_idx < 32; channel_idx++ ) {
    104            if( channel_map[ channel_idx ] < 0 ) continue;
    105            panning = 7;
    106            if( stereo_mode ) {
    107                panning = 12;
    108                if( ( s3m_file[ 64 + channel_idx ] & 0xFF ) < 8 ) {
    109                    panning = 3;
    110                }
    111            }
    112            if( default_panning ) {
    113                flags = s3m_file[ panning_offset + channel_idx ] & 0xFF;
    114                if( ( flags & 0x20 ) == 0x20 ) {
    115                    panning = flags & 0xF;
    116                }
    117            }
    118            module.set_initial_panning( channel_map[ channel_idx ], panning * 17 );
    119        }
    120        sequence = read_s3m_sequence( s3m_file );
    121        module.set_sequence_length( sequence.length );
    122        for( order_idx = 0; order_idx < sequence.length; order_idx++ ) {
    123            module.set_sequence( order_idx, sequence[ order_idx ] );
    124        }
    125        module.set_num_instruments( num_instruments );
    126        for( instrument_idx = 0; instrument_idx < num_instruments; instrument_idx++ ) {
    127            instrument = read_s3m_instrument( s3m_file, instrument_idx, signed_samples );
    128            module.set_instrument( instrument_idx + 1, instrument );
    129        }
    130        module.set_num_patterns( num_patterns );
    131        for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) {
    132            module.set_pattern( pattern_idx, read_s3m_pattern( s3m_file, pattern_idx, channel_map ) );
    133        }
    134        return module;
    135    }
    136
    137    private static int[] read_s3m_sequence( byte[] s3m_file ) {
    138        int num_pattern_orders, sequence_length;
    139        int sequence_idx, order_idx, pattern_order;
    140        int[] sequence;
    141        num_pattern_orders = get_num_pattern_orders( s3m_file );
    142        sequence_length = 0;
    143        for( order_idx = 0; order_idx < num_pattern_orders; order_idx++ ) {
    144            pattern_order = s3m_file[ 96 + order_idx ] & 0xFF;
    145            if( pattern_order == 255 ) {
    146                break;
    147            } else if( pattern_order < 254 ) {
    148                sequence_length += 1;
    149            }
    150        }
    151        sequence = new int[ sequence_length ];
    152        sequence_idx = 0;
    153        for( order_idx = 0; order_idx < num_pattern_orders; order_idx++ ) {
    154            pattern_order = s3m_file[ 96 + order_idx ] & 0xFF;
    155            if( pattern_order == 255 ) {
    156                break;
    157            } else if( pattern_order < 254 ) {
    158                sequence[ sequence_idx ] = pattern_order;
    159                sequence_idx += 1;
    160            }
    161        }
    162        return sequence;
    163    }
    164
    165    private static Instrument read_s3m_instrument( byte[] s3m_file, int instrument_idx, boolean signed_samples ) {
    166        int instrument_offset;
    167        int sample_data_offset, sample_data_length;
    168        int loop_start, loop_length, c2_rate, sample_idx, amplitude;
    169        boolean sixteen_bit;
    170        Instrument instrument;
    171        Sample sample;
    172        short[] sample_data;
    173        instrument_offset = get_instrument_offset( s3m_file, instrument_idx );
    174        instrument = new Instrument();
    175        instrument.name = ascii_text( s3m_file, instrument_offset + 48, 28 );
    176        sample = new Sample();
    177        if( s3m_file[ instrument_offset ] == 1 ) {
    178            sample_data_length = get_sample_data_length( s3m_file, instrument_offset );
    179            loop_start = unsigned_short_le( s3m_file, instrument_offset + 20 );
    180            loop_length = unsigned_short_le( s3m_file, instrument_offset + 24 ) - loop_start;
    181            sample.volume = s3m_file[ instrument_offset + 28 ] & 0xFF;
    182            if( s3m_file[ instrument_offset + 30 ] != 0 ) {
    183                throw new IllegalArgumentException( "ScreamTracker3: Packed samples not supported!" );
    184            }
    185            if( ( s3m_file[ instrument_offset + 31 ] & 0x01 ) == 0 ) {
    186                loop_length = 0;
    187            }
    188            if( ( s3m_file[ instrument_offset + 31 ] & 0x02 ) != 0 ) {
    189                throw new IllegalArgumentException( "ScreamTracker3: Stereo samples not supported!" );
    190            }
    191            sixteen_bit = ( s3m_file[ instrument_offset + 31 ] & 0x04 ) != 0;
    192            c2_rate = unsigned_short_le( s3m_file, instrument_offset + 32 );
    193            sample.transpose = LogTable.log_2( c2_rate ) - LogTable.log_2( 8363 );
    194            sample_data_offset = get_sample_data_offset( s3m_file, instrument_offset );
    195            if( sixteen_bit ) {
    196                if( signed_samples ) {
    197                    throw new IllegalArgumentException( "ScreamTracker3: Signed 16-bit samples not supported!" );
    198                }
    199                sample_data_length >>= 1;
    200                sample_data = new short[ sample_data_length ];
    201                for( sample_idx = 0; sample_idx < sample_data_length; sample_idx++ ) {
    202                    amplitude  = s3m_file[ sample_data_offset + sample_idx * 2 ] & 0xFF;
    203                    amplitude |= ( s3m_file[ sample_data_offset + sample_idx * 2 + 1 ] & 0xFF ) << 8;
    204                    sample_data[ sample_idx ] = ( short ) ( amplitude - 32768 );
    205                }
    206            } else {
    207                sample_data = new short[ sample_data_length ];
    208                if( signed_samples ) {
    209                    for( sample_idx = 0; sample_idx < sample_data_length; sample_idx++ ) {
    210                        amplitude = s3m_file[ sample_data_offset + sample_idx ] << 8;
    211                        sample_data[ sample_idx ] = ( short ) amplitude;
    212                    }
    213                } else {
    214                    for( sample_idx = 0; sample_idx < sample_data_length; sample_idx++ ) {
    215                        amplitude = ( s3m_file[ sample_data_offset + sample_idx ] & 0xFF ) << 8;
    216                        sample_data[ sample_idx ] = ( short ) ( amplitude - 32768 );
    217                    }
    218                }
    219            }
    220            sample.set_sample_data( sample_data, loop_start, loop_length, false );
    221        }
    222        instrument.set_num_samples( 1 );
    223        instrument.set_sample( 0, sample );
    224        return instrument;
    225    }
    226
    227    private static Pattern read_s3m_pattern( byte[] s3m_file, int pattern_idx, int[] channel_map ) {
    228        int pattern_offset;
    229        int num_channels, num_notes;
    230        int row_idx, channel_idx, note_idx;
    231        int token, key, volume_column, effect, effect_param;
    232        byte[] pattern_data;
    233        Pattern pattern;
    234        num_channels = 0;
    235        for( channel_idx = 0; channel_idx < 32; channel_idx++ ) {
    236            if( channel_map[ channel_idx ] >= num_channels ) {
    237                num_channels = channel_idx + 1;
    238            }
    239        }
    240        num_notes = num_channels * 64;
    241        pattern_data = new byte[ num_notes * 5 ];
    242        row_idx = 0;
    243        pattern_offset = get_pattern_offset( s3m_file, pattern_idx ) + 2;
    244        while( row_idx < 64 ) {
    245            token = s3m_file[ pattern_offset ] & 0xFF;
    246            pattern_offset += 1;
    247            if( token > 0 ) {
    248                channel_idx = channel_map[ token & 0x1F ];
    249                note_idx = ( num_channels * row_idx + channel_idx ) * 5;
    250                if( ( token & 0x20 ) == 0x20 ) {
    251                    /* Key + Instrument.*/
    252                    if( channel_idx >= 0 ) {
    253                        key = s3m_file[ pattern_offset ] & 0xFF;
    254                        if( key == 255 ) {
    255                            key = 0;
    256                        } else if( key == 254 ) {
    257                            key = 97;
    258                        } else {
    259                            key = ( ( key & 0xF0 ) >> 4 ) * 12 + ( key & 0x0F ) + 1;
    260                            while( key > 96 ) {
    261                                key = key - 12;
    262                            }
    263                        }
    264                        pattern_data[ note_idx ] = ( byte ) key;
    265                        pattern_data[ note_idx + 1 ] = s3m_file[ pattern_offset + 1 ];
    266                    }
    267                    pattern_offset += 2;
    268                }
    269                if( ( token & 0x40 ) == 0x40 ) {
    270                    /* Volume.*/
    271                    if( channel_idx >= 0 ) {
    272                        volume_column = ( s3m_file[ pattern_offset ] & 0xFF ) + 0x10;
    273                        pattern_data[ note_idx + 2 ] = ( byte ) volume_column;
    274                    }
    275                    pattern_offset += 1;
    276                }
    277                if( ( token & 0x80 ) == 0x80 ) {
    278                    /* Effect + Param.*/
    279                    if( channel_idx >= 0 ) {
    280                        effect = s3m_file[ pattern_offset ] & 0xFF;
    281                        effect_param = s3m_file[ pattern_offset + 1 ] & 0xFF;
    282                        effect = effect_map[ effect & 0x1F ];
    283                        if( effect == 0xFF ) {
    284                            effect = 0;
    285                            effect_param = 0;
    286                        }
    287                        if( effect == 0x0E ) {
    288                            effect = effect_s_map[ ( effect_param & 0xF0 ) >> 4 ];
    289                            effect_param = effect_param & 0x0F;
    290                            switch( effect ) {
    291                                case 0x08:
    292                                    effect = 0x08;
    293                                    effect_param = effect_param * 17;
    294                                    break;
    295                                case 0x09:
    296                                    effect = 0x08;
    297                                    if( effect_param > 7 ) {
    298                                        effect_param -= 8;
    299                                    } else {
    300                                        effect_param += 8;
    301                                    }
    302                                    effect_param = effect_param * 17;
    303                                    break;
    304                                case 0xFF:
    305                                    effect = 0;
    306                                    effect_param = 0;
    307                                    break;
    308                                default:
    309                                    effect_param = ( ( effect & 0x0F ) << 4 ) | ( effect_param & 0x0F );
    310                                    effect = 0x0E;
    311                                    break;
    312                            }
    313                        }
    314                        pattern_data[ note_idx + 3 ] = ( byte ) effect;
    315                        pattern_data[ note_idx + 4 ] = ( byte ) effect_param;
    316                    }
    317                    pattern_offset += 2;
    318                }
    319            } else {
    320                row_idx += 1;
    321            }
    322        }
    323        pattern = new Pattern();
    324        pattern.num_rows = 64;
    325        pattern.set_pattern_data( pattern_data );
    326        return pattern;
    327    }
    328
    329    private static byte[] read_s3m_file( byte[] header_96_bytes, DataInput data_input ) throws IOException {
    330        int s3m_file_length;
    331        int num_pattern_orders, num_instruments, num_patterns;
    332        int instrument_idx, pattern_idx;
    333        int instrument_offset, sample_data_offset, pattern_offset;
    334        byte[] s3m_file;
    335        if( !is_s3m( header_96_bytes ) ) {
    336            throw new IllegalArgumentException( "ScreamTracker3: Not an S3M file!" );
    337        }
    338        s3m_file = header_96_bytes;
    339        s3m_file_length = header_96_bytes.length;
    340        num_pattern_orders = get_num_pattern_orders( s3m_file );
    341        num_instruments = get_num_instruments( s3m_file );
    342        num_patterns = get_num_patterns( s3m_file );
    343        s3m_file_length += num_pattern_orders;
    344        s3m_file_length += num_instruments * 2;
    345        s3m_file_length += num_patterns * 2;
    346        /* Read enough of file to calculate the length.*/
    347        s3m_file = read_more( s3m_file, s3m_file_length, data_input );
    348        for( instrument_idx = 0; instrument_idx < num_instruments; instrument_idx++ ) {
    349            instrument_offset = get_instrument_offset( s3m_file, instrument_idx );
    350            instrument_offset += 80;
    351            if( instrument_offset > s3m_file_length ) {
    352                s3m_file_length = instrument_offset;
    353            }
    354        }
    355        for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) {
    356            pattern_offset = get_pattern_offset( s3m_file, pattern_idx );
    357            pattern_offset += 2;
    358            if( pattern_offset > s3m_file_length ) {
    359                s3m_file_length = pattern_offset;
    360            }
    361        }
    362        s3m_file = read_more( s3m_file, s3m_file_length, data_input );
    363        /* Read rest of file.*/
    364        for( instrument_idx = 0; instrument_idx < num_instruments; instrument_idx++ ) {
    365            instrument_offset = get_instrument_offset( s3m_file, instrument_idx );
    366            sample_data_offset = get_sample_data_offset( s3m_file, instrument_offset );
    367            sample_data_offset += get_sample_data_length( s3m_file, instrument_offset );
    368            if( sample_data_offset > s3m_file_length ) {
    369                s3m_file_length = sample_data_offset;
    370            }
    371        }
    372        for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) {
    373            pattern_offset = get_pattern_offset( s3m_file, pattern_idx );
    374            pattern_offset += get_pattern_length( s3m_file, pattern_offset );
    375            pattern_offset += 2;
    376            if( pattern_offset > s3m_file_length ) {
    377                s3m_file_length = pattern_offset;
    378            }
    379        }
    380        s3m_file = read_more( s3m_file, s3m_file_length, data_input );
    381        return s3m_file;
    382    }
    383
    384    private static int get_num_pattern_orders( byte[] s3m_file ) {
    385        int num_pattern_orders;
    386        num_pattern_orders = unsigned_short_le( s3m_file, 32 );
    387        return num_pattern_orders;
    388    }
    389
    390    private static int get_num_instruments( byte[] s3m_file ) {
    391        int num_instruments;
    392        num_instruments = unsigned_short_le( s3m_file, 34 );
    393        return num_instruments;
    394    }
    395
    396    private static int get_num_patterns( byte[] s3m_file ) {
    397        int num_patterns;
    398        num_patterns = unsigned_short_le( s3m_file, 36 );
    399        return num_patterns;
    400    }
    401
    402    private static int get_instrument_offset( byte[] s3m_file, int instrument_idx ) {
    403        int instrument_offset, pointer_offset;
    404        pointer_offset = 96 + get_num_pattern_orders( s3m_file );
    405        instrument_offset = unsigned_short_le( s3m_file, pointer_offset + instrument_idx * 2 ) << 4;
    406        return instrument_offset;
    407    }
    408
    409    private static int get_sample_data_offset( byte[] s3m_file, int instrument_offset ) {
    410        int sample_data_offset;
    411        sample_data_offset = 0;
    412        if( s3m_file[ instrument_offset ] == 1 ) {
    413            sample_data_offset = ( s3m_file[ instrument_offset + 13 ] & 0xFF ) << 20;
    414            sample_data_offset |= unsigned_short_le( s3m_file, instrument_offset + 14 ) << 4;
    415        }
    416        return sample_data_offset;
    417    }
    418
    419    private static int get_sample_data_length( byte[] s3m_file, int instrument_offset ) {
    420        int sample_data_length;
    421        boolean sixteen_bit;
    422        sample_data_length = 0;
    423        if( s3m_file[ instrument_offset ] == 1 ) {
    424            sample_data_length = unsigned_short_le( s3m_file, instrument_offset + 16 );
    425            sixteen_bit = ( s3m_file[ instrument_offset + 31 ] & 0x04 ) != 0;
    426            if( sixteen_bit ) {
    427                sample_data_length <<= 1;
    428            }
    429        }
    430        return sample_data_length;
    431    }
    432
    433    private static int get_pattern_offset( byte[] s3m_file, int pattern_idx ) {
    434        int pattern_offset, pointer_offset;
    435        pointer_offset = 96 + get_num_pattern_orders( s3m_file );
    436        pointer_offset += get_num_instruments( s3m_file ) * 2;
    437        pattern_offset = unsigned_short_le( s3m_file, pointer_offset + pattern_idx * 2 ) << 4;
    438        return pattern_offset;
    439    }
    440
    441    private static int get_pattern_length( byte[] s3m_file, int pattern_offset ) {
    442        int pattern_length;
    443        pattern_length = unsigned_short_le( s3m_file, pattern_offset );
    444        return pattern_length;
    445    }
    446
    447    private static byte[] read_more( byte[] old_data, int new_length, DataInput data_input ) throws IOException {
    448        byte[] new_data;
    449        new_data = old_data;
    450        if( new_length > old_data.length ) {
    451            new_data = new byte[ new_length ];
    452            System.arraycopy( old_data, 0, new_data, 0, old_data.length );
    453            try {
    454                data_input.readFully( new_data, old_data.length, new_data.length - old_data.length );
    455            } catch( EOFException e ) {
    456                System.out.println( "ScreamTracker3: Module has been truncated!" );
    457            }
    458        }
    459        return new_data;
    460    }
    461
    462    private static int unsigned_short_le( byte[] buffer, int offset ) {
    463        int value;
    464        value = buffer[ offset ] & 0xFF;
    465        value = value | ( ( buffer[ offset + 1 ] & 0xFF ) << 8 );
    466        return value;
    467    }
    468
    469    private static String ascii_text( byte[] buffer, int offset, int length ) {
    470        int idx, chr;
    471        byte[] string_buffer;
    472        String string;
    473        string_buffer = new byte[ length ];
    474        for( idx = 0; idx < length; idx++ ) {
    475            chr = buffer[ offset + idx ];
    476            if( chr < 32 ) {
    477                chr = 32;
    478            }
    479            string_buffer[ idx ] = ( byte ) chr;
    480        }
    481        try {
    482            string = new String( string_buffer, 0, length, "ISO-8859-1" );
    483        } catch( UnsupportedEncodingException e ) {
    484            string = "";
    485        }
    486        return string;
    487    }
    488}
    489