1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
#include <vector>
#include "audiere.h"
#include "debug.h"
#include "internal.h"
#include "utility.h"
namespace audiere {
struct LoopPoint {
int location;
int target;
int loopCount;
int originalLoopCount;
bool operator<(const LoopPoint& rhs) const {
return location < rhs.location;
}
};
class LoopPointSourceImpl : public RefImplementation<LoopPointSource> {
public:
LoopPointSourceImpl(SampleSource* source) {
source->reset();
m_source = source;
m_length = m_source->getLength();
m_frame_size = GetFrameSize(source);
}
// LoopPointSource implementation
void ADR_CALL addLoopPoint(int location, int target, int loopCount) {
LoopPoint lp;
lp.location = clamp(0, location, m_length);
lp.target = clamp(0, target, m_length);
lp.loopCount = loopCount;
lp.originalLoopCount = lp.loopCount;
for (size_t i = 0; i < m_loop_points.size(); ++i) {
if (m_loop_points[i].location == location) {
m_loop_points[i] = lp;
return;
}
}
m_loop_points.push_back(lp);
size_t idx = m_loop_points.size() - 1;
while (idx > 0 && m_loop_points[idx] < m_loop_points[idx - 1]) {
std::swap(m_loop_points[idx], m_loop_points[idx - 1]);
--idx;
}
}
void ADR_CALL removeLoopPoint(int index) {
m_loop_points.erase(m_loop_points.begin() + index);
}
int ADR_CALL getLoopPointCount() {
return static_cast<int>(m_loop_points.size());
}
bool ADR_CALL getLoopPoint(
int index, int& location, int& target, int& loopCount)
{
if (index < 0 || index >= getLoopPointCount()) {
return false;
}
location = m_loop_points[index].location;
target = m_loop_points[index].target;
loopCount = m_loop_points[index].originalLoopCount;
return true;
}
// SampleSource implementation
void ADR_CALL getFormat(
int& channel_count, int& sample_rate, SampleFormat& sample_format)
{
m_source->getFormat(channel_count, sample_rate, sample_format);
}
int ADR_CALL read(int fc, void* buffer) {
const int frame_count = fc;
// not repeating? then ignore loop points.
if (!m_source->getRepeat()) {
return m_source->read(frame_count, buffer);
}
int frames_read = 0;
int frames_left = frame_count;
u8* out = (u8*)buffer;
while (frames_left > 0) {
int position = m_source->getPosition();
int next_point_idx = getNextLoopPoint(position);
int next_point = (next_point_idx == -1
? m_length
: m_loop_points[next_point_idx].location);
int to_read = std::min(frames_left, next_point - position);
ADR_ASSERT(to_read >= 0, "How can we read a negative number of frames?");
int read = m_source->read(to_read, out);
out += read * m_frame_size;
frames_read += read;
frames_left -= read;
if (read != to_read) {
return frames_read;
}
if (position + read == next_point) {
if (next_point_idx == -1) {
m_source->setPosition(0);
} else {
LoopPoint& lp = m_loop_points[next_point_idx];
bool doloop = (lp.originalLoopCount <= 0 || lp.loopCount > 0);
if (doloop && lp.originalLoopCount > 0) {
--lp.loopCount;
}
if (doloop) {
if (lp.target == lp.location) {
return frames_read;
}
m_source->setPosition(lp.target);
}
}
}
}
return frames_read;
}
int getNextLoopPoint(int position) {
for (size_t i = 0; i < m_loop_points.size(); ++i) {
if (position < m_loop_points[i].location) {
return static_cast<int>(i);
}
}
return -1;
}
void ADR_CALL reset() {
for (size_t i = 0; i < m_loop_points.size(); ++i) {
m_loop_points[i].loopCount = m_loop_points[i].originalLoopCount;
}
m_source->reset();
}
bool ADR_CALL isSeekable() {
// must be seekable, otherwise this class wouldn't even be instantiated
return true;
}
int ADR_CALL getLength() {
return m_length;
}
void ADR_CALL setPosition(int position) {
m_source->setPosition(position);
}
int ADR_CALL getPosition() {
return m_source->getPosition();
}
bool ADR_CALL getRepeat() {
return m_source->getRepeat();
}
void ADR_CALL setRepeat(bool repeat) {
m_source->setRepeat(repeat);
}
int ADR_CALL getTagCount() { return m_source->getTagCount(); }
const char* ADR_CALL getTagKey(int i) { return m_source->getTagKey(i); }
const char* ADR_CALL getTagValue(int i) { return m_source->getTagValue(i); }
const char* ADR_CALL getTagType(int i) { return m_source->getTagType(i); }
private:
SampleSourcePtr m_source;
int m_length;
int m_frame_size;
std::vector<LoopPoint> m_loop_points;
};
ADR_EXPORT(LoopPointSource*) AdrCreateLoopPointSource(
SampleSource* source)
{
if (!source || !source->isSeekable()) {
return 0;
}
return new LoopPointSourceImpl(source);
}
}
|