Doing MSP (MUD Sound Protocol) with MUSHclient

Posted by Nick Gammon on Wed 16 Jan 2002 01:45 AM — 18 posts, 111,819 views.

Australia Forum Administrator #0
After a few requests for MSP, I am pleased to present a way of handling MSP in the existing version of MUSHclient, which should be acceptable for players wishing to hear sounds, before MSP is integrated into MUSHclient itself.

It involves setting up a single trigger, which matches on a MSP line. The trigger calls a script, which plays the appropriate file.

Here is an example of an MSP line, from the Dawn Of Time codebase ...


!!SOUND(action/huh.wav V=75 L=1 P=50 T=action U=http://www.stormbringer.sytes.net/msp/action/huh.wav)Huh?


This is sent when the player makes a typing mistake. It plays the file "huh.wav" and sends "Huh?" to the player.

The problem with making a trigger to match sounds is that the !!SOUND directive might be preceded by, and followed by, text the player is supposed to see, so we have to make a trigger that returns 3 wildcards:

  1. The text before the sound
  2. The sound file name
  3. The text after the sound


For example:


text-before !!SOUND(action/huh.wav V=75 L=1 P=50) text-after


The parts in bold will be the three wildcards.

Below are the steps for getting MSP to work for you ...




1. Add the following script to your script file (VBscript)


'
' Trigger script to simulate MSP (MUD Sound Protocol)
'

sub OnSound (strName, strLine, aryWildcards) 
dim sBefore, sSound, sAfter, iColourFore, iColourBack

' extract text from wildcards
'  wildcard 1 is the text before the sound
'  wildcard 2 is the sound file name
'  wildcard 3 is the text after the sound

  sBefore = aryWildcards (1)  ' what arrived before the !!SOUND directive
  sSound  = replace (aryWildcards (2), "/", "\")  ' sound file to play
  sAfter  = aryWildcards (3)  ' what arrived after the !!SOUND directive

' play sound - AMEND DIRECTORY as required
  
  world.Sound ("c:\mushclient\msp\" & sSound)

' remember current world.note colours

  iColourFore = world.notecolourfore 
  iColourBack = world.notecolourback 

' set note colour to default text colour

  world.NoteColourRGB world.NormalColour (8), world.NormalColour (1)

' display the text surrounding the sound

  world.note sBefore & sAfter

' set note colour back to what it was

  world.NoteColourRGB iColourFore, iColourBack

end sub





2. Add a trigger

Trigger: ^(.*)\!\!SOUND\(([A-Za-z0-9./]+).*\)(.*)$
Regular expression: checked
Omit from output: checked
Label: sound
Script: OnSound




3. Get the sound files

This technique does not automatically download sound files like some other client programs do. However most MUDs that support MSP will supply all their sound files as a single "zipped" file. If not, ask their admins nicely for one, I'm sure they will be happy to oblige.

Download that file, and then put your sounds in a subdirectory "msp" below the MUSHclient install directory.

If you put them somewhere else (eg. in a directory per world) then amend then
script above to reflect the location of the sound files.

In my example, if MUSHclient was installed into C:\MUSHclient, then the "huh" sound might be in:


c:\MUSHclient\msp\action\huh.wav





4. Enable MSP

MSP has a telnet negotiation sequence which lets the server auto-detect whether the client supports MSP. However some servers, at least, let you turn MSP on manually (eg. Dawn Of Time).

Type in whatever command you need to enable MSP, eg.


msp on





5. Test

Now you should be ready to test. Type in whatever is needed to trigger a sound (eg. a nonsense command in Dawn Of Time) and listen to see if the sound is played.




Limitations

This method is not a full implementation of MSP, however it should get you up and running with sounds if that is what you want.

Here are some limitations of it ...

  • Sounds are not automatically downloaded, you must get the sound files manually (this should not be a big deal, it just means you have to download one big file and unzip it).
  • MSP parameters such as sound volume are ignored, so all sounds will play at the same volume
  • Multiple sounds will not play simultaneously
  • In order to stop the !!SOUND text from displaying the whole matching line is omitted from output. The script uses world.note to display any other text (eg. "Huh?") however that will be displayed in the default text colour. Any colouring of the line that the server had put there will be discarded.
  • There is no telnet negotiation, so some servers might not send down the !!SOUND lines, unless you can turn MSP on manually.


Having said all that, it seems to work fine on the DOT servers, so if you want to try MSP in MUSHclient, give it a go! :)
Amended on Sat 19 Jan 2002 03:50 AM by Nick Gammon
Australia Forum Administrator #1
This is now available as a MUSHclient plugin - see MSP Plugin forum message.
Amended on Sun 05 Dec 2004 09:57 PM by Nick Gammon
Australia Forum Administrator #2
Can you elaborate a bit? You added what trigger? The plugin has one, you just customise its trigger, you don't add another one.

I don't understand the display you gave, that doesn't look much like MSP.

With MSP you expect to get something like this from the MUD:

!!SOUND(action/huh.wav V=75 L=1 P=50 T=action U=http://www.stormbringer.sytes.net/msp/action/huh.wav)Huh?

Not:

Display: No entry for 'Subspace'.
Sound: nofile.wav
#3
I think I get it now, the trigger is -

^(.*)\!\!SOUND\(([A-Za-z0-9./]+).*\)(.*)$

and is triggered when something like this shows up (yes?).
Oh oh, !!SOUND(beat.wav V=75 L=1 P=50 T=action U=beat.wav)The shiznit has just bean beat'n out of you.

If this right then I need to change all the in built mush messages to this format?
Amended on Tue 26 Aug 2003 11:10 PM by Spud
Australia Forum Administrator #4
Er, yes. Are you modifying a MUSH server? Is that what you are doing?

If that is what you are doing then you need to output the !!SOUND message in the format that MUSHclient is expecting. You would need to check that they are expecting it (eg. have a flag) otherwise people will get that message even if they can't handle it.
#5
having a small problem with the message after the emit'd string. Sting looks like this:

&CMD_Desk.test desk=$error:@emit Huh?!!SOUND(PRR.wav V=75 L=1 P=50 T=action U=PRR.wav) (Type "help" for help.)

I noticed that anything in the () will be omited. Is there a way around this?
Australia Forum Administrator #6
There, is but I forget what it is. Maybe this:

\( instead of (

USA #7
I realize this is a REALLY old topic but I just recently decided to set this up. Anyways, the mud I play doesn't include the .wav file extension when it triggers the sounds. It just shows something like this: !!SOUND(door).

My question is, how do I edit the code in the script file to tack the .wav extension onto the end of the file name?

Thanks.
USA #8
Search for the line:
sSound = replace (aryWildcards (2), "/", "\")
in the plugin.
If you change that to:
sSound = replace (aryWildcards (2), "/", "\") & ".wav"
then it should work.


EDIT:
This means, of course, that sounds will only work on MUDs that don't output the ".wav". You'd have to do something a little bit more clever. Maybe something like:

sSound = replace (aryWildcards (2), "/", "\")

if Right(sSound, 4) != ".wav" then
  sSound = sSound & ".wav"
endif
Amended on Fri 10 Mar 2006 09:40 AM by David Haley
USA #9
Thank you much!
USA #10
Hmm. Wouldn't this be safer Ksilyan:

if Right(sSound, 4) != ".wav" and not instr(sSound,".") then
  sSound = sSound & ".wav"
endif


That way, if it does have an extension and its "not" a .wav, you won't end up tacking on .wav to the end, like "My_Sound.ogg.wav". This is bound to be less than helpful. ;) The above should handle cases where there is already a file extension, even if someone uses a four character one, like .mpeg. Though I don't think even an audio only of that would play anyway and can't think of any case where a four letter type is used for sounds, but some clown could always make them .wave or some dumb thing, then wonder why about 80% of the applications won't play it. lol Always a good idea to cover all your bases.
#11
Hello!

I got MSP to somewhat work using the above code to allow a .wav to play when not specified (was error'ing out before), but the sounds only play a windows 'beep', not the file(s).

I've tested the .wav's it is trying to play and they are valid.

Any ideas?
Australia Forum Administrator #12
See this thread for more information:

http://www.gammon.com.au/forum/?id=8721

I think you will find that the internal format of the .wav file is not supported. The fact that you can play it using some other program, only shows that the other program supports more encoding formats.

I suggest you convert the files to:

  • 16-bit
  • 22.05 KHz
  • PCM (ie. uncompressed)
  • Mono or Stereo


I believe "sound recorder" utility may be able to open your file, and then you can re-save in that format. Failing that, try Audacity:

http://audacity.sourceforge.net

This is a free program that opens many different formats, and exports a .wav file in a format that should be readable.
#13
Thanks for the assistance Nick.

Unfortunately, I still couldn't get it to work. I exported a few .wav's using Audicity but it didn't seem to save the 16-bit (kept using them as 32-bit).

No worries though, after hearing some of the sound effects this particular mud uses I think I may be better off with silence *chuckles*

Again, thanks for your help and quick response. It is most appreciated (_LOVE_ your client for the record, very well done. Had I the extra money to donate, you'd have it :) )
Germany #14
Following a discussion on my mud last night, I decided to take look at using PlaySound() for MSP triggers, because it allows up to 10 sounds to be played simultaneously.

It turned out that all I needed was the following (using the existing MSP trigger):

function OnSound (name, line, wildcards)
  if wildcards[2] ~= nil then
    PlaySound (0, wildcards[2], false, 0, 0)
  end -- if
end -- function OnSound
Okay so it doesn't do any of the other fancy stuff mentioned in the MSP specification, but just that one tiny function alone is enough to play multiple sounds at once - and it automatically uses the appropriate relative path for the sound files, too (with the current MSP plugin my players keep putting their sounds in the wrong directory, because they don't read the plugin first).

If you're using the latest version of MUSHclient you can also add negotiation support just as easily:

function OnPluginTelnetRequest (type, data)
  if type == 90 and data == "WILL" then
    return true -- IAC DO MSP
  else
    return false
  end -- if
end -- function OnPluginTelnetRequest
With a little tokenising, the plugin could implement full MSP support (the "U" download URL might be more tricky, but I read on another thread that someone had managed it). You could even extend the protocol with an option for panning, which is something that would work particularly well in a coordinate-based mud like mine (because the mud tracks which direction you're facing, and your exact position relative to everything else).

I'm not quite sure how you'd handle the !!MUSIC() trigger though. You could allocate a specific PlaySound() buffer for it easily enough, but then it would be limited to WAV files in the same way as !!SOUND().

There was some talk in the past of building MSP into the client, but if that's no longer the case, might it be worth having a more fleshed-out plugin?

EDIT: Added "else return false" to OnPluginTelnetRequest(), otherwise it accepts every handshake with DO or WILL.
Amended on Thu 24 Jun 2010 02:37 PM by KaVir
Australia Forum Administrator #15
Yes, good idea. Any volunteers?
Germany #16
I'm still new to plugins and Lua. But if nobody else does it first, and I manage to come up with a working solution, I'll post it.
Australia Forum Administrator #17
An improved version of this plugin, written in Lua, is described here:

http://www.gammon.com.au/forum/?id=12542&reply=6#reply6