[aquaria] Ogg streaming implemented
Andrea Palmatè
andrea at amigasoft.net
Sun Jul 18 06:33:09 EDT 2010
FANTASTIC!!
this is the time for a new update! :)
Il giorno 17/lug/2010, alle ore 19.48, Andrew Church ha scritto:
> I've finally gotten myself to buckle down and implement streamed decoding
> for Ogg Vorbis audio using the OpenAL backend, as was discussed a while
> ago. As expected, it cuts down memory usage by close to 200MB, and fixes
> the short freezes when changing areas or starting a cutscene.
>
> The patch against current icculus.org code is below, and is also on the
> ogg-streaming branch in my repository (http://achurch.org/cgi-bin/hg/aquaria/).
>
> --Andrew Church
> achurch at achurch.org
> http://achurch.org/
>
> ---------------------------------------------------------------------------
>
> diff -r f08314f4174e -r a2b8997718d6 BBGE/FmodOpenALBridge.cpp
> --- a/BBGE/FmodOpenALBridge.cpp Sat Jul 10 15:04:54 2010 +0900
> +++ b/BBGE/FmodOpenALBridge.cpp Sun Jul 18 02:09:58 2010 +0900
> @@ -45,6 +45,421 @@
> //#define _DEBUG 1
> #endif
>
> +///////////////////////////////////////////////////////////////////////////
> +
> +// Decoder implementation for streamed Ogg Vorbis audio.
> +
> +class OggDecoder {
> +public:
> + // Create a decoder that streams from a file.
> + OggDecoder(FILE *fp);
> +
> + // Create a decoder that streams from a memory buffer.
> + OggDecoder(const void *data, long data_size);
> +
> + ~OggDecoder();
> +
> + // Start playing on the given channel, with optional looping.
> + bool start(ALuint source, bool loop);
> +
> + // Decode audio into any free buffers. Must be called periodically
> + // on systems without threads; may be called without harm on systems
> + // with threads (the function does nothing in that case).
> + void update();
> +
> + // Terminate playback.
> + void stop();
> +
> + // Return the current playback position in seconds.
> + double position();
> +
> + // Memory buffer I/O callback functions for libvorbisfile.
> + static size_t mem_read(void *ptr, size_t size, size_t nmemb, void *datasource);
> + static int mem_seek(void *datasource, ogg_int64_t offset, int whence);
> + static long mem_tell(void *datasource);
> +
> +private:
> + // Decoding loop, run in a separate thread (if threads are available).
> + static void decode_loop(OggDecoder *this_);
> +
> + // Decode and queue PCM data for one buffer; does nothing if the end
> + // of the stream has already been reached or an unrecoverable error
> + // has occurred during decoding. If looping, the audio will instead
> + // restart at the beginning of the stream after reaching the end,
> + // but will still stop on an unrecoverable error.
> + void queue(ALuint buffer);
> +
> + static const int NUM_BUFFERS = 8;
> + static const int BUFFER_LENGTH = 4096; // In samples (arbitrary)
> + char pcm_buffer[BUFFER_LENGTH * 4]; // Temporary buffer for decoding
> + ALuint buffers[NUM_BUFFERS];
> + ALuint source;
> +
> + // Data source. If fp != NULL, the source is that file; otherwise, the
> + // source is the buffer pointed to by "data" with size "data_size" bytes.
> + FILE *fp;
> + const char *data;
> + long data_size;
> + long data_pos; // Current read position for memory buffers
> +
> + OggVorbis_File vf;
> + ALenum format;
> + int freq;
> +
> +#ifdef BBGE_BUILD_SDL
> + SDL_Thread *thread;
> +#else
> + #warning Threads not supported, music may cut out on area changes!
> + // ... because the stream runs out of decoded data while the area is
> + // still loading, so OpenAL aborts playback.
> +#endif
> + volatile bool stop_thread;
> +
> + bool playing;
> + bool loop;
> + bool eof; // End of file _or_ unrecoverable error encountered
> + unsigned int samples_done; // Number of samples played and dequeued
> +};
> +
> +// File I/O callback set (OV_CALLBACKS_NOCLOSE from libvorbis 1.2.0).
> +// It might be better to just update libogg/libvorbis to the current
> +// versions so we don't have to worry about identifier collisions --
> +// we can then drop all this and use OV_CALLBACKS_NOCLOSE in the
> +// ov_open_callbacks() call.
> +static int _ov_header_fseek_wrap(FILE *f,ogg_int64_t off,int whence){
> + if(f==NULL)return(-1);
> +#ifdef __MINGW32__
> + return fseeko64(f,off,whence);
> +#elif defined (_WIN32)
> + return _fseeki64(f,off,whence);
> +#else
> + return fseek(f,off,whence);
> +#endif
> +}
> +static int noclose(FILE *f) {return 0;}
> +static const ov_callbacks local_OV_CALLBACKS_NOCLOSE = {
> + (size_t (*)(void *, size_t, size_t, void *)) fread,
> + (int (*)(void *, ogg_int64_t, int)) _ov_header_fseek_wrap,
> + (int (*)(void *)) noclose, // NULL doesn't work in libvorbis-1.1.2
> + (long (*)(void *)) ftell
> +};
> +
> +// Memory I/O callback set.
> +static const ov_callbacks ogg_memory_callbacks = {
> + OggDecoder::mem_read,
> + OggDecoder::mem_seek,
> + (int (*)(void *))noclose,
> + OggDecoder::mem_tell
> +};
> +
> +
> +OggDecoder::OggDecoder(FILE *fp)
> +{
> + for (int i = 0; i < NUM_BUFFERS; i++)
> + {
> + buffers[i] = 0;
> + }
> + this->source = 0;
> + this->fp = fp;
> + this->data = NULL;
> + this->data_size = 0;
> + this->data_pos = 0;
> +#ifdef BBGE_BUILD_SDL
> + this->thread = NULL;
> +#endif
> + this->stop_thread = true;
> + this->playing = false;
> + this->loop = false;
> + this->eof = false;
> + this->samples_done = 0;
> +}
> +
> +OggDecoder::OggDecoder(const void *data, long data_size)
> +{
> + for (int i = 0; i < NUM_BUFFERS; i++)
> + {
> + buffers[i] = 0;
> + }
> + this->source = 0;
> + this->fp = NULL;
> + this->data = (const char *)data;
> + this->data_size = data_size;
> + this->data_pos = 0;
> +#ifdef BBGE_BUILD_SDL
> + this->thread = NULL;
> +#endif
> + this->stop_thread = true;
> + this->playing = false;
> + this->loop = false;
> + this->eof = false;
> + this->samples_done = 0;
> +}
> +
> +OggDecoder::~OggDecoder()
> +{
> + if (playing)
> + stop();
> +
> + for (int i = 0; i < NUM_BUFFERS; i++)
> + {
> + if (buffers[i])
> + alDeleteBuffers(1, &buffers[i]);
> + }
> +}
> +
> +bool OggDecoder::start(ALuint source, bool loop)
> +{
> + this->source = source;
> + this->loop = loop;
> +
> + if (fp) {
> + if (ov_open_callbacks(fp, &vf, NULL, 0, local_OV_CALLBACKS_NOCLOSE) != 0)
> + {
> + debugLog("ov_open() failed for file");
> + return false;
> + }
> + }
> + else
> + {
> + data_pos = 0;
> + if (ov_open_callbacks(this, &vf, NULL, 0, ogg_memory_callbacks) != 0)
> + {
> + debugLog("ov_open() failed for memory buffer");
> + return false;
> + }
> + }
> +
> + vorbis_info *info = ov_info(&vf, -1);
> + if (!info)
> + {
> + debugLog("ov_info() failed");
> + ov_clear(&vf);
> + return false;
> + }
> + if (info->channels == 1)
> + format = AL_FORMAT_MONO16;
> + else if (info->channels == 2)
> + format = AL_FORMAT_STEREO16;
> + else
> + {
> + std::ostringstream os;
> + os << "Bad channel count " << info->channels;
> + debugLog(os.str());
> + ov_clear(&vf);
> + return false;
> + }
> + freq = info->rate;
> +
> + /* NOTE: The failure to use alGetError() here and elsewhere is
> + * intentional -- since alGetError() writes to a global buffer and
> + * is thus not thread-safe, we can't use it either in the decoding
> + * threads _or_ here in the main thread. In this case, we rely on
> + * the specification that failing OpenAL calls do not modify return
> + * parameters to detect failure; for functions that do not return
> + * values, we have no choice but to hope for the best. (From a
> + * multithreading point of view, the insistence on using a global
> + * error buffer instead of returning success/failure or error codes
> + * from functions is a remarkably poor design decision. Not that a
> + * mere library user has much choice except to live with it...)
> + * --achurch */
> + buffers[0] = 0;
> + alGenBuffers(NUM_BUFFERS, buffers);
> + if (!buffers[0])
> + {
> + debugLog("Failed to generate OpenAL buffers");
> + ov_clear(&vf);
> + return false;
> + }
> +
> + playing = true;
> + eof = false;
> + samples_done = 0;
> + for (int i = 0; i < NUM_BUFFERS; i++)
> + queue(buffers[i]);
> +
> +#ifdef BBGE_BUILD_SDL
> + stop_thread = false;
> + thread = SDL_CreateThread((int (*)(void *))decode_loop, this);
> + if (!thread)
> + {
> + debugLog("Failed to create Ogg Vorbis decode thread: "
> + + std::string(SDL_GetError()));
> + }
> +#endif
> +
> + return true;
> +}
> +
> +void OggDecoder::update()
> +{
> + if (!playing)
> + return;
> +#ifdef BBGE_BUILD_SDL
> + if (thread)
> + return;
> +#endif
> +
> + int processed = 0;
> + alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
> + for (int i = 0; i < processed; i++)
> + {
> + samples_done += BUFFER_LENGTH;
> + ALuint buffer;
> + alSourceUnqueueBuffers(source, 1, &buffer);
> + queue(buffer);
> + }
> +}
> +
> +void OggDecoder::stop()
> +{
> + if (!playing)
> + return;
> +
> +#ifdef BBGE_BUILD_SDL
> + if (thread)
> + {
> + stop_thread = true;
> + SDL_WaitThread(thread, NULL);
> + thread = NULL;
> + }
> +#endif
> +
> + alSourceStop(source);
> + int queued = 0;
> + alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
> + for (int i = 0; i < queued; i++)
> + {
> + ALuint buffer;
> + alSourceUnqueueBuffers(source, 1, &buffer);
> + }
> + for (int i = 0; i < NUM_BUFFERS; i++)
> + {
> + alDeleteBuffers(1, &buffers[i]);
> + buffers[i] = 0;
> + }
> +}
> +
> +double OggDecoder::position()
> +{
> + ALint samples_played = 0;
> + alGetSourcei(source, AL_SAMPLE_OFFSET, &samples_played);
> + samples_played += samples_done;
> + return (double)samples_played / (double)freq;
> +}
> +
> +void OggDecoder::decode_loop(OggDecoder *this_)
> +{
> + while (!this_->stop_thread)
> + {
> +#ifdef BBGE_BUILD_SDL
> + SDL_Delay(1);
> +#endif
> +
> + int processed = 0;
> + alGetSourcei(this_->source, AL_BUFFERS_PROCESSED, &processed);
> + for (int i = 0; i < processed; i++)
> + {
> + this_->samples_done += BUFFER_LENGTH;
> + ALuint buffer = 0;
> + alSourceUnqueueBuffers(this_->source, 1, &buffer);
> + if (buffer)
> + this_->queue(buffer);
> + }
> + }
> +}
> +
> +void OggDecoder::queue(ALuint buffer)
> +{
> + if (!playing || eof)
> + return;
> +
> + const int channels = (format == AL_FORMAT_STEREO16 ? 2 : 1);
> + const int buffer_size = BUFFER_LENGTH * channels * 2;
> + int pcm_size = 0;
> + bool just_looped = false; // Avoid infinite loops on empty files.
> +
> + while (pcm_size < buffer_size && !eof)
> + {
> + int bitstream_unused;
> + const int nread = ov_read(
> + &vf, pcm_buffer + pcm_size, buffer_size - pcm_size,
> + /*bigendianp*/ 0, /*word*/ 2, /*sgned*/ 1, &bitstream_unused
> + );
> + if (nread == 0 || nread == OV_EOF)
> + {
> + if (loop && !just_looped)
> + {
> + just_looped = true;
> + samples_done = 0;
> + ov_pcm_seek(&vf, 0);
> + }
> + else
> + {
> + eof = true;
> + }
> + }
> + else if (nread == OV_HOLE)
> + {
> + debugLog("Warning: decompression error, data dropped");
> + }
> + else if (nread < 0)
> + {
> + std::ostringstream os;
> + os << "Decompression error: " << nread;
> + debugLog(os.str());
> + eof = true;
> + }
> + else
> + {
> + pcm_size += nread;
> + just_looped = false;
> + }
> + }
> +
> + if (pcm_size > 0)
> + {
> + alBufferData(buffer, format, pcm_buffer, pcm_size, freq);
> + alSourceQueueBuffers(source, 1, &buffer);
> + }
> +}
> +
> +size_t OggDecoder::mem_read(void *ptr, size_t size, size_t nmemb, void *datasource)
> +{
> + OggDecoder *this_ = (OggDecoder *)datasource;
> +
> + long to_read = size * nmemb;
> + if (to_read > this_->data_size - this_->data_pos)
> + to_read = this_->data_size - this_->data_pos;
> + if (to_read < 0)
> + to_read = 0;
> + memcpy(ptr, this_->data + this_->data_pos, to_read);
> + this_->data_pos += to_read;
> + return to_read / size;
> +}
> +
> +int OggDecoder::mem_seek(void *datasource, ogg_int64_t offset, int whence)
> +{
> + OggDecoder *this_ = (OggDecoder *)datasource;
> + if (whence == SEEK_CUR)
> + offset += this_->data_pos;
> + else if (whence == SEEK_END)
> + offset += this_->data_size;
> + if (offset < 0)
> + offset = 0;
> + else if (offset > this_->data_size)
> + offset = this_->data_size;
> + this_->data_pos = offset;
> + return 0;
> +}
> +
> +long OggDecoder::mem_tell(void *datasource)
> +{
> + OggDecoder *this_ = (OggDecoder *)datasource;
> + return this_->data_pos;
> +}
> +
> +///////////////////////////////////////////////////////////////////////////
> +
> /* for porting purposes... */
> #ifndef STUBBED
> #ifndef _DEBUG
> @@ -92,8 +507,63 @@
>
> static ALenum GVorbisFormat = AL_NONE;
>
> +// FMOD::Sound implementation ...
> +
> +class OpenALSound
> +{
> +public:
> + OpenALSound(FILE *_fp, const bool _looping);
> + OpenALSound(void *_data, long _size, const bool _looping);
> + FILE *getFile() const { return fp; }
> + const void *getData() const { return data; }
> + long getSize() const { return size; }
> + bool isLooping() const { return looping; }
> + FMOD_RESULT release();
> + void reference() { refcount++; }
> +
> +private:
> + FILE * const fp;
> + void * const data; // Only used if fp==NULL
> + const long size; // Only used if fp==NULL
> + const bool looping;
> + int refcount;
> +};
> +
> +OpenALSound::OpenALSound(FILE *_fp, const bool _looping)
> + : fp(_fp)
> + , data(NULL)
> + , size(0)
> + , looping(_looping)
> + , refcount(1)
> +{
> +}
> +
> +OpenALSound::OpenALSound(void *_data, long _size, const bool _looping)
> + : fp(NULL)
> + , data(_data)
> + , size(_size)
> + , looping(_looping)
> + , refcount(1)
> +{
> +}
> +
> +ALBRIDGE(Sound,release,(),())
> +FMOD_RESULT OpenALSound::release()
> +{
> + refcount--;
> + if (refcount <= 0)
> + {
> + if (fp)
> + fclose(fp);
> + else
> + free(data);
> + delete this;
> + }
> + return FMOD_OK;
> +}
> +
> +
> class OpenALChannelGroup;
> -class OpenALSound;
>
> class OpenALChannel
> {
> @@ -111,6 +581,7 @@
> void setGroupVolume(const float _volume);
> void setSourceName(const ALuint _sid) { sid = _sid; }
> ALuint getSourceName() const { return sid; }
> + bool start(OpenALSound *sound);
> void update();
> void reacquire();
> bool isInUse() const { return inuse; }
> @@ -125,6 +596,7 @@
> float frequency;
> OpenALChannelGroup *group;
> OpenALSound *sound;
> + OggDecoder *decoder;
> bool inuse;
> bool initial;
> };
> @@ -188,10 +660,29 @@
> SANITY_CHECK_OPENAL_CALL();
> }
>
> +bool OpenALChannel::start(OpenALSound *sound)
> +{
> + if (decoder)
> + delete decoder;
> + if (sound->getFile())
> + decoder = new OggDecoder(sound->getFile());
> + else
> + decoder = new OggDecoder(sound->getData(), sound->getSize());
> + if (!decoder->start(sid, sound->isLooping()))
> + {
> + delete decoder;
> + decoder = NULL;
> + return false;
> + }
> + return true;
> +}
> +
> void OpenALChannel::update()
> {
> if (inuse)
> {
> + if (decoder)
> + decoder->update();
> ALint state = 0;
> alGetSourceiv(sid, AL_SOURCE_STATE, &state);
> SANITY_CHECK_OPENAL_CALL();
> @@ -214,10 +705,17 @@
> FMOD_RESULT OpenALChannel::getPosition(unsigned int *position, FMOD_TIMEUNIT postype)
> {
> assert(postype == FMOD_TIMEUNIT_MS);
> - ALfloat secs = 0.0f;
> - alGetSourcefv(sid, AL_SEC_OFFSET, &secs);
> - SANITY_CHECK_OPENAL_CALL();
> - *position = (unsigned int) (secs * 1000.0f);
> + if (decoder)
> + {
> + *position = (unsigned int) (decoder->position() * 1000.0);
> + }
> + else
> + {
> + ALfloat secs = 0.0f;
> + alGetSourcefv(sid, AL_SEC_OFFSET, &secs);
> + SANITY_CHECK_OPENAL_CALL();
> + *position = (unsigned int) (secs * 1000.0f);
> + }
> return FMOD_OK;
> }
>
> @@ -432,44 +930,6 @@
> }
>
>
> -// FMOD::Sound implementation ...
> -
> -class OpenALSound
> -{
> -public:
> - OpenALSound(const ALuint _bid, const bool _looping);
> - bool isLooping() const { return looping; }
> - ALuint getBufferName() const { return bid; }
> - FMOD_RESULT release();
> - void reference() { refcount++; }
> -
> -private:
> - const ALuint bid; // buffer id
> - const bool looping;
> - int refcount;
> -};
> -
> -OpenALSound::OpenALSound(const ALuint _bid, const bool _looping)
> - : bid(_bid)
> - , looping(_looping)
> - , refcount(1)
> -{
> -}
> -
> -ALBRIDGE(Sound,release,(),())
> -FMOD_RESULT OpenALSound::release()
> -{
> - refcount--;
> - if (refcount <= 0)
> - {
> - alDeleteBuffers(1, &bid);
> - SANITY_CHECK_OPENAL_CALL();
> - delete this;
> - }
> - return FMOD_OK;
> -}
> -
> -
> void OpenALChannel::setSound(OpenALSound *_sound)
> {
> if (sound)
> @@ -485,6 +945,11 @@
> ALBRIDGE(Channel,stop,(),())
> FMOD_RESULT OpenALChannel::stop()
> {
> + if (decoder)
> + {
> + delete decoder;
> + decoder = NULL;
> + }
> alSourceStop(sid);
> SANITY_CHECK_OPENAL_CALL();
> alSourcei(sid, AL_BUFFER, 0);
> @@ -566,17 +1031,16 @@
> return FMOD_ERR_INTERNAL;
> }
>
> -static void *decode_to_pcm(const char *_fname, ALenum &format, ALsizei &size, ALuint &freq, const bool streaming)
> +ALBRIDGE(System,createSound,(const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound),(name_or_data,mode,exinfo,sound))
> +FMOD_RESULT OpenALSystem::createSound(const char *name_or_data, const FMOD_MODE mode, const FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound)
> {
> -#ifdef __POWERPC__
> - const int bigendian = 1;
> -#else
> - const int bigendian = 0;
> -#endif
> + assert(!exinfo);
> +
> + FMOD_RESULT retval = FMOD_ERR_INTERNAL;
>
> // !!! FIXME: if it's not Ogg, we don't have a decoder. I'm lazy. :/
> - char *fname = (char *) alloca(strlen(_fname) + 16);
> - strcpy(fname, _fname);
> + char *fname = (char *) alloca(strlen(name_or_data) + 16);
> + strcpy(fname, name_or_data);
> char *ptr = strrchr(fname, '.');
> if (ptr) *ptr = '\0';
> strcat(fname, ".ogg");
> @@ -585,118 +1049,45 @@
> #undef fopen
> FILE *io = fopen(core->adjustFilenameCase(fname).c_str(), "rb");
> if (io == NULL)
> - return NULL;
> + return FMOD_ERR_INTERNAL;
>
> - ALubyte *retval = NULL;
> -
> - if ((streaming) && (GVorbisFormat != AL_NONE))
> + if (mode & FMOD_CREATESTREAM)
> {
> - // Can we just feed it to the AL compressed?
> - format = GVorbisFormat;
> - freq = 44100;
> + *sound = (Sound *) new OpenALSound(io, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
> + retval = FMOD_OK;
> + }
> + else
> + {
> fseek(io, 0, SEEK_END);
> - size = ftell(io);
> - fseek(io, 0, SEEK_SET);
> - retval = (ALubyte *) malloc(size);
> - size_t rc = fread(retval, size, 1, io);
> - fclose(io);
> - if (rc != 1)
> + long size = ftell(io);
> + if (fseek(io, 0, SEEK_SET) != 0)
> {
> - free(retval);
> - return NULL;
> - }
> - return retval;
> - }
> -
> - // Uncompress and feed to the AL.
> - OggVorbis_File vf;
> - memset(&vf, '\0', sizeof (vf));
> - if (ov_open(io, &vf, NULL, 0) == 0)
> - {
> - int bitstream = 0;
> - vorbis_info *info = ov_info(&vf, -1);
> - size = 0;
> - format = (info->channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
> - freq = info->rate;
> -
> - if ((info->channels != 1) && (info->channels != 2))
> - {
> - ov_clear(&vf);
> - return NULL;
> + debugLog("Seek error on " + std::string(fname));
> + fclose(io);
> + return FMOD_ERR_INTERNAL;
> }
>
> - char buf[1024 * 16];
> - long rc = 0;
> - size_t allocated = 64 * 1024;
> - retval = (ALubyte *) malloc(allocated);
> - while ( (rc = ov_read(&vf, buf, sizeof (buf), bigendian, 2, 1, &bitstream)) != 0 )
> + void *data = malloc(size);
> + if (data == NULL)
> {
> - if (rc > 0)
> - {
> - size += rc;
> - if (size >= allocated)
> - {
> - allocated *= 2;
> - ALubyte *tmp = (ALubyte *) realloc(retval, allocated);
> - if (tmp == NULL)
> - {
> - free(retval);
> - retval = NULL;
> - break;
> - }
> - retval = tmp;
> - }
> - memcpy(retval + (size - rc), buf, rc);
> - }
> + debugLog("Out of memory for " + std::string(fname));
> + fclose(io);
> + return FMOD_ERR_INTERNAL;
> }
> - ov_clear(&vf);
> - return retval;
> - }
>
> - fclose(io);
> - return NULL;
> -}
> + long nread = fread(data, 1, size, io);
> + fclose(io);
> + if (nread != size)
> + {
> + debugLog("Failed to read data from " + std::string(fname));
> + free(data);
> + return FMOD_ERR_INTERNAL;
> + }
>
> -
> -ALBRIDGE(System,createSound,(const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound),(name_or_data,mode,exinfo,sound))
> -FMOD_RESULT OpenALSystem::createSound(const char *name_or_data, const FMOD_MODE mode, const FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound)
> -{
> - assert(!exinfo);
> -
> - FMOD_RESULT retval = FMOD_ERR_INTERNAL;
> - ALenum pcmfmt = AL_NONE;
> - ALsizei pcmsize = 0;
> - ALuint pcmfreq = 0;
> - void *pcm = decode_to_pcm(name_or_data, pcmfmt, pcmsize, pcmfreq, (mode & FMOD_CREATESTREAM) != 0);
> - if (pcm == NULL)
> - return FMOD_ERR_INTERNAL;
> -
> - #if 0
> - static int dump_id = 0;
> - char buf[128];
> - snprintf(buf, sizeof (buf), "dump_%d.pcm", dump_id++);
> - FILE *io = fopen(buf, "wb");
> - if (io != NULL)
> - {
> - fwrite(pcm, pcmsize, 1, io);
> - fclose(io);
> - }
> - #endif
> -
> - ALuint bid = 0;
> - alGetError();
> - alGenBuffers(1, &bid);
> - SANITY_CHECK_OPENAL_CALL();
> - if (alGetError() == AL_NO_ERROR)
> - {
> - alBufferData(bid, pcmfmt, pcm, pcmsize, pcmfreq);
> - SANITY_CHECK_OPENAL_CALL();
> - *sound = (Sound *) new OpenALSound(bid, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
> + *sound = (Sound *) new OpenALSound(data, size, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
> retval = FMOD_OK;
> }
>
> - free(pcm);
> -
> return retval;
> }
>
> @@ -815,10 +1206,11 @@
> alSourceStop(sid); // stop any playback, set to AL_INITIAL.
> alSourceRewind(sid); // stop any playback, set to AL_INITIAL.
> SANITY_CHECK_OPENAL_CALL();
> - alSourcei(sid, AL_BUFFER, sound->getBufferName());
> + alSourcei(sid, AL_BUFFER, NULL); // Reset state to AL_UNDETERMINED.
> SANITY_CHECK_OPENAL_CALL();
> - alSourcei(sid, AL_LOOPING, sound->isLooping() ? AL_TRUE : AL_FALSE);
> - SANITY_CHECK_OPENAL_CALL();
> +
> + if (!channels[channelid].start(sound))
> + return FMOD_ERR_INTERNAL;
>
> channels[channelid].reacquire();
> channels[channelid].setPaused(paused);
> _______________________________________________
> aquaria mailing list
> aquaria at icculus.org
> http://icculus.org/mailman/listinfo/aquaria
>
More information about the aquaria
mailing list