001 package ibxm;
002
003 import java.io.*;
004
005 public class ProTracker {
006 public static boolean is_mod( byte[] header_1084_bytes ) {
007 boolean is_mod;
008 is_mod = false;
009 if( calculate_num_channels( header_1084_bytes ) > 0 ) {
010 is_mod = true;
011 }
012 return is_mod;
013 }
014
015 public static Module load_mod( byte[] header_1084_bytes, DataInput data_input ) throws IOException {
016 int num_channels, channel_idx, panning;
017 int sequence_length, restart_idx, sequence_idx;
018 int num_patterns, pattern_idx, instrument_idx;
019 Module module;
020 num_channels = calculate_num_channels( header_1084_bytes );
021 if( num_channels < 1 ) {
022 throw new IllegalArgumentException( "ProTracker: Unrecognised module format!" );
023 }
024 module = new Module();
025 module.song_title = ascii_text( header_1084_bytes, 0, 20 );
026 module.pal = ( num_channels == 4 );
027 module.global_volume = 64;
028 module.channel_gain = IBXM.FP_ONE * 3 / 8;
029 module.default_speed = 6;
030 module.default_tempo = 125;
031 module.set_num_channels( num_channels );
032 for( channel_idx = 0; channel_idx < num_channels; channel_idx++ ) {
033 panning = 64;
034 if( ( channel_idx & 0x03 ) == 0x01 || ( channel_idx & 0x03 ) == 0x02 ) {
035 panning = 192;
036 }
037 module.set_initial_panning( channel_idx, panning );
038 }
039 sequence_length = header_1084_bytes[ 950 ] & 0x7F;
040 restart_idx = header_1084_bytes[ 951 ] & 0x7F;
041 if( restart_idx >= sequence_length ) {
042 restart_idx = 0;
043 }
044 module.restart_sequence_index = restart_idx;
045 module.set_sequence_length( sequence_length );
046 for( sequence_idx = 0; sequence_idx < sequence_length; sequence_idx++ ) {
047 module.set_sequence( sequence_idx, header_1084_bytes[ 952 + sequence_idx ] & 0x7F );
048 }
049 num_patterns = calculate_num_patterns( header_1084_bytes );
050 module.set_num_patterns( num_patterns );
051 for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) {
052 module.set_pattern( pattern_idx, read_mod_pattern( data_input, num_channels ) );
053 }
054 module.set_num_instruments( 31 );
055 for( instrument_idx = 1; instrument_idx <= 31; instrument_idx++ ) {
056 module.set_instrument( instrument_idx, read_mod_instrument( header_1084_bytes, instrument_idx, data_input ) );
057 }
058 return module;
059 }
060
061 private static int calculate_num_patterns( byte[] module_header ) {
062 int num_patterns, order_entry, pattern_idx;
063 num_patterns = 0;
064 for( pattern_idx = 0; pattern_idx < 128; pattern_idx++ ) {
065 order_entry = module_header[ 952 + pattern_idx ] & 0x7F;
066 if( order_entry >= num_patterns ) {
067 num_patterns = order_entry + 1;
068 }
069 }
070 return num_patterns;
071 }
072
073 private static int calculate_num_channels( byte[] module_header ) {
074 int num_channels;
075 switch( ( module_header[ 1082 ] << 8 ) | module_header[ 1083 ] ) {
076 case 0x4b2e: /* M.K. */
077 case 0x4b21: /* M!K! */
078 case 0x542e: /* N.T. */
079 case 0x5434: /* FLT4 */
080 num_channels = 4;
081 break;
082 case 0x484e: /* xCHN */
083 num_channels = module_header[ 1080 ] - 48;
084 break;
085 case 0x4348: /* xxCH */
086 num_channels = ( ( module_header[ 1080 ] - 48 ) * 10 ) + ( module_header[ 1081 ] - 48 );
087 break;
088 default:
089 /* Not recognised. */
090 num_channels = 0;
091 break;
092 }
093 return num_channels;
094 }
095
096 private static Pattern read_mod_pattern( DataInput data_input, int num_channels ) throws IOException {
097 int input_idx, output_idx;
098 int period, instrument, effect, effect_param;
099 Pattern pattern;
100 byte[] input_pattern_data, output_pattern_data;
101 pattern = new Pattern();
102 pattern.num_rows = 64;
103 input_pattern_data = new byte[ 64 * num_channels * 4 ];
104 output_pattern_data = new byte[ 64 * num_channels * 5 ];
105 data_input.readFully( input_pattern_data );
106 input_idx = 0;
107 output_idx = 0;
108 while( input_idx < input_pattern_data.length ) {
109 period = ( input_pattern_data[ input_idx ] & 0x0F ) << 8;
110 period = period | ( input_pattern_data[ input_idx + 1 ] & 0xFF );
111 output_pattern_data[ output_idx ] = to_key( period );
112 instrument = input_pattern_data[ input_idx ] & 0x10;
113 instrument = instrument | ( ( input_pattern_data[ input_idx + 2 ] & 0xF0 ) >> 4 );
114 output_pattern_data[ output_idx + 1 ] = ( byte ) instrument;
115 effect = input_pattern_data[ input_idx + 2 ] & 0x0F;
116 effect_param = input_pattern_data[ input_idx + 3 ] & 0xFF;
117 if( effect == 0x01 && effect_param == 0 ) {
118 /* Portamento up of zero has no effect. */
119 effect = 0;
120 }
121 if( effect == 0x02 && effect_param == 0 ) {
122 /* Portamento down of zero has no effect. */
123 effect = 0;
124 }
125 if( effect == 0x08 && num_channels == 4 ) {
126 /* Some Amiga mods use effect 0x08 for reasons other than panning.*/
127 effect = 0;
128 effect_param = 0;
129 }
130 if( effect == 0x0A && effect_param == 0 ) {
131 /* Volume slide of zero has no effect.*/
132 effect = 0;
133 }
134 if( effect == 0x05 && effect_param == 0 ) {
135 /* Porta + Volume slide of zero has no effect.*/
136 effect = 0x03;
137 }
138 if( effect == 0x06 && effect_param == 0 ) {
139 /* Vibrato + Volume slide of zero has no effect.*/
140 effect = 0x04;
141 }
142 output_pattern_data[ output_idx + 3 ] = ( byte ) effect;
143 output_pattern_data[ output_idx + 4 ] = ( byte ) effect_param;
144 input_idx += 4;
145 output_idx += 5;
146 }
147 pattern.set_pattern_data( output_pattern_data );
148 return pattern;
149 }
150
151 private static Instrument read_mod_instrument( byte[] mod_header, int idx, DataInput data_input ) throws IOException {
152 int header_offset, sample_data_length;
153 int loop_start, loop_length, sample_idx, fine_tune;
154 Instrument instrument;
155 Sample sample;
156 byte[] raw_sample_data;
157 short[] sample_data;
158 header_offset = ( idx - 1 ) * 30 + 20;
159 instrument = new Instrument();
160 instrument.name = ascii_text( mod_header, header_offset, 22 );
161 sample = new Sample();
162 sample_data_length = unsigned_short_be( mod_header, header_offset + 22 ) << 1;
163 fine_tune = mod_header[ header_offset + 24 ] & 0x0F;
164 if( fine_tune > 7 ) {
165 fine_tune -= 16;
166 }
167 sample.transpose = ( fine_tune << IBXM.FP_SHIFT ) / 96;
168 sample.volume = mod_header[ header_offset + 25 ] & 0x7F;
169 loop_start = unsigned_short_be( mod_header, header_offset + 26 ) << 1;
170 loop_length = unsigned_short_be( mod_header, header_offset + 28 ) << 1;
171 if( loop_length < 4 ) {
172 loop_length = 0;
173 }
174 raw_sample_data = new byte[ sample_data_length ];
175 sample_data = new short[ sample_data_length ];
176 try {
177 data_input.readFully( raw_sample_data );
178 } catch( EOFException e ) {
179 System.out.println( "ProTracker: Instrument " + idx + " has samples missing." );
180 }
181 for( sample_idx = 0; sample_idx < raw_sample_data.length; sample_idx++ ) {
182 sample_data[ sample_idx ] = ( short ) ( raw_sample_data[ sample_idx ] << 8 );
183 }
184 sample.set_sample_data( sample_data, loop_start, loop_length, false );
185 instrument.set_num_samples( 1 );
186 instrument.set_sample( 0, sample );
187 return instrument;
188 }
189
190 private static byte to_key( int period ) {
191 int oct, key;
192 if( period < 32 ) {
193 key = 0;
194 } else {
195 oct = LogTable.log_2( 7256 ) - LogTable.log_2( period );
196 if( oct < 0 ) {
197 key = 0;
198 } else {
199 key = oct * 12;
200 key = key >> ( IBXM.FP_SHIFT - 1 );
201 key = ( key >> 1 ) + ( key & 1 );
202 }
203 }
204 return ( byte ) key;
205 }
206
207 private static int unsigned_short_be( byte[] buf, int offset ) {
208 int value;
209 value = ( buf[ offset ] & 0xFF ) << 8;
210 value = value | ( buf[ offset + 1 ] & 0xFF );
211 return value;
212 }
213
214 private static String ascii_text( byte[] buffer, int offset, int length ) {
215 int idx, chr;
216 byte[] string_buffer;
217 String string;
218 string_buffer = new byte[ length ];
219 for( idx = 0; idx < length; idx++ ) {
220 chr = buffer[ offset + idx ];
221 if( chr < 32 ) {
222 chr = 32;
223 }
224 string_buffer[ idx ] = ( byte ) chr;
225 }
226 try {
227 string = new String( string_buffer, 0, length, "ISO-8859-1" );
228 } catch( UnsupportedEncodingException e ) {
229 string = "";
230 }
231 return string;
232 }
233 }
234