From 2d98baf8e58aa25a0baba549d5e8bc3f4e5aa802 Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Thu, 18 Jan 2007 16:24:37 +0000 Subject: [PATCH] # Sound file fixes. JSI_Sound: Fixed problems with freeing sounds after they've been played. Fixed non-working exception code when failing to load a file (and made it throw an obvious std::exception instead of a hidden LibError). Changed most functions to return false when called on a sound that has been played already, instead of causing an invalid-handle error. Consistentised whitespace. This was SVN commit r4789. --- source/sound/JSI_Sound.cpp | 127 +++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 53 deletions(-) diff --git a/source/sound/JSI_Sound.cpp b/source/sound/JSI_Sound.cpp index c71a747922..ed8c49d657 100644 --- a/source/sound/JSI_Sound.cpp +++ b/source/sound/JSI_Sound.cpp @@ -6,15 +6,14 @@ #include "lib/res/h_mgr.h" // h_filename -JSI_Sound::JSI_Sound( const CStr& Filename ) +JSI_Sound::JSI_Sound(const CStr& Filename) { - const char* fn = Filename.c_str(); - m_Handle = snd_open( fn ); + m_Handle = snd_open(Filename); // special-case to avoid throwing exceptions if quickstart has // disabled sound: set a flag queried by Construct; the object will // then immediately be freed. - if(m_Handle == ERR::AGAIN) + if (m_Handle == ERR::AGAIN) { m_SoundDisabled = true; return; @@ -24,9 +23,10 @@ JSI_Sound::JSI_Sound( const CStr& Filename ) // if open failed, raise an exception - it's the only way to // report errors, since we're in the ctor and don't want to move // the open call elsewhere (by requiring an explicit open() call). - THROW_ERR(m_Handle); // caught by JSI_Sound::Construct. + if (m_Handle < 0) + throw std::exception("sound load failed"); // caught by JSI_Sound::Construct. - snd_set_pos( m_Handle, 0,0,0, true); + snd_set_pos(m_Handle, 0,0,0, true); } JSI_Sound::~JSI_Sound() @@ -35,34 +35,44 @@ JSI_Sound::~JSI_Sound() } -bool JSI_Sound::SetGain( JSContext* cx, uintN argc, jsval* argv ) +bool JSI_Sound::SetGain(JSContext* cx, uintN argc, jsval* argv) { - debug_assert( argc >= 1 ); + if (! m_Handle) + return false; + + debug_assert(argc >= 1); // FIXME float gain; - if( !ToPrimitive( cx, argv[0], gain) ) + if (! ToPrimitive(cx, argv[0], gain)) return false; snd_set_gain(m_Handle, gain); return true; } -bool JSI_Sound::SetPitch( JSContext* cx, uintN argc, jsval* argv ) +bool JSI_Sound::SetPitch(JSContext* cx, uintN argc, jsval* argv) { - debug_assert( argc >= 1 ); + if (! m_Handle) + return false; + + debug_assert(argc >= 1); // FIXME float pitch; - if( !ToPrimitive( cx, argv[0], pitch) ) + if (! ToPrimitive(cx, argv[0], pitch)) return false; snd_set_pitch(m_Handle, pitch); return true; } -bool JSI_Sound::SetPosition( JSContext* cx, uintN argc, jsval* argv ) +bool JSI_Sound::SetPosition(JSContext* cx, uintN argc, jsval* argv) { - debug_assert( argc >= 1 ); + if (! m_Handle) + return false; + + debug_assert(argc >= 1); // FIXME + CVector3D pos; // absolute world coords - if( ToPrimitive( cx, argv[0], pos ) ) + if (ToPrimitive(cx, argv[0], pos)) snd_set_pos(m_Handle, pos[0], pos[1], pos[2]); // relative, 0 offset - right on top of the listener // (we don't need displacement from the listener, e.g. always behind) @@ -73,17 +83,19 @@ bool JSI_Sound::SetPosition( JSContext* cx, uintN argc, jsval* argv ) } -bool JSI_Sound::Fade( JSContext* cx, uintN argc, jsval* argv ) +bool JSI_Sound::Fade(JSContext* cx, uintN argc, jsval* argv) { - debug_assert( argc >= 3 ); + if (! m_Handle) + return false; + + debug_assert(argc >= 3); // FIXME float initial_gain, final_gain; float length; - if( !ToPrimitive( cx, argv[0], initial_gain) ) - return false; - if( !ToPrimitive( cx, argv[1], final_gain) ) - return false; - if( !ToPrimitive( cx, argv[2], length) ) + if (! (ToPrimitive(cx, argv[0], initial_gain) + && ToPrimitive(cx, argv[1], final_gain) + && ToPrimitive(cx, argv[2], length))) return false; + snd_fade(m_Handle, initial_gain, final_gain, length, FT_S_CURVE); // HACK: snd_fade causes to be automatically freed when a @@ -99,15 +111,26 @@ bool JSI_Sound::Fade( JSContext* cx, uintN argc, jsval* argv ) // 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) ) +bool JSI_Sound::Play(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv)) { + if (! m_Handle) + return false; + snd_play(m_Handle); + // We can't do anything else with this sound now, since it's impossible to + // know whether or not it's still valid (since it might have finished playing + // already). So set it to 0, so we don't try doing anything (like freeing it) + // in the future. + m_Handle = 0; return true; } // request the sound be played until free() is called. returns immediately. -bool JSI_Sound::Loop( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) ) +bool JSI_Sound::Loop(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv)) { + if (! m_Handle) + return false; + snd_set_loop(m_Handle, true); snd_play(m_Handle); return true; @@ -116,10 +139,12 @@ bool JSI_Sound::Loop( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(a // stop sound if currently playing and free resources. // doesn't need to be called unless played via loop() - // sounds are freed automatically when done playing. -bool JSI_Sound::Free( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) ) +bool JSI_Sound::Free(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv)) { - if(m_Handle) - snd_free(m_Handle); // resets it to 0 + if (! m_Handle) + return false; + + snd_free(m_Handle); // resets it to 0 return true; } @@ -129,57 +154,53 @@ bool JSI_Sound::Free( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(a void JSI_Sound::ScriptingInit() { - AddMethod( "toString", 0 ); - AddMethod( "play", 0 ); - AddMethod( "loop", 0 ); - AddMethod( "free", 0 ); - AddMethod( "setGain", 0 ); - AddMethod( "setPitch", 0 ); - AddMethod( "setPosition", 0 ); - AddMethod( "fade", 0 ); + AddMethod("toString", 0); + AddMethod("play", 0); + AddMethod("loop", 0); + AddMethod("free", 0); + AddMethod("setGain", 0); + AddMethod("setPitch", 0); + AddMethod("setPosition", 0); + AddMethod("fade", 0); - CJSObject::ScriptingInit( "Sound", &JSI_Sound::Construct, 1 ); + CJSObject::ScriptingInit("Sound", &JSI_Sound::Construct, 1); } -jsval JSI_Sound::ToString( JSContext* cx, uintN UNUSED(argc), jsval* UNUSED(argv) ) +jsval JSI_Sound::ToString(JSContext* cx, uintN UNUSED(argc), jsval* UNUSED(argv)) { - const char* Filename = h_filename(m_Handle); - wchar_t buffer[256]; - swprintf( buffer, 256, L"[object Sound: %hs]", Filename ); - buffer[255] = 0; - utf16string str16(buffer, buffer+wcslen(buffer)); - return( STRING_TO_JSVAL( JS_NewUCStringCopyZ( cx, str16.c_str() ) ) ); + CStr name = "[object Sound: " + CStr(h_filename(m_Handle)) + "]"; + return STRING_TO_JSVAL(JS_NewStringCopyZ(cx, name)); } -JSBool JSI_Sound::Construct( JSContext* cx, JSObject* UNUSED(obj), uint argc, jsval* argv, jsval* rval ) +JSBool JSI_Sound::Construct(JSContext* cx, JSObject* UNUSED(obj), uint argc, jsval* argv, jsval* rval) { - debug_assert( argc >= 1 ); + debug_assert(argc >= 1); // FIXME CStrW filename; - if( !ToPrimitive( cx, argv[0], filename ) ) - return( JS_FALSE ); + if (! ToPrimitive(cx, argv[0], filename)) + return JS_FALSE; try { - JSI_Sound* newObject = new JSI_Sound( filename ); + JSI_Sound* newObject = new JSI_Sound(filename); // somewhat of a hack to avoid throwing exceptions if // sound was disabled due to quickstart. see JSI_Sound(). - if( newObject->m_SoundDisabled ) + if (newObject->m_SoundDisabled) { delete newObject; *rval = JSVAL_NULL; - return( JS_TRUE ); + return JS_TRUE; } newObject->m_EngineOwned = false; - *rval = OBJECT_TO_JSVAL( newObject->GetScript() ); + *rval = OBJECT_TO_JSVAL(newObject->GetScript()); } - catch(int) + catch (std::exception) { // failed, but this can happen easily enough that we don't want to // return JS_FALSE (since that stops the script). *rval = JSVAL_NULL; } - return( JS_TRUE ); + return JS_TRUE; }