package ibxm; public class Channel { public int pattern_loop_row; private Module module; private Instrument instrument; private Sample sample; private int[] global_volume, current_note; private boolean linear_periods, fast_volume_slides, key_on, silent; private int sample_idx, sample_frac, step, left_gain, right_gain; private int volume, panning, fine_tune, period, porta_period, key_add; private int tremolo_speed, tremolo_depth, tremolo_tick, tremolo_wave, tremolo_add; private int vibrato_speed, vibrato_depth, vibrato_tick, vibrato_wave, vibrato_add; private int volume_slide_param, portamento_param, retrig_param; private int volume_envelope_tick, panning_envelope_tick; private int effect_tick, trigger_tick, fade_out_volume, random_seed; private int log_2_sampling_rate; private static final int LOG_2_29024 = LogTable.log_2( 29024 ); private static final int LOG_2_8287 = LogTable.log_2( 8287 ); private static final int LOG_2_8363 = LogTable.log_2( 8363 ); private static final int LOG_2_1712 = LogTable.log_2( 1712 ); private static final int[] sine_table = new int[] { 0, 24 , 49, 74, 97, 120, 141, 161, 180, 197, 212, 224, 235, 244, 250, 253, 255, 253, 250, 244, 235, 224, 212, 197, 180, 161, 141, 120, 97, 74, 49, 24 }; public Channel( Module mod, int sampling_rate, int[] global_vol ) { module = mod; global_volume = global_vol; linear_periods = module.linear_periods; fast_volume_slides = module.fast_volume_slides; current_note = new int[ 5 ]; log_2_sampling_rate = LogTable.log_2( sampling_rate ); } public void reset() { tremolo_speed = 0; tremolo_depth = 0; tremolo_wave = 0; vibrato_speed = 0; vibrato_depth = 0; vibrato_wave = 0; volume_slide_param = 0; portamento_param = 0; retrig_param = 0; random_seed = 0xABC123; instrument = module.get_instrument( 0 ); row( 48, 256, 0, 0, 0 ); } public void resample( int[] mixing_buffer, int frame_offset, int frames, int quality ) { if( !silent ) { switch( quality ) { default: sample.resample_nearest( sample_idx, sample_frac, step, left_gain, right_gain, mixing_buffer, frame_offset, frames ); break; case 1: sample.resample_linear( sample_idx, sample_frac, step, left_gain, right_gain, mixing_buffer, frame_offset, frames ); break; case 2: sample.resample_sinc( sample_idx, sample_frac, step, left_gain, right_gain, mixing_buffer, frame_offset, frames ); break; } } } public void update_sample_idx( int samples ) { sample_frac += step * samples; sample_idx += sample_frac >> IBXM.FP_SHIFT; sample_frac &= IBXM.FP_MASK; } public void set_volume( int vol ) { if( vol < 0 ) { vol = 0; } if( vol > 64 ) { vol = 64; } volume = vol; } public void set_panning( int pan ) { if( pan < 0 ) { pan = 0; } if( pan > 255 ) { pan = 255; } panning = pan; } public void row( int key, int inst_idx, int volume_column, int effect, int effect_param ) { effect = effect & 0xFF; if( effect >= 0x30 ) { /* Effects above 0x30 are internal.*/ effect = 0; } if( effect == 0x00 && effect_param != 0 ) { /* Arpeggio.*/ effect = 0x40; } if( effect == 0x0E ) { /* Renumber 0x0Ex effect command.*/ effect = 0x30 + ( ( effect_param & 0xF0 ) >> 4 ); effect_param = effect_param & 0x0F; } if( effect == 0x21 ) { /* Renumber 0x21x effect command.*/ effect = 0x40 + ( ( effect_param & 0xF0 ) >> 4 ); effect_param = effect_param & 0x0F; } current_note[ 0 ] = key; current_note[ 1 ] = inst_idx; current_note[ 2 ] = volume_column; current_note[ 3 ] = effect; current_note[ 4 ] = effect_param; effect_tick = 0; trigger_tick += 1; update_envelopes(); key_add = 0; vibrato_add = 0; tremolo_add = 0; if( ! ( effect == 0x3D && effect_param > 0 ) ) { /* Not note delay.*/ trigger( key, inst_idx, volume_column, effect ); /* Handle volume column.*/ switch( volume_column & 0xF0 ) { case 0x00: /* Do nothing.*/ break; case 0x60: /* Volume slide down.*/ break; case 0x70: /* Volume slide up.*/ break; case 0x80: /* Fine volume slide down.*/ set_volume( volume - ( volume_column & 0x0F ) ); break; case 0x90: /* Fine volume slide up.*/ set_volume( volume + ( volume_column & 0x0F ) ); break; case 0xA0: /* Set vibrato speed.*/ set_vibrato_speed( volume_column & 0x0F ); break; case 0xB0: /* Vibrato.*/ set_vibrato_depth( volume_column & 0x0F ); vibrato(); break; case 0xC0: /* Set panning.*/ set_panning( ( volume_column & 0x0F ) << 4 ); break; case 0xD0: /* Panning slide left.*/ break; case 0xE0: /* Panning slide right.*/ break; case 0xF0: /* Tone portamento.*/ set_portamento_param( volume_column & 0x0F ); break; default: /* Set volume.*/ set_volume( volume_column - 0x10 ); break; } } if( instrument.vibrato_depth > 0 ) { auto_vibrato(); } switch( effect ) { case 0x01: /* Portmento Up.*/ set_portamento_param( effect_param ); portamento_up(); break; case 0x02: /* Portamento Down.*/ set_portamento_param( effect_param ); portamento_down(); break; case 0x03: /* Tone Portamento.*/ set_portamento_param( effect_param ); break; case 0x04: /* Vibrato.*/ set_vibrato_speed( ( effect_param & 0xF0 ) >> 4 ); set_vibrato_depth( effect_param & 0x0F ); vibrato(); break; case 0x05: /* Tone Portamento + Volume Slide.*/ set_volume_slide_param( effect_param ); volume_slide(); break; case 0x06: /* Vibrato + Volume Slide.*/ set_volume_slide_param( effect_param ); vibrato(); volume_slide(); break; case 0x07: /* Tremolo.*/ set_tremolo_speed( ( effect_param & 0xF0 ) >> 4 ); set_tremolo_depth( effect_param & 0x0F ); tremolo(); break; case 0x08: /* Set Panning.*/ set_panning( effect_param ); break; case 0x09: /* Set Sample Index.*/ set_sample_index( effect_param << 8 ); break; case 0x0A: /* Volume Slide.*/ set_volume_slide_param( effect_param ); volume_slide(); break; case 0x0B: /* Pattern Jump.*/ break; case 0x0C: /* Set volume.*/ set_volume( effect_param ); break; case 0x0D: /* Pattern Break.*/ break; case 0x0E: /* Extended Commands (See 0x30-0x3F).*/ break; case 0x0F: /* Set Speed/Tempo.*/ break; case 0x10: /* Set Global Volume.*/ set_global_volume( effect_param ); break; case 0x11: /* global Volume Slide.*/ set_volume_slide_param( effect_param ); break; case 0x14: /* Key Off*/ if( effect_param == 0 ) { key_on = false; } break; case 0x15: /* Set Envelope Tick.*/ set_envelope_tick( effect_param ); break; case 0x19: /* Panning Slide.*/ set_volume_slide_param( effect_param ); break; case 0x1B: /* Retrig + Volume Slide.*/ set_retrig_param( effect_param ); retrig_volume_slide(); break; case 0x1D: /* Tremor.*/ set_retrig_param( effect_param ); tremor(); break; case 0x24: /* S3M Fine Vibrato.*/ set_vibrato_speed( ( effect_param & 0xF0 ) >> 4 ); set_vibrato_depth( effect_param & 0x0F ); fine_vibrato(); break; case 0x25: /* S3M Set Speed.*/ break; case 0x30: /* Amiga Set Filter.*/ break; case 0x31: /* Fine Portamento Up.*/ set_portamento_param( 0xF0 | effect_param ); portamento_up(); break; case 0x32: /* Fine Portamento Down.*/ set_portamento_param( 0xF0 | effect_param ); portamento_down(); break; case 0x33: /* Set Glissando Mode.*/ break; case 0x34: /* Set Vibrato Waveform.*/ set_vibrato_wave( effect_param ); break; case 0x35: /* Set Fine Tune.*/ break; case 0x36: /* Pattern Loop.*/ break; case 0x37: /* Set Tremolo Waveform.*/ set_tremolo_wave( effect_param ); break; case 0x38: /* Set Panning(Obsolete).*/ break; case 0x39: /* Retrig.*/ set_retrig_param( effect_param ); break; case 0x3A: /* Fine Volume Slide Up.*/ set_volume_slide_param( ( effect_param << 4 ) | 0x0F ); volume_slide(); break; case 0x3B: /* Fine Volume Slide Down.*/ set_volume_slide_param( 0xF0 | effect_param ); volume_slide(); break; case 0x3C: /* Note Cut.*/ if( effect_param == 0 ) { set_volume( 0 ); } break; case 0x3D: /* Note Delay.*/ break; case 0x3E: /* Pattern Delay.*/ break; case 0x3F: /* Invert Loop.*/ break; case 0x40: /* Arpeggio.*/ break; case 0x41: /* Extra Fine Porta Up.*/ set_portamento_param( 0xE0 | effect_param ); portamento_up(); break; case 0x42: /* Extra Fine Porta Down.*/ set_portamento_param( 0xE0 | effect_param ); portamento_down(); break; } calculate_amplitude(); calculate_frequency(); } public void tick() { int volume_column, effect, effect_param; volume_column = current_note[ 2 ]; effect = current_note[ 3 ]; effect_param = current_note[ 4 ]; effect_tick += 1; if( effect == 0x3D && effect_param == effect_tick ) { /* Note delay.*/ row( current_note[ 0 ], current_note[ 1 ], volume_column, 0, 0 ); } else { trigger_tick += 1; vibrato_tick += 1; tremolo_tick += 1; update_envelopes(); key_add = 0; vibrato_add = 0; tremolo_add = 0; if( instrument.vibrato_depth > 0 ) { auto_vibrato(); } switch( volume_column & 0xF0 ) { case 0x60: /* Volume Slide Down.*/ set_volume( volume - ( volume_column & 0x0F ) ); break; case 0x70: /* Volume Slide Up.*/ set_volume( volume + ( volume_column & 0x0F ) ); break; case 0xB0: /* Vibrato.*/ vibrato(); break; case 0xD0: /* Panning Slide Left.*/ set_panning( panning - ( volume_column & 0x0F ) ); break; case 0xE0: /* Panning Slide Right.*/ set_panning( panning + ( volume_column & 0x0F ) ); break; case 0xF0: /* Tone Portamento.*/ tone_portamento(); break; } switch( effect ) { case 0x01: /* Portamento Up.*/ portamento_up(); break; case 0x02: /* Portamento Down.*/ portamento_down(); break; case 0x03: /* Tone Portamento.*/ tone_portamento(); break; case 0x04: /* Vibrato.*/ vibrato(); break; case 0x05: /* Tone Portamento + Volume Slide.*/ tone_portamento(); volume_slide(); break; case 0x06: /* Vibrato + Volume Slide */ vibrato(); volume_slide(); break; case 0x07: /* Tremolo.*/ tremolo(); break; case 0x0A: /* Volume Slide.*/ volume_slide(); break; case 0x11: /* Global Volume Slide.*/ global_volume_slide(); break; case 0x14: /* Key off.*/ if( effect_tick == effect_param ) { key_on = false; } break; case 0x19: /* Panning Slide.*/ panning_slide(); break; case 0x1B: /* Retrig + Volume Slide.*/ retrig_volume_slide(); break; case 0x1D: /* Tremor.*/ tremor(); break; case 0x24: /* S3M Fine Vibrato.*/ fine_vibrato(); break; case 0x39: /* Retrig.*/ retrig_volume_slide(); break; case 0x3C: /* Note Cut.*/ if( effect_tick == effect_param ) { set_volume( 0 ); } break; case 0x40: /* Arpeggio.*/ switch( effect_tick % 3 ) { case 1: key_add = ( effect_param & 0xF0 ) >> 4; break; case 2: key_add = effect_param & 0x0F; break; } break; } } calculate_amplitude(); calculate_frequency(); } private void set_vibrato_speed( int speed ) { if( speed > 0 ) { vibrato_speed = speed; } } private void set_vibrato_depth( int depth ) { if( depth > 0 ) { vibrato_depth = depth; } } private void set_vibrato_wave( int wave ) { if( wave < 0 || wave > 7 ) { wave = 0; } vibrato_wave = wave; } private void set_tremolo_speed( int speed ) { if( speed > 0 ) { tremolo_speed = speed; } } private void set_tremolo_depth( int depth ) { if( depth > 0 ) { tremolo_depth = depth; } } private void set_tremolo_wave( int wave ) { if( wave < 0 || wave > 7 ) { wave = 0; } tremolo_wave = wave; } private void vibrato() { int vibrato_phase; vibrato_phase = vibrato_tick * vibrato_speed; vibrato_add += waveform( vibrato_phase, vibrato_wave ) * vibrato_depth >> 5; } private void fine_vibrato() { int vibrato_phase; vibrato_phase = vibrato_tick * vibrato_speed; vibrato_add += waveform( vibrato_phase, vibrato_wave ) * vibrato_depth >> 7; } private void tremolo() { int tremolo_phase; tremolo_phase = tremolo_tick * tremolo_speed; tremolo_add += waveform( tremolo_phase, tremolo_wave ) * tremolo_depth >> 6; } private void set_portamento_param( int param ) { if( param != 0 ) { portamento_param = param; } } private void tone_portamento() { int new_period; if( porta_period < period ) { new_period = period - ( portamento_param << 2 ); if( new_period < porta_period ) { new_period = porta_period; } set_period( new_period ); } if( porta_period > period ) { new_period = period + ( portamento_param << 2 ); if( new_period > porta_period ) { new_period = porta_period; } set_period( new_period ); } } private void portamento_up() { if( ( portamento_param & 0xF0 ) == 0xE0 ) { /* Extra-fine porta.*/ if( effect_tick == 0 ) { set_period( period - ( portamento_param & 0x0F ) ); } } else if( ( portamento_param & 0xF0 ) == 0xF0 ) { /* Fine porta.*/ if( effect_tick == 0 ) { set_period( period - ( ( portamento_param & 0x0F ) << 2 ) ); } } else { /* Normal porta.*/ if( effect_tick > 0 ) { set_period( period - ( portamento_param << 2 ) ); } } } private void portamento_down() { if( ( portamento_param & 0xF0 ) == 0xE0 ) { /* Extra-fine porta.*/ if( effect_tick == 0 ) { set_period( period + ( portamento_param & 0x0F ) ); } } else if( ( portamento_param & 0xF0 ) == 0xF0 ) { /* Fine porta.*/ if( effect_tick == 0 ) { set_period( period + ( ( portamento_param & 0x0F ) << 2 ) ); } } else { /* Normal porta.*/ if( effect_tick > 0 ) { set_period( period + ( portamento_param << 2 ) ); } } } private void set_period( int p ) { if( p < 32 ) { p = 32; } if( p > 32768 ) { p = 32768; } period = p; } private void set_global_volume( int vol ) { if( vol < 0 ) { vol = 0; } if( vol > 64 ) { vol = 64; } global_volume[ 0 ] = vol; } private void set_volume_slide_param( int param ) { if( param != 0 ) { volume_slide_param = param; } } private void global_volume_slide() { int up, down; up = ( volume_slide_param & 0xF0 ) >> 4; down = volume_slide_param & 0x0F; set_global_volume( global_volume[ 0 ] + up - down ); } private void volume_slide() { int up, down; up = ( volume_slide_param & 0xF0 ) >> 4; down = volume_slide_param & 0x0F; if( down == 0x0F && up > 0 ) { /* Fine slide up.*/ if( effect_tick == 0 ) { set_volume( volume + up ); } } else if( up == 0x0F && down > 0 ) { /* Fine slide down.*/ if( effect_tick == 0 ) { set_volume( volume - down ); } } else { /* Normal slide.*/ if( effect_tick > 0 || fast_volume_slides ) { set_volume( volume + up - down ); } } } private void panning_slide() { int left, right; left = ( volume_slide_param & 0xF0 ) >> 4; right = volume_slide_param & 0x0F; set_panning( panning - left + right ); } private void set_retrig_param( int param ) { if( param != 0 ) { retrig_param = param; } } private void tremor() { int on_ticks, cycle_length, cycle_index; on_ticks = ( ( retrig_param & 0xF0 ) >> 4 ) + 1; cycle_length = on_ticks + ( retrig_param & 0x0F ) + 1; cycle_index = trigger_tick % cycle_length; if( cycle_index >= on_ticks ) { tremolo_add = -64; } } private void retrig_volume_slide() { int retrig_volume, retrig_tick; retrig_volume = ( retrig_param & 0xF0 ) >> 4; retrig_tick = retrig_param & 0x0F; if( retrig_tick > 0 && ( trigger_tick % retrig_tick ) == 0 ) { set_sample_index( 0 ); switch( retrig_volume ) { case 0x01: set_volume( volume - 1 ); break; case 0x02: set_volume( volume - 2 ); break; case 0x03: set_volume( volume - 4 ); break; case 0x04: set_volume( volume - 8 ); break; case 0x05: set_volume( volume - 16 ); break; case 0x06: set_volume( volume - volume / 3 ); break; case 0x07: set_volume( volume / 2 ); break; case 0x09: set_volume( volume + 1 ); break; case 0x0A: set_volume( volume + 2 ); break; case 0x0B: set_volume( volume + 4 ); break; case 0x0C: set_volume( volume + 8 ); break; case 0x0D: set_volume( volume + 16 ); break; case 0x0E: set_volume( volume + volume / 2 ); break; case 0x0F: set_volume( volume * 2 ); break; } } } private void set_sample_index( int index ) { if( index < 0 ) { index = 0; } sample_idx = index; sample_frac = 0; } private void set_envelope_tick( int tick ) { volume_envelope_tick = tick; panning_envelope_tick = tick; } private void trigger( int key, int instrument_idx, int volume_column, int effect ) { if( instrument_idx > 0 ) { instrument = module.get_instrument( instrument_idx ); sample = instrument.get_sample_from_key( key ); set_volume( sample.volume ); if( sample.set_panning ) { set_panning( sample.panning ); } set_envelope_tick( 0 ); fade_out_volume = 32768; key_on = true; } if( key > 0 ) { if( key < 97 ) { porta_period = key_to_period( key ); if( effect != 0x03 && effect != 0x05 ) { if( ( volume_column & 0xF0 ) != 0xF0 ) { /* Not portamento.*/ trigger_tick = 0; if( vibrato_wave < 4 ) { vibrato_tick = 0; } if( tremolo_wave < 4 ) { tremolo_tick = 0; } set_period( porta_period ); set_sample_index( 0 ); } } } else { /* Key off.*/ key_on = false; } } } private void update_envelopes() { Envelope envelope; if( instrument.volume_envelope_active ) { if( !key_on ) { fade_out_volume -= instrument.volume_fade_out & 0xFFFF; if( fade_out_volume < 0 ) { fade_out_volume = 0; } } envelope = instrument.get_volume_envelope(); volume_envelope_tick = envelope.next_tick( volume_envelope_tick, key_on ); } if( instrument.panning_envelope_active ) { envelope = instrument.get_panning_envelope(); panning_envelope_tick = envelope.next_tick( panning_envelope_tick, key_on ); } } private void auto_vibrato() { int sweep, depth, rate; sweep = instrument.vibrato_sweep & 0xFF; depth = instrument.vibrato_depth & 0x0F; rate = instrument.vibrato_rate & 0x3F; if( trigger_tick < sweep ) { depth = depth * trigger_tick / sweep; } vibrato_add += waveform( trigger_tick * rate, 0 ) * depth >> 9; } private int waveform( int phase, int wform ) { int amplitude; amplitude = 0; switch( wform & 0x3 ) { case 0: /* Sine. */ if( ( phase & 0x20 ) == 0 ) { amplitude = sine_table[ phase & 0x1F ]; } else { amplitude = -sine_table[ phase & 0x1F ]; } break; case 1: /* Saw. */ if( ( phase & 0x20 ) == 0 ) { amplitude = ( phase & 0x1F ) << 3; } else { amplitude = ( ( phase & 0x1F ) << 3 ) - 255; } break; case 2: /* Square. */ if( ( phase & 0x20 ) == 0 ) { amplitude = 255; } else { amplitude = -255; } break; case 3: /* Random. */ amplitude = ( random_seed >> 15 ) - 255; random_seed = ( random_seed * 65 + 17 ) & 0xFFFFFF; break; } return amplitude; } private int key_to_period( int key ) { int octave, log_2_period, period_out; octave = ( key << IBXM.FP_SHIFT ) / 12 + sample.transpose; if( linear_periods ) { period_out = 7744 - ( octave * 768 >> IBXM.FP_SHIFT ); } else { log_2_period = LOG_2_29024 - octave; period_out = LogTable.raise_2( log_2_period ); period_out = period_out >> ( IBXM.FP_SHIFT - 1 ); period_out = ( period_out >> 1 ) + ( period_out & 1 ); } return period_out; } private void calculate_amplitude() { int envelope_volume, tremolo_volume, amplitude; int envelope_panning, mixer_panning, panning_range; Envelope envelope; envelope_volume = 0; if( instrument.volume_envelope_active ) { envelope = instrument.get_volume_envelope(); envelope_volume = envelope.calculate_ampl( volume_envelope_tick ); } else { if( key_on ) { envelope_volume = 64; } } tremolo_volume = volume + tremolo_add; if( tremolo_volume < 0 ) { tremolo_volume = 0; } if( tremolo_volume > 64 ) { tremolo_volume = 64; } amplitude = tremolo_volume << IBXM.FP_SHIFT - 6; amplitude = amplitude * envelope_volume >> 6; amplitude = amplitude * fade_out_volume >> 15; amplitude = amplitude * global_volume[ 0 ] >> 6; amplitude = amplitude * module.channel_gain >> IBXM.FP_SHIFT; silent = sample.has_finished( sample_idx ); if( amplitude <= 0 ) { silent = true; } else { envelope_panning = 32; if( instrument.panning_envelope_active ) { envelope = instrument.get_panning_envelope(); envelope_panning = envelope.calculate_ampl( panning_envelope_tick ); } mixer_panning = ( panning & 0xFF ) << IBXM.FP_SHIFT - 8; panning_range = IBXM.FP_ONE - mixer_panning; if( panning_range > mixer_panning ) { panning_range = mixer_panning; } mixer_panning = mixer_panning + ( panning_range * ( envelope_panning - 32 ) >> 5 ); left_gain = amplitude * ( IBXM.FP_ONE - mixer_panning ) >> IBXM.FP_SHIFT; right_gain = amplitude * mixer_panning >> IBXM.FP_SHIFT; } } private void calculate_frequency() { int vibrato_period, log_2_freq; vibrato_period = period + vibrato_add; if( vibrato_period < 32 ) { vibrato_period = 32; } if( vibrato_period > 32768 ) { vibrato_period = 32768; } if( linear_periods ) { log_2_freq = LOG_2_8363 + ( 4608 - vibrato_period << IBXM.FP_SHIFT ) / 768; } else { log_2_freq = module.pal ? LOG_2_8287 : LOG_2_8363; log_2_freq = log_2_freq + LOG_2_1712 - LogTable.log_2( vibrato_period ); } log_2_freq += ( key_add << IBXM.FP_SHIFT ) / 12; step = LogTable.raise_2( log_2_freq - log_2_sampling_rate ); } }