Outerra forum

Please login or register.

Login with username, password and session length
Advanced search  

News:

Download Outerra Tech Demo. Unofficial Outerra Discord server, MicroProse Discord server for OWS.

Pages: 1 2 [3]

Author Topic: engine sounds  (Read 37010 times)

angrypig

  • Sr. Member
  • ****
  • Posts: 454
Re: engine sounds
« Reply #30 on: June 25, 2013, 11:08:28 am »

there are loops in Javascript :) so all you need is a list with file names...
Logged

angrypig

  • Sr. Member
  • ****
  • Posts: 454
Re: engine sounds
« Reply #31 on: June 25, 2013, 11:17:38 am »

Logged

hhrhhr

  • Member
  • **
  • Posts: 60
Re: engine sounds
« Reply #32 on: July 04, 2013, 12:15:17 pm »

my attempt to implement this "how to" (simple gearbox, 32 sound samples, "equalizer" shows the volume level for each sample):



I do not quite like the idea of ​​simultaneous download and play as many sounds. I tried to stop the unnecessary sounds and play only the current 2-3, but there are problems (clicks, pops).

or Outerra has no problem with the use of a large number of sounds?

test model and V8 sound bank from sonory.org - https://dl.dropboxusercontent.com/u/95785614/sound_test.hhrhhr.otx
Logged

murkz

  • Full Member
  • ***
  • Posts: 152
    • The Antisocial Gamer
Re: engine sounds
« Reply #33 on: July 04, 2013, 12:23:06 pm »

Excellent hr, a very good start.

ZeosPantera

  • ||>>-Z-<<||
  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2520
  • #1 Outerra Fan Boy
    • My Youtube
Re: engine sounds
« Reply #34 on: July 04, 2013, 12:24:50 pm »

I am without words.. What a contribution! And to get the visuals in-game.

EDIT: I set the Engine Power to 150 300 in the script and it shows it off a bit better. Will mess with gearing. SOUNDS GREAT!

EDIT2: Played around and decided on these tweaks.

Code: [Select]
// !!! not optimized for multiple vehicles in scene !!!


const PI = Math.PI;
const PI_2 = PI / 2.0;
const DEG2RAD = PI / 180.0;
const RAD2DEG = 180.0 / PI;

// dashboard
const MAX_RPM = 9000.0
const MAX_SPEED = 180.0
const MAX_ANGLE = 270.0

const MS2KMH2RAD = 3.6 * MAX_ANGLE / MAX_SPEED * DEG2RAD;
const HOURS2RAD = 360.0 / 12 * DEG2RAD;
const MIN2RAD = 360.0 / 60 * DEG2RAD;
const RPM2RAD = MAX_ANGLE / MAX_RPM * DEG2RAD


// engine
const EK = 300;
const BK = 2000;
//             1      2      3     4     5     R(not work now)
const gears = [4.124, 2.641, 1.88, 1.40, 1.05, -5.224];
const ratio = 3.0;


// 16 samples
const rpm_val = [756,
                 859,  984,  1126, 1289, 1476, 1690, 1935, 2215,
                 2536, 2904, 3324, 3806, 4358, 4989, 5712, 6540,
                 9999];
const sound_path = "sound_v8/";

const rpm_num = rpm_val.length - 2;

const RPM_IDLE2RAD = rpm_val[0] / MAX_RPM * MAX_ANGLE * DEG2RAD;

/*
// V4
var rpm_val = [ 756,
               1052, 1126, 1205, 1289, 1380, 1476, 1579,
               1690, 1808, 1935, 2070, 2215, 2370, 2536,
               2714, 2904, 3107, 3324, 3557, 3806, 4073,
               4358, 4663, 4989, 5338, 5712, 6112, 6540,
               9999 ];
// V8
var rpm_val = [ 756,
               859, 919, 984,
               1052, 1126, 1205, 1289, 1380, 1476, 1579,
               1690, 1808, 1935, 2070, 2215, 2370, 2536,
               2714, 2904, 3107, 3324, 3557, 3806, 4073,
               4358, 4663, 4989, 5338, 5712, 6112, 6540,
               9999 ];
// V12
var rpm_val = [ 756,
                803,  859,  919,  984,  1052, 1126, 1205,
                1289, 1380, 1476, 1579, 1690, 1808, 1935,
               9999 ];
*/


var rpm_vol = [];
var rpm_pit = [];
var rpm_snd = [];
var rpm_snd_load = [];
var rpm_src = [];
var rpm_src_load = [];

for (var i = 0; i < rpm_val.length; i++) {
    rpm_vol[i] = 0;
    rpm_pit[i] = 0;
    rpm_snd[i] = 0;
    rpm_snd_load[i] = 0;
    rpm_src[i] = 0;
    rpm_src_load[i] = 0;
}

function process_engine_sound(rpm)
{
    if (rpm <= rpm_val[1]) {
        // only first sample
        rpm_pit[1] = rpm / rpm_val[1];
        rpm_vol[1] = 1.0;
        for (var i = 2; i <= rpm_num; i++)
            rpm_vol[i] = 0.0;

    } else if (rpm <= rpm_val[rpm_num]) {
        // mix 2 samples
        for (var i = 1; i <= rpm_num; i++) {
            if (rpm > rpm_val[i+1] || rpm <= rpm_val[i-1]) {
                rpm_vol[i] = 0.0;
            } else {
                if (rpm > rpm_val[i]) {
                    var rpm_d = rpm_val[i+1] - rpm_val[i];
                    var vol_l = (rpm_val[i+1] - rpm) / rpm_d;
                    var vol_h = (rpm - rpm_val[i]) / rpm_d;

                    // sin
                    rpm_vol[i] = Math.sin(vol_l * PI_2);
                    rpm_vol[i+1] = Math.sin(vol_h * PI_2);

                    rpm_pit[i] = rpm / rpm_val[i];
                    rpm_pit[i+1] = rpm / rpm_val[i+1];
                }
            }
        }
    } else {
        // only last sample
        rpm_pit[rpm_num] = rpm / rpm_val[rpm_num];
        rpm_vol[rpm_num] = 1.0;
        for (var i = 1; i < rpm_num; i++)
            rpm_vol[i] = 0.0;
    }
}


// equalizer mesh init
var band = [];
for (var i = 0; i < 16; i++) {
    band[i] = 0;
}


//invoked only the first time the model is loaded, or upon reload
function init_chassis()
{
    this.log_inf("don't forget to assign ShiftUp and ShiftDown keys");
    var wheelparam_left = {
        radius: 0.365,
        width: 0.220,
        suspension_max: 0.1,
        suspension_min: -0.25,
        suspension_stiffness: 18.0,
        damping_compression: 0.4,
        damping_relaxation: 0.12,
        slip: 0.6,
slip_lateral_coef: 1.5,
        rotation: -1
    };

    var wheelparam_right = {
        radius: 0.365,
        width: 0.220,
        suspension_max: 0.1,
        suspension_min: -0.25,
        suspension_stiffness: 18.0,
        damping_compression: 0.4,
        damping_relaxation: 0.12,
        slip: 0.75,
slip_lateral_coef: 1.3,
        rotation: 1
    };

    var vehicle_params = {
        mass: 1100.0,
        steering: 2.0,
        steering_ecf: 60.0,
        centering: 3.0,
        centering_ecf: 40.0,
        com: {x: 0.0, y: 0.0, z: -0.0}
    };

    this.add_wheel("wfl", wheelparam_left);
    this.add_wheel("wfr", wheelparam_right);
    this.add_wheel("wrl", wheelparam_left);
    this.add_wheel("wrr", wheelparam_right);


    //sounds
    for (var i = 1; i <= rpm_num; i++) {
        rpm_snd[i] = this.load_sound("" + sound_path + rpm_val[i] + ".ogg");
        rpm_src[i] = this.add_sound_emitter("snd_engine");
        rpm_snd_load[i] = this.load_sound("" + sound_path + rpm_val[i] + "_P.ogg");
        rpm_src_load[i] = this.add_sound_emitter("snd_engine_load");
    };
    this.log_inf("loaded " + rpm_num*2 + " engine sound samples");

    return vehicle_params;
}


//invoked for each new instance of the vehicle
function init_vehicle()
{
    this.started = 0;
    this.speed_old = 0;
    this.gear_idx = 0;


    this.body = this.get_geomob(0);

    var cam_fps = this.body.get_joint_local_pos(this.body.get_joint("cam_fps"));
    this.set_fps_camera_pos(cam_fps);

    this.arrow_speed = this.body.get_joint("arrow_speed");
    this.arrow_rpm = this.body.get_joint("arrow_rpm");
    this.arrow_hour = this.body.get_joint("arrow_clock_hour");
    this.arrow_min = this.body.get_joint("arrow_clock_min");

    this.arrow_1 = this.body.get_joint("arrow_1");
    this.arrow_2 = this.body.get_joint("arrow_2");
    this.arrow_3 = this.body.get_joint("arrow_3");
    this.arrow_4 = this.body.get_joint("arrow_4");
    this.arrow_5 = this.body.get_joint("arrow_5");


    // sounds
    this.snd = this.sound();
    for (var i = 1; i <= rpm_num; i++) {
        this.snd.set_ref_distance(rpm_src[i], 5.0);
        this.snd.set_ref_distance(rpm_src_load[i], 5.0);
    };


    // "equalizer" meshes
    for (var i = 0; i < 16; i++) {
        band[i] = this.body.get_joint("band" + (i+1));
    }
}


//invoked when engine starts or stops
function engine(start)
{
    if (start) {
        this.started = 1;
        for (var i = 1; i <= rpm_num; i++) {
            rpm_vol[i] = 0.0;
            this.snd.play_loop(rpm_src[i], rpm_snd[i]);
            this.snd.play_loop(rpm_src_load[i], rpm_snd_load[i]);
        }
    } else {
        this.started = 0;
        for (var i = 1; i <= rpm_num; i++) {
            rpm_vol[i] = 0.0;
            this.snd.stop(rpm_src[i]);
            this.snd.stop(rpm_src_load[i]);
        }
    }
}


function action(k, v, dt)
{
    switch(k) {
    case AShiftUp: {
        if (v)
            this.gear_idx = this.gear_idx < 4 ? this.gear_idx + 1 : 4;
        break;
    }
    case AShiftDown: {
        if (v)
            this.gear_idx = this.gear_idx > 0 ? this.gear_idx - 1 : 0;
        break;
    }
    case AReverse: {
        if (v)
            this.gear_idx = this.gear_idx < 5 ? 5 : 0;
        break;
    }
    }
}

//invoked each frame to handle the inputs and animate the model
function update_frame(dt, engine, brake, steering)
{
    var steer = steering * 0.5;
    this.steer(0, steer);
    this.steer(1, steer);

    if (this.started) {
        var eng = engine * EK * gears[this.gear_idx] * ratio;
        this.wheel_force(2, eng);
        this.wheel_force(3, eng);
    }

    var brake_idle = (1.0 - engine) * BK * 0.1;
    var brake_front = brake * BK * 0.5 + brake_idle;
    var brake_rear = brake * BK + brake_idle;
    this.wheel_brake(0, brake_front);
    this.wheel_brake(1, brake_front);
    this.wheel_brake(2, brake_rear);
    this.wheel_brake(3, brake_rear);

    this.animate_wheels();


    // dashboard
    // // speed
    var spd = Math.abs(this.speed() * MS2KMH2RAD);
    this.body.rotate_joint_orig(this.arrow_speed, spd, {x: 0, y: 1, z: 0});

    // // rpm
    var rpm = 0.0;
    var max_wheel_rpm = Math.abs(Math.max(this.wheel(2).rpm, this.wheel(3).rpm));
    if (this.started)
        rpm += max_wheel_rpm * gears[this.gear_idx] * ratio * RPM2RAD + RPM_IDLE2RAD;
    this.body.rotate_joint_orig(this.arrow_rpm, rpm, {x: 0, y: 1, z: 0});

    // // clock
    var time = new Date();
    var hour = time.getHours() * HOURS2RAD;
    var mins = time.getMinutes() * MIN2RAD;
    this.body.rotate_joint_orig(this.arrow_hour, hour, {x: 0, y: 1, z: 0});
    this.body.rotate_joint_orig(this.arrow_min, mins, {x: 0, y: 1, z: 0});

    // // accelerate
    var acc = (this.speed() - this.speed_old) / dt;
    this.speed_old = this.speed();
    acc *= 12 * DEG2RAD; // +/- 6 m/s^2
    this.body.rotate_joint_orig(this.arrow_1, acc, {x: 0, y: 1, z: 0});

    // // gears
    var gear = this.gear_idx * 30 * DEG2RAD;
    this.body.rotate_joint_orig(this.arrow_2, gear, {x: 0, y: 1, z: 0});

    // // throtle
    this.body.rotate_joint_orig(this.arrow_3, engine * PI_2, {x: 0, y: 1, z: 0});
    this.body.rotate_joint_orig(this.arrow_4, brake * PI_2, {x: 0, y: -1, z: 0});


    // FIXME:
    var torque = engine;


    // engine sounds
    if (this.started) {
        rpm = max_wheel_rpm * gears[this.gear_idx] * ratio + rpm_val[0];
        process_engine_sound(rpm);

        // set pitch and volume
        for (var i = 1; i <= rpm_num; i++) {
            this.snd.set_pitch(rpm_src[i], rpm_pit[i]);
            this.snd.set_gain(rpm_src[i], rpm_vol[i] * (1.0 - torque));
            this.snd.set_pitch(rpm_src_load[i], rpm_pit[i]);
            this.snd.set_gain(rpm_src_load[i], rpm_vol[i] * torque);
        }
    }

    // debug "equalizer"
    for (var i = 1; i <= rpm_num; i++) {
        var s = Math.ceil(rpm_vol[i] * 20.0) * 0.01; // 1/20 * 0.20m (lenght of band);
        var move = {x: 0, y: s * 0.5, z: s * 0.866};   // sin(30), cos(30)
        this.body.move_joint_orig(band[i-1], move);
    }

}

Using my Gas Pedal instead of keys is way better. Pretty much just gearing, engine and suspension/tire tweaks. I wouldn't dare touch the other code.
« Last Edit: July 04, 2013, 01:15:18 pm by ZeosPantera »
Logged
"Fear accompanies the possibility of death, Calm shepherds its certainty" - General Ka Dargo

giucam

  • Full Member
  • ***
  • Posts: 171
  • It's an ugly pile of bones... like me.
Re: engine sounds
« Reply #35 on: July 04, 2013, 01:47:25 pm »

Great work hhrhhr!! The sin really makes the trick on not showing the switching of the samples. How did you found it out, just by trial and error?
Logged
ResidualVM 0.1.1 is OUT! www.residualvm.org

hhrhhr

  • Member
  • **
  • Posts: 60
Re: engine sounds
« Reply #36 on: July 04, 2013, 02:37:31 pm »

The sin really makes the trick on not showing the switching of the samples
vol * 0.667 + 0.333 can be used instead of the sine ;) but then you also need to keep an eye on 0.0 <= vol <= 1.0.

2ZeosPantera
for the best results we need to count the current torque. now "torque = engine",  for the "discrete" keyboard is bad, for analog control - a little better, but still not what we need.
Logged

giucam

  • Full Member
  • ***
  • Posts: 171
  • It's an ugly pile of bones... like me.
Re: engine sounds
« Reply #37 on: July 04, 2013, 04:03:04 pm »

I managed to port hhrhhr's sound code to my script, works great.
I'm gonna test it with the BMW next, and hopefully release a new version in some days.
Logged
ResidualVM 0.1.1 is OUT! www.residualvm.org

hhrhhr

  • Member
  • **
  • Posts: 60
Re: engine sounds
« Reply #38 on: July 04, 2013, 04:18:28 pm »

I managed to port hhrhhr's sound code to my script, works great.
Pay attention to the first line: "// !!! not optimized for multiple vehicles in scene !!!"

for the release version the part of the global constants should be moved to init_vehicle().
Logged

giucam

  • Full Member
  • ***
  • Posts: 171
  • It's an ugly pile of bones... like me.
Re: engine sounds
« Reply #39 on: July 04, 2013, 04:31:19 pm »

Yeah, but i actually only took the process_engine_sound function, i didn't use the other things.

still, the constants shouldn't be a problem for multiple vehicles, they should instead reduce the overhead of multiple per-object variables.
Logged
ResidualVM 0.1.1 is OUT! www.residualvm.org

hhrhhr

  • Member
  • **
  • Posts: 60
Re: engine sounds
« Reply #40 on: July 04, 2013, 04:41:38 pm »

at least array of pitch and volume should be unique for every vehicle, otherwise the all the vehicles in the scene will be played the same way.
Logged

giucam

  • Full Member
  • ***
  • Posts: 171
  • It's an ugly pile of bones... like me.
Re: engine sounds
« Reply #41 on: July 04, 2013, 05:02:16 pm »

Ah yeah, right. But i don't keep them stored, i just apply the calculated gain and pitch.
Logged
ResidualVM 0.1.1 is OUT! www.residualvm.org
Pages: 1 2 [3]