DEV Community

Paul Halliday
Paul Halliday

Posted on • Originally published at developer.school on

#2 Developing World of Warcraft AddOns - Music Player

#2 Developing World of Warcraft AddOns - Music Player

In Part One of our Developing World of Warcraft AddOns series we looked at how to create a basic "Hello, World!" AddOn. We managed to load it up in game and display a message on screen, both at initialisation time and with a slash command.

#2 Developing World of Warcraft AddOns - Music Player
Zolten gave me 16g whilst writing this article. He's a cool guy!

Today we'll be looking at how to play music and sound file(s) with our AddOns and creating a sound board, of sorts. It'll be slash command based, so the user will be able to type in something like:

  1. /playsound ding
  2. /playsound murlocs
  3. /playsound main theme
  4. /playsound custom
  5. /stopsound

As you can imagine, each one allows us to play a particular sound or music file. We'll also be able to play custom sounds that we've added directly to our AddOn!

New AddOn

Let's create a new AddOn folder at Interface/AddOns/MusicPlayer with the following MusicPlayer.toc:

## Interface: 11303
## Title: MusicPlayer
## Notes: Play sounds and music inside of the game.
## Author: Paul Halliday
## Version: 0.0.1

MusicPlayer.lua

Finding Sounds

The easiest way to find sounds from World of Warcraft is to head over to Wowhead and find the in-game ID. For example, if we wanted to add the MurlocAggro sound, we'd likely search for Murloc and then click Links > Copy In-game Sound Command:

#2 Developing World of Warcraft AddOns - Music Player

This gives us the following command:

/script PlaySound(416)
Try it in-game. You'll hear mrlrlrmrmrrrgllkrkglrl!

We can also go ahead and do the same for the Ding! noise:

#2 Developing World of Warcraft AddOns - Music Player

This gives us the following command:

/script PlaySound(888)
> Ding! > Grats!

We can also find game music with sites such as wow.tools which we can play using PlayMusic(id)

#2 Developing World of Warcraft AddOns - Music Player

This can be played in-game by typing the following command:

/script PlayMusic("Sound\\Music\\GlueScreenMusic\\wow_main_theme.mp3")

You'll need to ensure that you've got music enabled for this to work.

If you're making an AddOn for retail, you'll want to use the fileId instead, i.e. PlayMusic(53223)

We're then able to stop the music by typing:

/script StopMusic()
That's enough title music for now... :)

Given what we now know, we can create a little MusicPlayer which allows us to play sounds with a slash command.

It's time to write some code!

Registering Slash Commands

The first thing that we're going to do is register a slash command for our sound player. We'll want to register both /playsound and /stopsound inside of MusicPlayer.lua:

SLASH_SOUND1 = "/playsound"
SLASH_STOPSOUND1 = "/stopsound"

local function playSoundHandler()
  print("Play sound!")
end

local function stopSoundHandler()
  print("Stop sound!")
end

SlashCmdList["SOUND"] = playSoundHandler;
SlashCmdList["STOPSOUND"] = stopSoundHandler;

If we type /reload in-game, we should be able to see our messages if we type either of our slash commands.

#2 Developing World of Warcraft AddOns - Music Player

Displaying Sounds

In order to play these sounds with our AddOn, we can make a table named sounds which contains information about the sound we'd like to play.

This allows us to either make a decision on which method we want to call to play the sound, or display information on screen to the user about the sound.

local soundType = {
    SOUND = 1,
    GAME_MUSIC = 2,
    CUSTOM = 3
}

local sounds = {
    ["murloc"] = {
        ["sound"] = 416,
        ["description"] = "Mglrlrlrlrlrl!",
        ["type"] = soundType.SOUND
    },
    ["ding"] = {
        ["sound"] = 888,
        ["description"] = "Grats!",
        ["type"] = soundType.SOUND
    },
    ["main theme"] = {
        ["sound"] = "Sound\\Music\\GlueScreenMusic\\wow_main_theme.mp3",
        ["description"] = "DUN DUNNN... DUNNNNNNNNNN",
        ["type"] = soundType.GAME_MUSIC
    },
    ["custom"] = {
        ["sound"] = "Interface\\AddOns\\MusicPlayer\\Sounds\\custom.mp3",
        ["description"] = "Custom sound!",
        ["type"] = soundType.CUSTOM
    }
}

Feel free to add your own sounds here and experiment with different sounds from Wowhead.

I've also added a sound called custom.mp3 inside of a new folder I created at AddOns/MusicPlayer/Sounds. This represents the ability to play a sound outside of the standard game files.

There isn't anything special about the folder name Sounds, so feel free to add a custom sound wherever suits your use case. If you'd like to play your own sounds, go ahead and add it to the directory and sounds table like I did.

We can now create a new function named displaySoundList which will be used to print the potential sounds on screen to the user:

local function displaySoundList()
    print("----------------------------")
    for command in pairs(sounds) do
        local description = sounds[command].description
        print("Command: /playsound " .. command .. " - Description: " .. description)
    end
    print("----------------------------")
end

In order to use this, update your playSoundHandler to call the displaySoundList whenever we activate this command:

local function playSoundHandler()
  displaySoundList()
end

#2 Developing World of Warcraft AddOns - Music Player

Playing Sounds

Now that we've got a very helpful sound list, the user knows that they can type a particular command to play a sound!

Let's now wire up that functionality to actually play a sound by updating our playSoundHandler:

local function playSoundHandler(trackId)
  if(string.len(trackId) > 0) then
      local matchesKnownTrack = sounds[trackId] ~= nil

      if (matchesKnownTrack) then
          local track = sounds[trackId]

          playTrack(track)
      else
          displaySoundList()

          print(trackId .. " - Doesn't match a known track.")
      end
  else
      displaySoundList()
  end
end

Our control flow now looks like the following:

  1. If there has been a track passed in by the user and it exists, play the track.
  2. If there has been a track passed in by the user and it doesn't exist, display the sound list and a message.
  3. If there is no track, display the sound list.

Let's write our playTrack method so that we can actually play a sound!

local customSoundId

local function playTrack(track)
  print(track.description)

  if(track.type == soundType.GAME_MUSIC) then
      PlayMusic(track.sound)

      print("To stop the music type /stopsound")
  elseif(track.type == soundType.SOUND) then
      PlaySound(track.sound)
  elseif(track.type == soundType.CUSTOM) then
      stopSoundHandler()
      customSoundId = select(2, PlaySoundFile(track.sound))
  end
end

We're now able to either PlayMusic(track.sound), PlaySound(track.sound) or PlaySoundFile(track.sound) depending on the type that we determined inside of our sounds table earlier.

#2 Developing World of Warcraft AddOns - Music Player

Notice how we're creating a customSoundId and only defining a value when we use PlaySoundFile as this returns us an id which we can use to stop the sound later in the next step.

Stopping Sounds

For the next step, I'm going to assume that any sound is just a few seconds long and a user wouldn't want to type /stopsound to cancel it. A user may want to stop music and custom sound files though.

Let's update our stopSoundHandler to support this:

local function stopSoundHandler()
  StopMusic()

  if(customSoundId ~= nil) then
      StopSound(customSoundId)
      customSoundId = nil
  end
end

We're now able to stop sounds using /stopsound!

You can try this out if you either play a custom sound file or some music with PlayMusic.

Summary

In the second part of our Developing WoW AddOns series we created a little Music Player! It's not going to win AddOn of the year award by any stretch just yet, but we hopefully learned a little more about playing sound files.

Code for this article: https://github.com/PaulHalliday/wow_addon_music_player

Top comments (1)