static void I_SDLUpdateSound(void *userdata, Uint8 *stream, int len) { // Mix current sound data. // Data, from raw sound, for right and left. Uint8 sample; Sint32 dl; Sint32 dr; // Pointers in audio stream, left, right, end. Sint16 *leftout, *rightout, *leftend; // haleyjd: channel pointer for speed++ channel_info_t *chan; // Determine end, for left channel only // (right channel is implicit). leftend = leftout + len / STEP; // Love thy L2 cache - made this a loop. // Now more channels could be set at compile time // as well. Thus loop those channels. for(chan = channelinfo; chan != &channelinfo[MAX_CHANNELS]; ++chan) { // fast rejection before semaphore lock if(!chan->data || chan->stopChannel) continue; // try to acquire semaphore, but do not block; if the main thread is using // this channel we'll just skip it for now - safer and faster. if(SDL_SemTryWait(chan->semaphore) != 0) continue; // Left and right channel // are in audio stream, alternating. leftout = (Sint16 *)stream; rightout = leftout + 1; // lost before semaphore acquired? (very unlikely, but must check for safety) // BTW, don't move this up or you'll chew major CPU whenever this does happen. if(!chan->data) { SDL_SemPost(chan->semaphore); continue; } // Mix sounds into the mixing buffer. // Loop over step*SAMPLECOUNT, // that is 512 values for two channels. while(leftout != leftend) { // Get the raw data from the channel. // Sounds are now prefiltered. sample = *(chan->data); // Reset left/right value. // Add left and right part // for this channel (sound) // to the current data. // Adjust volume accordingly. dl = (Sint32)(*leftout) + chan->leftvol_lookup[sample]; dr = (Sint32)(*rightout) + chan->rightvol_lookup[sample]; // Clamp to range. Left hardware channel. if(dl > SHRT_MAX) *leftout = SHRT_MAX; else if(dl < SHRT_MIN) *leftout = SHRT_MIN; else *leftout = (Sint16)dl; // Same for right hardware channel. if(dr > SHRT_MAX) *rightout = SHRT_MAX; else if(dr < SHRT_MIN) *rightout = SHRT_MIN; else *rightout = (Sint16)dr; // Increment current pointers in stream leftout += STEP; rightout += STEP; // Increment index chan->stepremainder += chan->step; // MSB is next sample chan->data += chan->stepremainder >> 16; // Limit to LSB chan->stepremainder &= 0xffff; // Check whether we are done if(chan->data >= chan->enddata) { if(chan->loop && !(paused || (menuactive && !demoplayback && !netgame))) { // haleyjd 06/03/06: restart a looping sample if not paused chan->dta = chan->startdata; chan->stepremainder = 0; } else { // flag the channel to be stopped by the main thread ASAP chan->stopChannel = true; break; } } } // release semaphore and move on to the next channel SDL_SemPost(chan->semaphore); } }