In the end, your sounds must be streamlined as one flux of bytes to the DSP device. Check how it works in linux, you get
/dev/dsp which is a link to
/dev/dsp0 (but its a detail) and it accepts only ONE process to open one descriptor on it, and you stream your flux to it and it gets played on the speakers provided your driver is working.
The driver will copy chunks of the buffered data in the
dsp file into the sound card device onboard memory which is itself playd-back by the actual dsp processor, and output to the cards
DAC (digital to analog converter), then to operational amplifiers, then to jack output.
The way for multiple process to play sounds together, is to go throug a
mixer. The mixer is a virtual device which works in software, and accepts multiple streams, these streams are additionned and result in one unique stream, that is then output to
Windows and Mac have mixers set by default as well.
When a game is outputting multiple sounds, it better do its own mixing, which libraries will provice. like SDL_mixer. Or fmod, or OpenAL. You are not obligated to use those but I strongly recommended it !
Then it is quite easy, the library will take sound files as input, give them to decompress to the appropriate sub-library (libvorbis, libffmpeg...) and buffer or streams the sound according to heuristics based on the file size. Then the library will use threads internally to make sure the mixer buffer is always filled by the currently played sound samples.
A typicall buffer is 2048 of size, which at 44kHz stereo sampling will give you 23 mili-seconds, this is just enough to get re-scheduled by the OS in time.
Every serious OS on this planet will have a "multimedia scheduler", which is a heuristical weight atribution for threads that have a connection opened with the DSP device. This helps getting rescheduled faster, which in turns helps into preventing the mixer buffer to become empty. This would results in cracks in the sound, which is ugly and scary.
If you do not want to use a library for sound playing, then you need to make the sample mixer yourself and this is no play in the park. You need to keep pointers to the last sampled played in each of your currently playing sounds, you need to keep a state machine for each sample, that will remember its configuration. Like infinite loop, or "just 2 loops please", this is set by the client of your sound library. You need to make it thread safe, and also care about memory usage if all your sounds need to be in memory. If its impossible you need to do a cache prefetcher system that streams on demand. Also reading esoteric formats like mp3 will be tough unless you use a library.
Final point with the GPU. this would be a bad idea, because GPU uses loose floating point operation precisions and you will get losses in your sound. Also you need to move samples into texture memory and particuarly bad : do a lot of read-backs from the render targets to get the result of your mixing. This would be done easily using microsoft
AMP or nvidia
boost compute. Because the operation is a simple
However, be please mind the latency, in general you want your sounds to react very fast, 20ms is a long delay for profesionals. (look up
ASIO drivers) using the GPU you are contemplating at 3 frame delays usually, so 48ms... keep in on CPU. srsly.