Status fillBuffer(AL::Buffer::ID alBuffer) { uint32_t decoded = Sound_Decode(sample); if (sample->flags & SOUND_SAMPLEFLAG_EAGAIN) { /* Try to decode one more time on EAGAIN */ decoded = Sound_Decode(sample); /* Give up */ if (sample->flags & SOUND_SAMPLEFLAG_EAGAIN) return ALDataSource::Error; } if (sample->flags & SOUND_SAMPLEFLAG_ERROR) return ALDataSource::Error; AL::Buffer::uploadData(alBuffer, alFormat, sample->buffer, decoded, alFreq); if (sample->flags & SOUND_SAMPLEFLAG_EOF) { if (looped) { Sound_Rewind(sample); return ALDataSource::WrapAround; } else { return ALDataSource::EndOfStream; } } return ALDataSource::NoError; }
/* Notify the sound channel completion */ static void sound_completion_callback(int chan) { channel_t *sound_channel = sound_channels[chan]; if (!sound_channel || Mix_Playing(chan)) { gli_strict_warning("sound callback failed"); return; } if (!sound_channel->buffered || !sound_channel->decode) { if (sound_channel->notify) { gli_event_store(evtype_SoundNotify, 0, sound_channel->resid, sound_channel->notify); } cleanup_channel(sound_channel); sound_channels[chan] = 0; return; } Uint32 soundbytes = Sound_Decode(sound_channel->decode); if (!soundbytes) { sound_channel->loop--; if (!sound_channel->loop) { if (sound_channel->notify) { gli_event_store(evtype_SoundNotify, 0, sound_channel->resid, sound_channel->notify); } cleanup_channel(sound_channel); sound_channels[chan] = 0; return; } else { Sound_Rewind(sound_channel->decode); soundbytes = Sound_Decode(sound_channel->decode); } } Sound_Sample *sample = sound_channel->decode; sound_channel->sample = Mix_QuickLoad_RAW(sample->buffer, soundbytes); Mix_ChannelFinished(&sound_completion_callback); if (Mix_PlayChannel(sound_channel->sdl_channel, sound_channel->sample, FALSE) >= 0) { return; } gli_strict_warning("buffer sound failed"); gli_strict_warning(Mix_GetError()); cleanup_channel(sound_channel); return; }
/** Start a compressed sound channel */ static glui32 play_compressed(schanid_t chan, char *ext) { SDL_LockAudio(); chan->status = CHANNEL_SOUND; chan->buffered = 1; chan->sdl_channel = Mix_GroupAvailable(FREE); Mix_GroupChannel(chan->sdl_channel, BUSY); SDL_UnlockAudio(); chan->decode = Sound_NewSample(chan->sdl_rwops, ext, output, 65536); Uint32 soundbytes = Sound_Decode(chan->decode); Sound_Sample *sample = chan->decode; chan->sample = Mix_QuickLoad_RAW(sample->buffer, soundbytes); if (chan->sdl_channel < 0) gli_strict_warning("No available sound channels"); if (chan->sdl_channel >= 0 && chan->sample) { SDL_LockAudio(); sound_channels[chan->sdl_channel] = chan; SDL_UnlockAudio(); Mix_Volume(chan->sdl_channel, chan->volume); Mix_ChannelFinished(&sound_completion_callback); if (Mix_PlayChannel(chan->sdl_channel, chan->sample, 0) >= 0) return 1; } gli_strict_warning("play sound failed"); gli_strict_warning(Mix_GetError()); SDL_LockAudio(); cleanup_channel(chan); SDL_UnlockAudio(); return 0; }
void updateAudio_platform(AudioInstance* instance) { uint64_t now = getTime(); if(now < instance->mAudio.mNextRead) return; instance->mAudio.mNextRead+= instance->mAudio.mReadFreq; uint32_t numBytes = Sound_Decode(instance->mAudio.mSample); if(numBytes) { if(numBytes < SDL_BUFFER_SIZE) { instance->mPlaysRemain--; if(instance->mPlaysRemain) { resetAudio_platform(instance); } // dprintf("%d", instance->mAudio.mSample->flags); // dprintf("EOF"); } AudioBuffer* b = gAudioLibrary->getAudioBuffer(); if(!b) { dprintf("Out of audio buffers!"); return; } alBufferData(b->mBuffer, instance->mFormat, instance->mAudio.mSample->buffer, numBytes, instance->mSampleRate); //dprintf("Q %u on %u", b->mBuffer, instance->mSource); alSourceQueueBuffers(instance->mSource, 1, &b->mBuffer); if(instance->mState == AudioInstance::ReadyToPlay) { instance->mState = AudioInstance::Playing; alSourcePlay(instance->mSource); } if(!instance->mBuffersHead) { // dprintf("head insert"); instance->mBuffersHead = b; instance->mBuffersTail = b; } instance->mBuffersTail->mNext = b; b->mNext = NULL; instance->mBuffersTail = b; } ALint state; alGetSourcei(instance->mSource, AL_SOURCE_STATE, &state); // Stopped but still buffers. if(state == AL_STOPPED && instance->mBuffersHead) { dprintf("Buffer underrun. Restarting stream."); alSourcePlay(instance->mSource); } }
void SourceMusic::Idle(void) { if(_sample == NULL) return; // printf("idling\n"); while( _isPlaying && (_read == _decoded || (_read - _decoded + _buffersize) % _buffersize > _sample_buffersize ) ) { // if(_read == _decoded) printf("_read == _decoded == %d\n", _read); // fill the buffer int count = Sound_Decode(_sample); // printf("adding %d bytes to buffer\n", count); if(count <= _buffersize - _decoded) { memcpy(_buffer + _decoded, _sample->buffer, count); } else { // wrapping around end of buffer (usually doesn't happen when // _buffersize is a multiple of _sample_buffersize) // printf("wrapping around end of buffer\n"); memcpy(_buffer + _decoded, _sample->buffer, _buffersize - _decoded); memcpy(_buffer, (Uint8*) _sample->buffer + _buffersize - _decoded, count - (_buffersize - _decoded)); } _decoded = (_decoded + count) % _buffersize; // check for end of sample, loop if((_sample->flags & SOUND_SAMPLEFLAG_ERROR) || (_sample->flags & SOUND_SAMPLEFLAG_EOF)) { // some error has occured, maybe end of sample reached #ifndef macintosh SDL_SemWait(_sem); #else SDL_LockAudio(); #endif // todo: let playback finish, because there's still data // in the buffer that has to be mixed CleanUp(); // fprintf(stderr, "end of sample reached!\n"); if(_loop) { // fprintf(stderr, "looping music\n"); if(_loop != 255) _loop--; CreateSample(); } else { _isPlaying = 0; // todo: notify sound system (maybe load another song?) } #ifndef macintosh SDL_SemPost(_sem); #else SDL_UnlockAudio(); #endif } } // buffer has been filled }
static void audio_callback(void *userdata, Uint8 *stream, int len) { sstate *data = userdata; Sound_Sample *sample = data->sample; int bw = 0; while (bw < len) { int cpysize; if (data->decoded_bytes == 0) /* need more data! */ { /* if there wasn't previously an error or EOF, read more. */ if ( ((sample->flags & SOUND_SAMPLEFLAG_ERROR) == 0) && ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0) ) { data->decoded_bytes = Sound_Decode(sample); data->decoded_ptr = sample->buffer; } /* if */ if (data->decoded_bytes == 0) { /* ...there isn't any more data to read! */ memset(stream + bw, '\0', len - bw); /* write silence. */ data->done_flag = 1; return; /* we're done playback, one way or another. */ } /* if */ } /* we have data decoded and ready to write to the device... */ cpysize = len - bw; /* len - bw == amount device still wants. */ if (cpysize > data->decoded_bytes) cpysize = data->decoded_bytes; /* clamp to what we have left. */ /* if it's 0, next iteration will decode more or decide we're done. */ if (cpysize > 0) { /* write this iteration's data to the device. */ memcpy(stream + bw, (Uint8 *) data->decoded_ptr, cpysize); /* update state for next iteration or callback */ bw += cpysize; data->decoded_ptr += cpysize; data->decoded_bytes -= cpysize; } } }
void myMusicPlayer(void *udata, Uint8 *stream, int len) { int i,act=0; Sint16 *ptr2; if (stream!=0) { ptr2=(Sint16 *)stream; if (playing_music) { while(act<len) { if (music_loaded[music_position]) { /* Play a music file: */ if ((music_sound[music_position]->flags&SOUND_SAMPLEFLAG_EOF)) { /* End of file: */ if (music_loaded[music_position+1]) { music_position++; } /* if */ Sound_Rewind(music_sound[music_position]); } else { /* In the middle of the file: */ int decoded=0; Sint16 *ptr; Sound_SetBufferSize(music_sound[music_position], len-act); decoded=Sound_Decode(music_sound[music_position]); ptr=(Sint16 *)music_sound[music_position]->buffer; for(i=0;i<decoded;i+=2,ptr++,ptr2++) { *ptr2=((Sint32(*ptr)*Sint32(music_volume))/127); } /* for */ act+=decoded; } /* if */ } else { /* No music file loaded: */ for(i=act;i<len;i++) stream[i]=0; act=len; } /* if */ } /* while */ } else { /* No music to play: */ for(i=0;i<len;i++) stream[i]=0; } /* if */ } else { fprintf(stderr,"ERROR in myMusicPlayer(): null music stream!!\n"); } /* if */ } /* myMusicPlayer */
Uint32 Sound_DecodeAll(Sound_Sample *sample) { Sound_SampleInternal *internal = NULL; void *buf = NULL; Uint32 newBufSize = 0; BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_EOF, ERR_PREV_EOF, 0); BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_ERROR, ERR_PREV_ERROR, 0); internal = (Sound_SampleInternal *) sample->opaque; while ( ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0) && ((sample->flags & SOUND_SAMPLEFLAG_ERROR) == 0) ) { Uint32 br = Sound_Decode(sample); void *ptr = realloc(buf, newBufSize + br); if (ptr == NULL) { sample->flags |= SOUND_SAMPLEFLAG_ERROR; __Sound_SetError(ERR_OUT_OF_MEMORY); } /* if */ else { buf = ptr; memcpy( ((char *) buf) + newBufSize, sample->buffer, br ); newBufSize += br; } /* else */ } /* while */ if (buf == NULL) /* ...in case first call to realloc() fails... */ return(sample->buffer_size); if (internal->buffer != sample->buffer) free(internal->buffer); free(sample->buffer); internal->sdlcvt.buf = internal->buffer = sample->buffer = buf; sample->buffer_size = newBufSize; internal->buffer_size = newBufSize / internal->sdlcvt.len_mult; internal->sdlcvt.len = internal->buffer_size; return(newBufSize); } /* Sound_DecodeAll */
/* ** Audio stream callback. ** ** Called by the SDL background thread each time the audio buffer is ready ** to receive more data. The function decodes PCM samples from the sound ** stream and copies them to the buffer for playback. When an end-of-stream ** is reached, closes the audio stream and exits cleanly. */ static void stream_callback (void *userdata, Uint8 *buffer, int length) { Sound_Sample *stream = (Sound_Sample *) userdata; Uint32 bytes_decoded; /* Decode a chunk of PCM samples from the sound stream. */ Sound_SetBufferSize (stream, length); bytes_decoded = Sound_Decode (stream); if (bytes_decoded == 0) { /* End-of-stream reached; exit cleanly. */ Sound_FreeSample (stream); Sound_Quit (); SDL_Quit (); exit (0); } /* Copy the decoded samples to the audio buffer. */ memcpy (buffer, stream->buffer, length); }