示例#1
0
        public void dx7_voice_calculate_runtime_parameters(hexter_instance instance)
        {
            int    i;
            double freq;

            dx7_pitch_envelope_prepare(instance);
            this.amp_mod_lfo_amd_value  = Inline.INT_TO_FP(-64);  /* force initial setup */
            this.amp_mod_lfo_mods_value = Inline.INT_TO_FP(-64);
            this.amp_mod_env_value      = Inline.INT_TO_FP(-64);
            this.lfo_delay_segment      = 0;
            this.lfo_delay_value        = instance.lfo_delay_value[0];
            this.lfo_delay_duration     = instance.lfo_delay_duration[0];
            this.lfo_delay_increment    = instance.lfo_delay_increment[0];
            this.mods_serial            = instance.mods_serial - 1; /* force mod depths update */
            dx7_portamento_prepare(instance);
            freq = dx7_voice_recalculate_frequency(instance);

            this.volume_value = -1.0f;                     /* force initial setup */
            dx7_voice_recalculate_volume(instance);

            for (i = 0; i < Constants.MAX_DX7_OPERATORS; i++)
            {
                this.op[i].frequency = freq;
                if (this.osc_key_sync != 0)
                {
                    this.op[i].phase = 0;
                }
                this.op[i].dx7_op_recalculate_increment(instance);
                this.op[i].dx7_op_envelope_prepare(instance,
                                                   limit_note(this.key + this.transpose - 24),
                                                   this.velocity);
            }
        }
示例#2
0
        public void dx7_eg_init_constants()
        {
            float duration = Data.dx7_voice_eg_rate_rise_duration[99] *
                             (Data.dx7_voice_eg_rate_rise_percent[99] -
                              Data.dx7_voice_eg_rate_rise_percent[0]);

            this.dx7_eg_max_slew = (int)Math.Round((float)Inline.INT_TO_FP(99) /
                                                   (duration * this.sample_rate));

            this.nugget_rate = this.sample_rate / (float)Constants.HEXTER_NUGGET_SIZE;

            this.ramp_duration = (UInt32)Math.Round(this.sample_rate * 0.006f);  /* 6ms ramp */
        }
示例#3
0
        public void dx7_op_eg_set_phase(hexter_instance instance, int phase)
        {
            this.phase = phase;

            if (phase == 0)
            {
                if (this.level[0] == this.level[1] &&
                    this.level[1] == this.level[2] &&
                    this.level[2] == this.level[3])
                {
                    this.mode      = dx7_eg_mode.DX7_EG_CONSTANT;
                    this.value     = Inline.INT_TO_FP(this.level[3]);
                    this.increment = 0;
                    this.duration  = -1;
                }
                else
                {
                    this.mode = dx7_eg_mode.DX7_EG_RUNNING;
                    this.dx7_op_eg_set_increment(instance, this.rate[phase], this.level[phase]);
                    if (this.duration == 1 && this.increment == 0)
                    {
                        this.dx7_op_eg_set_next_phase(instance);
                    }
                }
            }
            else
            {
                if (this.mode != dx7_eg_mode.DX7_EG_CONSTANT)
                {
                    this.mode = dx7_eg_mode.DX7_EG_RUNNING;
                    this.dx7_op_eg_set_increment(instance, this.rate[phase], this.level[phase]);
                    if (this.duration == 1 && this.increment == 0)
                    {
                        this.dx7_op_eg_set_next_phase(instance);
                    }
                }
            }
        }
示例#4
0
        public void dx7_op_eg_set_increment(hexter_instance instance,
                                            int new_rate, int new_level)
        {
            int   current_level = Inline.FP_TO_INT(this.value);
            int   need_compensation;
            float duration;

            this.target = Inline.INT_TO_FP(new_level);

            if (this.value <= this.target)
            {  /* envelope will be rising */
               /* DX7 envelopes, when rising from levels <= 31 to levels
                * >= 32, include a compensation feature to speed the
                * attack, thereby making it sound more natural.  The
                * behavior of some of the boundary cases is bizarre, and
                * this has been exploited by some patch programmers (the
                * "Watergarden" patch found in the original ROM cartridge
                * is one example). We try to emulate it here: */

                if (this.value <= Constants.INT_TO_FP_31)
                {
                    if (new_level > 31)
                    {
                        /* rise quickly to 31, then continue normally */
                        need_compensation = 1;
                        duration          = Data.dx7_voice_eg_rate_rise_duration[new_rate] *
                                            (Data.dx7_voice_eg_rate_rise_percent[new_level] -
                                             Data.dx7_voice_eg_rate_rise_percent[current_level]);
                    }
                    else if (new_level - current_level > 9)
                    {
                        /* these seem to take zero time */
                        need_compensation = 0;
                        duration          = 0.0f;
                    }
                    else
                    {
                        /* these are the exploited delays */
                        need_compensation = 0;
                        /* -FIX- this doesn't make WATER GDN work? */
                        duration = Data.dx7_voice_eg_rate_rise_duration[new_rate] *
                                   (float)(new_level - current_level) / 100.0f;
                    }
                }
                else
                {
                    need_compensation = 0;
                    duration          = Data.dx7_voice_eg_rate_rise_duration[new_rate] *
                                        (Data.dx7_voice_eg_rate_rise_percent[new_level] -
                                         Data.dx7_voice_eg_rate_rise_percent[current_level]);
                }
            }
            else
            {
                need_compensation = 0;
                duration          = Data.dx7_voice_eg_rate_decay_duration[new_rate] *
                                    (Data.dx7_voice_eg_rate_decay_percent[current_level] -
                                     Data.dx7_voice_eg_rate_decay_percent[new_level]);
            }

            duration *= instance.sample_rate;

            this.duration = (int)Math.Round(duration);
            if (this.duration < 1)
            {
                this.duration = 1;
            }

            if (need_compensation != 0)
            {
                Int32 precomp_duration = (Constants.INT_TO_FP_31 - this.value + instance.dx7_eg_max_slew - 1) /
                                         instance.dx7_eg_max_slew;

                if (precomp_duration >= this.duration)
                {
                    this.duration  = precomp_duration;
                    this.increment = (this.target - this.value) / this.duration;
                    if (this.increment > instance.dx7_eg_max_slew)
                    {
                        this.duration = (this.target - this.value + instance.dx7_eg_max_slew - 1) /
                                        instance.dx7_eg_max_slew;
                        this.increment = (this.target - this.value) / this.duration;
                    }
                    this.in_precomp = 0;
                }
                else if (precomp_duration < 1)
                {
                    this.increment = (this.target - this.value) / this.duration;
                    if (this.increment > instance.dx7_eg_max_slew)
                    {
                        this.duration = (this.target - this.value + instance.dx7_eg_max_slew - 1) /
                                        instance.dx7_eg_max_slew;
                        this.increment = (this.target - this.value) / this.duration;
                    }
                    this.in_precomp = 0;
                }
                else
                {
                    this.postcomp_duration  = this.duration - precomp_duration;
                    this.duration           = precomp_duration;
                    this.increment          = (Constants.INT_TO_FP_31 - this.value) / precomp_duration;
                    this.postcomp_increment = (this.target - Constants.INT_TO_FP_31) /
                                              this.postcomp_duration;
                    if (this.postcomp_increment > instance.dx7_eg_max_slew)
                    {
                        this.postcomp_duration = (this.target - Constants.INT_TO_FP_31 + instance.dx7_eg_max_slew - 1) /
                                                 instance.dx7_eg_max_slew;
                        this.postcomp_increment = (this.target - Constants.INT_TO_FP_31) /
                                                  this.postcomp_duration;
                    }
                    this.in_precomp = 1;
                }
            }
            else
            {
                this.increment = (this.target - this.value) / this.duration;
                if (Math.Abs(this.increment) > instance.dx7_eg_max_slew)
                {
                    this.duration = (Math.Abs(this.target - this.value) + instance.dx7_eg_max_slew - 1) /
                                    instance.dx7_eg_max_slew;
                    this.increment = (this.target - this.value) / this.duration;
                }
                this.in_precomp = 0;
            }
        }
示例#5
0
        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;
            }
        }
示例#6
0
        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);
        }