[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