• 🏆 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!

[GUI-friendly] Rapid Sound v1.91

This bundle is marked as awaiting update. A staff member has requested changes to it before it can be approved.
This is a (GUI-Friendly) version of [vJASS] - [Snippet] RapidSound

Updated! v1.91
  • renamed variables and function
I would highly-recommend you to download the map and read the easy-guide in it.

JASS:
//  =========================================================================================
//                           [GUI-Friendly] Rapid Sound v1.91
//
//  ~by Reventhous
//    http://www.hiveworkshop.com/threads/gui-friendly-rapid-sound.289576/
//
//  ~originally by Quilnez
//    http://www.hiveworkshop.com/threads/snippet-rapidsound.258991/
//
//  =========================================================================================
//  -----------------------------------------------------------------------------------------
//  -WHAT IS THIS?
//
//  A system that allows you to play sounds rapidly and flawlessly without limit.
//  Supports both .mp3 and .wav file
//  Remember! One sound file for one instance
//  -----------------------------------------------------------------------------------------
//  -----------------------------------------------------------------------------------------
//
//  -HOW TO IMPORT
//     1. Go to File [tab] > Preferences. Make sure "Automatically create unknwon variables...
//        is ticked.
//     2. Copy the "Rapid Sound" category with "GUI RapidSound" and "gRSound VarGen" triggers in it.
//     3. Paste it to your map.
//     4. Done.
//  -----------------------------------------------------------------------------------------
//
//  =========================================================================================

//  -----------------------------------------------------------------------------------------
//  Configurations
//

// facing problem?, turn this to true to see helpful messages
constant function GRS_IS_DEBUG_MODE takes nothing returns boolean
    return false
endfunction

// auto create RapidSound. Highly recommended to set it true
constant function GRS_AUTO_CREATE takes nothing returns boolean
    return true
endfunction

// auto preload sound, create RapidSound instance on map initialization and the system will
// automatically preload the sound.
constant function GRS_AUTO_PRELOAD takes nothing returns boolean
    return true
endfunction

//
//  End of configurations
//  -----------------------------------------------------------------------------------------

//  =========================================================================================
//  anything you do below this line is at your own risk
//  =========================================================================================
constant function GRS_MIN_DELAY_FACTOR takes nothing returns real
    return 4.00
endfunction

constant function GRS_MAX_COUNT takes nothing returns integer
    return 4
endfunction

//  -----------------------------------------------------------------------------------------
//  This function destroys/recycle stack
//  -----------------------------------------------------------------------------------------
function GRS_Stack_Destroy takes integer this returns nothing
    local integer last = udg_GRS_Stack_First[this]
    loop
        exitwhen udg_GRS_Stack_Next[last] == 0
        set last = udg_GRS_Stack_Next[last]
    endloop
 
    // recycle set of nodes
    set udg_GRS_Stack_Next[last] = udg_GRS_Stack_Next[0]
    set udg_GRS_Stack_Next[0] = udg_GRS_Stack_First[this]
 
    // recycle head
    set udg_GRS_Stack_Recycle[this] = udg_GRS_Stack_Recycle[0]
    set udg_GRS_Stack_Recycle[0] = this
endfunction

//  -----------------------------------------------------------------------------------------
//  Push/Add a instance to the stack
//  -----------------------------------------------------------------------------------------
function GRS_Stack_Push takes integer this returns integer
    local integer node
    if (udg_GRS_Stack_Next[0] == 0) then
        set udg_GRS_Stack_NodeCount = udg_GRS_Stack_NodeCount + 1
        set node = udg_GRS_Stack_NodeCount
    else
        set node = udg_GRS_Stack_Next[0]
        set udg_GRS_Stack_Next[0] = udg_GRS_Stack_Next[node]
    endif
 
    set udg_GRS_Stack_Next[node] = udg_GRS_Stack_First[this]
    set udg_GRS_Stack_First[this] = node
 
    return node
endfunction

//  -----------------------------------------------------------------------------------------
//  This function creates stack for sound
//  -----------------------------------------------------------------------------------------
function GRS_Stack_Create takes nothing returns integer
    local integer this
    if (udg_GRS_Stack_Recycle[0] == 0) then
        set udg_GRS_Stack_InstanceCount = udg_GRS_Stack_InstanceCount + 1
        set this = udg_GRS_Stack_InstanceCount
    else
        set this = udg_GRS_Stack_Recycle[0]
        set udg_GRS_Stack_Recycle[0] = udg_GRS_Stack_Recycle[this]
        set udg_GRS_Stack_First[this] = 0
    endif
    return this
endfunction

//  -----------------------------------------------------------------------------------------
//  This function gives the duration of a sound
//  -----------------------------------------------------------------------------------------
function GRS_GetDuration takes integer this returns real
    return udg_GRS_Duration_p[this]*GRS_MIN_DELAY_FACTOR()
endfunction

//  -----------------------------------------------------------------------------------------
//  This function will recycle the instance and the queue
//  -----------------------------------------------------------------------------------------
function GRS_Kill takes integer this returns nothing
    local integer i = 0
    local integer dex
 
    loop
        exitwhen i == GRS_MAX_COUNT()
        set dex = udg_GRS_First_p[this] + i
     
        call StopSound(udg_GRS_Sound_p[dex], true, false)
        call DestroyTimer(udg_GRS_Timer_p[dex])
        set udg_GRS_Sound_p[dex] = null
        set udg_GRS_Timer_p[dex] = null
     
        // recycle queue
        set udg_GRS_Recycle_p[dex] = udg_GRS_Recycle_p[0]
        set udg_GRS_Recycle_p[0] = dex
     
        set i = i + 1
    endloop
    call GRS_Stack_Destroy(this)
endfunction      

//  -----------------------------------------------------------------------------------------
//  This function stops each sound in RapidSound
//  -----------------------------------------------------------------------------------------
function GRS_Stop takes integer this, boolean fadeOut returns nothing
    local integer i = 0

    loop
        exitwhen i == GRS_MAX_COUNT()
        call StopSound(udg_GRS_Sound_p[udg_GRS_List_p[udg_GRS_First_p[this] + i]], false, fadeOut)
        set i = i + 1
    endloop
endfunction

//  -----------------------------------------------------------------------------------------
//  This function plays the sound
//  -----------------------------------------------------------------------------------------
function GRS_Play takes integer this, real x, real y, real z, integer volume returns nothing
    // the sound cycle
    if (udg_GRS_Array_p[this] == (udg_GRS_First_p[this]) + GRS_MAX_COUNT()) then
        set udg_GRS_Array_p[this] = udg_GRS_First_p[this]
    endif

    if TimerGetRemaining(udg_GRS_Timer_p[udg_GRS_List_p[udg_GRS_Array_p[this]]]) == 0 then
 
        call StopSound(udg_GRS_Sound_p[udg_GRS_List_p[udg_GRS_Array_p[this]]], false, false)
        call SetSoundPosition(udg_GRS_Sound_p[udg_GRS_List_p[udg_GRS_Array_p[this]]], x, y, z)
        call SetSoundVolume(udg_GRS_Sound_p[udg_GRS_List_p[udg_GRS_Array_p[this]]], volume)
        call StartSound(udg_GRS_Sound_p[udg_GRS_List_p[udg_GRS_Array_p[this]]])
        call TimerStart(udg_GRS_Timer_p[udg_GRS_List_p[udg_GRS_Array_p[this]]], udg_GRS_Duration_p[this], false, null)
    endif
 
    set udg_GRS_Array_p[this] = udg_GRS_Array_p[this] + 1
endfunction

//  -----------------------------------------------------------------------------------------
//  This function creates RapidSound instance
//  -----------------------------------------------------------------------------------------
function GRS_Create takes string fileName, boolean is3D, boolean autoStop, integer inRate, integer outRate returns integer
    local integer this
    local integer i = 1
    local integer s
    local integer q

    set this = GRS_Stack_Create()
    set udg_GRS_SoundName_p[this] = fileName
    set udg_GRS_Duration_p[this] = I2R(GetSoundFileDuration(fileName))/(1000.*GRS_MIN_DELAY_FACTOR())

    loop
        exitwhen i > GRS_MAX_COUNT()
        set s = GRS_Stack_Push(this)
             
        if udg_GRS_Recycle_p[0] == 0 then
            set udg_GRS_Queue_p = udg_GRS_Queue_p + 1
            set q = udg_GRS_Queue_p
        else
            set q = udg_GRS_Recycle_p[0]
            set udg_GRS_Recycle_p[0] = udg_GRS_Recycle_p[q]
        endif
     
        set udg_GRS_List_p[q] = s

        if i == 1 then
            set udg_GRS_First_p[this] = q
        endif

        set udg_GRS_Sound_p[s] = CreateSound(fileName, false, is3D, autoStop, inRate, outRate, "")
        set udg_GRS_Timer_p[s] = CreateTimer()
        set i = i + 1
    endloop
    set udg_GRS_Array_p[this] = udg_GRS_First_p[this]
 
    call SaveInteger(udg_GRS_Hash_p, StringHash(fileName), 0, this)
 
    return this
endfunction

// sound preloading, By Silvenon
function PreloadSoundPath takes string path returns nothing
    local sound snd = CreateSound(path, false, false, false, 10, 10, "")
    call SetSoundVolume(snd, 0)
    call StartSound(snd)
    call KillSoundWhenDone(snd)
    set snd = null
endfunction

// will tell if the sound file name is valid or not      >> I couldn't find any of this function anywhere, so...
// by Reventhous
function IsSoundFileNameValid takes string fileName returns boolean
    local sound snd = CreateSound(fileName, false, false, false, 10, 10, "")
    local boolean b = (GetSoundDuration(snd) > 0.00)
    call StopSound(snd, true, false)
    set snd = null
    return b
endfunction

function GRS_AutoSoundPreload takes string fileName returns nothing
    if not LoadBoolean(udg_GRS_Hash_p, StringHash(fileName), 0) then
        call PreloadSoundPath(fileName)
        call SaveBoolean(udg_GRS_Hash_p, StringHash(fileName), 0, true)
    endif
endfunction

// will search RapidSound instance by string
function GRS_Get takes string fileName returns integer
    return LoadInteger(udg_GRS_Hash_p, StringHash(fileName), 0)
endfunction

// will reset the gRSParam variable to its default
function GRS_ResetParameters takes nothing returns nothing
    set udg_GRS_autoStop = false
    set udg_GRS_fadeOut = false
    set udg_GRS_fileName = ""
    set udg_GRS_inRate = 0
    set udg_GRS_is3D = false
    set udg_GRS_outRate = 0
    set udg_GRS_State = 0
    set udg_GRS_Volume = 127
    set udg_GRS_X = 0.
    set udg_GRS_Y = 0.
    set udg_GRS_Z = 0.
endfunction

//  -----------------------------------------------------------------------------------------
//  The actions and the initializaion
//  -----------------------------------------------------------------------------------------
function GRS_Actions takes nothing returns nothing
    local integer i
 
    // prevent the system works for nothing
    if (udg_GRS_State < 1) or (udg_GRS_State > 6) then
        if GRS_IS_DEBUG_MODE() then
            call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 30, "|CFFFFCC00[GRapid Sound]|R: " + "Using undefined GRS_State" )
        endif
     
        call GRS_ResetParameters()
        return
    endif
 
    // reject invalid sound file name
    if not IsSoundFileNameValid(udg_GRS_fileName) then
        if GRS_IS_DEBUG_MODE() then
            call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 30, "|CFFFFCC00[GRapid Sound]|R: " + "invalid sound file name!" )
        endif
     
        call GRS_ResetParameters()
        return
    endif
 
    if GRS_AUTO_PRELOAD() then
        call GRS_AutoSoundPreload(udg_GRS_fileName)
    endif
 
    // create
    if (udg_GRS_State == udg_GRS_Create) then
        set udg_GRS_LastCreatedRSound = GRS_Create(udg_GRS_fileName, udg_GRS_is3D, udg_GRS_autoStop, udg_GRS_inRate, udg_GRS_outRate)
     
        call GRS_ResetParameters()
        return      
    endif
 
    // find RapidSound instance by string
    set i = GRS_Get(udg_GRS_fileName)
 
    // if not found,
    if (i == 0) then          
        // automatically create a new instance for the sound.
        if GRS_AUTO_CREATE() then
            set i = GRS_Create(udg_GRS_fileName, udg_GRS_is3D, udg_GRS_autoStop, udg_GRS_inRate, udg_GRS_outRate)
        else
            call GRS_ResetParameters()
            return
        endif
    endif
 
    // play
    if (udg_GRS_State == udg_GRS_Play) then
        call GRS_Play(i, udg_GRS_X, udg_GRS_Y, udg_GRS_Z, udg_GRS_Volume)
     
    // stop
    elseif (udg_GRS_State == udg_GRS_Stop) then
        call GRS_Stop(i, udg_GRS_fadeOut)
     
    // kill
    elseif (udg_GRS_State == udg_GRS_Kill) then
        call GRS_Kill(i)
     
    // get sound duration by RapidSound instance
    elseif (udg_GRS_State == udg_GRS_GetDuration) then
        set udg_GRS_SoundDuration = GRS_GetDuration(i)
     
    // preload
    elseif (udg_GRS_State == udg_GRS_Preload) then
        call PreloadSoundPath(udg_GRS_fileName)
 
    endif
 
    // reset gRSParam variables to its default
    call GRS_ResetParameters()
endfunction

function InitTrig_GUI_RapidSound takes nothing returns nothing  
    // hashtable for instance searching
    set udg_GRS_Hash_p = InitHashtable()
 
    // the state id
    set udg_GRS_Create = 1
    set udg_GRS_Play = 2
    set udg_GRS_Stop = 3
    set udg_GRS_Kill = 4
    set udg_GRS_GetDuration = 5
    set udg_GRS_Preload = 6
 
    set gg_trg_GUI_RapidSound = CreateTrigger()
    call TriggerAddAction( gg_trg_GUI_RapidSound, function GRS_Actions )
endfunction


v1.0
  • first release
v1.1
  • added guide for GUI user
  • added the feature to play sound by using the sound file name
v1.7
  • added debug mode
  • added sound preload method
  • added auto create feature
  • added auto preload feature
  • removed integer as system reference, replaced with string
  • removed loop to search instance, replaced with hashtable
  • the system now rejects invalid sound file
  • reconstructed the gRS_Actions function code
  • fixed some minor bug
v1.9
  • renamed variables and function
  • added guide
  • fixed some code
v1.91
  • renamed variables and function
Contents

Rapid Sound [GUI-Friendly] (Map)

Reviews
IcemanBo
Description is probably outdated?
Level 10
Joined
Aug 21, 2010
Messages
316
I expect that this is pure gui version.
This is not a gui version.
This is normal jass version.
Well, does not require jngp and it's ok but everything else is pretty much the same.
The only difference is shitty UDG.
Well, not really the only difference but generally, this is it.
 
Last edited:
Level 5
Joined
May 2, 2015
Messages
109
I have to use JASS as long as this system handles sound and I think JASS is better when creating a system for GUI user.
This system may not a GUI, but it supports GUI (GUI-friendly)

EDIT: If you really want a pure GUI system, just give me one or two system and I will try to convert it. (vJass > GUI)
 
Last edited:
Level 10
Joined
Aug 21, 2010
Messages
316
I have to use JASS as long as this system handles sound and I think JASS is better when creating a system for GUI user.
This system may not a GUI, but it supports GUI (GUI-friendly)

EDIT: If you really want a pure GUI system, just give me one or two system and I will try to convert it. (vJass > GUI)
I do not need a GUI system.
I'm just saying that this is not a gui
GUI and GUI-friendly are not the same
 
It should include a little guide only for GUI users /it's variables.

For example I was pretty confused about the meaning of "Set gRSParam_Which" until I looked it up inside the code.
By the way "_Which" allown is not a well chosen name for it's purpose. I suggest to choose something like "State" or "Flag", or ... you got the idea. But not simple "which" to define method of an operation.

The user has to keep track of the sounds by himself at the moment which isn't really flexible and can be bothering to destinguish in GUI if one have lots of sounds.
I believe the system would be able to take take some workload from this aspect. The idea is that you internaly store the created sounds and bind them to the sound name (string).
Then when the user wants to play the sound:

Init:
  • Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set HolyBoltPath = test\HolyBolt.wav
      • ....
      • ....
And on use:
  • Set gRSParam_fileName = HolyBoltPath
  • Set gRSParam_Which = gRS_Play
  • ...
  • Trigger - Run GUI RapidSound <gen> (ignoring conditions)
The other way, the user has needs to keep track of an un-intuitive counter by himself, like in the demo example:

  • Actions
    • Set gRSParam_RapidSound = rp[1]
    • Set gRSParam_Which = gRS_Play
    • ....
    • Trigger - Run GUI RapidSound <gen> (ignoring conditions)
I believe the first one is a bit more clear and easier to follow for GUI users.
 
Level 5
Joined
May 2, 2015
Messages
109
It should include a little guide only for GUI users /it's variables.
Ow! I forgot:p. Thanks for reminding me
I'll update ASAP

The user has to keep track of the sounds by himself at the moment which isn't really flexible and can be bothering to destinguish in GUI if one have lots of sounds.
I believe the system would be able to take take some workload from this aspect. The idea is that you internaly store the created sounds and bind them to the sound name (string).
Then when the user wants to play the sound:

Init:
  • base.gif
    Init
    • joinminus.gif
      events.gif
      Events
      • line.gif
        joinbottom.gif
        folder.gif
        Map initialization
    • join.gif
      cond.gif
      Conditions
    • joinbottomminus.gif
      actions.gif
      Actions
      • empty.gif
        join.gif
        set.gif
        Set HolyBoltPath = test\HolyBolt.wav
      • empty.gif
        join.gif
        if.gif
        ....
      • empty.gif
        joinbottom.gif
        if.gif
        ....


And on use:
  • set.gif
    Set gRSParam_fileName = HolyBoltPath
  • set.gif
    Set gRSParam_Which = gRS_Play
  • if.gif
    ...
  • page.gif
    Trigger - Run GUI RapidSound <gen> (ignoring conditions)
So, I have to use loop to get the instance, right?
 
Level 5
Joined
May 2, 2015
Messages
109
Why? It's a good idea. I've updated the system

Updated! v1.1
  • added guide for GUI user
  • added the feature to play sound by using the sound file name
Next update v1.5
  • the system automatically create RapidSound when user want to play a sound that is still not registered.
  • will add the feature to create RapidSound with various kind of sound (4-16 sound max).
  • will add sound preloading feature
  • will add debugging option
 
Last edited:
Level 10
Joined
Aug 21, 2010
Messages
316
Perhaps it would be better if the changelog found in the description and not in the comments.
In this case, would be located at the top of the page and not somewhere at the bottom.
How anyone could possibly know if you update something.Many users do not read all the comments.
 
Last edited:
The auto-create on first use with unknown string can be handy.

Why I meant this:
Forget my idea with the strings.
... is because my example didn't make much sense. When the user bothers to create a string variable for each sound, he also can bother to create an integer variable (with same descriptive name) for each sound which will be the sound instance/index.
 
Level 5
Joined
May 2, 2015
Messages
109
Why I meant this:
... is because my example didn't make much sense. When the user bothers to create a string variable for each sound, he also can bother to create an integer variable (with same descriptive name) for each sound which will be the sound instance/index.

No no, users don't have to do that to make things happen.

In this version (v1.1), the user can either store the created RSound instance (for maximum performance) into integer variable or just use the sound path to play the sound (uses loop to find the instance, slow).
In the demo/guide I given in the description, I stored the sound path into variable to make the code looks clean.
 
Last edited:
Level 38
Joined
Feb 27, 2007
Messages
4,951
I'm unsure how to stress test this in a way that the performance difference between using the integer reference vs. string (requiring loop lookup) would be readily apparent. I don't really see anything glaringly wrong with this. Add in creating the sound on unknown string and I would approve it (but I'm just a spell reviewer so take that as you will).
 
Level 5
Joined
May 2, 2015
Messages
109
Actually, I decided to replace the loop with hashtable in the next update.

But if you want to see the performance difference, create thousands of RapidSound instance and test using both method (integer, string), you'll see. When using string, the system will search any instance that match with the string. If 5000 instance exist, the system will loop 5000 time.

Add in creating the sound on unknown string and I would approve it (but I'm just a spell reviewer so take that as you will).

You mean, auto creating. Already on my next update list

EDIT: I've been thinking (hardly), how to make system rejects invalid sound path when creating or playing?
 
Last edited:
But if you want to see the performance difference, create thousands of RapidSound instance and test using both method (integer, string), you'll see. When using string, the system will search any instance that match with the string. If 5000 instance exist, the system will loop 5000 time.
Could you elaborate what you mean by example?
 
Level 5
Joined
May 2, 2015
Messages
109
From the system code,

JASS:
function RSStack_Create takes nothing returns integer
    local integer this
    if (udg_gRSStack_Recycle[0] == 0) then
        set udg_gRSStack_InstanceCount = udg_gRSStack_InstanceCount + 1
        set this = udg_gRSStack_InstanceCount
    else
        set this = udg_gRSStack_Recycle[0]
        set udg_gRSStack_Recycle[0] = udg_gRSStack_Recycle[this]
        set udg_gRSStack_First[this] = 0
    endif
    return this
endfunction
this is the function that I used to create the RapidSound instance.
From what you see, everytime I use this function, the udg_gRSStack_InstanceCount will increase by +1

JASS:
function gRS_GetRapidSound takes string fileName returns integer
    local integer i = udg_gRSStack_InstanceCount
    loop
        exitwhen udg_gRS_SoundName[i] == fileName or i == 0
        set i = i - 1
    endloop
    return i
endfunction
this is the function that I used to find RapidSound instance by string.

Let say the current udg_gRSStack_InstanceCount is 5000. The function will work like this
JASS:
function gRS_GetRapidSound takes string fileName returns integer
    local integer i = 5000
    //loops until finished decreasing 5000 to 0 or when it found matching instance
    loop
        exitwhen udg_gRS_SoundName[i] == fileName or i == 0
        set i = i - 1
    endloop
    return i
endfunction
If the matching instance/index is 1, can you imagine. The system will loop 4999x(how many times the user play the sound)

EDIT: I've been thinking (hardly), how to make system rejects invalid sound path when creating or playing?
Any answer?
 
Last edited:
Level 5
Joined
May 2, 2015
Messages
109
Actually, I decided to replace the loop with hashtable in the next update.
I already said that :)
Also, in the next update, users don't have to store RapidSound instance anymore. Only use sound file path as system reference.

EDIT:
Any answer?
Solved!

Updated! v1.7
  • added debug mode
  • added sound preload method
  • added auto create feature
  • added auto preload feature
  • removed integer as system reference, replaced with string
  • removed loop to search instance, replaced with hashtable
  • the system now rejects invalid sound file
  • reconstructed the
    gRS_Actions
    function code
  • fixed some minor bug
 
Last edited:
"GRS_Param_State"
^We would accept it, yes.
For me personaly it's not perfect, and I would just call it "GRS_State".
If you have the same variable used privatly by the system I would do following to avoid collision. "GRS_State_p" or so (for internal variable), so it just indicates the "private" with "p" for you.
But that's just style, you may go swim your own way through the ocean.

I'll update
Wanted to update something else, or only because of the naming?

I'm unsure why a API is listed, as the functions are not wrapped into a library.
Your call, but I personaly would just require JassHelper to use vjass, but still make it GUI-useable, so all have benefits, and JNGP is anyways a must have for map makers.

JASS:
function StopRapidSound takes integer this, boolean fadeOut returns nothing
    local integer i

    loop
        exitwhen i == MAX_COUNT()
        call StopSound(udg_gRS_Sound[udg_gRS_List[udg_gRS_First[this] + i]], false, fadeOut)
        set i = i + 1
    endloop
endfunction
^i isn't initialisized, and would crash the running thread.

Can't test it right now, but else all looks good for me. I would approve if mentioned things are changed, and you become happy with the namings and such.
Just check everything again and if you're happy we can go. :}
 
Ok, so as you didn't decide to put it into a library some names need to changed.

"constant function MAX_COUNT takes nothing returns integer"

^that's too generic, and might come in conflict. Please use your system prefix for all names.
Next update v2.0
  • add vJass version
There already exists vjass version. Maybe you want to suggest something at Quilnez thread if it's not good enough.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
I thought it's very obvious, unless you don't even understand how it works.

0. Initial state
sound 1 | sound 2 | sound 3 | sound 4

1. call play function => dequeue and enqueue sound 1
sound 2 | sound 3 | sound 4 | sound 1

2. call play function again => dequeue and enqueue sound 2
sound 3 | sound 4 | sound 1 | sound 2

and so on.. If a sound is about to be dequeued and it's still playing, stop it first then replay.
That's the sole reason why it sounds like the sound is played rapidly (more than 4 handles at once).

If you are using stack then:

0. Same initial state
sound 1 | sound 2 | sound 3 | sound 4

1. call play function => pop and push sound 1
(after pop) sound 2 | sound 3 | sound 4
(after push) sound 1 | sound 2 | sound 3 | sound 4 => back to initial state again thus the rapid playing effect isn't achieved because you are only playing 1 sound handle all the time.

and so on.
 
Level 5
Joined
May 2, 2015
Messages
109
I thought it's very obvious, unless you don't even understand how it works.

0. Initial state
sound 1 | sound 2 | sound 3 | sound 4

1. call play function => dequeue and enqueue sound 1
sound 2 | sound 3 | sound 4 | sound 1

2. call play function again => dequeue and enqueue sound 2
sound 3 | sound 4 | sound 1 | sound 2

and so on.. If a sound is about to be dequeued and it's still playing, stop it first then replay.
That's the sole reason why it sounds like the sound is played rapidly (more than 4 handles at once).
This system works just like you say.

In this system, 4 sound will be created for each sound file name and each one of them have their own index. (from 1 to 8190)
So, the max Rapid Sound instance is 8190/4. I use stack to group the sounds. For example,


User create a Rapid Sound (RS) > user get 5 as index for the created RS.

sound 1 [41] | sound 2 [42] | sound 3 [43] | sound 4 [44] created. 41,42,43,44 (the sound index)

The system store 41 into a variable to define the first sound instance of the RS[5].
When user want to play it, the system will take the first instance (sound 1 [41]) from the stack and play it. When user "call play" again,
the system will take the next instance (sound 2 [42]). When all the 4 sound has been played, the system will go back to the first instance and just like you said, the system stops the sounds before replay.

1. call play function => pop and push sound 1
(after pop) sound 2 | sound 3 | sound 4
(after push) sound 1 | sound 2 | sound 3 | sound 4 => back to initial state again thus the rapid playing effect isn't achieved because you are only playing 1 sound handle all the time.
Please download the test map and rapidly press Esc when you test it.
 
Last edited:
Top