-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AudioSource v2 API #1317
AudioSource v2 API #1317
Changes from 1 commit
3dad001
a942fe3
67353de
f8e5ddc
e1b6b07
baae34f
661691b
e1bcb82
c713d3c
7d6c622
a02fa40
36c51de
844cf35
085ff55
76215d2
f32e4ef
23be952
09f0e38
6d94410
a0cdbff
06bbc86
000441f
a5f4729
e4bd431
8d3b5c9
7aebcfe
d375111
1c7fe91
7a52da4
4a445a9
e323c74
828c2f2
e2586c9
5777283
820d086
4c4173b
2daa790
b382524
43b4cd9
bd4a2d2
2b1ecda
a51f666
bc32b72
f9a5364
dddc728
42184da
0db7619
d72fb9f
f239392
b1a8328
03222e3
a02cffd
30a8251
0985786
10f2f81
9bd0c33
b1d7fb2
38e8e21
1b4af53
6faefb5
bdef9be
e3bedc5
9420f2a
51cefc5
124df54
70b341c
a54db81
19da4ce
445a48b
de761e3
b7566c3
a257340
407b7f2
9382025
755d55b
ee517e3
8822348
66eaa75
70e29d5
665cf61
f63e2fa
d6765cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
#include "test/mixxxtest.h" | ||
#include "util/readaheadsamplebuffer.h" | ||
|
||
|
||
class ReadAheadSampleBufferTest: public MixxxTest { | ||
public: | ||
ReadAheadSampleBufferTest() | ||
|
@@ -15,29 +16,29 @@ class ReadAheadSampleBufferTest: public MixxxTest { | |
protected: | ||
static const SINT kCapacity; | ||
|
||
SINT write(mixxx::ReadAheadSampleBuffer* pSampleBuffer, SINT size) { | ||
SINT writeToTail(mixxx::ReadAheadSampleBuffer* pSampleBuffer, SINT size) { | ||
const mixxx::SampleBuffer::WritableSlice writableSlice( | ||
pSampleBuffer->write(size)); | ||
pSampleBuffer->writeToTail(size)); | ||
for (SINT i = 0; i < writableSlice.size(); ++i) { | ||
writableSlice[i] = m_writeValue; | ||
m_writeValue += CSAMPLE_ONE; | ||
} | ||
return writableSlice.size(); | ||
} | ||
|
||
SINT readFifoAndVerify(mixxx::ReadAheadSampleBuffer* pSampleBuffer, SINT size) { | ||
SINT readFromHeadAndVerify(mixxx::ReadAheadSampleBuffer* pSampleBuffer, SINT size) { | ||
const mixxx::SampleBuffer::ReadableSlice readableSlice( | ||
pSampleBuffer->readFifo(size)); | ||
pSampleBuffer->readFromHead(size)); | ||
for (SINT i = 0; i < readableSlice.size(); ++i) { | ||
EXPECT_EQ(readableSlice[i], m_readValue); | ||
m_readValue += CSAMPLE_ONE; | ||
} | ||
return readableSlice.size(); | ||
} | ||
|
||
SINT readLifoAndVerify(mixxx::ReadAheadSampleBuffer* pSampleBuffer, SINT size) { | ||
SINT readFromTailAndVerify(mixxx::ReadAheadSampleBuffer* pSampleBuffer, SINT size) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unused function. |
||
const mixxx::SampleBuffer::ReadableSlice readableSlice( | ||
pSampleBuffer->readLifo(size)); | ||
pSampleBuffer->readFromTail(size)); | ||
for (SINT i = readableSlice.size(); i-- > 0; ) { | ||
m_writeValue -= CSAMPLE_ONE; | ||
EXPECT_EQ(readableSlice[i], m_writeValue); | ||
|
@@ -66,13 +67,13 @@ TEST_F(ReadAheadSampleBufferTest, emptyWithoutCapacity) { | |
EXPECT_TRUE(sampleBuffer.empty()); | ||
|
||
const mixxx::SampleBuffer::WritableSlice writableSlice( | ||
sampleBuffer.write(10)); | ||
sampleBuffer.writeToTail(10)); | ||
EXPECT_EQ(writableSlice.data(), static_cast<CSAMPLE*>(NULL)); | ||
EXPECT_EQ(writableSlice.size(), 0); | ||
EXPECT_TRUE(sampleBuffer.empty()); | ||
|
||
const mixxx::SampleBuffer::ReadableSlice readableSlice( | ||
sampleBuffer.readLifo(10)); | ||
sampleBuffer.readFromTail(10)); | ||
EXPECT_EQ(readableSlice.data(), static_cast<const CSAMPLE*>(NULL)); | ||
EXPECT_EQ(readableSlice.size(), 0); | ||
EXPECT_TRUE(sampleBuffer.empty()); | ||
|
@@ -89,79 +90,103 @@ TEST_F(ReadAheadSampleBufferTest, emptyWithCapacity) { | |
TEST_F(ReadAheadSampleBufferTest, readWriteTrim) { | ||
mixxx::ReadAheadSampleBuffer sampleBuffer(kCapacity); | ||
|
||
SINT writeCount1 = write(&sampleBuffer, kCapacity + 10); | ||
EXPECT_EQ(writeCount1, kCapacity); // buffer is full | ||
SINT writeCount1 = writeToTail(&sampleBuffer, kCapacity + 10); | ||
// Buffer is completely filled with samples | ||
EXPECT_EQ(writeCount1, kCapacity); | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
EXPECT_EQ(sampleBuffer.readableLength(), kCapacity); | ||
EXPECT_EQ(sampleBuffer.writableLength(), 0); | ||
|
||
SINT readCount1 = readFifoAndVerify(&sampleBuffer, kCapacity - 10); | ||
SINT readCount1 = readFromHeadAndVerify(&sampleBuffer, kCapacity - 10); | ||
// Buffer contains the remaining 10 samples, but is still full | ||
EXPECT_EQ(readCount1, kCapacity - 10); | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
EXPECT_EQ(sampleBuffer.readableLength(), kCapacity - readCount1); | ||
EXPECT_EQ(sampleBuffer.writableLength(), 0); | ||
|
||
SINT writeCount2 = write(&sampleBuffer, kCapacity); | ||
EXPECT_EQ(writeCount2, 0); // no tail capacity left | ||
SINT writeCount2 = writeToTail(&sampleBuffer, kCapacity); | ||
// Impossible to write more samples | ||
EXPECT_EQ(writeCount2, 0); | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
EXPECT_EQ(sampleBuffer.readableLength(), kCapacity - readCount1); | ||
EXPECT_EQ(sampleBuffer.writableLength(), 0); | ||
|
||
// Trim buffer contents by reallocation | ||
mixxx::ReadAheadSampleBuffer(sampleBuffer).swap(sampleBuffer); | ||
|
||
SINT writeCount3 = write(&sampleBuffer, kCapacity); | ||
EXPECT_EQ(writeCount3, readCount1); // buffer has been refilled | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
EXPECT_EQ(sampleBuffer.readableLength(), kCapacity - readCount1); | ||
EXPECT_EQ(sampleBuffer.writableLength(), readCount1); | ||
|
||
SINT readCount2 = readFifoAndVerify(&sampleBuffer, kCapacity - 10); | ||
EXPECT_EQ(readCount2, kCapacity - 10); | ||
// Refill Buffer with samples | ||
SINT writeCount3 = writeToTail(&sampleBuffer, kCapacity); | ||
EXPECT_EQ(writeCount3, readCount1); | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
EXPECT_EQ(sampleBuffer.readableLength(), kCapacity); | ||
EXPECT_EQ(sampleBuffer.writableLength(), 0); | ||
|
||
// Trim buffer contents by reallocation | ||
// Read from the end | ||
SINT readCount2 = readFromTailAndVerify(&sampleBuffer, readCount1); | ||
EXPECT_EQ(readCount2, readCount1); | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
EXPECT_EQ(sampleBuffer.readableLength(), kCapacity - readCount1); | ||
EXPECT_EQ(sampleBuffer.writableLength(), readCount1); | ||
|
||
// Trim buffer contents by reallocation has no effect | ||
mixxx::ReadAheadSampleBuffer(sampleBuffer).swap(sampleBuffer); | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
EXPECT_EQ(sampleBuffer.readableLength(), kCapacity - readCount1); | ||
EXPECT_EQ(sampleBuffer.writableLength(), readCount1); | ||
|
||
SINT writeCount4 = write(&sampleBuffer, kCapacity); | ||
// Refill Buffer with samples | ||
SINT writeCount4 = writeToTail(&sampleBuffer, kCapacity); | ||
EXPECT_EQ(writeCount4, readCount2); // buffer has been refilled | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
EXPECT_EQ(sampleBuffer.readableLength(), kCapacity); | ||
EXPECT_EQ(sampleBuffer.writableLength(), 0); | ||
|
||
SINT readCount3 = readFifoAndVerify(&sampleBuffer, kCapacity + 10); | ||
EXPECT_EQ(readCount3, kCapacity); // whole buffer has been read | ||
// Read whole buffer | ||
SINT readCount3 = readFromTailAndVerify(&sampleBuffer, kCapacity + 10); | ||
EXPECT_EQ(readCount3, kCapacity); | ||
EXPECT_TRUE(sampleBuffer.empty()); | ||
EXPECT_EQ(sampleBuffer.readableLength(), 0); | ||
EXPECT_EQ(sampleBuffer.writableLength(), kCapacity); | ||
} | ||
|
||
TEST_F(ReadAheadSampleBufferTest, shrink) { | ||
mixxx::ReadAheadSampleBuffer sampleBuffer(kCapacity); | ||
|
||
SINT writeCount1 = write(&sampleBuffer, kCapacity - 10); | ||
SINT writeCount1 = writeToTail(&sampleBuffer, kCapacity - 10); | ||
EXPECT_EQ(writeCount1, kCapacity - 10); | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
SINT shrinkCount1 = readLifoAndVerify(&sampleBuffer, 10); | ||
SINT shrinkCount1 = readFromHeadAndVerify(&sampleBuffer, 10); | ||
EXPECT_EQ(shrinkCount1, 10); | ||
SINT readCount1 = readFifoAndVerify(&sampleBuffer, 10); | ||
SINT readCount1 = readFromTailAndVerify(&sampleBuffer, 10); | ||
EXPECT_EQ(readCount1, 10); | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
SINT readCount2 = readFifoAndVerify(&sampleBuffer, kCapacity - 40); | ||
SINT readCount2 = readFromTailAndVerify(&sampleBuffer, kCapacity - 40); | ||
EXPECT_EQ(readCount2, kCapacity - 40); | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
SINT readCount3 = readFifoAndVerify(&sampleBuffer, 20); | ||
SINT readCount3 = readFromTailAndVerify(&sampleBuffer, 20); | ||
EXPECT_EQ(readCount3, 10); | ||
EXPECT_TRUE(sampleBuffer.empty()); | ||
|
||
SINT writeCount2 = write(&sampleBuffer, 20); | ||
SINT writeCount2 = writeToTail(&sampleBuffer, 20); | ||
EXPECT_EQ(writeCount2, 20); | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
SINT shrinkCount2 = readLifoAndVerify(&sampleBuffer, 21); | ||
SINT shrinkCount2 = readFromHeadAndVerify(&sampleBuffer, 21); | ||
EXPECT_EQ(shrinkCount2, 20); | ||
EXPECT_TRUE(sampleBuffer.empty()); | ||
} | ||
|
||
TEST_F(ReadAheadSampleBufferTest, clear) { | ||
mixxx::ReadAheadSampleBuffer sampleBuffer(kCapacity); | ||
|
||
SINT writeCount = write(&sampleBuffer, 10); | ||
SINT writeCount = writeToTail(&sampleBuffer, 10); | ||
EXPECT_EQ(writeCount, 10); | ||
EXPECT_FALSE(sampleBuffer.empty()); | ||
clear(&sampleBuffer); | ||
EXPECT_TRUE(sampleBuffer.empty()); | ||
SINT readCount = readFifoAndVerify(&sampleBuffer, 10); | ||
SINT readCount = readFromTailAndVerify(&sampleBuffer, 10); | ||
EXPECT_EQ(readCount, 0); | ||
EXPECT_TRUE(sampleBuffer.empty()); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,8 +8,10 @@ | |
namespace mixxx { | ||
|
||
// A FIFO/LIFO sample buffer with fixed capacity and range checking. | ||
// It works best when consuming all buffered samples before writing | ||
// any new samples. | ||
// | ||
// Samples are written at the tail and read from the head (FIFO) or | ||
// from the tail (LIFO). It is intended to consume all buffered samples | ||
// before writing any new samples. | ||
// | ||
// This class is not thread-safe and is not intended to be used from | ||
// multiple threads! | ||
|
@@ -63,37 +65,37 @@ class ReadAheadSampleBuffer final { | |
return capacity() - m_readableRange.end(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. m_readableRange start always at 0? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. I added an additional comment that tries to clarify how the buffering internally works. Because it is not a full-featured ring buffer the full capacity only becomes available again after all written samples have been consumed. But that's sufficient for our use case. |
||
} | ||
|
||
// Reserves space at the buffer's back end for writing samples. | ||
// Reserves space at the buffer's tail for writing samples. | ||
// | ||
// Returns a pointer to the continuous memory region and the | ||
// actual number of samples that have been reserved. The maximum | ||
// length is limited by writableLength(). | ||
// | ||
// The returned pointer is valid until the next write() operation. | ||
SampleBuffer::WritableSlice write(SINT writeLength); | ||
// The returned pointer is valid until the next writeToTail() operation. | ||
SampleBuffer::WritableSlice writeToTail(SINT writeLength); | ||
|
||
// The number of readable samples. | ||
SINT readableLength() const { | ||
return m_readableRange.length(); | ||
} | ||
|
||
// Consumes buffered samples in FIFO order. | ||
// Consumes buffered samples from the head of the buffer. | ||
// | ||
// Returns a pointer to the continuous memory region and the actual | ||
// number of readable samples. The maximum length is limited by | ||
// readableLength(). | ||
// | ||
// The returned pointer is valid until the next write() operation. | ||
SampleBuffer::ReadableSlice readFifo(SINT readLength); | ||
// The returned pointer is valid until the next writeToTail() operation. | ||
SampleBuffer::ReadableSlice readFromHead(SINT readLength); | ||
|
||
// Consumes buffered samples in LIFO order. | ||
// Consumes buffered samples from the tail of the buffer | ||
// | ||
// Returns a pointer to the continuous memory region and the actual | ||
// number of readable samples. The maximum length is limited by | ||
// readableLength(). | ||
// | ||
// The returned pointer is valid until the next write() operation. | ||
SampleBuffer::ReadableSlice readLifo(SINT readLength); | ||
// The returned pointer is valid until the next writeToTail() operation. | ||
SampleBuffer::ReadableSlice readFromTail(SINT readLength); | ||
|
||
private: | ||
ReadAheadSampleBuffer( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you consider to rename this function to shrinkTail or something? The return value is never used.