diff options
| author | Bent Bisballe Nyeng <deva@aasimon.org> | 2015-04-23 15:20:48 +0200 | 
|---|---|---|
| committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2016-01-20 13:24:28 +0100 | 
| commit | b67e30cb862ab640e4a7ced48b1905b2421885b9 (patch) | |
| tree | 73bc34c7c88a6ba33ca6a9c22ed43cff86376e11 /src | |
| parent | eaa2062ea50fea853fa1852b152354ba50d44985 (diff) | |
Added run sempahore (wait until thread actually started). Fixed localpos bug. Added 'threaded' argument to init that handles events either directly or in a thread when dispatched. Added cachemanager unit test (currently failing).
Diffstat (limited to 'src')
| -rw-r--r-- | src/cachemanager.cc | 151 | ||||
| -rw-r--r-- | src/cachemanager.h | 13 | ||||
| -rw-r--r-- | src/drumgizmo.cc | 14 | ||||
| -rw-r--r-- | src/drumkitloader.cc | 3 | 
4 files changed, 120 insertions, 61 deletions
| diff --git a/src/cachemanager.cc b/src/cachemanager.cc index 3984447..e6c43cc 100644 --- a/src/cachemanager.cc +++ b/src/cachemanager.cc @@ -48,7 +48,9 @@ static size_t readChunk(std::string filename, int filechannel, size_t pos,      return 0;    } -  if(pos > sf_info.frames) return 0; +  if(pos > sf_info.frames) { +    return 0; +  }    sf_seek(fh, pos, SEEK_SET); @@ -57,11 +59,11 @@ static size_t readChunk(std::string filename, int filechannel, size_t pos,    sample_t* data = buf;    if(sf_info.channels == 1) { -    size = sf_read_float(fh, data, size); +    size = sf_readf_float(fh, data, size);    } else {      // check filechannel exists      if(filechannel >= sf_info.channels) { -        filechannel = sf_info.channels - 1; +      filechannel = sf_info.channels - 1;      }      sample_t buffer[BUFFER_SIZE];      int readsize = BUFFER_SIZE / sf_info.channels; @@ -89,8 +91,10 @@ CacheManager::~CacheManager()    deinit();  } -void CacheManager::init(size_t poolsize) +void CacheManager::init(size_t poolsize, bool threaded)  { +  this->threaded = threaded; +    for(size_t i = 0; i < FRAMESIZE; i++) {      nodata[i] = 0;    } @@ -101,21 +105,26 @@ void CacheManager::init(size_t poolsize)    }    running = true; -  run(); - -  // TODO: Add semaphore +  if(threaded) { +    run(); +    sem_run.wait(); +  }  }  void CacheManager::deinit()  {    if(!running) return;    running = false; -  wait_stop(); +  if(threaded) { +    sem.post(); +    wait_stop(); +  }  }  // Invariant: initial_samples_needed < preloaded audio data   // Proposal: preloaded > 2 x CHUNKSIZE? So that we can fill c.front immediatly on open -sample_t *CacheManager::open(AudioFile *file, size_t initial_samples_needed, int channel, cacheid_t &id)  +sample_t *CacheManager::open(AudioFile *file, size_t initial_samples_needed, +                             int channel, cacheid_t &id)  {    {      MutexAutolock l(m_ids); @@ -139,7 +148,11 @@ sample_t *CacheManager::open(AudioFile *file, size_t initial_samples_needed, int    c.front = new sample_t[CHUNKSIZE];    c.back = new sample_t[CHUNKSIZE]; -  memcpy(c.front, c.file->data + c.pos, CHUNKSIZE * sizeof(sample_t)); +  size_t size = CHUNKSIZE; +  if(size > file->size) size = file->size; +  memcpy(c.front, c.file->data + c.pos, size * sizeof(sample_t)); +  c.ready = false; +  //c.pos += size;    // Increase audio ref count @@ -148,36 +161,17 @@ sample_t *CacheManager::open(AudioFile *file, size_t initial_samples_needed, int      id2cache[id] = c;    } +  // Only load next buffer if there are more data in the file to be loaded...    if(initial_samples_needed < file->size) {      cevent_t e =        createLoadNextEvent(c.file, c.channel, c.pos + CHUNKSIZE, c.back); +    e.ready = &id2cache[id].ready;      pushEvent(e);    }    return file->data; // preloaded data  } -void CacheManager::close(cacheid_t id) -{ -  if(id == CACHE_DUMMYID) return; - -  cevent_t e = createCloseEvent(id); -  pushEvent(e); - -  { -//    event_t e = createEvent(id, CLEAN); -//    MutexAutolock l(m_events);  -//    eventqueue.push_front(e); -  } -   -  { -    MutexAutolock l(m_ids); -    availableids.push_back(id); -  } -  // Clean cache_t mapped to event -  // Decrement audiofile ref count -} -  sample_t *CacheManager::next(cacheid_t id, size_t &size)   {    size = FRAMESIZE; @@ -188,8 +182,13 @@ sample_t *CacheManager::next(cacheid_t id, size_t &size)    cache_t& c = id2cache[id];    if(c.localpos < CHUNKSIZE) { +    sample_t *s = c.front + c.localpos;      c.localpos += size; -    return c.front + c.localpos; +    return s; +  } + +  if(!c.ready) { +    printf("\nNOT READY!\n");    }    // Swap buffers @@ -197,22 +196,46 @@ sample_t *CacheManager::next(cacheid_t id, size_t &size)    c.front = c.back;    c.back = tmp; -  c.localpos = 0; +  c.localpos = size; // Next time we go here we have already read the first frame.    c.pos += CHUNKSIZE;    if(c.pos < c.file->size) { -    cevent_t e = createLoadNextEvent(c.file, c.channel, c.pos, c.back); +    cevent_t e = createLoadNextEvent(c.file, c.channel, c.pos + CHUNKSIZE, c.back); +    c.ready = false; +    e.ready = &c.ready;      pushEvent(e);    }     return c.front;  } +void CacheManager::close(cacheid_t id) +{ +return; + +  if(id == CACHE_DUMMYID) return; + +  cevent_t e = createCloseEvent(id); +  pushEvent(e); + +  // Clean cache_t mapped to event +  // Decrement audiofile ref count +} +  void CacheManager::handleLoadNextEvent(cevent_t &e)   { -//  memcpy(e.buffer, e.file->data + e.pos, CHUNKSIZE * sizeof(sample_t)); +#if 0 // memcpy +  size_t size = CHUNKSIZE; +  if(size > (e.file->size - e.pos)) { +    size = (e.file->size - e.pos); +  } +  memcpy(e.buffer, e.file->data + e.pos, size * sizeof(sample_t)); +#elif 1 // diskread +  //memset(e.buffer, 0, CHUNKSIZE * sizeof(sample_t));    readChunk(e.file->filename, e.channel, e.pos, CHUNKSIZE, e.buffer); +#endif +  *e.ready = true;  }  void CacheManager::handleCloseEvent(cevent_t &e)  @@ -220,44 +243,66 @@ void CacheManager::handleCloseEvent(cevent_t &e)    cache_t& c = id2cache[e.id];    delete[] c.front;    delete[] c.back; + +  { +    MutexAutolock l(m_ids); +    availableids.push_back(e.id); +  } +    // TODO: Count down ref coutner on c.file and close it if 0.  } + +void CacheManager::handleEvent(cevent_t &e) +{ +  switch(e.cmd) { +  case LOADNEXT: +    handleLoadNextEvent(e); +    break; +  case CLOSE: +    handleCloseEvent(e); +    break; +  } +} +  void CacheManager::thread_main()  { +  sem_run.post(); // Signal that the thread has been started +    while(running) {      sem.wait();      m_events.lock(); -    if(!eventqueue.empty()) { -      cevent_t e = eventqueue.front(); -      eventqueue.pop_front(); -      m_events.unlock(); - -      // TODO: Skip event if e.pos < cache.pos  -//      if(!e.active) continue; - -      switch(e.cmd) {   -        case LOADNEXT: -          handleLoadNextEvent(e); -          break; -        case CLOSE: -          handleCloseEvent(e); -          break; -      }       -    } else { +    if(eventqueue.empty()) {        m_events.unlock(); +      continue;      } + +    cevent_t e = eventqueue.front(); +    eventqueue.pop_front(); +    m_events.unlock(); + +    // TODO: Skip event if e.pos < cache.pos +    // if(!e.active) continue; + +    handleEvent(e);    }  }  void CacheManager::pushEvent(cevent_t e)  { -  // Check that if event should be merged (Maybe by event queue (ie. push in front). +  if(!threaded) { +    handleEvent(e); +    return; +  } + +  // Check that if event should be merged (Maybe by event queue (ie. push +  // in front).    {      MutexAutolock l(m_events);      eventqueue.push_back(e);    } +    sem.post();  } diff --git a/src/cachemanager.h b/src/cachemanager.h index 25115c3..f2c0122 100644 --- a/src/cachemanager.h +++ b/src/cachemanager.h @@ -41,8 +41,9 @@  #define CACHE_DUMMYID -2  #define CACHE_NOID -1 -#define FRAMESIZE 256 -#define CHUNKSIZE FRAMESIZE*100 +#define FRAMESIZE 2048 +#define CHUNKSIZE (FRAMESIZE * 16) +#define PRELOADSIZE (FRAMESIZE + CHUNKSIZE)  class AudioFile;  typedef int cacheid_t; @@ -88,7 +89,7 @@ public:     * This method blocks until the thread has been started.     * @param poolsize The maximum number of parellel events supported.      */ -  void init(size_t poolsize); +  void init(size_t poolsize, bool threaded);    /**     * Stop thread and clean up resources. @@ -138,6 +139,7 @@ private:      AudioFile *file;      size_t channel;      size_t pos; //< File possition +    volatile bool ready;      sample_t *front;      sample_t *back;      size_t localpos; //< Intra buffer (front) position. @@ -157,6 +159,7 @@ private:      // For load next event:      size_t pos;      sample_t *buffer; +    volatile bool *ready;      AudioFile *file;      size_t channel;    } cevent_t; @@ -168,6 +171,7 @@ private:    void handleLoadNextEvent(cevent_t &e);    void handleCloseEvent(cevent_t &e); +  void handleEvent(cevent_t &e);    void pushEvent(cevent_t e);    std::vector<cache_t> id2cache;  @@ -179,8 +183,9 @@ private:    Mutex m_events;    Mutex m_ids; +  bool threaded; // Indicates if we are running in thread mode or offline mode.    Semaphore sem; - +  Semaphore sem_run;    bool running;  }; diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc index 2f04488..6c40748 100644 --- a/src/drumgizmo.cc +++ b/src/drumgizmo.cc @@ -50,7 +50,7 @@ DrumGizmo::DrumGizmo(AudioOutputEngine *o, AudioInputEngine *i)      loader(), oe(o), ie(i)  {    is_stopping = false; -  cacheManager.init(1000); // start thread +  cacheManager.init(1000, true); // start thread  }  DrumGizmo::~DrumGizmo() @@ -415,10 +415,18 @@ void DrumGizmo::getSamples(int ch, int pos, sample_t *s, size_t sz)          {          MutexAutolock l(af->mutex); -        size_t n = 0; +        size_t n = 0; // default start point is 0. + +        // If we are not at offset 0 in current buffer:          if(evt->offset > (size_t)pos) n = evt->offset - pos; -        size_t end = sz; + +        size_t end = sz; // default end point is the end of the buffer. + +        // Find the end point intra-buffer          if((evt->t + end - n) > af->size) end = af->size - evt->t + n; + +        // This should not be necessary but make absolutely shure that we do +        // not write over the end of the buffer.          if(end > sz) end = sz;          if(evt->rampdown == NO_RAMPDOWN) { diff --git a/src/drumkitloader.cc b/src/drumkitloader.cc index bf01db6..2b66ae0 100644 --- a/src/drumkitloader.cc +++ b/src/drumkitloader.cc @@ -30,6 +30,7 @@  #include "drumkitparser.h"  #include "drumgizmo.h" +#include "cachemanager.h"  DrumKitLoader::DrumKitLoader()    : semaphore("drumkitloader") @@ -136,7 +137,7 @@ void DrumKitLoader::thread_main()        AudioFile *audiofile = load_queue.front();        load_queue.pop_front();        filename = audiofile->filename; -      audiofile->load(); +      audiofile->load(PRELOADSIZE);      }      loaded++; | 
