loop_point_source.cpp

Go to the documentation of this file.
00001 #include <vector>
00002 #include "audiere.h"
00003 #include "debug.h"
00004 #include "internal.h"
00005 #include "utility.h"
00006 
00007 
00008 namespace audiere {
00009 
00010   struct LoopPoint {
00011     int location;
00012     int target;
00013     int loopCount;
00014     int originalLoopCount;
00015 
00016     bool operator<(const LoopPoint& rhs) const {
00017       return location < rhs.location;
00018     }
00019   };
00020 
00021   class LoopPointSourceImpl : public RefImplementation<LoopPointSource> {
00022   public:
00023     LoopPointSourceImpl(SampleSource* source) {
00024       source->reset();
00025       m_source = source;
00026       m_length = m_source->getLength();
00027 
00028       m_frame_size = GetFrameSize(source);
00029     }
00030 
00031 
00032     // LoopPointSource implementation
00033 
00034     void ADR_CALL addLoopPoint(int location, int target, int loopCount) {
00035       LoopPoint lp;
00036       lp.location          = clamp(0, location, m_length);
00037       lp.target            = clamp(0, target,   m_length);
00038       lp.loopCount         = loopCount;
00039       lp.originalLoopCount = lp.loopCount;
00040 
00041       for (size_t i = 0; i < m_loop_points.size(); ++i) {
00042         if (m_loop_points[i].location == location) {
00043           m_loop_points[i] = lp;
00044           return;
00045         }
00046       }
00047 
00048       m_loop_points.push_back(lp);
00049       size_t idx = m_loop_points.size() - 1;
00050       while (idx > 0 && m_loop_points[idx] < m_loop_points[idx - 1]) {
00051         std::swap(m_loop_points[idx], m_loop_points[idx - 1]);
00052         --idx;
00053       }
00054     }
00055 
00056     void ADR_CALL removeLoopPoint(int index) {
00057       m_loop_points.erase(m_loop_points.begin() + index);
00058     }
00059 
00060     int ADR_CALL getLoopPointCount() {
00061       return static_cast<int>(m_loop_points.size());
00062     }
00063 
00064     bool ADR_CALL getLoopPoint(
00065       int index, int& location, int& target, int& loopCount)
00066     {
00067       if (index < 0 || index >= getLoopPointCount()) {
00068         return false;
00069       }
00070 
00071       location  = m_loop_points[index].location;
00072       target    = m_loop_points[index].target;
00073       loopCount = m_loop_points[index].originalLoopCount;
00074       return true;
00075     }
00076 
00077     
00078     // SampleSource implementation
00079 
00080     void ADR_CALL getFormat(
00081       int& channel_count, int& sample_rate, SampleFormat& sample_format)
00082     {
00083       m_source->getFormat(channel_count, sample_rate, sample_format);
00084     }
00085 
00086 
00087     int ADR_CALL read(int fc, void* buffer) {
00088       const int frame_count = fc;
00089 
00090       // not repeating?  then ignore loop points.
00091       if (!m_source->getRepeat()) {
00092         return m_source->read(frame_count, buffer);
00093       }
00094 
00095       int frames_read = 0;
00096       int frames_left = frame_count;
00097       u8* out = (u8*)buffer;
00098 
00099       while (frames_left > 0) {
00100         int position = m_source->getPosition();
00101         int next_point_idx = getNextLoopPoint(position);
00102         int next_point = (next_point_idx == -1
00103                             ? m_length
00104                             : m_loop_points[next_point_idx].location);
00105         int to_read = std::min(frames_left, next_point - position);
00106         ADR_ASSERT(to_read >= 0, "How can we read a negative number of frames?");
00107 
00108         int read = m_source->read(to_read, out);
00109         out += read * m_frame_size;
00110         frames_read += read;
00111         frames_left -= read;
00112 
00113         if (read != to_read) {
00114           return frames_read;
00115         }
00116 
00117         if (position + read == next_point) {
00118           if (next_point_idx == -1) {
00119             m_source->setPosition(0);
00120           } else {
00121             LoopPoint& lp = m_loop_points[next_point_idx];
00122 
00123             bool doloop = (lp.originalLoopCount <= 0 || lp.loopCount > 0);
00124             if (doloop && lp.originalLoopCount > 0) {
00125               --lp.loopCount;
00126             }
00127 
00128             if (doloop) {
00129               if (lp.target == lp.location) {
00130                 return frames_read;
00131               }
00132               m_source->setPosition(lp.target);
00133             }
00134           }
00135         }
00136       }
00137 
00138       return frames_read;
00139     }
00140 
00141     int getNextLoopPoint(int position) {
00142       for (size_t i = 0; i < m_loop_points.size(); ++i) {
00143         if (position < m_loop_points[i].location) {
00144           return static_cast<int>(i);
00145         }
00146       }
00147       return -1;
00148     }
00149 
00150 
00151     void ADR_CALL reset() {
00152       for (size_t i = 0; i < m_loop_points.size(); ++i) {
00153         m_loop_points[i].loopCount = m_loop_points[i].originalLoopCount;
00154       }
00155 
00156       m_source->reset();
00157     }
00158 
00159 
00160     bool ADR_CALL isSeekable() {
00161       // must be seekable, otherwise this class wouldn't even be instantiated
00162       return true;
00163     }
00164 
00165     int ADR_CALL getLength() {
00166       return m_length;
00167     }
00168 
00169     void ADR_CALL setPosition(int position) {
00170       m_source->setPosition(position);
00171     }
00172 
00173     int ADR_CALL getPosition() {
00174       return m_source->getPosition();
00175     }
00176 
00177     bool ADR_CALL getRepeat() {
00178       return m_source->getRepeat();
00179     }
00180 
00181     void ADR_CALL setRepeat(bool repeat) {
00182       m_source->setRepeat(repeat);
00183     }
00184 
00185     int ADR_CALL getTagCount()              { return m_source->getTagCount();  }
00186     const char* ADR_CALL getTagKey(int i)   { return m_source->getTagKey(i);   }
00187     const char* ADR_CALL getTagValue(int i) { return m_source->getTagValue(i); }
00188     const char* ADR_CALL getTagType(int i)  { return m_source->getTagType(i);  }
00189 
00190 
00191   private:
00192     SampleSourcePtr m_source;
00193     int m_length;
00194     int m_frame_size;
00195 
00196     std::vector<LoopPoint> m_loop_points;
00197   };
00198 
00199 
00200   ADR_EXPORT(LoopPointSource*) AdrCreateLoopPointSource(
00201     SampleSource* source)
00202   {
00203     if (!source || !source->isSeekable()) {
00204       return 0;
00205     }
00206 
00207     return new LoopPointSourceImpl(source);
00208   }
00209   
00210 }

Generated on Mon Feb 13 23:07:47 2006 for audiere by  doxygen 1.4.6