forked from 0ad/0ad
snd: support for fading (variable initial/final values and lengths; can choose linear,exponential or S-curve). also minor improvements.
timer: greatly speed up TIMER_ACCRUE by having it gather raw ticks and only converting those to wall-clock time at exit when displaying the values. old codepath remains and can be restored via TIMER_USE_RAW_TICKS This was SVN commit r3241.
This commit is contained in:
parent
e4cf72e949
commit
8792731c5c
@ -24,6 +24,11 @@
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
|
||||
// (some math.h versions omit this)
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <OpenAL/alut.h>
|
||||
#else
|
||||
@ -44,6 +49,7 @@
|
||||
|
||||
#include "../res.h"
|
||||
#include "snd.h"
|
||||
#include "lib/timer.h"
|
||||
|
||||
|
||||
|
||||
@ -1163,6 +1169,104 @@ static LibError snd_data_buf_free(Handle hsd, ALuint al_buf)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// fading
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct FadeInfo
|
||||
{
|
||||
double start_time;
|
||||
FadeType type;
|
||||
float length;
|
||||
float initial_val;
|
||||
float final_val;
|
||||
};
|
||||
|
||||
static float fade_factor_linear(float t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
static float fade_factor_exponential(float t)
|
||||
{
|
||||
// t**3
|
||||
return t*t*t;
|
||||
}
|
||||
|
||||
// cosine curve
|
||||
static float fade_factor_s_curve(float t)
|
||||
{
|
||||
float y = cos(t*M_PI + M_PI);
|
||||
// map [-1,1] to [0,1]
|
||||
return (y + 1.0f) / 2.0f;
|
||||
}
|
||||
|
||||
|
||||
enum FadeRet
|
||||
{
|
||||
FADE_NO_CHANGE,
|
||||
FADE_CHANGED,
|
||||
FADE_TO_0_FINISHED
|
||||
};
|
||||
|
||||
static FadeRet fade(FadeInfo& fi, double cur_time, float& out_val)
|
||||
{
|
||||
// how far into the fade are we? [0,1]
|
||||
const float t = (cur_time - fi.start_time) / fi.length;
|
||||
|
||||
float factor;
|
||||
switch(fi.type)
|
||||
{
|
||||
case FT_NONE:
|
||||
return FADE_NO_CHANGE;
|
||||
|
||||
case FT_LINEAR:
|
||||
factor = fade_factor_linear(t);
|
||||
break;
|
||||
case FT_EXPONENTIAL:
|
||||
factor = fade_factor_exponential(t);
|
||||
break;
|
||||
case FT_S_CURVE:
|
||||
factor = fade_factor_s_curve(t);
|
||||
break;
|
||||
|
||||
// initialize with anything at all, just so that the calculation
|
||||
// below runs through; we reset out_val after that.
|
||||
case FT_ABORT:
|
||||
factor = 0.0f;
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
|
||||
out_val = fi.initial_val + factor*(fi.final_val - fi.initial_val);
|
||||
|
||||
// end reached
|
||||
if(fi.type == FT_ABORT || (cur_time >= fi.start_time + fi.length))
|
||||
{
|
||||
// make sure exact value is hit
|
||||
out_val = fi.final_val;
|
||||
|
||||
// special case: we were fading out; caller will free the sound.
|
||||
if(fi.final_val == 0.0f)
|
||||
return FADE_TO_0_FINISHED;
|
||||
|
||||
// wipe out all values amd mark as no longer actively fading
|
||||
memset(&fi, 0, sizeof(fi));
|
||||
fi.type = FT_NONE;
|
||||
}
|
||||
|
||||
return FADE_CHANGED;
|
||||
}
|
||||
|
||||
|
||||
static bool fade_is_active(FadeInfo& fi)
|
||||
{
|
||||
return (fi.type != FT_NONE);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// virtual sound source: a sound the user wants played.
|
||||
@ -1193,17 +1297,12 @@ enum VSrcFlags
|
||||
|
||||
struct VSrc
|
||||
{
|
||||
ALuint al_src;
|
||||
|
||||
// handle to this VSrc, so that it can close itself.
|
||||
Handle hvs;
|
||||
|
||||
// associated sound data
|
||||
Handle hsd;
|
||||
|
||||
// controls vsrc_update behavior
|
||||
uint flags; // VSrcFlags
|
||||
|
||||
// AL source properties (set via snd_set*)
|
||||
ALfloat pos[3];
|
||||
ALfloat gain; // [0,1]
|
||||
@ -1211,9 +1310,16 @@ struct VSrc
|
||||
ALboolean loop;
|
||||
ALboolean relative;
|
||||
|
||||
// controls vsrc_update behavior
|
||||
uint flags; // VSrcFlags
|
||||
|
||||
ALuint al_src;
|
||||
|
||||
// priority for voice management
|
||||
float static_pri; // as given by snd_play
|
||||
float cur_pri; // holds newly calculated value
|
||||
|
||||
FadeInfo fade;
|
||||
};
|
||||
|
||||
H_TYPE_DEFINE(VSrc);
|
||||
@ -1221,6 +1327,7 @@ H_TYPE_DEFINE(VSrc);
|
||||
static void VSrc_init(VSrc* vs, va_list args)
|
||||
{
|
||||
vs->flags = va_arg(args, uint);
|
||||
vs->fade.type = FT_NONE;
|
||||
}
|
||||
|
||||
static void list_remove(VSrc* vs);
|
||||
@ -1366,7 +1473,7 @@ LibError snd_free(Handle& hvs)
|
||||
// everything that comes after them, so we want those to come last).
|
||||
//
|
||||
// don't use list, to avoid lots of allocs (expect thousands of VSrcs).
|
||||
typedef std::vector<VSrc*> VSrcs;
|
||||
typedef std::deque<VSrc*> VSrcs;
|
||||
typedef VSrcs::iterator It;
|
||||
static VSrcs vsrcs;
|
||||
|
||||
@ -1440,14 +1547,15 @@ static void list_prune_removed()
|
||||
vsrcs.erase(new_end, vsrcs.end());
|
||||
}
|
||||
|
||||
static void free_vs(VSrc* vs)
|
||||
|
||||
static void vsrc_free(VSrc* vs)
|
||||
{
|
||||
snd_free(vs->hvs);
|
||||
}
|
||||
|
||||
static LibError list_free_all()
|
||||
{
|
||||
list_foreach(free_vs);
|
||||
list_foreach(vsrc_free);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@ -1489,11 +1597,28 @@ static int vsrc_deque_finished_bufs(VSrc* vs)
|
||||
}
|
||||
|
||||
|
||||
// HACK: fade() requires the current time. we don't want to query that
|
||||
// anew in every vsrc_update (slow and may mess up crossfades), and passing
|
||||
// as a parameter isn't possible due to the list_foreach interface.
|
||||
// therefore, static variable (set from snd_update).
|
||||
static double snd_update_time;
|
||||
|
||||
static LibError vsrc_update(VSrc* vs)
|
||||
{
|
||||
if(!vs->al_src)
|
||||
return ERR_OK;
|
||||
|
||||
FadeRet ret = fade(vs->fade, snd_update_time, vs->gain);
|
||||
// auto-free after fadeout.
|
||||
if(ret == FADE_TO_0_FINISHED)
|
||||
{
|
||||
vsrc_free(vs);
|
||||
return ERR_OK; // don't continue - <vs> has been freed.
|
||||
}
|
||||
// fade in progress; latch current gain value.
|
||||
else if(ret == FADE_CHANGED)
|
||||
vsrc_latch(vs);
|
||||
|
||||
int num_queued;
|
||||
alGetSourcei(vs->al_src, AL_BUFFERS_QUEUED, &num_queued);
|
||||
al_check("vsrc_update alGetSourcei");
|
||||
@ -1629,6 +1754,7 @@ LibError snd_play(Handle hs, float static_pri)
|
||||
// change 3d position of the sound source.
|
||||
// if relative (default false), (x,y,z) is treated as relative to the
|
||||
// listener; otherwise, it is the position in world coordinates.
|
||||
//
|
||||
// may be called at any time; fails with invalid handle return if
|
||||
// the sound has already been closed (e.g. it never played).
|
||||
LibError snd_set_pos(Handle hvs, float x, float y, float z, bool relative)
|
||||
@ -1645,14 +1771,22 @@ LibError snd_set_pos(Handle hvs, float x, float y, float z, bool relative)
|
||||
|
||||
// change gain (amplitude modifier) of the sound source.
|
||||
// must be non-negative; 1 -> unattenuated, 0.5 -> -6 dB, 0 -> silence.
|
||||
// may be called at any time; fails with invalid handle return if
|
||||
// the sound has already been closed (e.g. it never played).
|
||||
//
|
||||
// should not be called during a fade (see note in implementation);
|
||||
// fails with invalid handle return if the sound has already been
|
||||
// closed (e.g. it never played).
|
||||
LibError snd_set_gain(Handle hvs, float gain)
|
||||
{
|
||||
H_DEREF(hvs, VSrc, vs);
|
||||
|
||||
if(!(0.0f <= gain && gain <= 1.0f))
|
||||
return ERR_INVALID_PARAM;
|
||||
WARN_RETURN(ERR_INVALID_PARAM);
|
||||
|
||||
// if fading, gain changes would be overridden during the next
|
||||
// snd_update. attempting this indicates a logic error. we abort to
|
||||
// avoid undesired jumps in gain that might surprise (and deafen) user.
|
||||
if(fade_is_active(vs->fade))
|
||||
WARN_RETURN(ERR_LOGIC);
|
||||
|
||||
vs->gain = gain;
|
||||
|
||||
@ -1664,6 +1798,7 @@ LibError snd_set_gain(Handle hvs, float gain)
|
||||
// change pitch shift of the sound source.
|
||||
// 1.0 means no change; each reduction by 50% equals a pitch shift of
|
||||
// -12 semitones (one octave). zero is invalid.
|
||||
//
|
||||
// may be called at any time; fails with invalid handle return if
|
||||
// the sound has already been closed (e.g. it never played).
|
||||
LibError snd_set_pitch(Handle hvs, float pitch)
|
||||
@ -1671,7 +1806,7 @@ LibError snd_set_pitch(Handle hvs, float pitch)
|
||||
H_DEREF(hvs, VSrc, vs);
|
||||
|
||||
if(!(0.0f < pitch && pitch <= 1.0f))
|
||||
return ERR_INVALID_PARAM;
|
||||
WARN_RETURN(ERR_INVALID_PARAM);
|
||||
|
||||
vs->pitch = pitch;
|
||||
|
||||
@ -1682,6 +1817,7 @@ LibError snd_set_pitch(Handle hvs, float pitch)
|
||||
|
||||
// enable/disable looping on the sound source.
|
||||
// used to implement variable-length sounds (e.g. while building).
|
||||
//
|
||||
// may be called at any time; fails with invalid handle return if
|
||||
// the sound has already been closed (e.g. it never played).
|
||||
//
|
||||
@ -1701,6 +1837,58 @@ LibError snd_set_loop(Handle hvs, bool loop)
|
||||
}
|
||||
|
||||
|
||||
// fade the sound source in or out over time.
|
||||
// its gain starts at <initial_gain> (immediately) and is moved toward
|
||||
// <final_gain> over <length> seconds. <type> determines the fade curve:
|
||||
// linear, exponential or S-curve. for guidance on which to use, see
|
||||
// http://www.transom.org/tools/editing_mixing/200309.stupidfadetricks.html
|
||||
// you can also pass FT_ABORT to stop fading (if in progress) and
|
||||
// set gain to the current <final_gain> parameter.
|
||||
// special cases:
|
||||
// - if <initial_gain> < 0 (an otherwise illegal value), the sound's
|
||||
// current gain is used as the start value (useful for fading out).
|
||||
// - if <final_gain> is 0, the sound is freed when the fade completes or
|
||||
// is aborted, thus allowing fire-and-forget fadeouts. no cases are
|
||||
// foreseen where this is undesirable, and it is easier to implement
|
||||
// than an extra set-free-after-fade-flag function.
|
||||
//
|
||||
// may be called at any time; fails with invalid handle return if
|
||||
// the sound has already been closed (e.g. it never played).
|
||||
//
|
||||
// note that this function doesn't busy-wait until the fade is complete;
|
||||
// any number of fades may be active at a time (allows cross-fading).
|
||||
// each snd_update calculates a new gain value for all pending fades.
|
||||
// each snd_update calculates a new gain value for all pending fades.
|
||||
// it is safe to start another fade on the same sound source while
|
||||
LibError snd_fade(Handle hvs, float initial_gain, float final_gain,
|
||||
float length, FadeType type)
|
||||
{
|
||||
H_DEREF(hvs, VSrc, vs);
|
||||
|
||||
if(type != FT_LINEAR && type != FT_EXPONENTIAL && type != FT_S_CURVE &&
|
||||
type != FT_ABORT)
|
||||
WARN_RETURN(ERR_INVALID_PARAM);
|
||||
|
||||
// special case - set initial value to current gain (see above).
|
||||
if(initial_gain < 0.0f)
|
||||
initial_gain = vs->gain;
|
||||
|
||||
const double cur_time = get_time();
|
||||
|
||||
FadeInfo& fi = vs->fade;
|
||||
fi.type = type;
|
||||
fi.start_time = cur_time;
|
||||
fi.initial_val = initial_gain;
|
||||
fi.final_val = final_gain;
|
||||
fi.length = length;
|
||||
|
||||
(void)fade(fi, cur_time, vs->gain);
|
||||
vsrc_latch(vs);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// voice management: grants the currently most 'important' sounds
|
||||
@ -1771,9 +1959,6 @@ static LibError vm_update()
|
||||
list_foreach(reclaim, first_unimportant, 0);
|
||||
list_foreach(grant, 0, first_unimportant);
|
||||
|
||||
// add / remove buffers for each source.
|
||||
list_foreach((void (*)(VSrc*))vsrc_update);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@ -1801,6 +1986,10 @@ LibError snd_update(const float* pos, const float* dir, const float* up)
|
||||
|
||||
vm_update();
|
||||
|
||||
// for each source: add / remove buffers; carry out fading.
|
||||
snd_update_time = get_time(); // see decl
|
||||
list_foreach((void (*)(VSrc*))vsrc_update);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
@ -167,25 +167,30 @@ extern LibError snd_play(Handle hs, float priority = 0.0f);
|
||||
// change 3d position of the sound source.
|
||||
// if relative (default false), (x,y,z) is treated as relative to the
|
||||
// listener; otherwise, it is the position in world coordinates.
|
||||
//
|
||||
// may be called at any time; fails with invalid handle return if
|
||||
// the sound has already been closed (e.g. it never played).
|
||||
extern LibError snd_set_pos(Handle hs, float x, float y, float z, bool relative = false);
|
||||
|
||||
// change gain (amplitude modifier) of the sound source.
|
||||
// must be non-negative; 1 -> unattenuated, 0.5 -> -6 dB, 0 -> silence.
|
||||
// may be called at any time; fails with invalid handle return if
|
||||
// the sound has already been closed (e.g. it never played).
|
||||
//
|
||||
// should not be called during a fade (see note in implementation);
|
||||
// fails with invalid handle return if the sound has already been
|
||||
// closed (e.g. it never played).
|
||||
extern LibError snd_set_gain(Handle hs, float gain);
|
||||
|
||||
// change pitch shift of the sound source.
|
||||
// 1.0 means no change; each reduction by 50% equals a pitch shift of
|
||||
// -12 semitones (one octave). zero is invalid.
|
||||
//
|
||||
// may be called at any time; fails with invalid handle return if
|
||||
// the sound has already been closed (e.g. it never played).
|
||||
extern LibError snd_set_pitch(Handle hs, float pitch);
|
||||
|
||||
// enable/disable looping on the sound source.
|
||||
// used to implement variable-length sounds (e.g. while building).
|
||||
//
|
||||
// may be called at any time; fails with invalid handle return if
|
||||
// the sound has already been closed (e.g. it never played).
|
||||
//
|
||||
@ -197,6 +202,43 @@ extern LibError snd_set_pitch(Handle hs, float pitch);
|
||||
extern LibError snd_set_loop(Handle hs, bool loop);
|
||||
|
||||
|
||||
enum FadeType
|
||||
{
|
||||
FT_NONE,
|
||||
FT_LINEAR,
|
||||
FT_EXPONENTIAL,
|
||||
FT_S_CURVE,
|
||||
|
||||
FT_ABORT
|
||||
};
|
||||
|
||||
// fade the sound source in or out over time.
|
||||
// its gain starts at <initial_gain> (immediately) and is moved toward
|
||||
// <final_gain> over <length> seconds. <type> determines the fade curve:
|
||||
// linear, exponential or S-curve. for guidance on which to use, see
|
||||
// http://www.transom.org/tools/editing_mixing/200309.stupidfadetricks.html
|
||||
// you can also pass FT_ABORT to stop fading (if in progress) and
|
||||
// set gain to the current <final_gain> parameter.
|
||||
// special cases:
|
||||
// - if <initial_gain> < 0 (an otherwise illegal value), the sound's
|
||||
// current gain is used as the start value (useful for fading out).
|
||||
// - if <final_gain> is 0, the sound is freed when the fade completes or
|
||||
// is aborted, thus allowing fire-and-forget fadeouts. no cases are
|
||||
// foreseen where this is undesirable, and it is easier to implement
|
||||
// than an extra set-free-after-fade-flag function.
|
||||
//
|
||||
// may be called at any time; fails with invalid handle return if
|
||||
// the sound has already been closed (e.g. it never played).
|
||||
//
|
||||
// note that this function doesn't busy-wait until the fade is complete;
|
||||
// any number of fades may be active at a time (allows cross-fading).
|
||||
// each snd_update calculates a new gain value for all pending fades.
|
||||
// it is safe to start another fade on the same sound source while
|
||||
// one is already in progress; the old one will be discarded.
|
||||
extern LibError snd_fade(Handle hvs, float initial_gain, float final_gain,
|
||||
float length, FadeType type);
|
||||
|
||||
|
||||
//
|
||||
// sound engine
|
||||
//
|
||||
|
@ -274,8 +274,8 @@ TimerClient* timer_add_client(TimerClient* tc, const char* description)
|
||||
}
|
||||
|
||||
|
||||
// add <dt> [s] to the client's total.
|
||||
void timer_bill_client(TimerClient* tc, double dt)
|
||||
// add <dt> to the client's total.
|
||||
void timer_bill_client(TimerClient* tc, TimerUnit dt)
|
||||
{
|
||||
tc->sum += dt;
|
||||
tc->num_calls++;
|
||||
@ -297,7 +297,18 @@ void timer_display_client_totals()
|
||||
clients = tc->next;
|
||||
num_clients--;
|
||||
|
||||
const double sum = tc->sum;
|
||||
// convert raw ticks into seconds, if necessary
|
||||
double sum;
|
||||
#if TIMER_USE_RAW_TICKS
|
||||
# if CPU_IA32
|
||||
sum = tc->sum / cpu_freq;
|
||||
# else
|
||||
# error "port"
|
||||
# endif
|
||||
#else
|
||||
sum = tc->sum;
|
||||
#endif
|
||||
|
||||
// determine scale factor for pretty display
|
||||
double scale = 1e6;
|
||||
const char* unit = "us";
|
||||
|
@ -44,6 +44,31 @@ extern float spf; // for time-since-last-frame use
|
||||
extern void calc_fps(void);
|
||||
|
||||
|
||||
// since TIMER_ACCRUE et al. are called so often, we try to keep
|
||||
// overhead to an absolute minimum. this flag allows storing
|
||||
// raw tick counts (e.g. CPU cycles returned by rdtsc) instead of
|
||||
// absolute time. there are two benefits:
|
||||
// - no need to convert from raw->time on every call
|
||||
// (instead, it's only done once when displaying the totals)
|
||||
// - possibly less overhead to querying the time itself
|
||||
// (get_time may be using slower time sources with ~3us overhead)
|
||||
//
|
||||
// however, the cycle count is not necessarily a measure of wall-clock time.
|
||||
// therefore, on systems with SpeedStep active, measurements of
|
||||
// I/O or other non-CPU bound activity may be skewed. this is ok because
|
||||
// the timer is only used for profiling; just be aware of the issue.
|
||||
// if it's a problem or no raw tick source is available, disable this.
|
||||
//
|
||||
// note that overflow isn't an issue either way (63 bit cycle counts
|
||||
// at 10 GHz cover intervals of 29 years).
|
||||
#define TIMER_USE_RAW_TICKS 1
|
||||
#if TIMER_USE_RAW_TICKS
|
||||
typedef i64 TimerUnit;
|
||||
#else
|
||||
typedef double TimerUnit;
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// cumulative timer API
|
||||
//
|
||||
@ -51,12 +76,13 @@ extern void calc_fps(void);
|
||||
// this supplements in-game profiling by providing low-overhead,
|
||||
// high resolution time accounting.
|
||||
|
||||
|
||||
// opaque - do not access its fields!
|
||||
// note: must be defined here because clients instantiate them;
|
||||
// fields cannot be made private due to C compatibility requirement.
|
||||
struct TimerClient
|
||||
{
|
||||
double sum; // total bill [s]
|
||||
TimerUnit sum; // total bill
|
||||
|
||||
// only store a pointer for efficiency.
|
||||
const char* description;
|
||||
@ -80,8 +106,8 @@ struct TimerClient
|
||||
// - description must remain valid until exit; a string literal is safest.
|
||||
extern TimerClient* timer_add_client(TimerClient* tc, const char* description);
|
||||
|
||||
// add <dt> [s] to the client's total.
|
||||
extern void timer_bill_client(TimerClient* tc, double dt);
|
||||
// add <dt> to the client's total.
|
||||
extern void timer_bill_client(TimerClient* tc, TimerUnit dt);
|
||||
|
||||
// display all clients' totals; does not reset them.
|
||||
// typically called at exit.
|
||||
@ -174,19 +200,35 @@ Example usage:
|
||||
// used via TIMER_ACCRUE
|
||||
class ScopeTimerAccrue
|
||||
{
|
||||
double t0;
|
||||
TimerUnit t0;
|
||||
TimerClient* tc;
|
||||
|
||||
public:
|
||||
ScopeTimerAccrue(TimerClient* tc_)
|
||||
{
|
||||
#if TIMER_USE_RAW_TICKS
|
||||
# if CPU_IA32
|
||||
t0 = rdtsc();
|
||||
# else
|
||||
# error "port"
|
||||
# endif
|
||||
#else
|
||||
t0 = get_time();
|
||||
#endif
|
||||
tc = tc_;
|
||||
}
|
||||
~ScopeTimerAccrue()
|
||||
{
|
||||
double t1 = get_time();
|
||||
double dt = t1-t0;
|
||||
#if TIMER_USE_RAW_TICKS
|
||||
# if CPU_IA32
|
||||
TimerUnit t1 = rdtsc();
|
||||
# else
|
||||
# error "port"
|
||||
# endif
|
||||
#else
|
||||
TimerUnit t1 = get_time();
|
||||
#endif
|
||||
TimerUnit dt = t1-t0;
|
||||
timer_bill_client(tc, dt);
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,31 @@ bool JSI_Sound::SetPosition( JSContext* cx, uintN argc, jsval* argv )
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool JSI_Sound::Fade( JSContext* cx, uintN argc, jsval* argv )
|
||||
{
|
||||
debug_assert( argc >= 3 );
|
||||
float initial_gain, final_gain;
|
||||
float length;
|
||||
if( !ToPrimitive<float>( cx, argv[0], initial_gain) )
|
||||
return false;
|
||||
if( !ToPrimitive<float>( cx, argv[1], final_gain) )
|
||||
return false;
|
||||
if( !ToPrimitive<float>( cx, argv[2], length) )
|
||||
return false;
|
||||
snd_fade(m_Handle, initial_gain, final_gain, length, FT_S_CURVE);
|
||||
|
||||
// HACK: snd_fade causes <m_Handle> to be automatically freed when a
|
||||
// fade to 0 has completed. however, we're still holding on to a
|
||||
// reference, which will cause a double-free warning when Free() is
|
||||
// called from the dtor. solution is to neuter our Handle by
|
||||
// setting it to 0 (ok since it'll be freed). this does mean that
|
||||
// no further operations can be carried out during that final fade.
|
||||
m_Handle = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// start playing the sound (one-shot).
|
||||
// it will automatically be freed when done.
|
||||
bool JSI_Sound::Play( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
|
||||
@ -110,6 +135,7 @@ void JSI_Sound::ScriptingInit()
|
||||
AddMethod<bool, &JSI_Sound::SetGain>( "setGain", 0 );
|
||||
AddMethod<bool, &JSI_Sound::SetPitch>( "setPitch", 0 );
|
||||
AddMethod<bool, &JSI_Sound::SetPosition>( "setPosition", 0 );
|
||||
AddMethod<bool, &JSI_Sound::Fade>( "fade", 0 );
|
||||
|
||||
CJSObject<JSI_Sound>::ScriptingInit( "Sound", &JSI_Sound::Construct, 1 );
|
||||
}
|
||||
|
@ -53,6 +53,8 @@ public:
|
||||
|
||||
bool SetPosition( JSContext* cx, uintN argc, jsval* argv );
|
||||
|
||||
bool Fade ( JSContext* cx, uintN argc, jsval* argv );
|
||||
|
||||
static JSBool Construct( JSContext* cx, JSObject* obj, uint argc, jsval* argv, jsval* rval );
|
||||
|
||||
static void ScriptingInit();
|
||||
|
Loading…
Reference in New Issue
Block a user