1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. The poll for Hive's 12th Concept Art Contest is up! Go cast your vote for your favourite genie!
    Dismiss Notice
  5. Travel to distant realms and encounter scenes unknown to the common folk. The Greatest of Adventures is upon us with the 8th Cinematic Contest. Join in on a fun ride.
    Dismiss Notice
  6. The 18th Icon Contest is ON! Choose any ingame unit and give him/her Hero abilities. Good luck to all.
    Dismiss Notice
  7. Contestants are to create a scene set in the Stone Age. Come and see what you can come up with. We wish you the best of luck!
    Dismiss Notice
  8. Colour outside the lines! Techtree Contest #13 is a go. The contest is optionally paired.
    Dismiss Notice
  9. Greetings cerebrates, our Swarm needs new spawners that will have numerous children. Join the HIVE's 31st Modeling Contest - Spawners and Spawned! The contest is optionally paired.
    Dismiss Notice
  10. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

External Music System V.1.5

Submitted by Arad MNK
This bundle is marked as approved. It works and satisfies the submission rules.
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.

Triggers and Scripts
MS Configuration
  • 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
  • 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. --------

MS System
Code (vJASS):
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
Moderator
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):...
  1. 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): using it does somewhat make dling from the maps section (with links to tracks for maps) rather necessary (dling a map through bnet won't give the appropriate track)
     
  2. Arad MNK

    Arad MNK

    Joined:
    Dec 11, 2014
    Messages:
    1,889
    Resources:
    3
    Maps:
    2
    Spells:
    1
    Resources:
    3
    Alright I haven't tested this for desyncs but it shouldn't afais.
     
  3. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,741
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Zwiebelchen is the master when it comes to sound handles in wc3.
    Maybe you're lucky and he drops a comment here.
     
  4. Arad MNK

    Arad MNK

    Joined:
    Dec 11, 2014
    Messages:
    1,889
    Resources:
    3
    Maps:
    2
    Spells:
    1
    Resources:
    3
    Actually, the main idea came from him ;)
    He told us that Warcraft III reads folders like .mpq archives and therefore finding a music in the .mpq archive is the same as finding a music in a custom folder!
     
  5. xYours Trulyx

    xYours Trulyx

    Joined:
    Jan 9, 2016
    Messages:
    852
    Resources:
    0
    Resources:
    0
    Nice memory-releasing trigger.I laugh horribly when I see the 'bleh' in your keywords.+rep

    (PS,love your avatar)
     
  6. Arad MNK

    Arad MNK

    Joined:
    Dec 11, 2014
    Messages:
    1,889
    Resources:
    3
    Maps:
    2
    Spells:
    1
    Resources:
    3
    Haha, thanks.
    Aw, so you reached this by typing in "Bleh"? The reason it is in there is to attract bored people who type in "Bleh"!

    Oh, it's Zed from League of Legends. You can get the GIF avatar(s!) from leagueoflegends.com.
     
  7. xYours Trulyx

    xYours Trulyx

    Joined:
    Jan 9, 2016
    Messages:
    852
    Resources:
    0
    Resources:
    0
    Let us hope that this will be approved.

    (PS,I doubt that there's more of those LOL GIF avatars since there's only four;which is Garen,Sona,Vi and Zed(which is you))
     
  8. Arad MNK

    Arad MNK

    Joined:
    Dec 11, 2014
    Messages:
    1,889
    Resources:
    3
    Maps:
    2
    Spells:
    1
    Resources:
    3
    Let us hope :)

    Oh all those 4 are on the Hive right now (Zed: Me, Vi: ~Nightmare, Sona: Apheraz, Garen: userid907).

    EDIT: There's something wrong with the system. Some weird mistakes (thread crashes!!) by me. Don't review this while I fix them! Done. Ready.
    EDIT 2: Another shameful update. Removed
    BJDebugMsg("hh")
    !!
     
    Last edited: Jan 13, 2016
  9. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,334
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    Made a quick look in the system,
    • Why not use a timer instead of
      call TriggerRegisterTimerEvent(EMS_Trig, (1 / udg_MS_Timeout), true)
      . Read more about
      TimerStart
    • Why not use
      initializer
      so you don't have to force users to
      call InitEMS()
      ?
    • Try adding a check in your loop for picking all players like
      PLAYER_SLOT_STATE_PLAYING
      and
      MAP_CONTROL_USER
    • You could store
      (1 / udg_MS_Timeout)
      to a variable to avoid re-calculating them every loop.
    • Why are you not indenting your
      local
      variables?
    • Feel free to use the
      and
      boolean operator instead of putting two
      if ... endif
      . You also might wanna use
      elseif
      for more readability so you don't have to indent again.
    • Do you really have to put a "by Arad MNK" in the name?
     
  10. Arad MNK

    Arad MNK

    Joined:
    Dec 11, 2014
    Messages:
    1,889
    Resources:
    3
    Maps:
    2
    Spells:
    1
    Resources:
    3
    • Timers are going to be removed in the system, they stop when a player pauses the game, fucking the timing. I'll just use a periodic timer, and figure it out.
      And I'm the master of
      TimerStart
      already, used it in my cinematic system for my Cinematic 1000 times.
    • This is going to be GUI friendly, so that the user would use it with any GUI event.
    • Well, I gotta check for all AVAILABLE people in all slots... meh. Will do it by forces.
    • OK. Will try. (In the new system it no longer exists 2 times)
    • Why should I? the readability is still fine.
    • If you're talking about the GetLocalPlayer() part then I'm not sure if it will still localize.
    • Sure. Will remove it.

    Thanks for viewing this!
     
  11. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,334
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    - I mean using TimerStart instead of creating a trigger with a periodic timer event.
    - I don't see a disadvantage of using
    initializer
    . It prevents users from manually calling InitEMS.
    - I mean just adding a condition in the beginning of the loop so it won't execute on empty slots or computer players.
    - Ok if you're comfortable with that indention scheme. It was merely a suggestion because it's best to have uniform coding style. Read more here
    - I think it will work fine with
    and
    though I'm not 100% sure.
     
  12. LordDz

    LordDz

    Joined:
    May 11, 2007
    Messages:
    4,308
    Resources:
    0
    Resources:
    0
    Can you add an option to add specific songs from inside the map, to play?
     
  13. Arad MNK

    Arad MNK

    Joined:
    Dec 11, 2014
    Messages:
    1,889
    Resources:
    3
    Maps:
    2
    Spells:
    1
    Resources:
    3
    Good idea Lord. Though you can use the specific song in the folder itself but I'll consider that.
     
  14. HaaG

    HaaG

    Joined:
    Jul 2, 2013
    Messages:
    110
    Resources:
    0
    Resources:
    0
    Dude, It doesn't work for me. :( I edited the folder name and set random = true, prefix = false.
     
  15. Arad MNK

    Arad MNK

    Joined:
    Dec 11, 2014
    Messages:
    1,889
    Resources:
    3
    Maps:
    2
    Spells:
    1
    Resources:
    3
    Well I will take a look into it. Thank you!
     
  16. Skyflash

    Skyflash

    Joined:
    Mar 6, 2015
    Messages:
    129
    Resources:
    0
    Resources:
    0
    Nice idea alas it`s Vjass it would be great if it was in GUI
     
  17. Arad MNK

    Arad MNK

    Joined:
    Dec 11, 2014
    Messages:
    1,889
    Resources:
    3
    Maps:
    2
    Spells:
    1
    Resources:
    3
    You control the system via GUI (aka it's GUI friendly) although it can be used in JASS and vJASS too.
     
  18. ExotiK

    ExotiK

    Joined:
    Jan 16, 2016
    Messages:
    103
    Resources:
    0
    Resources:
    0
    Can i use this Arad?

    Nice system btw
     
  19. Arad MNK

    Arad MNK

    Joined:
    Dec 11, 2014
    Messages:
    1,889
    Resources:
    3
    Maps:
    2
    Spells:
    1
    Resources:
    3
    This system is open for public. Like, even people not registered on hive.

    Although this system currently uses timers, that is inaccurate when somebody pauses the game. Maybe the next update removes this issue.

    EDIT:

    Tune up for the next update as IT'S COMING SOON!!!
     
    Last edited: Feb 3, 2016