001    
002    package ibxm;
003    
004    import java.io.*;
005    
006    public 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