void AUD_SoftwareDevice::mix(data_t* buffer, int length) { m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_specs)); lock(); { AUD_Reference<AUD_SoftwareDevice::AUD_SoftwareHandle> sound; int len; int pos; bool eos; std::list<AUD_Reference<AUD_SoftwareDevice::AUD_SoftwareHandle> > stopSounds; std::list<AUD_Reference<AUD_SoftwareDevice::AUD_SoftwareHandle> > pauseSounds; sample_t* buf = m_buffer.getBuffer(); m_mixer->clear(length); // for all sounds AUD_HandleIterator it = m_playingSounds.begin(); while(it != m_playingSounds.end()) { sound = *it; // increment the iterator to make sure it's valid, // in case the sound gets deleted after stopping ++it; // get the buffer from the source pos = 0; len = length; // update 3D Info sound->update(); sound->m_reader->read(len, eos, buf); // in case of looping while(pos + len < length && sound->m_loopcount && eos) { m_mixer->mix(buf, pos, len, sound->m_volume); pos += len; if(sound->m_loopcount > 0) sound->m_loopcount--; sound->m_reader->seek(0); len = length - pos; sound->m_reader->read(len, eos, buf); // prevent endless loop if(!len) break; } m_mixer->mix(buf, pos, len, sound->m_volume); // in case the end of the sound is reached if(eos && !sound->m_loopcount) { if(sound->m_stop) sound->m_stop(sound->m_stop_data); if(sound->m_keep) pauseSounds.push_back(sound); else stopSounds.push_back(sound); } } // superpose m_mixer->read(buffer, m_volume); // cleanup while(!stopSounds.empty()) { sound = stopSounds.front(); stopSounds.pop_front(); sound->stop(); } while(!pauseSounds.empty()) { sound = pauseSounds.front(); pauseSounds.pop_front(); sound->pause(); } } unlock(); }
void AUD_OpenALDevice::updateStreams() { AUD_Reference<AUD_OpenALHandle> sound; int length; ALint info; AUD_DeviceSpecs specs = m_specs; ALCenum cerr; std::list<AUD_Reference<AUD_OpenALHandle> > stopSounds; std::list<AUD_Reference<AUD_OpenALHandle> > pauseSounds; AUD_HandleIterator it; while(1) { lock(); alcSuspendContext(m_context); cerr = alcGetError(m_device); if(cerr == ALC_NO_ERROR) { // for all sounds for(it = m_playingSounds.begin(); it != m_playingSounds.end(); it++) { sound = *it; // is it a streamed sound? if(!sound->m_isBuffered) { // check for buffer refilling alGetSourcei(sound->m_source, AL_BUFFERS_PROCESSED, &info); if(info) { specs.specs = sound->m_reader->getSpecs(); m_buffer.assureSize(m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs)); // for all empty buffers while(info--) { // if there's still data to play back if(!sound->m_eos) { // read data length = m_buffersize; sound->m_reader->read(length, sound->m_eos, m_buffer.getBuffer()); // looping necessary? if(length == 0 && sound->m_loopcount) { if(sound->m_loopcount > 0) sound->m_loopcount--; sound->m_reader->seek(0); length = m_buffersize; sound->m_reader->read(length, sound->m_eos, m_buffer.getBuffer()); } if(sound->m_loopcount != 0) sound->m_eos = false; // read nothing? if(length == 0) { break; } // unqueue buffer alSourceUnqueueBuffers(sound->m_source, 1, &sound->m_buffers[sound->m_current]); ALenum err; if((err = alGetError()) != AL_NO_ERROR) { sound->m_eos = true; break; } // fill with new data alBufferData(sound->m_buffers[sound->m_current], sound->m_format, m_buffer.getBuffer(), length * AUD_DEVICE_SAMPLE_SIZE(specs), specs.rate); if((err = alGetError()) != AL_NO_ERROR) { sound->m_eos = true; break; } // and queue again alSourceQueueBuffers(sound->m_source, 1, &sound->m_buffers[sound->m_current]); if(alGetError() != AL_NO_ERROR) { sound->m_eos = true; break; } sound->m_current = (sound->m_current+1) % AUD_OpenALHandle::CYCLE_BUFFERS; } else break; } } } // check if the sound has been stopped alGetSourcei(sound->m_source, AL_SOURCE_STATE, &info); if(info != AL_PLAYING) { // if it really stopped if(sound->m_eos) { if(sound->m_stop) sound->m_stop(sound->m_stop_data); // pause or if(sound->m_keep) pauseSounds.push_back(sound); // stop else stopSounds.push_back(sound); } // continue playing else alSourcePlay(sound->m_source); } } for(it = pauseSounds.begin(); it != pauseSounds.end(); it++) (*it)->pause(); for(it = stopSounds.begin(); it != stopSounds.end(); it++) (*it)->stop(); pauseSounds.clear(); stopSounds.clear(); alcProcessContext(m_context); } // stop thread if(m_playingSounds.empty() || (cerr != ALC_NO_ERROR)) { m_playing = false; unlock(); pthread_exit(NULL); } unlock(); #ifdef WIN32 Sleep(20); #else usleep(20000); #endif } }