I assume it works like this:
There is a limited number of simultaneous sounds - platform dependent.
But you can "load" a large number of sounds. When you play a sound it occupies a "slot" in the limited array of available actual sounds. This is the instance - an index into the limited array.
Big pool of sounds: [1..339] of whatever.
Dynamic slots: [1..32] perhaps?
PlaySound(231) looks for an empty slot in the dynamic slots, starts the sound in that slot and returns the slot index (the instance). Suppose there are sounds in slots 1 and 2:
[1] Bang1.wav playing
[2] Zap44.wav playing
[3] <Empty>
PlaySound(231) returns 3. Operations like SetSoundInstanceRate() use the index 3 to manipulate that playing sound. That's NOT the same as the ID of the sound loaded into memory but not played.
Unless the sound is looped, when it reaches its end slot 3 becomes empty again. So LoadSound() return a static number - whereas PlaySound() returns a dynamic number. There are methods to check if an instance is playing before bending it, or whatever you want to do.
Maybe Paul can confirm that this is the case.
<<It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration.>> Dijkstra