Play Sfall Sound

Endocore

Look, Ma! Two Heads!
Modder



Has anyone ever successfully used this function to play a sound during gameplay? After researching everything that's ever been written in our forum on the subject, I have my doubts-- my impression is that this function doesn't work, but that even if it did no one knows how to deploy it. I also noticed that even the hard-core sfall scripting guys like phobos2077 and Jim the Dinosaur are still adding sounds to their mods by modifying sndlst.lst rather than using play_sfall_sound. I've fooled around with it on several occassions, and can't get it to work. For the benefit of everyone (most previous discussion of the matter consists of unanswered queries), I decided to make this post and see if we can get to the bottom of this matter.

In theory, play_sfall_sound could be a great benefit for compatibility between mods. If each modder whose work adds sounds to the game makes acms and includes a custom sndlst.lst with his mod, most end-users won't understand how to combine different mods. For those interested, the Fallout 2 Mapper will make a new sndlst.lst to incorporate all acms it finds in the data\sound\SFX\ directory if the existing copies of sndlst.lst in both data\sound\SFX\ and master.dat\data\sound\SFX\ are deleted or renamed (e.g. old_sndlist.lst).

In any case, I can't get play_sfall_sound to work. For purposes of an example, let's say I have a harmonica item (obj pid 605). When the player-character uses the item, a short sound effect (harmonica.wav) of a harmonica tune is to be played. I put a wav file (22,050 kHz mono) called harmonica.wav in data\sound\SFX\. In the use_obj_on section of obj_dude.int, I include the following code (Ruby format-- FSE/sslc users should get rid of the "op_" prefixes):

Code:
    if (op_obj_pid(op_obj_being_used_with()) == 605) then
    begin
        op_play_sfall_sound("data\\sound\\SFX\\harmonica.wav", 0);
        op_script_overrides();
    end

For beginners, note that the "op_script_overrides()" is important to prevent a spurious message "That does nothing" from appearing in the message box during gameplay after the item is used.

Anyway, it doesn't work. When the pc uses the item during gameplay, the game crashes. There's nothing wrong with my object proto either, because a test function:

Code:
    if (op_obj_pid(op_obj_being_used_with()) == 605) then
    begin
        op_display_msg("Beep!");
        op_script_overrides();
    end

works fine.

Apart from a number of questions over time from various people that seem never to have been answered, the only substantive previous discussion of this issue was over here, where we find the following suggestion for using the function:

Timeslip said:
Code:
variable tmp;
tmp:=play_sfall_sound("Patch000.dat\\sound\\SFX\\geigerhigh.wav",1);

But this suggestion makes no sense, because a variable is not an instruction. In this case, the "tmp" would then have to be passed off somewhere else as part of a valid instruction in order to get a sound to actually play. And even if a sound did attempt to play, as I said earlier something is wrong because the game crashes when the function is called.

The function's documentation consists of the following:

sfall function notes.txt said:
play_sfall_sound and stop_sfall_sound are used to play mp3/wav/wma files. The path given is relative to the fallout folder. Specify loop as 1 to loop the file continuously, or 0 otherwise. If you don't wish to loop, play_sfall_sound returns 0. If you do loop, it returns an id which can be passed back to stop_sfall_sound when you want to stop the effect. All sounds effects will be stopped on game reload, looping or not. These functions do not require 'AllowDShowSound' to be set to 1 in ddraw.ini.

If anyone has experience on this issue and has both compiled a script including the function play_sfall_sound and has then seen the function actually work by hearing the sound in question played at the appropriate time during actual gameplay, please comment here for the benefit of all interested parties by including all the relevant code you used to accomplish this as well as any additional caveats (sound file in a certain format, required ddraw.ini settings, etc).

If play_sfall_sound doesn't work, it's no big deal-- we'll always have acms. But if that's the case then we're all better off knowing so no time is squandered messing around with it. Thanks.




 
Apart from a number of questions over time from various people that seem never to have been answered, the only substantive previous discussion of this issue was over here, where we find the following suggestion for using the function:

Timeslip said:
Code:
variable tmp;
tmp:=play_sfall_sound("Patch000.dat\\sound\\SFX\\geigerhigh.wav",1);

But this suggestion makes no sense, because a variable is not an instruction. In this case, the "tmp" would then have to be passed off somewhere else as part of a valid instruction in order to get a sound to actually play. And even if a sound did attempt to play, as I said earlier something is wrong because the game crashes when the function is called.

The function's documentation consists of the following:

sfall function notes.txt said:
play_sfall_sound and stop_sfall_sound are used to play mp3/wav/wma files. The path given is relative to the fallout folder. Specify loop as 1 to loop the file continuously, or 0 otherwise. If you don't wish to loop, play_sfall_sound returns 0. If you do loop, it returns an id which can be passed back to stop_sfall_sound when you want to stop the effect. All sounds effects will be stopped on game reload, looping or not. These functions do not require 'AllowDShowSound' to be set to 1 in ddraw.ini.

If anyone has experience on this issue and has both compiled a script including the function play_sfall_sound and has then seen the function actually work by hearing the sound in question played at the appropriate time during actual gameplay, please comment here for the benefit of all interested parties by including all the relevant code you used to accomplish this as well as any additional caveats (sound file in a certain format, required ddraw.ini settings, etc).

If play_sfall_sound doesn't work, it's no big deal-- we'll always have acms. But if that's the case then we're all better off knowing so no time is squandered messing around with it. Thanks.

He actually explains the rationale for using a temporary in that thread:

Timeslip said:
Another quirk of the compiler is that you (normally) can't ignore a functions return value.

I think by "functions" he means "instructions" though.

I haven't used play_sfall_sound, so are you (a) storing its return value in a temporary, and (b) is AllowDShowSound set to 1?
 
I definitely got the feature to work by attaching the code to a script for a cassette player in the game. Can't post the code now, though, since I am not on my computer.
 
But this suggestion makes no sense, because a variable is not an instruction. In this case, the "tmp" would then have to be passed off somewhere else as part of a valid instruction in order to get a sound to actually play. And even if a sound did attempt to play, as I said earlier something is wrong because the game crashes when the function is called.

It makes plenty of sense, given the stack based nature of fallouts script interperater. play_sfall_sound pushes a result value onto the stack, your script never pops it off, and fallout ends up crashing. Storing the result in a variable, even if you don't use that variable later, gets the stack back into the correct state. One of the advantages to the sslc compiler is that it knows about that sort of thing, and rather then generating a broken .int it would have refused to compile your code. (Albeit with a completely useless error message... :/)
 
Sorry if I'm unusually dense on this one, but I still don't get it. :confused: I think I follow the logic behind using a temporary variable, but don't understand what then to do in order to get a sound to actually play. If someone would be kind enough to hold my hand on this one and walk me through step by step, I'd appreciate it.
 
Have you tried
Code:
variable tmp;
tmp:=play_sfall_sound("Patch000.dat\\sound\\SFX\\geigerhigh.wav",1);

verbatim, with the path changed, and does it not work? Does it still crash?
 

@darkf

Yes, I just tried it again to verify.

Code:
procedure use_obj_on_p_proc
begin
    variable tmp;
    if (op_obj_pid(op_obj_being_used_with()) == 605) then
        tmp := op_play_sfall_sound("data\\sound\\SFX\\zmnc1.wav", 0);

Upon trying to use the harmonica during gameplay, the game immediately crashes (blank screen, non-responding process Fallout2.exe must be ended with Windows XP Task Manager).

Side issue: perhaps there's some functionality I don't understand, because this doesn't seem to me like it should do anything at all (though it obviously does, since it crashes the game). When I said before this form doesn't make sense, what I meant was this would be rather like saying:

Code:
variable is-it-raining;
is-it-raining := yes;

I'm certainly no computer programmer, but I know a few scripting languages and as far as I was aware in all of them such is useless unless we do something with the variable, for example by going on to say:

Code:
if (is-it-raining == yes) then
    move umbrella to inventory;
else
    move sunglasses to inventory;

That's why I said it seemed to me the example was incomplete, but maybe I don't fully understand the situation.

If anyone actually has play_sfall_sound working during gameplay (rather than merely successfully compiled in an untested script), an example showing all the relevant code used would be much appreciated. One of my purposes in starting this discussion was that, given the lack of any examples of play_sfall_sound actually working despite a number of enquiries by various folks elsewhere in the forum, there is reason to think the function itself is simply not working rather than that there is a problem with my own code attempting to utilize it.

@MIB88

I dug around in your stuff since you use the same compiler as me, but all I turned up was a reference in bsitem23.int ("audio tape 2" from one of Lich's thingies), where you wrote

Code:
procedure Node002
begin
  op_play_sfall_sound("data/sfall/O1812.wav", 0);
  op_gsay_reply(219, 3200);
  op_giq_option(2, 219, 3150, @Node003, 50);
  op_giq_option(2, 219, 3110, @Node999, 50);
end

I know you're busy and don't have access to your stuff right now, but do you by chance recall whether you verified that this works during gameplay? The public MM doesn't have a data\sfall folder or include a file O1812.wav, so there's no way for me to test it myself to see if the problem is somewhere on my end. Otherwise, this is the same sort of thing I wrote with my harmonica that crashes the game. I did some major writing over the past month, but don't want to start a new test game until I know whether I have to fiddle around with sndlst (but maybe that's for the best, because in the meantime I'm continuing to write more every day rather than playtest).





 
I know you're busy and don't have access to your stuff right now, but do you by chance recall whether you verified that this works during gameplay? The public MM doesn't have a data\sfall folder or include a file O1812.wav, so there's no way for me to test it myself to see if the problem is somewhere on my end. Otherwise, this is the same sort of thing I wrote with my harmonica that crashes the game. I did some major writing over the past month, but don't want to start a new test game until I know whether I have to fiddle around with sndlst (but maybe that's for the best, because in the meantime I'm continuing to write more every day rather than playtest).

Back home now. :cool:
Don't know what the deal is. But it worked like a charm in game when I tested it just a few minutes ago. The song played once then stopped. And the game kept working afterwards. Didn't work for the MP3 format file. But the .wav file worked just fine. I actually tested it with a converted A Kiss to Build a Dream On song. But... no issues. And that was still the script... no changes.
 
Last edited:
I'm certainly no computer programmer, but I know a few scripting languages and as far as I was aware in all of them such is useless unless we do something with the variable, for example by going on to say:

Code:
if (is-it-raining == yes) then
    move umbrella to inventory;
else
    move sunglasses to inventory;

That's why I said it seemed to me the example was incomplete, but maybe I don't fully understand the situation.

Well, it's a technical thing. Timeslip explained it above, but let me try again:

The scripts are compiled down to a bytecode, which is a machine-readable binary format for script instructions. Now, making up instructions, this code:

Code:
f(x);
would produce something like:

Code:
push x
call f
where `push` pushes a value (`x`) onto the stack (which you can think of as a stack of blocks, where you can only remove (`pop`) the top block or push a block on top.

Now, since f returns a value on the stack, you'll cleverly notice that we do not have a `pop` after it! This means that instructions that happen after it will access the wrong values on the stack, possibly a return address or something, and undefined behavior will result. This is bad. :(

However, if you were to do:

Code:
variable tmp;
tmp := f(x);
then it would result in something like:

Code:
push x
call f
store tmp
where `store` pops a value (the return value of `f`) off of the stack and stores it in the variable `tmp`, and thus the stack is balanced again.

I can't answer about play_sfall_sound as I haven't used it (although if you had an example I could try to debug it I suppose), but hopefully that explains why it crashes.
 
Thanks for the explanation, darkf, that finally makes sense to me. MIB88-- I'll play around a little with your script when I get home based on what you said and see if I can get anything going on this issue. In the meantime, if anyone else has used play_sfall_sound this discussion can only benefit by others sharing their code examples as well.
 
Back
Top