testing improved runloop scheduling
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Thu, 5 Aug 2010 02:56:19 +0000 (20:56 -0600)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Thu, 5 Aug 2010 02:56:19 +0000 (20:56 -0600)
15 files changed:
data/scenes/Classic.lua
data/yoinkrc
src/Character.cc
src/GameLayer.cc
src/Main.cc
src/moof/log.cc
src/moof/log.hh
src/moof/mesh.cc
src/moof/resource.cc
src/moof/sound.cc
src/moof/sound.hh
src/moof/sound_bindings.cc
src/moof/timer.cc
src/moof/timer.hh
src/moof/view.cc

index 8476279e0d3aefd94ae4e7746dcc541cf35173ce..c2ca18387f1ecf01ae9d73b921faf6d522896da9 100644 (file)
@@ -68,6 +68,8 @@ Event = {}
 
 do
        local mysound = yoink.sound("Explosion")
+       --local mysound = yoink.sound()
+       --mysound:sample("Explosion")
        local count = 0
        function Event.Think()
                if count % 300 == 0 then
index d26ac4d83481a0a22dfb08bf9a72eb853f4fd0ab..af051b38bd1f83ec366469ee71bdb898e0d107dc 100644 (file)
@@ -47,13 +47,13 @@ fullscreen          = false
 resizable              = true
 
 -- Set the screen resolution or size of the window.  The value is an array
--- with three number elements representing the width, height, and bits per
--- pixel that make up the video mode.  If the fullscreen option is set, the
--- default behavior is to pick a native resolution.  You can use the
--- videomode to override the default resolution.  If the fullscreen option
--- is false, videomode will determine the size of the window.
+-- with three number elements representing the width, height, and
+-- (optionally) bits per pixel that make up the video mode.
 
-if fullscreen == false then
+if fullscreen then
+       -- In fullscreen mode, a native resolution will be picked.  You could
+       -- still set videomode if you want to use a different resolution.
+else
        videomode       = {800, 600}
 end
 
@@ -72,10 +72,11 @@ swapcontrol         = true
 
 -- Set the level of log detail that will be output to the console.
 -- Possible values are:
--- 0 print nothing
--- 1 output errors only
--- 2 include warnings
--- 3 print everything, including debug messages
+--   0 nothing
+--   1 errors
+--   2 warnings
+--   3 info
+--   4 debug messages
 
 loglevel               = 2
 
index c5d48385c8793bc71db777f4e3416bc4dabe3909..3cae68009e4b998bf8b4b823538204bf6c803a66 100644 (file)
@@ -74,12 +74,12 @@ Character::Character(const std::string& name) :
        // forces
        state_.force = moof::vector2(0.0, 0.0);
        //state_.forces.push_back(SpringForce(moof::vector2(5.0, 4.0)));
-       state_.forces.push_back(ResistanceForce(2.0));
+       //state_.forces.push_back(ResistanceForce(2.0));
        //state_.forces.push_back(moof::linear_state<2>::gravity_force(-9.8));
 
        // starting position
        state_.position = moof::vector2(5.0, 5.0);
-       state_.momentum = moof::vector2(1.0, 0.0);
+       state_.momentum = moof::vector2(3.0, 0.0);
        state_.recalculate();
 
        prev_state_ = state_;
index 8ff3a75a1cd5fecdb85144d2c7625ad5a7664731..7d36f3312045ca00781a6294e7cd0f4e45701fc9 100644 (file)
@@ -90,12 +90,12 @@ void GameLayer::advanceScene(moof::settings& settings)
 
 GameLayer::GameLayer()
 {
-       music_.sample("NightFusionIntro.ogg");
+       music_.queue("NightFusionIntro");
        music_.loop(true);
-       music_.enqueue("NightFusionLoop.ogg");
+       music_.queue("NightFusionLoop");
        music_.position(moof::vector3(10.0, 5.0, 0.0));
 
-       punch_sound_.sample("RobotPunch");
+       punch_sound_.sample("Thump");
 
        state_.heroine = Heroine::alloc();
        state_.heroine->animation.startSequence("FlyDiagonallyUp");
index 13681ee0625fa74d578fd1dcdb24f49db5e5129e..ff2ce61d081fc47ffa5a8c42c35322ea99db614d 100644 (file)
@@ -20,7 +20,7 @@
 #if !defined(__WIN32)
 #include <termios.h>
 #else
-int isatty(int dummy) { return 0; }
+inline int isatty(int dummy) { return 0; }
 #endif
 
 #include <stlplus/portability/file_system.hpp>
@@ -163,9 +163,9 @@ void Main::setup_opengl()
        glEnable(GL_DEPTH_TEST);
        //glEnable(GL_CULL_FACE);
 
-       //glEnable(GL_POINT_SMOOTH);
-       //glEnable(GL_LINE_SMOOTH);
-       //glEnable(GL_POLYGON_SMOOTH);
+       glEnable(GL_POINT_SMOOTH);
+       glEnable(GL_LINE_SMOOTH);
+       glEnable(GL_POLYGON_SMOOTH);
        glShadeModel(GL_SMOOTH);
 
        //glEnable(GL_BLEND);
@@ -331,7 +331,7 @@ void goodbye()
 
 int main(int argc, char* argv[])
 {
-       moof::backend backend;
+       //moof::backend backend;
 
        if (argc > 1)
        {
index f9a3ad97d3c397b4a21e33b4793ca8bcea021622..e59740dd2a00e487f2ace56cc84839d1e395db98 100644 (file)
@@ -14,7 +14,7 @@
 #if !defined(__WIN32)
 #include <termios.h>
 #else
-int isatty(int dummy) { return 0; }
+inline int isatty(int dummy) { return 0; }
 #endif
 
 
@@ -48,14 +48,16 @@ log::log(enum level level) :
                        case log::error:        prefix_ = "  error: ";  break;
                        case log::warning:      prefix_ = "warning: ";  break;
                        case log::info:         prefix_ = "   info: ";  break;
+                       case log::debug:        prefix_ = "  debug: ";  break;
                        case log::none:         break;
                }
        else
                switch (level)
                {
-                       case log::error:        prefix_ = "\033[101m  error: "; break;
-                       case log::warning:      prefix_ = "\033[103mwarning: "; break;
-                       case log::info:         prefix_ = "   info: ";                  break;
+                       case log::error:        prefix_ = "\033[30;101m  error: ";      break;
+                       case log::warning:      prefix_ = "\033[30;103mwarning: ";      break;
+                       case log::info:         prefix_ = "   info: ";                          break;
+                       case log::debug:        prefix_ = "\033[2m  debug: ";           break;
                        case log::none:         break;
                }
 }
@@ -79,14 +81,15 @@ std::ostream& log(std::cout);
 static std::ofstream null_log_;
 std::ostream& null_log(null_log_);
 
-class log log_error(  log::error);
+class log log_error(log::error);
 class log log_warning(log::warning);
-class log log_info(   log::info);
+class log log_info(log::info);
+class log log_debug(log::debug);
 
 
 static int log_script(script& script, enum log::level level)
 {
-       static class log* logs[] = {0, &log_error, &log_warning, &log_info};
+       static class log* logs[] = {0, &log_error, &log_warning, &log_info, &log_debug};
 
        script::slot param = script[1];
 
@@ -109,6 +112,8 @@ void log::import(script& script)
                                                  boost::bind(log_script, _1, log::info));
        script.import_function("print",
                                                  boost::bind(log_script, _1, log::info));
+       script.import_function("LogDebug",
+                                                 boost::bind(log_script, _1, log::debug));
 }
 
 
index e6e1a80c980400475e4476e271448f5bfdf75e00..1e2a2163e119b2988b33312a091375ed2b04a6c6 100644 (file)
@@ -50,6 +50,7 @@ public:
                error           = 1,            ///< Log only errors.
                warning         = 2,            ///< Log warnings and errors.
                info            = 3,            ///< Log everything.
+               debug           = 4,            ///< Log absolutely everything.
        };
 
 
@@ -149,6 +150,7 @@ extern std::ostream&        null_log;
 extern class log log_error;
 extern class log log_warning;
 extern class log log_info;
+extern class log log_debug;
 
 
 template <class T>
index 023138b6df39fa8a79aa8f043b62bc5a5a58f5ea..e380adfd19d6eb2ea9e9bc2bc9799eb0c2bf8362 100644 (file)
@@ -356,25 +356,8 @@ void mesh::import(std::istream& stream)
                                obj = obj->parent.lock();
                        }
                }
-               else
-               {
-                       log_warning("UNKNOWN ATOM:", atom);
-               }
        }
        while (stream);
-
-       std::vector<object_ptr>::iterator meh;
-       for (meh = objects_.begin(); meh != objects_.end(); ++meh)
-       {
-               object_ptr cow = *meh;
-               log_info("OBJ: -", cow->name, cow->kids.size());
-
-               std::vector<object_ptr>::iterator foo;
-               for (foo = cow->kids.begin(); foo != cow->kids.end(); ++foo)
-               {
-                       log_info("OBJ:   -", (*foo)->name, (*foo)->kids.size());
-               }
-       }
 }
 
 //unsigned mesh::read_vertex_line(std::istream& stream)
index 3cf901b06473ae730fccd87d556a05d973460fa6..35cd663ded7decff86f96321916b8ab5cef71f5b 100644 (file)
@@ -63,12 +63,12 @@ std::string resource::find_file(const std::string& name)
                        // try it with the prefix first
                        path = stlplus::filespec_to_path(*it, prefix);
                        path = stlplus::filespec_to_path(path, name);
-                       log_info("looking for", name, "at", path);
+                       log_debug("looking for", name, "at", path);
                        if (stlplus::file_exists(path)) return path;
                }
 
                path = stlplus::filespec_to_path(*it, name);
-               log_info("looking for", name, "at", path);
+               log_debug("looking for", name, "at", path);
                if (stlplus::file_exists(path)) return path;
        }
 
index 2c19d265b721f0b9d0e01a94f0bd93007157f948..f3060540eba005087560423b4dcdb0d167a524c6 100644 (file)
@@ -9,9 +9,7 @@
 *
 **************************************************************************/
 
-#include <cstdio>
 #include <deque>
-#include <list>
 #include <stdexcept>
 
 #include <boost/algorithm/string.hpp>
@@ -22,7 +20,6 @@
 #include <vorbis/codec.h>
 #include <vorbis/vorbisfile.h>
 
-#include "hash.hh"
 #include "log.hh"
 #include "sound.hh"
 #include "resource.hh"
 
 
 #ifndef BUF_SIZE
-#define BUF_SIZE       (4096 * 64)
+#define BUF_SIZE               (4096)
 #endif
 
-#define NUM_BUFFERS (4)
+#define NUM_SAMPLE_BITS        (16)
 
 
 namespace moof {
@@ -108,109 +105,6 @@ typedef resource_handle<sound_resource> sound_handle;
 MOOF_REGISTER_RESOURCE(sound_resource, ogg, sounds);
 
 
-/*] Sound buffer
- *************************************************************************/
-
-class buffer
-{
-public:
-
-       typedef hash<ALuint,int,hash_function> retcount_lookup;
-
-
-       buffer() :
-               buffer_((ALuint)-1) {}
-
-       buffer(const void* data,
-                  ALsizei size,
-                  ALenum format,
-                  ALsizei freq)
-       {
-               alGenBuffers(1, &buffer_);
-               alBufferData(buffer_, format, data, size, freq);
-
-               retain_counts_[buffer_] = 1;
-       }
-
-       buffer(const buffer& buf)
-       {
-               buffer_ = buf.buffer_;
-               retain();
-       }
-
-       buffer& operator = (const buffer& buf)
-       {
-               buffer_ = buf.buffer_;
-               retain();
-               return *this;
-       }
-
-       ~buffer()
-       {
-               release();
-       }
-
-
-       void queue(ALuint source) const
-       {
-               if (*this)
-               {
-                       alSourceQueueBuffers(source, 1, &buffer_);
-                       retain();
-               }
-       }
-
-       static buffer unqueue(ALuint source)
-       {
-               ALuint buf = (ALuint)-1;
-               alSourceUnqueueBuffers(source, 1, &buf);
-               return buffer(buf);
-       }
-
-       void set(ALuint source) const
-       {
-               if (*this) alSourcei(source, AL_BUFFER, buffer_);
-       }
-
-       operator bool () const
-       {
-               return buffer_ != (ALuint)-1;
-       }
-
-
-private:
-
-       explicit buffer(ALuint buf) :
-               buffer_(buf) {}
-
-
-       void retain() const
-       {
-               retcount_lookup::iterator it = retain_counts_.find(buffer_);
-               if (it.valid()) ++it->second;
-       }
-
-       void release() const
-       {
-               retcount_lookup::iterator it = retain_counts_.find(buffer_);
-               if (it.valid() && --it->second <= 0)
-               {
-                       alDeleteBuffers(1, &buffer_);
-                       retain_counts_.erase(it);
-               }
-       }
-
-
-       ALuint                                  buffer_;
-       sound_backend                   backend_;
-
-       static retcount_lookup  retain_counts_;
-};
-
-buffer::retcount_lookup buffer::retain_counts_;
-
-
-
 /*] Sound resource
  *************************************************************************/
 
@@ -218,7 +112,9 @@ class sound_resource : public boost::noncopyable
 {
 public:
 
-       sound_resource(const std::string& path)
+       sound_resource(const std::string& path) :
+               buffer_(AL_NONE),
+               sample_(0)
        {
                if (ov_fopen((char*)path.c_str(), &file_) < 0)
                {
@@ -229,24 +125,23 @@ public:
        ~sound_resource()
        {
                ov_clear(&file_);
+               if (buffer_) alDeleteBuffers(1, &buffer_);
        }
 
 
-       bool read(buffer& buf) const
+       ALuint read_all() const
        {
-               if (buffer_)
-               {
-                       buf = buffer_;
-                       return true;
-               }
+               if (buffer_) return buffer_;
 
-               if (ov_pcm_seek_lap(&file_, 0) != 0)
+               if (ov_pcm_seek(&file_, 0) != 0)
                {
                        log_warning("vorbis seek error");
-                       return false;
+                       return AL_NONE;
                }
 
-               char    data[64*BUF_SIZE];
+               ogg_int64_t samples = ov_pcm_total(&file_, 0);
+
+               char    data[2 * samples * (NUM_SAMPLE_BITS / 8)];
                size_t  size = 0;
 
                while (size < sizeof(data))
@@ -256,18 +151,21 @@ public:
                                                                 data + size, sizeof(data) - size,
                                                                 0, 2, 1, &section);
 
-                       if (result > 0)
+                       if (0 < result)
                        {
                                size += result;
-                               continue;
                        }
                        else if (result == 0 && size > 0)
                        {
                                vorbis_info* info = ov_info(&file_, section);
-                               buffer_ = buffer(data, size,
-                                                                get_audio_format(info), info->rate);
-                               buf = buffer_;
-                               return true;
+
+                               ALuint buffer;
+                               alGenBuffers(1, &buffer);
+                               alBufferData(buffer, get_audio_format(info),
+                                                        data, size, info->rate);
+
+                               buffer_ = buffer;
+                               return buffer;
                        }
                        else
                        {
@@ -276,16 +174,14 @@ public:
                        }
                }
 
-               if (size >= sizeof(data)) log_warning("sample is too big to play");
-               return false;
+               return AL_NONE;
        }
 
-
-       bool read(buffer& buf, uint64_t& sample) const
+       bool read(ALuint buffer, uint64_t& sample) const
        {
-               if (ov_pcm_seek_lap(&file_, sample) != 0)
+               if ((sample == sample_ && ov_pcm_seek_lap(&file_, sample) != 0) ||
+                       (sample != sample_ && ov_pcm_seek(&file_, sample) != 0))
                {
-                       log_warning("vorbis seek error");
                        return false;
                }
 
@@ -293,30 +189,73 @@ public:
                int     section;
                int     result = ov_read(&file_, data, sizeof(data), 0, 2, 1, &section);
 
-               if (result > 0)
+               if (0 < result)
+               {
+                       vorbis_info* info = ov_info(&file_, section);
+                       alBufferData(buffer, get_audio_format(info),
+                                                data, result, info->rate);
+                       sample_ = sample = ov_pcm_tell(&file_);
+                       return true;
+               }
+               else if (result < 0) log_warning("vorbis playback error");
+
+               return false;
+       }
+
+       bool read(ALuint buffer, uint64_t& sample, sound_handle other) const
+       {
+               ov_crosslap(&other->file_, &file_);
+
+               char data[BUF_SIZE];
+               int     section;
+               int     result = ov_read(&file_, data, sizeof(data), 0, 2, 1, &section);
+
+               if (0 < result)
                {
                        vorbis_info* info = ov_info(&file_, section);
-                       buf = buffer(data, result, get_audio_format(info), info->rate);
-                       sample = ov_pcm_tell(&file_);
+                       alBufferData(buffer, get_audio_format(info),
+                                                data, result, info->rate);
+                       sample_ = sample = ov_pcm_tell(&file_);
                        return true;
                }
+               else if (result < 0) log_warning("vorbis playback error");
 
-               if (result < 0) log_warning("vorbis playback error");
                return false;
        }
 
 
+       // determines the correct number of fixed-size buffers needed to hold a
+       // given number of seconds of PCM audio.
+       int num_buffers(scalar seconds) const
+       {
+               vorbis_info* info = ov_info(&file_, -1);
+               int count = scalar(info->rate) *                // sample rate
+                                       scalar(info->channels) *        // channels
+                                       scalar(NUM_SAMPLE_BITS) *       // sample size
+                                       seconds *                                       // time
+                                       SCALAR(0.125) /                         // bits to bytes
+                                       scalar(BUF_SIZE);                       // individual buffer size
+               return count;
+       }
+
+
        static ALenum get_audio_format(const vorbis_info* info)
        {
-               if (info->channels == 1) return AL_FORMAT_MONO16;
-               else                                     return AL_FORMAT_STEREO16;
+               if (info->channels == 1)      return AL_FORMAT_MONO16;
+               else if (info->channels == 2) return AL_FORMAT_STEREO16;
+
+               log_error("unsupported number of channels:", info->channels);
+               return 0;
        }
 
 
 private:
 
        mutable OggVorbis_File  file_;
-       mutable buffer                  buffer_;
+       mutable ALuint                  buffer_;
+       mutable uint64_t                sample_;
+
+       sound_backend                   backend_;
 };
 
 
@@ -335,7 +274,7 @@ public:
        impl(const std::string& name)
        {
                init();
-               enqueue(name);
+               sample(name);
        }
 
        void init()
@@ -344,6 +283,7 @@ public:
                is_looping_ = false;
 
                sample_ = 0;
+               buffer_size_ = SCALAR(1.0);
 
                alGenSources(1, &source_);
 
@@ -357,126 +297,175 @@ public:
        ~impl()
        {
                stop();
+               deplete_stream();
+
                alDeleteSources(1, &source_);
        }
 
 
-       void play()
+       void deplete_stream()
        {
-               if (queue_.empty()) return;
-
-               sound_handle    handle = queue_.front();
-               buffer                  buf;
-
-               if (handle->read(buf))
+               if (is_streaming_)
                {
-                       buf.set(source_);
-                       alSourcei(source_, AL_LOOPING, is_looping_);
-                       alSourcePlay(source_);
+                       ALint queued = 0;
+                       alGetSourcei(source_, AL_BUFFERS_QUEUED, &queued);
+                       ALuint buffers[queued];
+                       alSourceUnqueueBuffers(source_, queued, buffers);
+                       alDeleteBuffers(queued, buffers);
                }
+               else alSourcei(source_, AL_BUFFER, AL_NONE);
        }
 
-       void stream()
+       void play()
        {
-               if (queue_.empty()) return;
+               if (queue_.empty() || is_playing_) return;
 
-               if (!is_playing_)
+               ALenum state;
+               alGetSourcei(source_, AL_SOURCE_STATE, &state);
+               switch (state)
                {
-                       alSourcei(source_, AL_LOOPING, false);
+                       case AL_INITIAL:
+                       case AL_STOPPED:
 
-                       sound_handle handle = queue_.front();
+                               if (is_streaming_)
+                               {
+                                       start_update_timer();
+                                       num_buffers_ = queue_.front()->num_buffers(buffer_size_);
+                                       fill_stream();
+                                       is_playing_ = true;
+                                       alSourcei(source_, AL_LOOPING, false);
+                               }
+                               else
+                               {
+                                       ALuint buffer = queue_.front()->read_all();
+                                       alSourcei(source_, AL_BUFFER, buffer);
+                                       alSourcei(source_, AL_LOOPING, is_looping_);
+                               }
+                               break;
 
-                       for (int i = 0; i < NUM_BUFFERS; ++i)
-                       {
-                               buffer buf;
-                               if (handle->read(buf, sample_))
+                       case AL_PAUSED:
+                               
+                               if (is_streaming_)
                                {
-                                       buf.queue(source_);
+                                       start_update_timer();
+                                       is_playing_ = true;
                                }
+                               break;
+               }
+
+               alSourcePlay(source_);
+       }
+
+       void start_update_timer()
+       {
+               stream_timer_.init(boost::bind(&impl::stream_update, this, _1, _2),
+                               SCALAR(0.1), timer::repeat);
+       }
+
+       void fill_stream()
+       {
+               ALenum type;
+               alGetSourcei(source_, AL_SOURCE_TYPE, &type);
+               ASSERT(type != AL_STATIC && "source shouldn't be static");
+               
+               ALint   processed = 0;
+               ALint   queued = 0;
+               alGetSourcei(source_, AL_BUFFERS_QUEUED, &queued);
+               alGetSourcei(source_, AL_BUFFERS_PROCESSED, &processed);
+
+               int             target_diff = num_buffers_ - queued + processed;
+
+               ALuint  bufs[processed];
+               alSourceUnqueueBuffers(source_, processed, bufs);
+               for (int i = 0; i < processed; ++i)
+               {
+                       ALuint& buf = bufs[i];
+
+                       if (0 < target_diff)
+                       {
+                               if (queue_buffer(buf)) --target_diff;
                                else
                                {
-                                       log_error("failed to start stream");
+                                       alDeleteBuffers(processed - i - 1, &bufs[i+1]);
                                        break;
                                }
-
-                               ALint queued = 0;
-                               alGetSourcei(source_, AL_BUFFERS_QUEUED, &queued);
                        }
+                       else alDeleteBuffers(1, &buf);
                }
 
-               if (!stream_timer_.is_valid())
+               if (stream_timer_.is_valid() && 0 < target_diff)
                {
-                       stream_timer_.init(boost::bind(&impl::stream_update, this, _1, _2),
-                                       SCALAR(0.5), timer::repeat);
+                       for (int i = 0; i < target_diff; ++i)
+                       {
+                               if (!queue_buffer(AL_NONE)) break;
+                       }
                }
 
-               alSourcePlay(source_);
-               is_playing_ = true;
+               if (is_playing_)
+               {
+                       ALenum state;
+                       alGetSourcei(source_, AL_SOURCE_STATE, &state);
+                       if (state != AL_PLAYING)
+                       {
+                               // restart playing if we're stopped but supposed to be
+                               // playing...  this means we didn't queue enough...
+                               alSourcePlay(source_);
+                               log_warning("not enough audio buffered");
+                       }
+               }
        }
 
-
-       void update()
+       bool queue_buffer(ALuint buffer)
        {
-               ALint finished = 0;
-
-               alGetSourcei(source_, AL_BUFFERS_PROCESSED, &finished);
+               if (buffer == AL_NONE) alGenBuffers(1, &buffer);
 
-               while (finished-- > 0)
+               bool looped_once = false;
+               
+               while (0 < queue_.size())
                {
-                       buffer::unqueue(source_);
-                       bool streamed = false;
-                       //if (handle->is_loaded())
-                       //{
-                               //streamed = handle->read(buf);
-                       //}
-                       //else
-                       //{
-                               buffer buf;
-                               sound_handle handle = queue_.front();
-                               streamed = handle->read(buf, sample_);
-                       //}
-
-                       if (streamed)
+                       sound_handle sound = queue_.front();
+
+                       bool result = sound->read(buffer, sample_);
+                       if (result)
                        {
-                               buf.queue(source_);
+                               alSourceQueueBuffers(source_, 1, &buffer);
+                               return true;
                        }
                        else
                        {
-                               // the buffer couldn't be streamed, so get rid of it
-                               queue_.pop_front();
                                sample_ = 0;
+                               queue_.pop_front();
 
-                               if (!queue_.empty())
-                               {
-                                       // begin the next buffer in the queue
-                                       handle->read(buf, sample_);
-                                       buf.queue(source_);
-                               }
-                               else if (is_looping_)
+                               if (0 < queue_.size())
                                {
-                                       // reload the same buffer
-                                       queue_.push_back(handle);
-                                       handle->read(buf, sample_);
-                                       buf.queue(source_);
+                                       sound_handle new_sound = queue_.front();
+                                       result = new_sound->read(buffer, sample_, sound);
+                                       if (result)
+                                       {
+                                               queue_.push_back(new_sound);
+                                               alSourceQueueBuffers(source_, 1, &buffer);
+                                               num_buffers_ = new_sound->num_buffers(buffer_size_);
+                                               return true;
+                                       }
+                                       else
+                                       {
+                                               queue_.pop_front();
+                                               queue_.push_front(sound);
+                                       }
                                }
-                               else
+                               else if (is_looping_ && !looped_once)
                                {
-                                       // nothing more to play, stopping...
-                                       stop();
-                                       queue_.push_back(handle);
+                                       queue_.push_back(sound);
+                                       looped_once = true;
                                }
+                               else break;
                        }
                }
 
-               ALenum state;
-               alGetSourcei(source_, AL_SOURCE_STATE, &state);
-
-               // restart playing if we're stopped but supposed to be playing...
-               // this means we didn't queue enough and the audio skipped :-(
-               if (is_playing_ && state != AL_PLAYING)
-               {
-                       alSourcePlay(source_);
-               }
+               alDeleteBuffers(1, &buffer);
+               is_playing_ = false;
+               stream_timer_.invalidate();
+               return false;
        }
 
 
@@ -487,7 +476,7 @@ public:
 
                stream_timer_.invalidate();
 
-               // TODO: clear buffers if streaming
+               sample_ = 0;
        }
 
        void pause()
@@ -498,27 +487,22 @@ public:
                stream_timer_.invalidate();
        }
 
-       void rewind()
-       {
-               alSourceRewind(source_);
-               sample_ = 0;
-       }
-
 
        void sample(const std::string& name)
        {
                stop();
-               alSourcei(source_, AL_BUFFER, AL_NONE);
+               deplete_stream();
 
                queue_.clear();
-
-               enqueue(name);
+               queue(name);
+               is_streaming_ = false;
        }
 
-       void enqueue(const std::string& name)
+       void queue(const std::string& name)
        {
                sound_handle handle = resource::load(name, "ogg");
-               queue_.push_back(handle);
+               if (handle) queue_.push_back(handle);
+               is_streaming_ = true;
        }
 
 
@@ -538,7 +522,6 @@ public:
 
                ALenum type;
                alGetSourcei(source_, AL_SOURCE_TYPE, &type);
-
                if (type != AL_STREAMING)
                {
                        alSourcei(source_, AL_LOOPING, is_looping_);
@@ -548,7 +531,8 @@ public:
 
        void stream_update(timer& timer, scalar t)
        {
-               update();
+               //log_error("blaaaaaaaaaaaaaaaaaaaaaaaaaaahhhhhhhhhhhhhhhhrrrrrg");
+               fill_stream();
                // TODO: might be nice to also allow using threads for streaming
                // rather than a timer, probably as a compile-time option
        }
@@ -558,9 +542,12 @@ public:
 
        bool                                            is_playing_;
        bool                                            is_looping_;
+       bool                                            is_streaming_;
 
        std::deque<sound_handle>        queue_;
        uint64_t                                        sample_;
+       int                                                     num_buffers_;
+       scalar                                          buffer_size_;
 
        timer                                           stream_timer_;
 
@@ -583,17 +570,17 @@ void sound::sample(const std::string& path)
        impl_->sample(path);
 }
 
-void sound::enqueue(const std::string& path)
+void sound::queue(const std::string& path)
 {
        // pass through
-       impl_->enqueue(path);
+       impl_->queue(path);
 }
 
 
 void sound::play()
 {
        // pass through
-       impl_->stream();
+       impl_->play();
 }
 
 void sound::stop()
@@ -608,13 +595,6 @@ void sound::pause()
        impl_->pause();
 }
 
-void sound::rewind()
-{
-       // pass through
-       impl_->rewind();
-}
-
-
 void sound::toggle()
 {
        if (is_playing()) pause();
@@ -627,6 +607,11 @@ bool sound::is_playing() const
        return impl_->is_playing();
 }
 
+void sound::buffer_size(scalar seconds)
+{
+       impl_->buffer_size_ = seconds;
+}
+
 
 void sound::position(const vector3& position)
 {
index f920f49daf16804e735424fea855b4b207b38a03..d4c1bcdc9db5253ec849fec3fc2e58a1cd39a4fb 100644 (file)
@@ -38,16 +38,17 @@ public:
        explicit sound(const std::string& name);
 
        void sample(const std::string& name);
-       void enqueue(const std::string& name);
+       void queue(const std::string& name);
 
        void play();
        void stop();
        void pause();
-       void rewind();
 
        void toggle();
        bool is_playing() const;
 
+       void buffer_size(scalar seconds);
+
        void position(const vector3& position);
        void velocity(const vector3& velocity);
        void gain(scalar gain);
index 9e81aa34a4aa1880f932bcbb373f5419493b8d05..6849d91696e66f3fd2a625a968e6f165d43dc481 100644 (file)
@@ -18,16 +18,26 @@ namespace moof {
 
 static int sound_new(script& script)
 {
-       script::slot name = script[2].require_string("sound name");
-
        std::string str;
-       name.get(str);
-
-       script.push(sound(str));
+       if (script[2].get(str))
+       {
+               sound sound(str);
+
+               for (int i = 3; script[i]; ++i)
+               {
+                       if (script[i].get(str)) sound.queue(str);
+                       else break;
+               }
+
+               script.push(sound);
+               return 1;
+       }
+       
+       script.push(sound());
        return 1;
 }
 
-static int sound_enqueue(script& script)
+static int sound_sample(script& script)
 {
        sound* sound;
        script[1].require_object<moof::sound>("sound").get(sound);
@@ -35,39 +45,45 @@ static int sound_enqueue(script& script)
        std::string name;
        script[2].require_string("sound name").get(name);
 
-       sound->enqueue(name);
+       sound->sample(name);
        return 0;
 }
 
-static int sound_play(script& script)
+static int sound_queue(script& script)
 {
        sound* sound;
        script[1].require_object<moof::sound>("sound").get(sound);
-       sound->play();
+
+       std::string name;
+       for (int i = 2; script[i]; ++i)
+       {
+               if (script[i].get(name)) sound->queue(name);
+               else break;
+       }
        return 0;
 }
 
-static int sound_stop(script& script)
+static int sound_play(script& script)
 {
        sound* sound;
        script[1].require_object<moof::sound>("sound").get(sound);
-       sound->stop();
+       sound->play();
        return 0;
 }
 
-static int sound_pause(script& script)
+static int sound_stop(script& script)
 {
        sound* sound;
        script[1].require_object<moof::sound>("sound").get(sound);
-       sound->pause();
+       sound->stop();
        return 0;
 }
 
-static int sound_rewind(script& script)
+static int sound_pause(script& script)
 {
        sound* sound;
        script[1].require_object<moof::sound>("sound").get(sound);
-       sound->rewind();
+       sound->pause();
        return 0;
 }
 
@@ -95,11 +111,11 @@ void sound::import(script& script, const std::string& nspace)
        script::slot parent = script.push_table(nspace);
        script::slot meta = script.push_class<sound>(sound_new);
 
-       meta.set_field("enqueue", sound_enqueue);
+       meta.set_field("sample", sound_sample);
+       meta.set_field("queue", sound_queue);
        meta.set_field("play", sound_play);
        meta.set_field("stop", sound_stop);
        meta.set_field("pause", sound_pause);
-       meta.set_field("rewind", sound_rewind);
        meta.set_field("toggle", sound_toggle);
        meta.set_field("is_playing", sound_is_playing);
 
index 74acc1c203a9bc45b7cb894835e55b9e760162fc..f16a962dfa688b032ad92da9506a92c6b24ab416 100644 (file)
@@ -24,7 +24,7 @@
 namespace moof {
 
 
-scalar timer::next_expiration_ = std::numeric_limits<scalar>::max();
+scalar timer::next_event_ = std::numeric_limits<scalar>::max();
 hash<unsigned,timer*,hash_function> timer::timers_;
 
 
@@ -58,7 +58,7 @@ void timer::init(const function& function, scalar seconds, mode mode)
                id_ = new_identifier();
                timers_.insert(std::pair<unsigned,timer*>(id_, this));
 
-               if (absolute_ < next_expiration_) next_expiration_ = absolute_;
+               if (absolute_ < next_event_) next_event_ = absolute_;
        }
 }
 
@@ -75,9 +75,9 @@ void timer::invalidate()
                timers_.erase(id_);
                mode_ = invalid;
 
-               if (is_equal(absolute_, next_expiration_))
+               if (is_equal(absolute_, next_event_))
                {
-                       next_expiration_ = find_next_expiration();
+                       next_event_ = find_next_event();
                }
        }
 }
@@ -96,9 +96,9 @@ void timer::fire()
                if (is_equal(absolute_, t, 1.0)) absolute_ += interval_;
                else absolute_ = interval_ + t;
 
-               if (is_equal(absolute, next_expiration_))
+               if (is_equal(absolute, next_event_))
                {
-                       next_expiration_ = find_next_expiration();
+                       next_event_ = find_next_event();
                }
        }
        else
@@ -108,7 +108,7 @@ void timer::fire()
 }
 
 
-scalar timer::find_next_expiration()
+scalar timer::find_next_event()
 {
        scalar next_fire = std::numeric_limits<scalar>::max();
 
@@ -128,6 +128,11 @@ scalar timer::seconds_remaining() const
        return absolute_ - ticks();
 }
 
+scalar timer::next_expiration() const
+{
+       return absolute_;
+}
+
 bool timer::is_expired() const
 {
        return seconds_remaining() < 0.0;
@@ -141,7 +146,7 @@ bool timer::is_repeating() const
 
 void timer::fire_expired_timers(scalar t)
 {
-       if (next_expiration_ > t) return;
+       if (t < next_event_) return;
 
        hash<unsigned,timer*,hash_function>::iterator it;
        for (it = timers_.begin(); it.valid(); ++it)
@@ -191,18 +196,15 @@ scalar timer::ticks()
 
 void timer::sleep(scalar seconds, mode mode)
 {
-       struct timespec ts;
-       int ret;
-
        if (mode == absolute) seconds -= ticks();
-       ts.tv_sec = time_t(seconds);
-       ts.tv_nsec = long((seconds - scalar(ts.tv_sec)) * SCALAR(1000000000.0));
+       if (seconds < SCALAR(0.0)) return;
 
-       do
-       {
-               ret = nanosleep(&ts, &ts);
-       }
-       while (ret == -1 && errno == EINTR);
+       struct timespec ts;
+       ts.tv_sec = seconds;
+       ts.tv_nsec = (seconds - scalar(ts.tv_sec)) * SCALAR(1000000000.0);
+
+       int ret;
+       do ret = nanosleep(&ts, &ts); while (ret == -1 && errno == EINTR);
 }
 
 
@@ -211,18 +213,18 @@ void timer::sleep(scalar seconds, mode mode)
 
 // If we don't have posix timers, we'll have to use a different timing
 // method.  SDL only promises centisecond accuracy, but that's better than
-// a kick in the pants.  
+// a kick in the pants.  It could end up being just as good anyway.
 
 scalar timer::ticks()
 {
-       Uint32 ms = SDL_GetTicks();
-       return scalar(ms / 1000) + scalar(ms % 1000) * SCALAR(0.001);
+       return scalar(SDL_GetTicks()) * SCALAR(0.001);
 }
 
 void timer::sleep(scalar seconds, mode mode)
 {
        if (mode == absolute) seconds -= ticks();
-       SDL_Delay(Uint32(clamp(Uint32(seconds * SCALAR(1000.0)), 0, 1000)));
+       if (seconds < SCALAR(0.0)) return;
+       SDL_Delay(seconds * SCALAR(1000.0));
 }
 
 #endif // USE_CLOCK_GETTIME
index cb50c3bbc0f6d40a1328d584b93655abf945d2fa..f5c3583ccc0525c90adf616979fddfb82d8819ce 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
 
 #include <moof/hash.hh>
 #include <moof/math.hh>
@@ -33,7 +34,7 @@ namespace moof {
  * runloop associated with the current running view will make an attempt to
  * fire any expired timers as close to their scheduled times as possible.
  */
-class timer
+class timer : public boost::noncopyable
 {
 public:
 
@@ -148,6 +149,8 @@ public:
         */
        scalar seconds_remaining() const;
 
+       scalar next_expiration() const;
+
        /**
         * Get whether or not the timer is expired.  A timer on a repeating
         * schedule will never be expired since it will always have a scheduled
@@ -191,9 +194,9 @@ public:
         * Get the absolute time when the next timer is scheduled to expire.
         * \return Absolute time, in seconds.
         */
-       static scalar next_expiration()
+       static scalar next_event()
        {
-               return next_expiration_;
+               return next_event_;
        }
 
 
@@ -216,7 +219,7 @@ public:
 private:
 
        static unsigned new_identifier();
-       static scalar find_next_expiration();
+       static scalar find_next_event();
 
        function        function_;
        mode            mode_;
@@ -224,7 +227,7 @@ private:
        scalar          interval_;
        unsigned        id_;
 
-       static scalar                                                           next_expiration_;
+       static scalar                                                           next_event_;
        static hash<unsigned,timer*,hash_function>      timers_;
 };
 
index 5c10378022032afc7e3aceaaedee110893392808..ab0058b5b115954262d0c105d3cba85791484a2d 100644 (file)
 namespace moof {
 
 
+// Timestep Example Source Code
+// Copyright (c) Glenn Fiedler 2004
+// http://www.gaffer.org/articles
+
+struct State
+{
+       float x;
+       float v;
+};
+
+struct Derivative
+{
+       float dx;
+       float dv;
+};
+
+State interpolate(const State &previous, const State &current, float alpha)
+{
+       State state;
+       state.x = current.x*alpha + previous.x*(1-alpha);
+       state.v = current.v*alpha + previous.v*(1-alpha);
+       return state;
+}
+
+float acceleration(const State &state, float t)
+{
+       const float k = 10;
+       const float b = 1;
+       return - k*state.x - b*state.v;
+}
+
+Derivative evaluate(const State &initial, float t)
+{
+       Derivative output;
+       output.dx = initial.v;
+       output.dv = acceleration(initial, t);
+       return output;
+}
+
+Derivative evaluate(const State &initial, float t, float dt, const Derivative &d)
+{
+       State state;
+       state.x = initial.x + d.dx*dt;
+       state.v = initial.v + d.dv*dt;
+       Derivative output;
+       output.dx = state.v;
+       output.dv = acceleration(state, t+dt);
+       return output;
+}
+
+void integrate(State &state, float t, float dt)
+{
+       Derivative a = evaluate(state, t);
+       Derivative b = evaluate(state, t, dt*0.5f, a);
+       Derivative c = evaluate(state, t, dt*0.5f, b);
+       Derivative d = evaluate(state, t, dt, c);
+       
+       const float dxdt = 1.0f/6.0f * (a.dx + 2.0f*(b.dx + c.dx) + d.dx);
+       const float dvdt = 1.0f/6.0f * (a.dv + 2.0f*(b.dv + c.dv) + d.dv);
+       
+       state.x = state.x + dxdt*dt;
+       state.v = state.v + dvdt*dt;
+}
+
+
 class root_view : public view
 {
        void update(scalar t, scalar dt)
@@ -93,10 +158,57 @@ public:
         * function will return the exit code used to stop the loop.
         */
 
+       scalar nextUpdate;
+       scalar totalTime;
+
+       void U(timer& T, scalar t)
+       {
+               const int MAX_FRAMESKIP = 15;
+
+               log_info("update");
+
+               int i = 0;
+               while (nextUpdate < t && ++i < MAX_FRAMESKIP)
+               {
+                       totalTime += timestep_;                 // 3. update state
+                       view_.update(totalTime, timestep_);
+
+                       //previous = current;
+                       //integrate(current, totalTime, timestep);
+
+                       nextUpdate += timestep_;
+               }
+       }
+
+       void D(timer& T, scalar t)
+       {
+               const scalar inverseTimestep = SCALAR(1.0) / timestep_;
+
+               log_info("draw");
+
+               scalar alpha = (t + timestep_ - nextUpdate) * inverseTimestep;
+               //scalar alpha = (nextUpdate - t) * inverseTimestep;
+               if (alpha < SCALAR(0.0)) log_error("UH OH!!!!!  It's NEGATIVE", alpha);
+               if (alpha > SCALAR(1.0)) log_error("UH OH!!!!!  It's POSITIVE", alpha);
+               log_info("alpha:", alpha);
+
+               view_.draw(alpha);
+               video_->swap();                                 // 4. draw state
+       }
+
+       timer utimer, dtimer;
+
        void run()
        {
                ASSERT(video_ && "running without video set");
 
+               utimer.init(boost::bind(&impl::U, this, _1, _2), timestep_, timer::repeat);
+               dtimer.init(boost::bind(&impl::D, this, _1, _2), framerate_, timer::repeat);
+
+               totalTime = 0.0f;
+               nextUpdate = timer::ticks();
+
+
                scalar totalTime = 0.0;
                scalar ticks = timer::ticks();
 
@@ -107,7 +219,7 @@ public:
                fps_ = 0;
                int frameCount = 0;
 
-               const scalar timestep = timestep_;
+               const scalar timestep = SCALAR(0.01);//timestep_;
                const scalar framerate = framerate_;
 
                const int MAX_FRAMESKIP = 15;
@@ -119,44 +231,97 @@ public:
                        timer::fire_expired_timers();           // 1. fire timers
                        dispatch_events();                                      // 2. dispatch events
 
-                       if (!is_running_) break;
-
-                       int i = 0;
-                       while (nextUpdate < timer::ticks() && i < MAX_FRAMESKIP)
-                       {
-                               totalTime += timestep;                  // 3. update state
-                               view_.update(totalTime, timestep);
-
-                               nextUpdate += timestep;
-                               ++i;
-
-                               if (!is_running_) break;
-                       }
-
-                       if (nextDraw < (ticks = timer::ticks()))
-                       {
-                               view_.draw(
-                                        (ticks + timestep - nextUpdate) * inverseTimestep);
-                               video_->swap();                                 // 4. draw state
-
-                               nextDraw += framerate;
-                               ++frameCount;
-
-                               if (nextSecond < timer::ticks())
-                               {
-                                       fps_ = frameCount;
-                                       frameCount = 0;
+                       //if (!is_running_) break;
+
+                       //int i = 0;
+                       //while (nextUpdate < timer::ticks() && i < MAX_FRAMESKIP)
+                       //{
+                               //totalTime += timestep;                        // 3. update state
+                               //view_.update(totalTime, timestep);
+
+                               ////previous = current;
+                               ////integrate(current, totalTime, timestep);
+
+                               //nextUpdate += timestep;
+                               //++i;
+
+                               //if (!is_running_) break;
+                       //}
+
+               ////const float newTime = timer::ticks();
+               ////float deltaTime = newTime - currentTime;
+               ////currentTime = newTime;
+               
+               ////if (deltaTime>0.25f)
+                       ////deltaTime = 0.25f;
+               
+               ////accumulator += deltaTime;
+               
+               ////while (accumulator>=dt)
+               ////{
+                       ////accumulator -= dt;
+                       ////previous = current;
+                       ////integrate(current, t, dt);
+                       ////t += dt;
+               ////}
+
+                       ////if (nextDraw < (ticks = timer::ticks()))
+                       ////{
+                       //ticks = timer::ticks();
+                               //scalar diff = ticks - nextDraw;
+                               ////log_info("difference:", diff);
+                               //scalar alpha = (ticks + timestep - nextUpdate) * inverseTimestep;
+                               ////scalar alpha = (nextUpdate - ticks) * inverseTimestep;
+                               ////float alpha = accumulator/dt;
+                               //if (alpha < SCALAR(0.0)) log_error("UH OH!!!!!  It's NEGATIVE", alpha);
+                               //if (alpha > SCALAR(1.0)) log_error("UH OH!!!!!  It's POSITIVE", alpha);
+                               //log_info("alpha:", alpha);
+
+                               //view_.draw(alpha);
+
+                               //// TEMP
+                       ////State state = interpolate(previous, current, alpha);
+                       ////glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+                       ////glBegin(GL_POINTS);
+                       ////glColor3f(1,1,1);
+                       ////glVertex3f(state.x, 0, 0);
+                       ////glEnd();
+               
+
+
+                               //video_->swap();                                       // 4. draw state
+
+                               //nextDraw += framerate;
+                               //++frameCount;
+
+                               //if (nextSecond < ticks)//timer::ticks())
+                               //{
+                                       //fps_ = frameCount;
+                                       //frameCount = 0;
+
+                                       //if (show_fps_) log_info << fps_ << " fps" << std::endl;
+
+                                       //nextSecond += SCALAR(1.0);
+                               //}
+                       ////}
 
-                                       if (show_fps_) log_info << fps_ << " fps" << std::endl;
+                       if (!is_running_) break;
 
-                                       nextSecond += SCALAR(1.0);
-                               }
-                       }
+                       //ticks = timer::ticks();                               // 5. yield timeslice
+                       //scalar next = std::min(nextUpdate, nextDraw);
+                       //next = std::min(next, timer::next_event());
+                       //if (ticks < next) timer::sleep(next, timer::absolute);
 
-                       if (!is_running_) break;
+                       timer::sleep(timer::next_event(), timer::absolute);
 
-                       ticks = timer::ticks();                         // 5. yield timeslice
-                       if (ticks < nextUpdate && ticks < nextDraw) timer::sleep(0.0);
+                       // Animation is choppy... the sound timer makes the draw occur
+                       // late.  It's not usually enough to make the FPS drop, but it
+                       // certainly is noticeably choppy.  Maybe update and draw
+                       // should both be scheduled like timers.  That should reduce
+                       // the number of times either update or draw occur late.  It
+                       // doesn't really matter if update is late, but it's ugly if
+                       // draw is late.
                }
        }
 
This page took 0.069958 seconds and 4 git commands to generate.