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
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
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
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
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 }