public double dx7_voice_recalculate_frequency(hexter_instance instance) { double freq; this.last_port_tuning = instance.tuning; instance.fixed_freq_multiplier = instance.tuning / 440.0; freq = this.pitch_eg.value + this.portamento.value + instance.pitch_bend - instance.lfo_value_for_pitch * (this.pitch_mod_depth_pmd * Inline.FP_TO_DOUBLE(this.lfo_delay_value) + this.pitch_mod_depth_mods); this.last_pitch = freq; freq += (double)(limit_note(this.key + this.transpose - 24)); /* -FIX- this maybe could be optimized */ /* a lookup table of 8k values would give ~1.5 cent accuracy, * but then would interpolating that be faster than exp()? */ freq = instance.tuning * Math.Exp((freq - 69.0) * Constants.M_LN2 / 12.0); return(freq); }
public void dx7_voice_do_control_update() { double new_pitch; /* do those things which should be done only once per control- * calculation interval ("nugget"), such as voice check-for-dead, * pitch envelope calculations, etc. */ /* check if we've decayed to nothing, turn off voice if so */ if (dx7_voice_check_for_dead() != 0) { return; /* we're dead now, so return */ } /* update pitch envelope and portamento */ this.pitch_eg.dx7_pitch_eg_process(instance); this.portamento.dx7_portamento_process(instance); /* update phase increments if pitch or tuning changed */ new_pitch = this.pitch_eg.value + this.portamento.value + instance.pitch_bend - instance.lfo_value_for_pitch * (this.pitch_mod_depth_pmd * Inline.FP_TO_DOUBLE(this.lfo_delay_value) + this.pitch_mod_depth_mods); if ((this.last_pitch != new_pitch) || (this.last_port_tuning != instance.tuning)) { dx7_voice_recalculate_freq_and_inc(instance); } /* op envelope rounding correction */ this.op[Constants.OP_6].eg.dx7_op_eg_adjust(); this.op[Constants.OP_5].eg.dx7_op_eg_adjust(); this.op[Constants.OP_4].eg.dx7_op_eg_adjust(); this.op[Constants.OP_3].eg.dx7_op_eg_adjust(); this.op[Constants.OP_2].eg.dx7_op_eg_adjust(); this.op[Constants.OP_1].eg.dx7_op_eg_adjust(); /* mods and output volume */ if (!(this.amp_mod_env_duration != 0)) { this.amp_mod_env_value = this.amp_mod_env_target; } if (!(this.amp_mod_lfo_mods_duration != 0)) { this.amp_mod_lfo_mods_value = this.amp_mod_lfo_mods_target; } if (!(this.amp_mod_lfo_amd_duration != 0)) { this.amp_mod_lfo_amd_value = this.amp_mod_lfo_amd_target; } if (!(this.volume_duration != 0)) { this.volume_value = this.volume_target; } }
public void dx7_lfo_update(UInt64 sample_count) { UInt64 sample; switch (this.lfo_wave) { default: case 0: /* triangle */ case 1: /* saw down */ case 2: /* saw up */ for (sample = 0; sample < sample_count; sample++) { this.lfo_buffer[sample] = this.lfo_value; this.lfo_value += this.lfo_increment; if ((--this.lfo_duration) == 0) { if (this.lfo_phase != 0) { this.lfo_phase = 0; this.lfo_value = 0; this.lfo_duration = this.lfo_duration0; this.lfo_increment = this.lfo_increment0; } else { this.lfo_phase = 1; this.lfo_value = Constants.FP_SIZE; this.lfo_duration = this.lfo_duration1; this.lfo_increment = this.lfo_increment1; } } } this.lfo_value_for_pitch = Inline.FP_TO_DOUBLE(this.lfo_value) * 2.0 - 1.0; /* -FIX- this is still ramped for saw! */ break; case 3: /* square */ for (sample = 0; sample < sample_count; sample++) { this.lfo_buffer[sample] = this.lfo_value; this.lfo_value += this.lfo_increment; if ((--this.lfo_duration) == 0) { switch (this.lfo_phase) { default: case 0: this.lfo_phase = 1; this.lfo_duration = this.lfo_duration1; this.lfo_increment = this.lfo_increment0; break; case 1: this.lfo_phase = 2; this.lfo_value = 0; this.lfo_duration = this.lfo_duration0; this.lfo_increment = 0; break; case 2: this.lfo_phase = 3; this.lfo_duration = this.lfo_duration1; this.lfo_increment = this.lfo_increment1; break; case 3: this.lfo_phase = 0; this.lfo_value = Constants.FP_SIZE; this.lfo_duration = this.lfo_duration0; this.lfo_increment = 0; break; } } } if (this.lfo_phase == 0 || this.lfo_phase == 3) { this.lfo_value_for_pitch = 1.0; } else { this.lfo_value_for_pitch = -1.0; } break; case 4: /* sine */ for (sample = 0; sample < sample_count; sample++) { Int32 phase, index, outx; phase = this.lfo_value; index = (phase >> Constants.FP_TO_SINE_SHIFT) & Constants.SINE_MASK; outx = Data.dx7_voice_sin_table[index]; outx += (Int32)((((Int64)(Data.dx7_voice_sin_table[index + 1] - outx) * (Int64)(phase & Constants.FP_TO_SINE_MASK)) >> (Constants.FP_SHIFT + Constants.FP_TO_SINE_SHIFT))); outx = (outx + Constants.FP_SIZE) >> 1; /* shift to unipolar */ this.lfo_buffer[sample] = outx; this.lfo_value += this.lfo_increment; } this.lfo_value_for_pitch = Inline.FP_TO_DOUBLE(this.lfo_buffer[sample - 1]) * 2.0 - 1.0; break; case 5: /* sample/hold */ for (sample = 0; sample < sample_count; sample++) { this.lfo_buffer[sample] = this.lfo_value; this.lfo_value += this.lfo_increment; if ((--this.lfo_duration) == 0) { if (this.lfo_phase != 0) { this.lfo_phase = 0; this.lfo_value = this.lfo_target; this.lfo_duration = this.lfo_duration0; this.lfo_increment = 0; } else { this.lfo_phase = 1; this.lfo_duration = this.lfo_duration1; this.lfo_target = StaticRandom.Next(Constants.FP_SIZE); this.lfo_increment = (this.lfo_target - this.lfo_value) / (Int32)this.lfo_duration; } } } this.lfo_value_for_pitch = Inline.FP_TO_DOUBLE(this.lfo_target) * 2.0 - 1.0; break; } }