• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

External Music System V.1.5

This is an unbelievably simple system I've made with basic vJASS (First vJASS spell!!) as I currently don't know advanced vJASS (structs and stuff) but it wasn't needed, as the system is waaaaay too simple, but I think useful. Might not be approved, as it is too simple, but for some Map-Makers that don't want to waste filesize on Music files they can attach the soundtrack to the map and let the player install it.

The is the External Music System. A system where you give it the .mp3 files in your Warcraft III folder (you give the system the path) and it plays the music for you one by one, I tried to make it as Configurable as possible, like you can choose all .mp3 prefixes, the choice whether the 0 before 1 should be there or not (like "Track-01" and "Track-1"), playing the music random, etc. The user can fully configure the system, and of course the .mp3 files!

Fully MUI and GUI friendly. Demo map includes whatever you need to know, and a way to use the system is under the Category "Demo related".

Requirements:
JNGP
Local Files Enabled


Why JNGP?
Because this is coded in vJASS and also you need to have local files enabled. Tick it from the Grimoire extension of JNGP (thanks Emm-A-!).

Disclaimer:
Changing the .mp3 files in the middle of when system is ran is NOT supported.
Only works with .mp3 files. .wav file formats and others are basically avoided.

Remember, if anyone uses this and finds a problem with it, he has the Responsibility to report the problem here (using the debug messages).

Special thanks to Zwiebelchen for his helps.

  • MS Configuration
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- ===== --------
      • -------- Configuration --------
      • -------- ===== --------
      • -------- The Timeout for the system. --------
      • -------- The real timeout will be calculated by how many times(MS_Timeout) checks will happen in a SINGLE SECOND. So the system now currently works every 0.5 seconds. --------
      • -------- The bigger the variable is, the more percise the system gets. But with bigger values than like 40 or 50 you'll have some minor problems on Battle.net. --------
      • Set MS_Timeout = 20.00
      • -------- When set to true, "Test-01" will be used as a sound and "Test-1" won't be. Vica Versa as well. --------
      • Set MS_Use0 = True
      • -------- The Variable would look for a known number of tracks, so it will loop until then for like 3 times. --------
      • -------- Set it to 0 so it would look for all available tracks. (recommended) --------
      • Set MS_ForLoop = 0
      • -------- When true, it may choose random tracks from the folder (the one played earlier might be played :p). --------
      • Set MS_PlayingIsRandom = False
      • -------- ===== --------
      • -------- End of Configuration --------
      • -------- ===== --------
      • Sound - Clear the music list
      • Sound - Stop music Immediately

  • MS How to use
    • Events
    • Conditions
    • Actions
      • -------- ---- --------
      • -------- Just note that for these functions to run you'll need to call StartSoundtrack at least once. --------
      • -------- ---- --------
      • -------- Use this code to start your soundtrack. Most important function. --------
      • -------- The first parameter is the folder path and the second parameter is the .mp3 file prefix. --------
      • -------- So it's like this: Warcraft3Folder\MyFolderPath\MyFilePrefix-01.mp3 --------
      • Custom script: call StartSoundtrack("MyFolderPath", "MyFilePrefix")
      • -------- How to mute a player: --------
      • Set TempPlayer = Player 1 (Red)
      • -------- 0 Volume is mutation. --------
      • Custom script: call EMSSetVolume(udg_TempPlayer, 0)
      • -------- ---- --------
      • -------- You can unmute someone as well, using the line below: --------
      • Set TempPlayer = Player 1 (Red)
      • -------- 127 Is the highest volume possible, I don't know what will happen if it's greater than 127, but I'm not sure it'll work out well. --------
      • Custom script: call EMSSetVolume(udg_TempPlayer, 127)
      • -------- ---- --------
      • -------- ---- --------
      • -------- Here's how to get the number of tracks a player has: --------
      • Set TempPlayer = Player 1 (Red)
      • Custom script: set udg_DemoTrackNumber = EMSGetTrackNum(udg_TempPlayer)
      • -------- Variable Demo_TrackNumber now has the value. --------
      • -------- ---- --------
      • -------- Listen carefully to this one. --------
      • -------- This will get the number of tracks the player has "locally". The integer won't cause desyncs (dont' worry) but the results may be different for each player. --------
      • Custom script: set udg_DemoTrackNumber = EMSGetTrackNumLocal()
      • -------- Variable Demo_TrackNumber now has the value. --------
      • -------- ---- --------
      • -------- Gets the current Track playing. It's local just like GetTrackNumLocal(). --------
      • Custom script: set udg_DemoTrackNumber = EMSGetCurrentTrack()
      • -------- Variable Demo_TrackNumber now has the value. --------
JASS:
library EMS /* v.1.5 */ initializer Init /*
******************************************************************************************
*
*     EMS by Arad MNK
*
******************************************************************************************
*
*     EMS
*
*        EMS is the External Music System which is a GUI-Friendly system. You Can
*        use this system both with JASS and GUI (other things are supported too!)
*        You can control the music playing from other external folders with this system.
*
*           Notes:
*            - Changing the .mp3 files in the middle of when system is on is NOT supported.
*            - Only works with .mp3 files. .wav file formats and others are basically avoided.
*
******************************************************************************************
*/
//! novjass

//*      API

        function StartSoundtrack takes string path, string filePrefix returns nothing
//*         - Most important Function. Initializes the system with any GUI event, with the according folder and file prefix.

        function EMSSetVolume takes player p, integer vol returns nothing
//*       - Set a player's music volume to an integer.

        function EMSPlayCustomTrack takes integer track returns boolean
//*         - Play a custom track while the system is running.

        function EMSGetTrackNum takes player p returns integer
//*         - The number of tracks player p has.

        function EMSGetTrackNumLocal takes nothing returns integer
//*         - The number of tracks the player has. It's a local integer.

        function EMSGetCurrentTrack takes nothing returns integer
//*         - Current track running. Local integer.

//! endnovjass

/*
*
*
******************************************************************************************
*
*      Credits
*          Zwiebelchen - He helped me at some critical points. Also the main idea drives from him.
*
******************************************************************************************
*/

    globals
        private integer array TrackNum // Global how many tracks you have.
        private integer TrackNumLocal // Local how many tracks you have.
        private sound array Track // The sound handles of tracks.
        private integer CurrTrackNum // Current track playing number, i.e MusicFolder\Test-CurrTrackNum.mp3
        private boolean Allowed = true // Should the system run or it's not allowed?
        private string SoundtrackFilePrefix = "NULL" // These two NULLs are used in
        private string SoundtrackPath = "NULL"       //   the function Message.
        private timer SystemTimer = CreateTimer()
        private boolean FirstCall = false
    endglobals

//********************************************//
//*************/Message Function/*************//
//********************************************//
    private function Message takes string s returns nothing //Debug messages
        debug call DisplayTextToPlayer(Player(0), 0, 0, "|c00FFFF00EMS:|r " + s + "\n|c00FF0000ID:|r " + SoundtrackPath +" " + SoundtrackFilePrefix)
    endfunction

//*******************************//
//*************/API/*************//
//*******************************//

    function EMSSetVolume takes player p, integer vol returns nothing
        local integer i = 1

        if FirstCall then
            loop
                exitwhen i == TrackNum[GetPlayerId(p)] + 1
                if GetLocalPlayer() == p then
                    call SetSoundVolume(Track[i], vol)
                endif
                set i = i + 1
            endloop
        
            call Message("New Volume: " + I2S(vol))
        else
            call Message("System is not initialized for the first time yet...")
        endif
    endfunction

    function EMSPlayCustomTrack takes integer track returns boolean //The boolean means that the track exists or not
        local boolean b = track <= TrackNumLocal and FirstCall

        if b then
            set Allowed = false //Does not allow the core to detect the stopped sound and restart
            call StopSound(Track[CurrTrackNum], false, false)
            call Message("Custom Track Playing: " + I2S(track))
            set CurrTrackNum = track - 1
            call StartSound(Track[CurrTrackNum])
            set Allowed = true
        else
            call Message("Invalid Track.")
        endif

        return b
    endfunction

    function EMSGetTrackNum takes player p returns integer
        if FirstCall then
            return TrackNum[GetPlayerId(p)]
        else
            call Message("System is not initialized for the first time yet...")
            return 0
        endif
    endfunction

    function EMSGetTrackNumLocal takes nothing returns integer
        if FirstCall then
            return TrackNumLocal
        else
            call Message("System is not initialized for the first time yet...")
            return 0
        endif
    endfunction

    function EMSGetCurrentTrack takes nothing returns integer
        if FirstCall then
            return CurrTrackNum
        else
            call Message("System is not initialized for the first time yet...")
            return 0
        endif
    endfunction

//*********************************************************//
//*************/Functions used by the system./*************//
//*********************************************************//

    private function CreateTrackLocation takes integer i returns string
        local string s
        local string smsg

        if udg_MS_Use0 and i < 10 then
            set s = "0"
        else
            set s = ""
        endif

        set smsg = SoundtrackPath + "\\" + SoundtrackFilePrefix + "-" + s + I2S(i) + ".mp3"
        call Message("Track path generated: " + smsg)
        set s = null

        return smsg
    endfunction
    
    private function NumOfTracksLocal takes nothing returns integer
        local integer i = 1
        local integer i2 = 1

        loop
            exitwhen i != i2
            if GetSoundFileDuration(CreateTrackLocation(i)) > 0 then
                set i2 = i2 + 1
            endif
            set i = i + 1
        endloop

        return i2 - 1
    endfunction

    private function NumOfTracksLimitLocal takes integer limit returns integer
        local integer i = 1
        local integer i2 = 1

        loop
            exitwhen i == udg_MS_ForLoop or i != i2
            if GetSoundFileDuration(CreateTrackLocation(i)) > 0 then
                set i2 = i2 + 1
            endif
            set i = i + 1
        endloop

        return i2 - 1
    endfunction

    private function NumOfTracks takes player p returns integer
        local integer i = 1
        local integer i2 = 1

        loop
            exitwhen i != i2
            if GetLocalPlayer() == p then
            if GetSoundFileDuration(CreateTrackLocation(i)) > 0 then
                set i2 = i2 + 1
            endif
            endif
            set i = i + 1
        endloop
            return i2 - 1
    endfunction
    
    private function NumOfTracksLimit takes player p, integer limit returns integer
        local integer i = 1
        local integer i2 = 1
        loop
            exitwhen i == udg_MS_ForLoop or i != i2
            if GetLocalPlayer() == p then
            if GetSoundFileDuration(CreateTrackLocation(i)) > 0 then
                set i2 = i2 + 1
            endif
            endif
            set i = i + 1
        endloop

        return i2 - 1
    endfunction

    private function Core takes nothing returns nothing
        if not(GetSoundIsLoading(Track[CurrTrackNum]) or GetSoundIsPlaying(Track[CurrTrackNum])) and Allowed then
            call StopSound(Track[CurrTrackNum], false, false)
            if udg_MS_PlayingIsRandom then
                set CurrTrackNum = GetRandomInt(1, TrackNumLocal)
                call Message("Random Track: " + I2S(CurrTrackNum))
            else
                if CurrTrackNum != TrackNumLocal + 1 then
                    set CurrTrackNum = CurrTrackNum + 1
                elseif CurrTrackNum == TrackNumLocal + 1 then
                    set CurrTrackNum = 1 //start from beginning
                endif
            call Message("Next Track: " + I2S(CurrTrackNum))
            endif
            call StartSound(Track[CurrTrackNum])
        endif
    endfunction

    private function Init takes nothing returns nothing
        call Message("Initialized.\nDebug mode is on.")
    endfunction

//****************************************************************************//
//*************/Most Important user function, starts the system./*************//
//****************************************************************************//

    function StartSoundtrack takes string path, string filePrefix returns nothing
        local integer i = 1

        set Allowed = false
        set SoundtrackPath = path
        set SoundtrackFilePrefix = filePrefix

        if FirstCall then
            call Message("Not first call, Stopping music.")
            call Message("Track stopped: " + I2S(CurrTrackNum))
            call StopSound(Track[CurrTrackNum], false, false) //Stopping the music playing if called when a soundtrack is on

            loop
                exitwhen i == TrackNumLocal
                call KillSoundWhenDone(Track[i])
                call Message("Track destroyed. Track Number:" + I2S(i))
                set i = i + 1
            endloop
        else
            set FirstCall = true
            call Message("First call.")
        endif

        set CurrTrackNum = 1
        set i = 1
        call Message("Starting soundtrack: " + path + "\\" + filePrefix)

        if udg_MS_ForLoop == 0 then
            set TrackNumLocal = NumOfTracksLocal()
        elseif udg_MS_ForLoop > 0 then
            set TrackNumLocal = NumOfTracksLimitLocal(udg_MS_ForLoop)
        endif

        loop
            exitwhen i == TrackNumLocal
            set Track[i] = CreateSound(CreateTrackLocation(i), false, false, false, 12700, 12700, "")
            call Message("Track created. Track Number:" + I2S(i))
            set i = i + 1
        endloop

        call StartSound(Track[1])
        call TimerStart(SystemTimer, 1 / udg_MS_Timeout, true, function Core)
        set Allowed = true
    endfunction
endlibrary

Keywords:
Music, music, arad mnk, arad, mnk, m, n, k, external, system, external music, external music system, bleh, filesize, orpg, sound, mp3
Contents

EMS (Map)

Reviews
16:57, 8th Feb 2016 Tank-Commander: A small system with a lot of use - great for saving map memory space and a good edition to the section. Code looks good from where I'm sat and the API fully explains the system. Well done. Notes (for users)...
Level 2
Joined
Feb 25, 2016
Messages
20
" You don't have any selected music in your folder", I do change the path in "MS Init 1". I already created my Folder in warcraft folder and put a music in it. still it cannot detect it. Help?
 
Level 17
Joined
Dec 11, 2014
Messages
2,004
Um...
I have deleted wc3 and I no longer code. I have left hive but just smth made me look up here.

I remember the system had a bug, in which, the system couldn't play the last music (or was it the first?). Anyways, I can no longer test it (no Warcraft) but you can have a null mp3 file track in the end of it and use that as a music file, but the system won't play it. Basically you have avoided the bug.

If anyone wants to recreate/fix this system your totally open.
 
Top