public void dx7_voice_update_mod_depths(hexter_instance instance) { byte kp = instance.key_pressure[this.key]; byte cp = instance.channel_pressure; float pressure; float pdepth, adepth, mdepth, edepth; /* add the channel and key pressures together in a way that 'feels' good */ if (kp > cp) { pressure = (float)kp / 127.0f; pressure += (1.0f - pressure) * ((float)cp / 127.0f); } else { pressure = (float)cp / 127.0f; pressure += (1.0f - pressure) * ((float)kp / 127.0f); } /* calculate modulation depths */ pdepth = (float)this.lfo_pmd / 99.0f; this.pitch_mod_depth_pmd = (double)Data.dx7_voice_pms_to_semitones[this.lfo_pms] * (double)pdepth; // -FIX- this could be optimized: // -FIX- this just adds everything together -- maybe it should limit the result, or // combine the various mods like update_pressure() does pdepth = (((instance.mod_wheel_assign & 0x01) != 0) ? // -FIX- this assumes that mod_wheel_sensitivity, etc. scale linearly => verify (float)instance.mod_wheel_sensitivity / 15.0f * instance.mod_wheel : 0.0f) + (((instance.foot_assign & 0x01) != 0) ? (float)instance.foot_sensitivity / 15.0f * instance.foot : 0.0f) + (((instance.pressure_assign & 0x01) != 0) ? (float)instance.pressure_sensitivity / 15.0f * pressure : 0.0f) + (((instance.breath_assign & 0x01) != 0) ? (float)instance.breath_sensitivity / 15.0f * instance.breath : 0.0f); this.pitch_mod_depth_mods = (double)Data.dx7_voice_pms_to_semitones[this.lfo_pms] * (double)pdepth; // -FIX- these are total guesses at how to combine/limit the amp mods: adepth = Data.dx7_voice_amd_to_ol_adjustment[this.lfo_amd]; // -FIX- this could be optimized: mdepth = (((instance.mod_wheel_assign & 0x02) != 0) ? Data.dx7_voice_mss_to_ol_adjustment[instance.mod_wheel_sensitivity] * instance.mod_wheel : 0.0f) + (((instance.foot_assign & 0x02) != 0) ? Data.dx7_voice_mss_to_ol_adjustment[instance.foot_sensitivity] * instance.foot : 0.0f) + (((instance.pressure_assign & 0x02) != 0) ? Data.dx7_voice_mss_to_ol_adjustment[instance.pressure_sensitivity] * pressure : 0.0f) + (((instance.breath_assign & 0x02) != 0) ? Data.dx7_voice_mss_to_ol_adjustment[instance.breath_sensitivity] * instance.breath : 0.0f); edepth = // -FIX- this could be optimized: (((instance.mod_wheel_assign & 0x04) != 0) ? Data.dx7_voice_mss_to_ol_adjustment[instance.mod_wheel_sensitivity] * (1.0f - instance.mod_wheel) : 0.0f) + (((instance.foot_assign & 0x04) != 0) ? Data.dx7_voice_mss_to_ol_adjustment[instance.foot_sensitivity] * (1.0f - instance.foot) : 0.0f) + (((instance.pressure_assign & 0x04) != 0) ? Data.dx7_voice_mss_to_ol_adjustment[instance.pressure_sensitivity] * (1.0f - pressure) : 0.0f) + (((instance.breath_assign & 0x04) != 0) ? Data.dx7_voice_mss_to_ol_adjustment[instance.breath_sensitivity] * (1.0f - instance.breath) : 0.0f); /* full-scale amp mod for adepth and edepth should be 52.75 and * their sum _must_ be limited to less than 128, or bad things will happen! */ if (adepth > 127.5f) { adepth = 127.5f; } if (adepth + mdepth > 127.5f) { mdepth = 127.5f - adepth; } if (adepth + mdepth + edepth > 127.5f) { edepth = 127.5f - (adepth + mdepth); } this.amp_mod_lfo_amd_target = Inline.FLOAT_TO_FP(adepth); if (this.amp_mod_lfo_amd_value <= Inline.INT_TO_FP(-64)) { this.amp_mod_lfo_amd_value = this.amp_mod_lfo_amd_target; this.amp_mod_lfo_amd_increment = 0; this.amp_mod_lfo_amd_duration = 0; } else { this.amp_mod_lfo_amd_duration = instance.ramp_duration; this.amp_mod_lfo_amd_increment = (this.amp_mod_lfo_amd_target - this.amp_mod_lfo_amd_value) / (Int32)this.amp_mod_lfo_amd_duration; } this.amp_mod_lfo_mods_target = Inline.FLOAT_TO_FP(mdepth); if (this.amp_mod_lfo_mods_value <= Inline.INT_TO_FP(-64)) { this.amp_mod_lfo_mods_value = this.amp_mod_lfo_mods_target; this.amp_mod_lfo_mods_increment = 0; this.amp_mod_lfo_mods_duration = 0; } else { this.amp_mod_lfo_mods_duration = instance.ramp_duration; this.amp_mod_lfo_mods_increment = (this.amp_mod_lfo_mods_target - this.amp_mod_lfo_mods_value) / (Int32)this.amp_mod_lfo_mods_duration; } this.amp_mod_env_target = Inline.FLOAT_TO_FP(edepth); if (this.amp_mod_env_value <= Inline.INT_TO_FP(-64)) { this.amp_mod_env_value = this.amp_mod_env_target; this.amp_mod_env_increment = 0; this.amp_mod_env_duration = 0; } else { this.amp_mod_env_duration = instance.ramp_duration; this.amp_mod_env_increment = (this.amp_mod_env_target - this.amp_mod_env_value) / (Int32)this.amp_mod_env_duration; } }
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; } }
public void dx7_voice_set_data(hexter_instance instance) { byte[] edit_buffer = instance.current_patch_buffer; bool compat059 = (instance.performance_buffer[0] & 0x01) > 0 ? true : false; /* 0.5.9 compatibility */ int i, j; double aux_feedbk; for (i = 0; i < Constants.MAX_DX7_OPERATORS; i++) { byte[] eb_op = edit_buffer; int offset = ((5 - i) * 21); this.op[i].output_level = (byte)(Inline.limit(eb_op[16 + offset], 0, 99)); this.op[i].osc_mode = (byte)(eb_op[17 + offset] & 0x01); this.op[i].coarse = (byte)(eb_op[18 + offset] & 0x1f); this.op[i].fine = (byte)(Inline.limit(eb_op[19 + offset], 0, 99)); this.op[i].detune = (byte)(Inline.limit(eb_op[20 + offset], 0, 14)); this.op[i].level_scaling_bkpoint = (byte)(Inline.limit(eb_op[8 + offset], 0, 99)); this.op[i].level_scaling_l_depth = (byte)(Inline.limit(eb_op[9 + offset], 0, 99)); this.op[i].level_scaling_r_depth = (byte)(Inline.limit(eb_op[10 + offset], 0, 99)); this.op[i].level_scaling_l_curve = (byte)(eb_op[11 + offset] & 0x03); this.op[i].level_scaling_r_curve = (byte)(eb_op[12 + offset] & 0x03); this.op[i].rate_scaling = (byte)(eb_op[13 + offset] & 0x07); this.op[i].amp_mod_sens = (byte)((compat059 ? 0 : eb_op[14 + offset] & 0x03)); this.op[i].velocity_sens = (byte)(eb_op[15 + offset] & 0x07); for (j = 0; j < 4; j++) { this.op[i].eg.base_rate[j] = (byte)(Inline.limit(eb_op[j + offset], 0, 99)); this.op[i].eg.base_level[j] = (byte)(Inline.limit(eb_op[4 + j + offset], 0, 99)); } } for (i = 0; i < 4; i++) { this.pitch_eg.rate[i] = (byte)(Inline.limit(edit_buffer[126 + i], 0, 99)); this.pitch_eg.level[i] = (byte)(Inline.limit(edit_buffer[130 + i], 0, 99)); } this.algorithm = (byte)(edit_buffer[134] & 0x1f); aux_feedbk = (double)(edit_buffer[135] & 0x07) / (2.0 * Constants.M_PI) * 0.18 /* -FIX- feedback_scaling[this.algorithm] */; /* the "99.0" here is because we're also using this multiplier to scale the * eg level from 0-99 to 0-1 */ this.feedback_multiplier = (int)Math.Round(aux_feedbk / 99.0 * Constants.FP_SIZE); this.osc_key_sync = (byte)(edit_buffer[136] & 0x01); this.lfo_speed = (byte)(Inline.limit(edit_buffer[137], 0, 99)); this.lfo_delay = (byte)(Inline.limit(edit_buffer[138], 0, 99)); this.lfo_pmd = (byte)(Inline.limit(edit_buffer[139], 0, 99)); this.lfo_amd = (byte)(Inline.limit(edit_buffer[140], 0, 99)); this.lfo_key_sync = (byte)(edit_buffer[141] & 0x01); this.lfo_wave = (byte)(Inline.limit(edit_buffer[142], 0, 5)); this.lfo_pms = (byte)((compat059 ? 0 : edit_buffer[143] & 0x07)); this.transpose = Inline.limit(edit_buffer[144], 0, 48); }
public void dx7_op_envelope_prepare(hexter_instance instance, int transposed_note, int velocity) { int scaled_output_level, i, rate_bump; float vel_adj; scaled_output_level = this.output_level; /* things that affect breakpoint calculations: transpose, ? */ /* things that don't affect breakpoint calculations: pitch envelope, ? */ if ((transposed_note < this.level_scaling_bkpoint + 21) && (this.level_scaling_l_depth != 0)) { /* On the original DX7/TX7, keyboard level scaling calculations * group the keyboard into groups of three keys. This can be quite * noticeable on patches with extreme scaling depths, so I've tried * to replicate it here (the steps between levels may not occur at * exactly the keys). If you'd prefer smother scaling, define * SMOOTH_KEYBOARD_LEVEL_SCALING. */ //#ifndef SMOOTH_KEYBOARD_LEVEL_SCALING i = this.level_scaling_bkpoint - (((transposed_note + 2) / 3) * 3) + 21; //#else // i = this.level_scaling_bkpoint - transposed_note + 21; //#endif switch (this.level_scaling_l_curve) { case 0: /* -LIN */ scaled_output_level -= (int)((float)i / 45.0f * (float)this.level_scaling_l_depth); break; case 1: /* -EXP */ scaled_output_level -= (int)(Math.Exp((float)(i - 72) / 13.5f) * (float)this.level_scaling_l_depth); break; case 2: /* +EXP */ scaled_output_level += (int)(Math.Exp((float)(i - 72) / 13.5f) * (float)this.level_scaling_l_depth); break; case 3: /* +LIN */ scaled_output_level += (int)((float)i / 45.0f * (float)this.level_scaling_l_depth); break; } if (scaled_output_level < 0) { scaled_output_level = 0; } if (scaled_output_level > 99) { scaled_output_level = 99; } } else if ((transposed_note > this.level_scaling_bkpoint + 21) && (this.level_scaling_r_depth != 0)) { //#ifndef SMOOTH_KEYBOARD_LEVEL_SCALING i = (((transposed_note + 2) / 3) * 3) - this.level_scaling_bkpoint - 21; //#else // i = transposed_note - op.level_scaling_bkpoint - 21; //#endif switch (this.level_scaling_r_curve) { case 0: /* -LIN */ scaled_output_level -= (int)((float)i / 45.0f * (float)this.level_scaling_r_depth); break; case 1: /* -EXP */ scaled_output_level -= (int)(Math.Exp((float)(i - 72) / 13.5f) * (float)this.level_scaling_r_depth); break; case 2: /* +EXP */ scaled_output_level += (int)(Math.Exp((float)(i - 72) / 13.5f) * (float)this.level_scaling_r_depth); break; case 3: /* +LIN */ scaled_output_level += (int)((float)i / 45.0f * (float)this.level_scaling_r_depth); break; } if (scaled_output_level < 0) { scaled_output_level = 0; } if (scaled_output_level > 99) { scaled_output_level = 99; } } vel_adj = Data.dx7_voice_velocity_ol_adjustment[velocity] * (float)this.velocity_sens; /* DEBUG_MESSAGE(DB_NOTE, " dx7_op_envelope_prepare: s_o_l=%d, vel_adj=%f\n", scaled_output_level, vel_adj); */ /* -FIX- This calculation comes from Pinkston/Harrington; the original "* 6.0" scaling factor * was close to what my TX7 does, but tended to not bump the rate as much, so I changed it * to "* 6.5" which seems a little closer, but it's still not spot-on. */ /* Things which affect this calculation: transpose, ? */ /* rate_bump = lrintf((float)op.rate_scaling * (float)(transposed_note - 21) / (126.0f - 21.0f) * 127.0f / 128.0f * 6.0f - 0.5f); */ rate_bump = (int)Math.Round(((float)this.rate_scaling * (float)(transposed_note - 21) / (126.0f - 21.0f) * 127.0f / 128.0f * 6.5f - 0.5f)); /* -FIX- just a hunch: try it again with "* 6.0f" but also "(120.0f - 21.0f)" instead of "(126.0f - 21.0f)": */ /* rate_bump = lrintf((float)op.rate_scaling * (float)(transposed_note - 21) / (120.0f - 21.0f) * 127.0f / 128.0f * 6.0f - 0.5f); */ for (i = 0; i < 4; i++) { float level = (float)this.eg.base_level[i]; /* -FIX- is this scaling of eg.base_level values to og.level values correct, i.e. does a softer * velocity shorten the time, since the rate stays the same? */ level = level * (float)scaled_output_level / 99.0f + vel_adj; if (level < 0.0f) { level = 0.0f; } else if (level > 99.0f) { level = 99.0f; } this.eg.level[i] = (byte)Math.Round(level); this.eg.rate[i] = (byte)(this.eg.base_rate[i] + rate_bump); if (this.eg.rate[i] > 99) { this.eg.rate[i] = 99; } } this.eg.value = Inline.INT_TO_FP(this.eg.level[3]); this.eg.dx7_op_eg_set_phase(instance, 0); }