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