Play sound needs some work.

Play sound needs some work.

Discuss the source code and development of Spring Engine in general from a technical point of view. Patches go here too.

Moderator: Moderators

User avatar
smoth
Posts: 22309
Joined: 13 Jan 2005, 00:46

Play sound needs some work.

Post by smoth »

First things first, the play sound cob call is nice but it has the following issues:

Scales poorly to distance
All players can hear it.
all players can hear even if the unit is not seen
sounds sync, even if the units are not playing the same sound at the same time they still sync.
several simultaneous units make sound so loud I worry that I will damage speakers!

If this can be patched or fixed that would be really wonderful. I am not sure if any of you gents have the time to address this. Please consider looking into it.

Thanks in advance,
Smoth
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

all players can hear even if the unit is not seen
That part, in particular, is a tricky issue. I'd really like if we could have a different play-sound with more arguments:

SET PLAY_SOUND ("nameofsound", 15, 15, 1);

Where the digits correspond to volume, scalar falloff, and a boolean for "can be heard if Unit is not in LOS".

Some things should play, and be heard, even if not in LOS. Like, for example, you make a giant crunching walk noise, for a Krogoth. Um, you should hear that, imo. On the other hand, let's say it's something rather important that players out of LOS should not hear, like a Factory making sound effects during construction (I have this problem right now, as a matter of fact). So, I think there needs to be a bit of flexibility here- a boolean for GIANT HUGE NOISES that should be heard by anybody observing that part of the game world... and noises that we aren't making private, via the Unit sounds, but we don't want to be entirely public, either. Just my $0.02, of course.
User avatar
SwiftSpear
Classic Community Lead
Posts: 7287
Joined: 12 Aug 2005, 09:29

Post by SwiftSpear »

It'd be really nice to have lua access to some decent new playsound features so mods could set up lua based background music with whatever methods they felt like using. Thing's like soundstart points, sound volume control, sound endpoints being fed into info that lua can pick up would be golden.
User avatar
Zpock
Posts: 1218
Joined: 16 Sep 2004, 23:20

Post by Zpock »

Trepan (all praise) did this ages ago:

http://spring.clan-sy.com/phpbb/viewtop ... ht=#184057

Here is the LUA file thats not there, put in modfolder/LuaCOB:

Code: Select all

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--
--  file:    LuaCob/main.lua
--  brief:   lua based sound calls for COB scripts
--  author:  Dave Rodgers
--
--  Copyright (C) 2007.
--  Licensed under the terms of the GNU GPL, v2 or later.
--
--------------------------------------------------------------------------------
--
--  Provides the following COB calls:
--
--    PlayUnitSound (sndID          [, volume])
--    PlayLocalSound(sndID          [, volume])
--    PlayWorldSound(sndID, x, y, z [, volume])
--
--
--  Note 1:  [...]  means optional
--
--  Note 2:  this script loads its sound mapping from 'Units/LuaSounds.h'
--
--  Note 3:  volume is a 0 to 100 number for local sounds,
--           but values higher than 100 do make a difference
--           for global sounds
--
--  Note 4:  the unitID for PlayUnitSound does not have to be
--           explicitly passed by the COB script, it is done
--           automatically
--
--------------------------------------------------------------------------------
--
--  You can also use the following chat commands for testing:
--
--    .luacob print   -- print BOS format sound map into infolog.txt,
--                       the results can be copied into 'Units/LuaSounds.h'
--
--    .luacob unit   unitID  sndID   [volume]
--    .luacob local  sndID           [volume]
--    .luacob world  sndID  x  y  z  [volume]
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


Spring.Echo('LuaCob: wired for sound')


local volumeScale = 0.01  -- percent

local soundMap = {}


-- parse the sound definition file
do
  local soundFile = 'LuaCob/LuaSounds.h' -- for .devlua testing
--  local soundFile = 'Units/LuaSounds.h'
  local text = VFS.LoadFile(soundFile)
  if (text == nil) then
    Spring.Echo('LuaCob: missing ' .. soundFile)
    KillScript()
    return
  end
  local fmt = '#define%s+%S+%s+(%d+)%s+/%*%s*(%S+)%s*%*/'
  for id, name in string.gfind(text, fmt) do
    soundMap[tonumber(id)] = name
  end
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

local function SoundCheck(...)
  local argCount = table.getn(arg)
  if (argCount < 1) then
    return
  end
  local name = soundMap[arg[1]]
  if (name == nil) then
    return
  end
  return name, argCount
end


function PlayUnitSound(unitID, unitDefID, unitTeam, ...)
  local name, args = SoundCheck(unpack(arg))
  if (name == nil) then return false end
  local x, y, z = Spring.GetUnitPosition(unitID)
  if (x == nil) then return false end
  if (args == 1) then
    Spring.PlaySoundFile(name, 1.0, x, y, z)
  else
    Spring.PlaySoundFile(name, arg[2] * volumeScale, x, y, z)
  end
  return true
end


function PlayLocalSound(unitID, unitDefID, unitTeam, ...)
  local name, args = SoundCheck(unpack(arg))
  if (name == nil) then return false end
  if (args == 1) then
    Spring.PlaySoundFile(name)
  else
    Spring.PlaySoundFile(name, arg[2] * volumeScale + 50)
  end
  return true
end


function PlayWorldSound(unitID, unitDefID, unitTeam, ...)
  local name, args = SoundCheck(unpack(arg))
  if (name == nil) then return false end
  if (args <= 4) then return false end
  if (args == 4) then
    Spring.PlaySoundFile(name, 1.0, arg[2], arg[3], arg[4])
  else
    Spring.PlaySoundFile(name, arg[5] * volumeScale, arg[2], arg[3], arg[4])
  end
  return true
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

local function PrintSoundBOS()
  -- get the list of sounds, and print them in a BOS script compatible format
  local soundList = VFS.DirList("sounds/", "*", VFS.ZIP_ONLY)
  for i,n in ipairs(soundList) do
    local name = string.upper(n)
    name = string.gsub(name, '.-[/\\](.*)', '%1')
    name = string.sub(name, 1, -5)
    Spring.Echo(string.format('#define  SND_%-12s %3i  /*  %s  */', name, i, n))
  end
end


function GotChatMsg(msg, playerID)
  if (msg == 'print') then
    PrintSoundBOS()
    return
  elseif (msg == 'show') then
    for id, name in pairs(soundMap) do
      Spring.Echo(string.format('%-4i -> %s', id, name))
    end
    return
  end

  -- tokenize
  local args = {}
  local i = 1
  local cmd
  for w in string.gfind(msg, "[^%s]+") do
    if (i == 1) then
      cmd = w
    else
      table.insert(args, tonumber(w))
    end
    i = i + 1
  end
  argCount = i - 2
  if ((cmd == nil) or (argCount < 1)) then return end

  if (cmd == 'local') then
    if (argCount == 1) then
      PlayLocalSound(0, 0, 0, args[1])
    elseif (argCount == 2) then
      PlayLocalSound(0, 0, 0, args[1], args[2])
    end
  elseif (cmd == 'unit') then
    if (argCount == 2) then
      PlayUnitSound(args[1], 0, 0, args[2])
    elseif (argCount == 3) then
      PlayUnitSound(args[1], 0, 0, args[2], args[3])
    end
  elseif (cmd == 'world') then
    if (argCount == 4) then
      PlayWorldSound(0, 0, 0, args[1], args[2], args[3], args[4])
    elseif (argCount == 5) then
      PlayWorldSound(0, 0, 0, args[1], args[2], args[3], args[4], args[5])
    end
  end
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

Then u need a LuaSounds.h file that looks like this (this is autogenerated I think, somehow, so you dont need to write all this crap!):

Code: Select all

#define  SND_AALASER        1  /*  sounds/aalaser.wav  */
#define  SND_AALASERHIT     2  /*  sounds/aalaserhit.wav  */
#define  SND_ARTY           3  /*  sounds/arty.wav  */
#define  SND_ARTY2          4  /*  sounds/arty2.wav  */
#define  SND_ARTYHIT        5  /*  sounds/artyhit.wav  */
#define  SND_BASEUNDERATTACK1   6  /*  sounds/baseunderattack1.wav  */
#define  SND_BEEP4          7  /*  sounds/beep4.wav  */
#define  SND_BEEP4_OLD      8  /*  sounds/beep4_old.wav  */
#define  SND_BEEP6          9  /*  sounds/beep6.wav  */
#define  SND_BIGDEATH      10  /*  sounds/bigdeath.wav  */
#define  SND_BIGPLASMAHIT  11  /*  sounds/bigplasmahit.wav  */
#define  SND_BMLAUNCH      12  /*  sounds/bmlaunch.wav  */
#define  SND_BUILDINGEXPLODEHIT  13  /*  sounds/buildingexplodehit.wav  */
#define  SND_BUILDINGEXPLODEHITS  14  /*  sounds/buildingexplodehits.wav  */
#define  SND_BUILDINGEXPLODESTART  15  /*  sounds/buildingexplodestart.wav  */
#define  SND_BUILDINGSELFDESTRUCT  16  /*  sounds/buildingselfdestruct.wav  */
#define  SND_BURN02        17  /*  sounds/burn02.wav  */
#define  SND_BUTTON6       18  /*  sounds/button6.wav  */
#define  SND_BUTTON9       19  /*  sounds/button9.wav  */
#define  SND_CANNONHITGD   20  /*  sounds/cannonhitgd.wav  */
#define  SND_CANNONHITURC  21  /*  sounds/cannonhiturc.wav  */
#define  SND_CANNONHITURC2  22  /*  sounds/cannonhiturc2.wav  */
Then to call in the bos/cob:

Code: Select all

call-script lua_PlayUnitSound(119,300);
The first number is the sound ID in the .h file above, the other the volume.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Wow, that's totally cool! Thanks bunches! Looks like editing it, just to keep things simple, should be very easy- I'll almost certainly create a list of sounds, assign them to a category, and then just pull from that list. Awesome, just what I wanted, I think this will solve the main problem here.

Oh, and the ".luacob print" command is what generates that list, btw, just posts it to Infolog, I'm guessing, for easy manipulation afterwards... great stuff!
User avatar
SwiftSpear
Classic Community Lead
Posts: 7287
Joined: 12 Aug 2005, 09:29

Post by SwiftSpear »

I still advocate fixing spring generic sound generators, but it's nice to know there are cool lua versions now...
User avatar
smoth
Posts: 22309
Joined: 13 Jan 2005, 00:46

Post by smoth »

Lua sound is all fine and good but I am going to have a lot of lua running in the final gundam 2.0 I want to try and use in engine functionality as much as I can. If I can get a confirmation that this lua code would cost less or equally to play sound that is fine and good but I am skeptical.
User avatar
smoth
Posts: 22309
Joined: 13 Jan 2005, 00:46

Post by smoth »

I am not trying to sound pushy or maybe I am, I don't know but this is my last semester I am already working as fast as I can on my projects that I am involved with. I am very worried about after graduation and whether or not I will be able to be as active as I am now. If I went and implemented that long pile of lua for every sound effect in gundam that needs to be done it will take weeks. This will also be assuming that this isn't going to cause a major performance hit as I've no idea whether or not using lua instead is expensive.

if it is an expensive performance hit I will lose weeks that are priceless, please someone answer this query.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

I will know fairly soon, Smoth. I'm going to use this foot-stomps for mecha, so that players hear their own mecha, but do not hear anybody else's, and see what happens when 100 little guys are all trying to "stomp, stomp, stomp" across a battlefield. I will let you know how this works out.
User avatar
smoth
Posts: 22309
Joined: 13 Jan 2005, 00:46

Post by smoth »

thx
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Hmm. Installed it, and get the following error, when I attempted to use the print command:
LuaCob: error = 2, GotChatMsg, [string "LuaCob/Gadgets/luasound.lua"]:157: bad argument #1 to 'gfind' (string expected, got table)
Maybe something got broken up, when I took that text from the post, but it looks ok... must be missing something basic here... I have an empty LuaSounds.h, in LuaCob root... hrmm

<tries something>
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Nope, that didn't work (tried manually writing a proper sound reference and playing it through chat). Almost the same error, same cause:
LuaCob: error = 1, GotChatMsg, [string "LuaCob/Gadgets/luasound.lua"]:157: bad argument #1 to 'gfind' (string expected, got table)
So, like... wtf does this mean?

The offending line reads,

" for w in string.gfind(msg, "[^%s]+") do"

Ok, so it's a string-parsing line, it's grabbing, I presume, the contents of the msg field, and the data returns as a table, causing the crash. Is that because the data returned by msg has been changed, since this was written?

<sighs>

Lemme go do the important part, which is seeing what happens when I invoke this, player-side only, for a footstomp for 100 stompy robots... I'll come back to this later. It's not like writing out the config is so painful, and I'm so lazy, that I can't just do it that way- we're maybe talking 20-30 sounds here. I'll just comment out all this diagnostic code for now, and make sure the core stuff works...

Sorry for whining, folks, just was hoping that I'd already be boasting about how great it is to run the sounds through LUA already, and I just know that whatever's causing that error is almost certainly easy to fix, if I wasn't blitheringly ignorant.
User avatar
Snipawolf
Posts: 4357
Joined: 12 Dec 2005, 01:49

Post by Snipawolf »

Huhhmmm...

I have tons of units that use continous sounds... Vehicles, infantry, some buildings. I like being able to hear an approaching army rumbling forward and scramble my units. However, I don't like hearing enemy buildings, which gives away the position... Hope this can work, at least for my buildings.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

We'll see, in about 5 minutes.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Nope, hit another snag, because of the call-script, which is, obviously, trying to call a script that doesn't exist. Which, obviously, won't compile. I'm missing something very important here, obviously... there must be one more piece of BOS, here.

So, how does BOS communicate with LuaCob? GET / SET? And how the heck do I know I'm sending to the right script?


I mean, I can see what this does:

Code: Select all

function PlayUnitSound(unitID, unitDefID, unitTeam, ...)
  local name, args = SoundCheck(unpack(arg))
  if (name == nil) then return false end
  local x, y, z = Spring.GetUnitPosition(unitID)
  if (x == nil) then return false end
  if (args == 1) then
    Spring.PlaySoundFile(name, 1.0, x, y, z)
  else
    Spring.PlaySoundFile(name, arg[2] * volumeScale, x, y, z)
  end
  return true
end
I can see that I've used a define, in the un-necessary, but handy .h file... so, what's the last step here? Because lua_PlayUnitSound(arg) is obviously not a valid BOS command. Therefore, it must be a GET / SET. Therefore, I need a command number to pass, because that's all it can do, is pass the number from the header to Spring, with arguments.

What number do I need?

<looks at more crap>

Ok, so I need to SET LUA0 TO... what? Because that's the final step here. I need to pass an arg, which must be integers, or Scriptor pukes...
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Oh, goodie. In the Wiki, there are instructions, to get me out've the wilderness.

Finally, this is starting to make sense, although the whole call-script thing is very weird.

What I'll do, is first, add this to my STANDARD_COMMANDS.h header file, because there's no harm in having it there, since the COBHandler will never actually use them:

PlayUnitSound() { return 0; }
PlayLocalSound() { return 0; }
PlayWorldSound() { return 0; }

Next... well, I guess I could maintain a #define table of sounds, now that I know that the LUA code is sorting it all alphanumerically. However, that seems dumb, to have this huge list of defined variables sitting in memory for every Unit.

Nope, gonna get around this the smart way, by just renaming the (relative handful) of sound files I need, so that they are always in a very specific alphnumeric order, i.e., 0001_Argh_Mech_Stompy_Sound.wav....

So, I have a LuaSounds.h that just reads:

Code: Select all

#define  Argh_Mech_Footstomp	1  /*  sounds/Argh_Mech_Footstomp.wav  */ 
I have the following lines in my STANDARD_COMMANDS.h

Code: Select all

PlayUnitSound() { return 0; }
PlayLocalSound() { return 0; }
PlayWorldSound() { return 0; }
And I have this line, where I need it to be:

Code: Select all

		call-script PlayUnitSound(1,4);	
... it compiles. Let's see if this was even worth bothering with in the first place ;)
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

It doesn't even fricking work yet :roll:

Ok, back to square one... must've done something obviously wrong here. Moreover, it's locking up my animation, but the script just says "return(0)", so it shouldn't be doing anything, not even sleeping a frame. Puzzling.

Oh... I see, it's a 1-100 scale, instead of the scale originally used for play-sound. So a value of 4, which with play-sound, is fairly darn loud, but scales enough you can't hear it everywhere, is, like... almost silent...

<tries value 100>
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Nope :roll:

Well, the Wiki always prefaces Function calls with lua_ ... let's try that.

Ok, great! LuaCOB knows that I'm trying to pass it an argument through the COB interface. Good times. However...

Code: Select all

LuaCob: wired for sound
LUACOB-MAIN  (GADGETS)
So, it initialized.

Code: Select all

CLuaCob::CallFunction() missing function: PlayUnitSound
... but it the no longer knows how to find the !!@&#!@ function sometime quickly after that.

<slams forehead on desk>

I think... I need a cigarette.
trepan
Former Engine Dev
Posts: 1200
Joined: 17 Nov 2005, 00:52

Post by trepan »

1. this is old code (pre-gadgets), i haven't looked at it in a while
(ex: KillScript() no longer exists, Script.Kill() does)

2. this code is not a gadget (I see you have a gadget handler message)
If you want to make it into a gadget, use the
gadgetHandler:RegisterGlobal('PlayUnitSound', PlayUnitSound) type calls

3. if you don't want for it to be a gadget, move the file to:
LuaCob/main.lua (which will block the gadget handler from being loaded)
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Ok. In Main, it goes. Which, if it makes you feel any better, is what I was going to try next, because the original code, up above, reads main.lua in your preface, so I was kind've desperately hoping that might be what I need to do here.

You do realise, that this is like assembling one of those cheap model kits whose only instructions are in Korean(or, for you Koreans, anything else, I'm sure), and are wrong at least 90% of the time, right? Blindfolded? Using super-glue?

Or something. It's not that bad, I guess, having tried the blindfolded-model thing once (hint- acetone is the only major solvent that will get your fingers unstuck, and probably won't cause all of your braincells to die, or cause your children to be mutants).

I'm frustrated, and I want to get back to the great problems of the Rocket Factory's landing sequence, where I'm on 100% familiar ground. I know I will eventually become un-frustrated. And it's not your fault I'm stupid.

But after the cigarette. Because, as I've just found, the only thing worse than being driven to smoke by code... is being driven to smoke by code, discovering I'm out, and then arriving at a gas station where everybody just wanted to vaguely hang out, in front of the armored glass, and the lady supposed to be selling stuff is so slow that people are forming friendships... nay, they are having entire relationships before I can shove some grubby ones at her and mutter something about nicotine. In a box.
Post Reply

Return to “Engine”