Play sound needs some work.
Moderator: Moderators
Play sound needs some work.
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
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
That part, in particular, is a tricky issue. I'd really like if we could have a different play-sound with more arguments:all players can hear even if the unit is not seen
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.
- SwiftSpear
- Classic Community Lead
- Posts: 7287
- Joined: 12 Aug 2005, 09:29
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:
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!):
Then to call in the bos/cob:
The first number is the sound ID in the .h file above, the other the volume.
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
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
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 */
Code: Select all
call-script lua_PlayUnitSound(119,300);
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!
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!
- SwiftSpear
- Classic Community Lead
- Posts: 7287
- Joined: 12 Aug 2005, 09:29
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.
if it is an expensive performance hit I will lose weeks that are priceless, please someone answer this query.
Hmm. Installed it, and get the following error, when I attempted to use the print command:
<tries something>
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... hrmmLuaCob: error = 2, GotChatMsg, [string "LuaCob/Gadgets/luasound.lua"]:157: bad argument #1 to 'gfind' (string expected, got table)
<tries something>
Nope, that didn't work (tried manually writing a proper sound reference and playing it through chat). Almost the same error, same cause:
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.
So, like... wtf does this mean?LuaCob: error = 1, GotChatMsg, [string "LuaCob/Gadgets/luasound.lua"]:157: bad argument #1 to 'gfind' (string expected, got table)
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.
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.
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.
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:
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...
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
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...
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:
I have the following lines in my STANDARD_COMMANDS.h
And I have this line, where I need it to be:
... it compiles. Let's see if this was even worth bothering with in the first place 
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 */
Code: Select all
PlayUnitSound() { return 0; }
PlayLocalSound() { return 0; }
PlayWorldSound() { return 0; }
Code: Select all
call-script PlayUnitSound(1,4);

It doesn't even fricking work yet
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>

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>
Nope
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...
So, it initialized.
... 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.

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)
Code: Select all
CLuaCob::CallFunction() missing function: PlayUnitSound
<slams forehead on desk>
I think... I need a cigarette.
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)
(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)
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.
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.