Initial commit
This commit is contained in:
208
test/audio/audiostream.h
Normal file
208
test/audio/audiostream.h
Normal file
@@ -0,0 +1,208 @@
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
#include "helper.h"
|
||||
|
||||
class AudioStreamTestSuite : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_convertTimeToStreamPos() {
|
||||
const Audio::Timestamp a = Audio::convertTimeToStreamPos(Audio::Timestamp(500, 1000), 11025, true);
|
||||
// The last bit has to be 0 in any case for a stereo stream.
|
||||
TS_ASSERT_EQUALS(a.totalNumberOfFrames() & 1, 0);
|
||||
|
||||
// TODO: This test is rather hacky... actually converTimeToStreamPos might also return 11026
|
||||
// instead of 11024 and it would still be a valid sample position for ~500ms.
|
||||
TS_ASSERT_EQUALS(a.totalNumberOfFrames(), 11024);
|
||||
|
||||
const Audio::Timestamp b = Audio::convertTimeToStreamPos(Audio::Timestamp(500, 1000), 11025, false);
|
||||
TS_ASSERT_EQUALS(b.totalNumberOfFrames(), 500 * 11025 / 1000);
|
||||
|
||||
// Test Audio CD positioning
|
||||
|
||||
// for 44kHz and stereo
|
||||
const Audio::Timestamp c = Audio::convertTimeToStreamPos(Audio::Timestamp(0, 50, 75), 44100, true);
|
||||
TS_ASSERT_EQUALS(c.totalNumberOfFrames(), 50 * 44100 * 2 / 75);
|
||||
|
||||
// for 11kHz and mono
|
||||
const Audio::Timestamp d = Audio::convertTimeToStreamPos(Audio::Timestamp(0, 50, 75), 11025, false);
|
||||
TS_ASSERT_EQUALS(d.totalNumberOfFrames(), 50 * 11025 / 75);
|
||||
|
||||
// Some misc test
|
||||
const Audio::Timestamp e = Audio::convertTimeToStreamPos(Audio::Timestamp(1, 1, 4), 11025, false);
|
||||
TS_ASSERT_EQUALS(e.totalNumberOfFrames(), 5 * 11025 / 4);
|
||||
}
|
||||
|
||||
private:
|
||||
void testLoopingAudioStreamFixedIter(const int sampleRate, const bool isStereo) {
|
||||
const int secondLength = sampleRate * (isStereo ? 2 : 1);
|
||||
|
||||
int16 *sine = 0;
|
||||
Audio::SeekableAudioStream *s = createSineStream<int16>(sampleRate, 1, &sine, false, isStereo);
|
||||
Audio::LoopingAudioStream *loop = new Audio::LoopingAudioStream(s, 7);
|
||||
|
||||
int16 *buffer = new int16[secondLength * 3];
|
||||
|
||||
// Check parameters
|
||||
TS_ASSERT_EQUALS(loop->isStereo(), isStereo);
|
||||
TS_ASSERT_EQUALS(loop->getRate(), sampleRate);
|
||||
TS_ASSERT_EQUALS(loop->endOfData(), false);
|
||||
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)0);
|
||||
|
||||
// Read one second
|
||||
TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength), secondLength);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer, sine, secondLength * sizeof(int16)), 0);
|
||||
|
||||
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)1);
|
||||
TS_ASSERT_EQUALS(loop->endOfData(), false);
|
||||
|
||||
// Read two seconds
|
||||
TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength * 2), secondLength * 2);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer, sine, secondLength * sizeof(int16)), 0);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer + secondLength, sine, secondLength * sizeof(int16)), 0);
|
||||
|
||||
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)3);
|
||||
TS_ASSERT_EQUALS(loop->endOfData(), false);
|
||||
|
||||
// Read three seconds
|
||||
TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength * 3), secondLength * 3);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer, sine, secondLength * sizeof(int16)), 0);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer + secondLength, sine, secondLength * sizeof(int16)), 0);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer + secondLength * 2, sine, secondLength * sizeof(int16)), 0);
|
||||
|
||||
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)6);
|
||||
TS_ASSERT_EQUALS(loop->endOfData(), false);
|
||||
|
||||
// Read the last second in two parts
|
||||
const int firstStep = secondLength / 2;
|
||||
const int secondStep = secondLength - firstStep;
|
||||
|
||||
TS_ASSERT_EQUALS(loop->readBuffer(buffer, firstStep), firstStep);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer, sine, firstStep * sizeof(int16)), 0);
|
||||
|
||||
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)6);
|
||||
TS_ASSERT_EQUALS(loop->endOfData(), false);
|
||||
|
||||
TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength), secondStep);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer, sine + firstStep, secondStep * sizeof(int16)), 0);
|
||||
|
||||
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)7);
|
||||
TS_ASSERT_EQUALS(loop->endOfData(), true);
|
||||
|
||||
// Try to read beyond the end of the stream
|
||||
TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength), 0);
|
||||
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)7);
|
||||
TS_ASSERT_EQUALS(loop->endOfData(), true);
|
||||
|
||||
delete[] buffer;
|
||||
delete loop;
|
||||
delete[] sine;
|
||||
}
|
||||
|
||||
public:
|
||||
void test_looping_audio_stream_mono_11025_fixed_iter() {
|
||||
testLoopingAudioStreamFixedIter(11025, false);
|
||||
}
|
||||
|
||||
void test_looping_audio_stream_mono_22050_fixed_iter() {
|
||||
testLoopingAudioStreamFixedIter(22050, false);
|
||||
}
|
||||
|
||||
void test_looping_audio_stream_stereo_11025_fixed_iter() {
|
||||
testLoopingAudioStreamFixedIter(11025, true);
|
||||
}
|
||||
|
||||
void test_looping_audio_stream_stereo_22050_fixed_iter() {
|
||||
testLoopingAudioStreamFixedIter(22050, true);
|
||||
}
|
||||
|
||||
private:
|
||||
void testSubLoopingAudioStreamFixedIter(const int sampleRate, const bool isStereo, const int time, const int loopEndTime) {
|
||||
const int secondLength = sampleRate * (isStereo ? 2 : 1);
|
||||
|
||||
const Audio::Timestamp loopStart(500, 1000), loopEnd(loopEndTime * 1000, 1000);
|
||||
|
||||
const int32 loopStartPos = Audio::convertTimeToStreamPos(loopStart, sampleRate, isStereo).totalNumberOfFrames();
|
||||
const int32 loopEndPos = Audio::convertTimeToStreamPos(loopEnd, sampleRate, isStereo).totalNumberOfFrames();
|
||||
|
||||
const int32 loopIteration = loopEndPos - loopStartPos;
|
||||
|
||||
int16 *sine = 0;
|
||||
Audio::SeekableAudioStream *s = createSineStream<int16>(sampleRate, time, &sine, false, isStereo);
|
||||
Audio::SubLoopingAudioStream *loop = new Audio::SubLoopingAudioStream(s, 5, loopStart, loopEnd);
|
||||
|
||||
const int32 bufferLen = MAX<int32>(loopIteration * 3, loopEndPos);
|
||||
int16 *buffer = new int16[bufferLen];
|
||||
|
||||
// Check parameters
|
||||
TS_ASSERT_EQUALS(loop->isStereo(), isStereo);
|
||||
TS_ASSERT_EQUALS(loop->getRate(), sampleRate);
|
||||
TS_ASSERT_EQUALS(loop->endOfData(), false);
|
||||
|
||||
// Read the non-looped part + one iteration
|
||||
TS_ASSERT_EQUALS(loop->readBuffer(buffer, loopEndPos), loopEndPos);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer, sine, loopEndPos * sizeof(int16)), 0);
|
||||
TS_ASSERT_EQUALS(loop->endOfData(), false);
|
||||
|
||||
// We should have one full iteration now
|
||||
|
||||
// Read another loop iteration
|
||||
TS_ASSERT_EQUALS(loop->readBuffer(buffer, loopIteration), loopIteration);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer, sine + loopStartPos, loopIteration * sizeof(int16)), 0);
|
||||
TS_ASSERT_EQUALS(loop->endOfData(), false);
|
||||
|
||||
// We should have two full iterations now
|
||||
|
||||
// Read three loop iterations at once
|
||||
TS_ASSERT_EQUALS(loop->readBuffer(buffer, loopIteration * 3), loopIteration * 3);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer + loopIteration * 0, sine + loopStartPos, loopIteration * sizeof(int16)), 0);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer + loopIteration * 1, sine + loopStartPos, loopIteration * sizeof(int16)), 0);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer + loopIteration * 2, sine + loopStartPos, loopIteration * sizeof(int16)), 0);
|
||||
TS_ASSERT_EQUALS(loop->endOfData(), true);
|
||||
|
||||
// We should have five full iterations now, thus the stream should be done
|
||||
|
||||
// Try to read beyond the end of the stream (note this only applies, till we define that SubLoopingAudioStream should
|
||||
// stop playing after the looped area).
|
||||
TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength), 0);
|
||||
TS_ASSERT_EQUALS(loop->endOfData(), true);
|
||||
|
||||
delete[] buffer;
|
||||
delete loop;
|
||||
delete[] sine;
|
||||
}
|
||||
|
||||
public:
|
||||
void test_sub_looping_audio_stream_mono_11025_mid_fixed_iter() {
|
||||
testSubLoopingAudioStreamFixedIter(11025, false, 2, 1);
|
||||
}
|
||||
|
||||
void test_sub_looping_audio_stream_mono_22050_mid_fixed_iter() {
|
||||
testSubLoopingAudioStreamFixedIter(22050, false, 2, 1);
|
||||
}
|
||||
|
||||
void test_sub_looping_audio_stream_stereo_11025_mid_fixed_iter() {
|
||||
testSubLoopingAudioStreamFixedIter(11025, true, 2, 1);
|
||||
}
|
||||
|
||||
void test_sub_looping_audio_stream_stereo_22050_mid_fixed_iter() {
|
||||
testSubLoopingAudioStreamFixedIter(22050, true, 2, 1);
|
||||
}
|
||||
|
||||
void test_sub_looping_audio_stream_mono_11025_end_fixed_iter() {
|
||||
testSubLoopingAudioStreamFixedIter(11025, false, 2, 2);
|
||||
}
|
||||
|
||||
void test_sub_looping_audio_stream_mono_22050_end_fixed_iter() {
|
||||
testSubLoopingAudioStreamFixedIter(22050, false, 2, 2);
|
||||
}
|
||||
|
||||
void test_sub_looping_audio_stream_stereo_11025_end_fixed_iter() {
|
||||
testSubLoopingAudioStreamFixedIter(11025, true, 2, 2);
|
||||
}
|
||||
|
||||
void test_sub_looping_audio_stream_stereo_22050_end_fixed_iter() {
|
||||
testSubLoopingAudioStreamFixedIter(22050, true, 2, 2);
|
||||
}
|
||||
};
|
||||
68
test/audio/helper.h
Normal file
68
test/audio/helper.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef TEST_SOUND_HELPER_H
|
||||
#define TEST_SOUND_HELPER_H
|
||||
|
||||
#include "audio/decoders/raw.h"
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "common/endian.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <limits>
|
||||
|
||||
template<typename T>
|
||||
static T *createSine(const int sampleRate, const int time) {
|
||||
T *sine = (T *)malloc(sizeof(T) * time * sampleRate);
|
||||
|
||||
const bool isUnsigned = !std::numeric_limits<T>::is_signed;
|
||||
const T xorMask = isUnsigned ? (1 << (std::numeric_limits<T>::digits - 1)) : 0;
|
||||
const T maxValue = std::numeric_limits<T>::max() ^ xorMask;
|
||||
|
||||
for (int i = 0; i < time * sampleRate; ++i)
|
||||
sine[i] = ((T)(sin((double)i / sampleRate * 2 * M_PI) * maxValue)) ^ xorMask;
|
||||
|
||||
return sine;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Audio::SeekableAudioStream *createSineStream(const int sampleRate, const int time, int16 **comp, bool le, bool isStereo) {
|
||||
T *sine = createSine<T>(sampleRate, time * (isStereo ? 2 : 1));
|
||||
|
||||
const bool isUnsigned = !std::numeric_limits<T>::is_signed;
|
||||
const T xorMask = isUnsigned ? (1 << (std::numeric_limits<T>::digits - 1)) : 0;
|
||||
const bool is16Bits = (sizeof(T) == 2);
|
||||
assert(sizeof(T) == 2 || sizeof(T) == 1);
|
||||
|
||||
const int samples = sampleRate * time * (isStereo ? 2 : 1);
|
||||
|
||||
if (comp) {
|
||||
*comp = new int16[samples];
|
||||
for (int i = 0; i < samples; ++i) {
|
||||
if (is16Bits)
|
||||
(*comp)[i] = sine[i] ^ xorMask;
|
||||
else
|
||||
(*comp)[i] = (sine[i] ^ xorMask) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (is16Bits) {
|
||||
if (le) {
|
||||
for (int i = 0; i < samples; ++i)
|
||||
WRITE_LE_UINT16(&sine[i], sine[i]);
|
||||
} else {
|
||||
for (int i = 0; i < samples; ++i)
|
||||
WRITE_BE_UINT16(&sine[i], sine[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Audio::SeekableAudioStream *s = 0;
|
||||
Common::SeekableReadStream *sD = new Common::MemoryReadStream((const byte *)sine, sizeof(T) * samples, DisposeAfterUse::YES);
|
||||
s = Audio::makeRawStream(sD, sampleRate,
|
||||
(is16Bits ? Audio::FLAG_16BITS : 0)
|
||||
| (isUnsigned ? Audio::FLAG_UNSIGNED : 0)
|
||||
| (le ? Audio::FLAG_LITTLE_ENDIAN : 0)
|
||||
| (isStereo ? Audio::FLAG_STEREO : 0));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif
|
||||
291
test/audio/raw.h
Normal file
291
test/audio/raw.h
Normal file
@@ -0,0 +1,291 @@
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include "audio/decoders/raw.h"
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
#include "helper.h"
|
||||
|
||||
class RawStreamTestSuite : public CxxTest::TestSuite
|
||||
{
|
||||
private:
|
||||
template<typename T>
|
||||
void readBufferTestTemplate(const int sampleRate, const int time, const bool le, const bool isStereo) {
|
||||
int16 *sine;
|
||||
Audio::SeekableAudioStream *s = createSineStream<int8>(sampleRate, time, &sine, le, isStereo);
|
||||
|
||||
const int totalSamples = sampleRate * time * (isStereo ? 2 : 1);
|
||||
int16 *buffer = new int16[totalSamples];
|
||||
TS_ASSERT_EQUALS(s->readBuffer(buffer, totalSamples), totalSamples);
|
||||
TS_ASSERT_EQUALS(memcmp(sine, buffer, sizeof(int16) * totalSamples), 0);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), true);
|
||||
|
||||
delete[] sine;
|
||||
delete[] buffer;
|
||||
delete s;
|
||||
}
|
||||
|
||||
public:
|
||||
void test_read_buffer_8_bit_signed_mono() {
|
||||
readBufferTestTemplate<int8>(11025, 2, false, false);
|
||||
}
|
||||
|
||||
void test_read_buffer_8_bit_signed_stereo() {
|
||||
readBufferTestTemplate<int8>(11025, 2, false, true);
|
||||
}
|
||||
|
||||
void test_read_buffer_8_bit_unsigned_mono() {
|
||||
readBufferTestTemplate<uint8>(11025, 2, false, false);
|
||||
}
|
||||
|
||||
void test_read_buffer_16_bit_signed_be_mono() {
|
||||
readBufferTestTemplate<int16>(11025, 2, false, false);
|
||||
}
|
||||
|
||||
void test_read_buffer_16_bit_signed_be_stereo() {
|
||||
readBufferTestTemplate<int16>(11025, 2, false, true);
|
||||
}
|
||||
|
||||
void test_read_buffer_16_bit_unsigned_be_mono() {
|
||||
readBufferTestTemplate<uint16>(11025, 2, false, false);
|
||||
}
|
||||
|
||||
void test_read_buffer_16_bit_unsigned_be_stereo() {
|
||||
readBufferTestTemplate<uint16>(11025, 2, false, true);
|
||||
}
|
||||
|
||||
void test_read_buffer_16_bit_signed_le_mono() {
|
||||
readBufferTestTemplate<int16>(11025, 2, true, false);
|
||||
}
|
||||
|
||||
void test_read_buffer_16_bit_signed_le_stereo() {
|
||||
readBufferTestTemplate<int16>(11025, 2, true, true);
|
||||
}
|
||||
|
||||
void test_read_buffer_16_bit_unsigned_le_mono() {
|
||||
readBufferTestTemplate<uint16>(11025, 2, true, false);
|
||||
}
|
||||
|
||||
void test_read_buffer_16_bit_unsigned_le_stereo() {
|
||||
readBufferTestTemplate<uint16>(11025, 2, true, true);
|
||||
}
|
||||
|
||||
private:
|
||||
void partialReadTest() {
|
||||
const int sampleRate = 11025;
|
||||
const int time = 4;
|
||||
|
||||
int16 *sine;
|
||||
Audio::SeekableAudioStream *s = createSineStream<int8>(sampleRate, time, &sine, false, false);
|
||||
int16 *buffer = new int16[sampleRate * time];
|
||||
|
||||
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate), sampleRate);
|
||||
TS_ASSERT_EQUALS(memcmp(sine, buffer, sampleRate), 0);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), false);
|
||||
|
||||
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate * 2), sampleRate * 2);
|
||||
TS_ASSERT_EQUALS(memcmp(sine + sampleRate, buffer, sampleRate * 2), 0);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), false);
|
||||
|
||||
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate), sampleRate);
|
||||
TS_ASSERT_EQUALS(memcmp(sine + sampleRate * 3, buffer, sampleRate), 0);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), true);
|
||||
|
||||
delete[] sine;
|
||||
delete[] buffer;
|
||||
delete s;
|
||||
}
|
||||
public:
|
||||
void test_partial_read() {
|
||||
partialReadTest();
|
||||
}
|
||||
|
||||
private:
|
||||
void readAfterEndTest() {
|
||||
const int sampleRate = 11025;
|
||||
const int time = 1;
|
||||
Audio::SeekableAudioStream *s = createSineStream<int8>(sampleRate, time, 0, false, false);
|
||||
int16 *buffer = new int16[sampleRate * time];
|
||||
|
||||
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate * time), sampleRate * time);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), true);
|
||||
|
||||
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate * time), 0);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), true);
|
||||
|
||||
delete[] buffer;
|
||||
delete s;
|
||||
}
|
||||
|
||||
public:
|
||||
void test_read_after_end() {
|
||||
readAfterEndTest();
|
||||
}
|
||||
|
||||
private:
|
||||
void rewindTest() {
|
||||
const int sampleRate = 11025;
|
||||
const int time = 2;
|
||||
Audio::SeekableAudioStream *s = createSineStream<int8>(sampleRate, time, 0, false, false);
|
||||
int16 *buffer = new int16[sampleRate * time];
|
||||
|
||||
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate * time), sampleRate * time);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), true);
|
||||
|
||||
s->rewind();
|
||||
TS_ASSERT_EQUALS(s->endOfData(), false);
|
||||
|
||||
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate * time), sampleRate * time);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), true);
|
||||
|
||||
delete[] buffer;
|
||||
delete s;
|
||||
}
|
||||
public:
|
||||
void test_rewind() {
|
||||
rewindTest();
|
||||
}
|
||||
|
||||
private:
|
||||
void lengthTest() {
|
||||
int sampleRate = 0;
|
||||
const int time = 4;
|
||||
|
||||
Audio::SeekableAudioStream *s = 0;
|
||||
|
||||
// 11025 Hz tests
|
||||
sampleRate = 11025;
|
||||
s = createSineStream<int8>(sampleRate, time, 0, false, false);
|
||||
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
|
||||
delete s;
|
||||
|
||||
s = createSineStream<uint16>(sampleRate, time, 0, false, false);
|
||||
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
|
||||
delete s;
|
||||
|
||||
// 48000 Hz tests
|
||||
sampleRate = 48000;
|
||||
s = createSineStream<int8>(sampleRate, time, 0, false, false);
|
||||
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
|
||||
delete s;
|
||||
|
||||
s = createSineStream<uint16>(sampleRate, time, 0, true, false);
|
||||
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
|
||||
delete s;
|
||||
|
||||
// 11840 Hz tests
|
||||
sampleRate = 11840;
|
||||
s = createSineStream<int8>(sampleRate, time, 0, false, false);
|
||||
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
|
||||
delete s;
|
||||
|
||||
s = createSineStream<uint16>(sampleRate, time, 0, false, false);
|
||||
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
|
||||
delete s;
|
||||
|
||||
// 11111 Hz tests
|
||||
sampleRate = 11111;
|
||||
s = createSineStream<int8>(sampleRate, time, 0, false, false);
|
||||
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
|
||||
delete s;
|
||||
|
||||
s = createSineStream<uint16>(sampleRate, time, 0, false, false);
|
||||
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
|
||||
delete s;
|
||||
|
||||
// 22050 Hz stereo test
|
||||
sampleRate = 22050;
|
||||
s = createSineStream<int8>(sampleRate, time, 0, false, true);
|
||||
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
|
||||
delete s;
|
||||
|
||||
s = createSineStream<uint16>(sampleRate, time, 0, true, true);
|
||||
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
|
||||
delete s;
|
||||
}
|
||||
|
||||
public:
|
||||
void test_length() {
|
||||
lengthTest();
|
||||
}
|
||||
|
||||
private:
|
||||
void seekTest(const int sampleRate, const int time, const bool isStereo) {
|
||||
const int totalFrames = sampleRate * time * (isStereo ? 2 : 1);
|
||||
int readData = 0, offset = 0;
|
||||
|
||||
int16 *buffer = new int16[totalFrames];
|
||||
Audio::SeekableAudioStream *s = 0;
|
||||
int16 *sine = 0;
|
||||
|
||||
s = createSineStream<int8>(sampleRate, time, &sine, false, isStereo);
|
||||
|
||||
// Seek to 500ms
|
||||
const Audio::Timestamp a(0, 1, 2);
|
||||
offset = Audio::convertTimeToStreamPos(a, sampleRate, isStereo).totalNumberOfFrames();
|
||||
readData = totalFrames - offset;
|
||||
|
||||
TS_ASSERT_EQUALS(s->seek(a), true);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), false);
|
||||
TS_ASSERT_EQUALS(s->readBuffer(buffer, readData), readData);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer, sine + offset, readData * sizeof(int16)), 0);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), true);
|
||||
|
||||
// Seek to 3/4 of a second
|
||||
const Audio::Timestamp b(0, 3, 4);
|
||||
offset = Audio::convertTimeToStreamPos(b, sampleRate, isStereo).totalNumberOfFrames();
|
||||
readData = totalFrames - offset;
|
||||
|
||||
TS_ASSERT_EQUALS(s->seek(b), true);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), false);
|
||||
TS_ASSERT_EQUALS(s->readBuffer(buffer, readData), readData);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer, sine + offset, readData * sizeof(int16)), 0);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), true);
|
||||
|
||||
// Seek to the start of the stream
|
||||
TS_ASSERT_EQUALS(s->seek(0), true);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), false);
|
||||
|
||||
// Seek to the mid of the stream
|
||||
const Audio::Timestamp c(time * 1000 / 2, 1000);
|
||||
offset = Audio::convertTimeToStreamPos(c, sampleRate, isStereo).totalNumberOfFrames();
|
||||
readData = totalFrames - offset;
|
||||
|
||||
TS_ASSERT_EQUALS(s->seek(c), true);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), false);
|
||||
TS_ASSERT_EQUALS(s->readBuffer(buffer, readData), readData);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer, sine + offset, readData * sizeof(int16)), 0);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), true);
|
||||
|
||||
// Seek to the 1/4th of the last second of the stream
|
||||
const Audio::Timestamp d(time - 1, 1, 4);
|
||||
offset = Audio::convertTimeToStreamPos(d, sampleRate, isStereo).totalNumberOfFrames();
|
||||
readData = totalFrames - offset;
|
||||
|
||||
TS_ASSERT_EQUALS(s->seek(d), true);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), false);
|
||||
TS_ASSERT_EQUALS(s->readBuffer(buffer, readData), readData);
|
||||
TS_ASSERT_EQUALS(memcmp(buffer, sine + offset, readData * sizeof(int16)), 0);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), true);
|
||||
|
||||
// Try to seek after the end of the stream
|
||||
TS_ASSERT_EQUALS(s->seek(Audio::Timestamp(time, 1, 100000)), false);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), true);
|
||||
|
||||
// Try to seek exactly at the end of the stream
|
||||
TS_ASSERT_EQUALS(s->seek(Audio::Timestamp(time * 1000, 1000)), true);
|
||||
TS_ASSERT_EQUALS(s->endOfData(), true);
|
||||
|
||||
delete[] sine;
|
||||
delete s;
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
public:
|
||||
void test_seek_mono() {
|
||||
seekTest(11025, 2, false);
|
||||
}
|
||||
|
||||
void test_seek_stereo() {
|
||||
seekTest(11025, 2, true);
|
||||
}
|
||||
};
|
||||
252
test/audio/timestamp.h
Normal file
252
test/audio/timestamp.h
Normal file
@@ -0,0 +1,252 @@
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include "audio/timestamp.h"
|
||||
|
||||
class TimestampTestSuite : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_diff_add_frames() {
|
||||
const Audio::Timestamp a(10000, 1000);
|
||||
const Audio::Timestamp b(10001, 1000);
|
||||
const Audio::Timestamp c(10002, 1000);
|
||||
|
||||
TS_ASSERT_EQUALS(a.frameDiff(b), -1);
|
||||
TS_ASSERT_EQUALS(b.frameDiff(a), 1);
|
||||
TS_ASSERT_EQUALS(c.frameDiff(a), 2);
|
||||
TS_ASSERT_EQUALS(b.addFrames(2000).frameDiff(a), 2001);
|
||||
TS_ASSERT_EQUALS(a.frameDiff(b), -1);
|
||||
TS_ASSERT_EQUALS(b.frameDiff(a), 1);
|
||||
TS_ASSERT_EQUALS(c.frameDiff(a), 2);
|
||||
TS_ASSERT_EQUALS(b.addFrames(2000).frameDiff(a.addFrames(-1000)), 3001);
|
||||
TS_ASSERT_EQUALS(a.frameDiff(b), -1);
|
||||
TS_ASSERT_EQUALS(b.frameDiff(a), 1);
|
||||
TS_ASSERT_EQUALS(c.frameDiff(a), 2);
|
||||
}
|
||||
|
||||
void test_diff_add_msecs() {
|
||||
Audio::Timestamp ts0(3, 22050);
|
||||
Audio::Timestamp ts1(0, 22050);
|
||||
Audio::Timestamp ts2(0, 22050);
|
||||
|
||||
TS_ASSERT_EQUALS(ts0.msecs(), 3);
|
||||
TS_ASSERT_EQUALS(ts0.totalNumberOfFrames(), 3 * 22050 / 1000);
|
||||
TS_ASSERT_EQUALS(ts0.numberOfFrames(), 3 * 22050 / 1000);
|
||||
|
||||
ts1 = ts1.addFrames(53248);
|
||||
TS_ASSERT_EQUALS(ts1.secs(), 2);
|
||||
TS_ASSERT_EQUALS(ts1.msecs(), 53248 * 1000 / 22050);
|
||||
TS_ASSERT_EQUALS(ts1.totalNumberOfFrames(), 53248);
|
||||
TS_ASSERT_EQUALS(ts1.numberOfFrames(), 53248 - 2 * 22050);
|
||||
ts1 = ts1.addMsecs(47);
|
||||
TS_ASSERT_EQUALS(ts1.secs(), 2);
|
||||
TS_ASSERT_EQUALS(ts1.msecs(), 2414+47);
|
||||
TS_ASSERT_EQUALS(ts1.totalNumberOfFrames(), 47*22050 / 1000 + 53248);
|
||||
TS_ASSERT_EQUALS(ts1.numberOfFrames(), 47*22050 / 1000 + 53248 - 2 * 22050);
|
||||
|
||||
ts2 = ts2.addMsecs(47);
|
||||
TS_ASSERT_EQUALS(ts2.secs(), 0);
|
||||
TS_ASSERT_EQUALS(ts2.msecs(), 47);
|
||||
TS_ASSERT_EQUALS(ts2.totalNumberOfFrames(), 47*22050 / 1000);
|
||||
TS_ASSERT_EQUALS(ts2.numberOfFrames(), 47*22050 / 1000);
|
||||
ts2 = ts2.addFrames(53248);
|
||||
TS_ASSERT_EQUALS(ts2.secs(), 2);
|
||||
TS_ASSERT_EQUALS(ts2.msecs(), 2414+47);
|
||||
TS_ASSERT_EQUALS(ts2.totalNumberOfFrames(), 47*22050 / 1000 + 53248);
|
||||
TS_ASSERT_EQUALS(ts2.numberOfFrames(), 47*22050 / 1000 + 53248 - 2 * 22050);
|
||||
}
|
||||
|
||||
void test_ticks() {
|
||||
const Audio::Timestamp a(1234, 60);
|
||||
const Audio::Timestamp b(5678, 60);
|
||||
|
||||
TS_ASSERT_EQUALS(a.msecs(), 1234);
|
||||
TS_ASSERT_EQUALS(b.msecs(), 5678);
|
||||
|
||||
TS_ASSERT_EQUALS(a.secs(), 1);
|
||||
TS_ASSERT_EQUALS(b.secs(), 5);
|
||||
|
||||
TS_ASSERT_EQUALS(a.msecsDiff(b), 1234 - 5678);
|
||||
TS_ASSERT_EQUALS(b.msecsDiff(a), 5678 - 1234);
|
||||
|
||||
TS_ASSERT_EQUALS(a.frameDiff(b), (1234 - 5678) * 60 / 1000);
|
||||
TS_ASSERT_EQUALS(b.frameDiff(a), (5678 - 1234) * 60 / 1000);
|
||||
|
||||
TS_ASSERT_EQUALS(a.addFrames(1).msecs(), (1234 + 1000 * 1/60));
|
||||
TS_ASSERT_EQUALS(a.addFrames(59).msecs(), (1234 + 1000 * 59/60));
|
||||
TS_ASSERT_EQUALS(a.addFrames(60).msecs(), (1234 + 1000 * 60/60));
|
||||
|
||||
// As soon as we go back even by only one frame, the msec value
|
||||
// has to drop by at least one.
|
||||
TS_ASSERT_EQUALS(a.addFrames(-1).msecs(), (1234 - 1000 * 1/60 - 1));
|
||||
TS_ASSERT_EQUALS(a.addFrames(-59).msecs(), (1234 - 1000 * 59/60 - 1));
|
||||
TS_ASSERT_EQUALS(a.addFrames(-60).msecs(), (1234 - 1000 * 60/60));
|
||||
}
|
||||
|
||||
void test_more_add_diff() {
|
||||
const Audio::Timestamp c(10002, 1000);
|
||||
|
||||
for (int i = -10000; i < 10000; i++) {
|
||||
int v = c.addFrames(i).frameDiff(c);
|
||||
TS_ASSERT_EQUALS(v, i);
|
||||
}
|
||||
}
|
||||
|
||||
void test_negate() {
|
||||
const Audio::Timestamp a = Audio::Timestamp(0, 60).addFrames(13);
|
||||
const Audio::Timestamp b = -a;
|
||||
|
||||
TS_ASSERT_EQUALS(a.msecs() + 1, -b.msecs());
|
||||
TS_ASSERT_EQUALS(a.totalNumberOfFrames(), -b.totalNumberOfFrames());
|
||||
TS_ASSERT_EQUALS(a.numberOfFrames(), 60 - b.numberOfFrames());
|
||||
}
|
||||
|
||||
void test_add_sub() {
|
||||
const Audio::Timestamp a = Audio::Timestamp(0, 60).addFrames(13);
|
||||
const Audio::Timestamp b = -a;
|
||||
const Audio::Timestamp c = Audio::Timestamp(0, 60).addFrames(20);
|
||||
|
||||
TS_ASSERT_EQUALS((a+a).secs(), 0);
|
||||
TS_ASSERT_EQUALS((a+a).numberOfFrames(), 2*13);
|
||||
|
||||
TS_ASSERT_EQUALS((a+b).secs(), 0);
|
||||
TS_ASSERT_EQUALS((a+b).numberOfFrames(), 0);
|
||||
|
||||
TS_ASSERT_EQUALS((a+c).secs(), 0);
|
||||
TS_ASSERT_EQUALS((a+c).numberOfFrames(), 13+20);
|
||||
|
||||
TS_ASSERT_EQUALS((a-a).secs(), 0);
|
||||
TS_ASSERT_EQUALS((a-a).numberOfFrames(), 0);
|
||||
|
||||
TS_ASSERT_EQUALS((a-b).secs(), 0);
|
||||
TS_ASSERT_EQUALS((a-b).numberOfFrames(), 2*13);
|
||||
|
||||
TS_ASSERT_EQUALS((a-c).secs(), -1);
|
||||
TS_ASSERT_EQUALS((a-c).numberOfFrames(), 60 + (13 - 20));
|
||||
}
|
||||
|
||||
void test_diff_with_conversion() {
|
||||
const Audio::Timestamp a = Audio::Timestamp(10, 1000).addFrames(20);
|
||||
const Audio::Timestamp b = Audio::Timestamp(10, 1000/5).addFrames(20/5);
|
||||
const Audio::Timestamp c = Audio::Timestamp(10, 1000*2).addFrames(20*2);
|
||||
|
||||
TS_ASSERT_EQUALS(a.frameDiff(a), 0);
|
||||
TS_ASSERT_EQUALS(a.frameDiff(b), 0);
|
||||
TS_ASSERT_EQUALS(a.frameDiff(c), 0);
|
||||
|
||||
TS_ASSERT_EQUALS(b.frameDiff(a), 0);
|
||||
TS_ASSERT_EQUALS(b.frameDiff(b), 0);
|
||||
TS_ASSERT_EQUALS(b.frameDiff(c), 0);
|
||||
|
||||
TS_ASSERT_EQUALS(c.frameDiff(a), 0);
|
||||
TS_ASSERT_EQUALS(c.frameDiff(b), 0);
|
||||
TS_ASSERT_EQUALS(c.frameDiff(c), 0);
|
||||
}
|
||||
|
||||
|
||||
void test_convert() {
|
||||
const Audio::Timestamp a = Audio::Timestamp(10, 1000).addFrames(20);
|
||||
const Audio::Timestamp b = Audio::Timestamp(10, 1000/5).addFrames(20/5);
|
||||
const Audio::Timestamp c = Audio::Timestamp(10, 1000*2).addFrames(20*2);
|
||||
|
||||
TS_ASSERT_EQUALS(a.convertToFramerate(1000/5), b);
|
||||
TS_ASSERT_EQUALS(a.convertToFramerate(1000*2), c);
|
||||
}
|
||||
|
||||
void test_equals() {
|
||||
const Audio::Timestamp a = Audio::Timestamp(500, 1000);
|
||||
Audio::Timestamp b = Audio::Timestamp(0, 1000);
|
||||
Audio::Timestamp c = Audio::Timestamp(0, 100);
|
||||
|
||||
TS_ASSERT_EQUALS(a, Audio::Timestamp(0, 500, 1000));
|
||||
|
||||
TS_ASSERT(a != b);
|
||||
TS_ASSERT(a != c);
|
||||
TS_ASSERT(b == c);
|
||||
|
||||
b = b.addFrames(500);
|
||||
c = c.addFrames(50);
|
||||
|
||||
TS_ASSERT(a == b);
|
||||
TS_ASSERT(a == c);
|
||||
TS_ASSERT(b == c);
|
||||
}
|
||||
|
||||
|
||||
void test_compare() {
|
||||
const Audio::Timestamp a = Audio::Timestamp(60, 1000);
|
||||
Audio::Timestamp b = Audio::Timestamp(60, 60);
|
||||
Audio::Timestamp c = Audio::Timestamp(60, 44100);
|
||||
|
||||
TS_ASSERT(a <= b);
|
||||
TS_ASSERT(b <= c);
|
||||
TS_ASSERT(a <= c);
|
||||
|
||||
TS_ASSERT(b >= a);
|
||||
TS_ASSERT(c >= b);
|
||||
TS_ASSERT(c >= a);
|
||||
|
||||
b = b.addFrames(60 / 12);
|
||||
c = c.addFrames(44100 / 10);
|
||||
|
||||
TS_ASSERT(a < b);
|
||||
TS_ASSERT(b < c);
|
||||
TS_ASSERT(a < c);
|
||||
|
||||
TS_ASSERT(b > a);
|
||||
TS_ASSERT(c > b);
|
||||
TS_ASSERT(c > a);
|
||||
|
||||
TS_ASSERT(a <= b);
|
||||
TS_ASSERT(b <= c);
|
||||
TS_ASSERT(a <= c);
|
||||
|
||||
TS_ASSERT(b >= a);
|
||||
TS_ASSERT(c >= b);
|
||||
TS_ASSERT(c >= a);
|
||||
}
|
||||
|
||||
|
||||
void test_framerate() {
|
||||
const Audio::Timestamp a = Audio::Timestamp(500, 1000);
|
||||
const Audio::Timestamp b = Audio::Timestamp(500, 67);
|
||||
const Audio::Timestamp c = Audio::Timestamp(500, 100);
|
||||
const Audio::Timestamp d = Audio::Timestamp(500, 44100);
|
||||
|
||||
TS_ASSERT_EQUALS(a.framerate(), (uint)1000);
|
||||
TS_ASSERT_EQUALS(b.framerate(), (uint)67);
|
||||
TS_ASSERT_EQUALS(c.framerate(), (uint)100);
|
||||
TS_ASSERT_EQUALS(d.framerate(), (uint)44100);
|
||||
}
|
||||
|
||||
void test_direct_query() {
|
||||
const Audio::Timestamp a = Audio::Timestamp(0, 22050);
|
||||
const Audio::Timestamp b = a.addFrames(11025);
|
||||
const Audio::Timestamp c = Audio::Timestamp(1500, 22050);
|
||||
|
||||
TS_ASSERT_EQUALS(a.secs(), 0);
|
||||
TS_ASSERT_EQUALS(a.msecs(), 0);
|
||||
TS_ASSERT_EQUALS(a.numberOfFrames(), 0);
|
||||
TS_ASSERT_EQUALS(a.totalNumberOfFrames(), 0);
|
||||
|
||||
TS_ASSERT_EQUALS(b.secs(), 0);
|
||||
TS_ASSERT_EQUALS(b.msecs(), 500);
|
||||
TS_ASSERT_EQUALS(b.numberOfFrames(), 11025);
|
||||
TS_ASSERT_EQUALS(b.totalNumberOfFrames(), 11025);
|
||||
|
||||
TS_ASSERT_EQUALS(c.secs(), 1);
|
||||
TS_ASSERT_EQUALS(c.msecs(), 1500);
|
||||
TS_ASSERT_EQUALS(c.numberOfFrames(), 11025);
|
||||
TS_ASSERT_EQUALS(c.totalNumberOfFrames(), 33075);
|
||||
}
|
||||
|
||||
void test_no_overflow() {
|
||||
// The constructor should not overflow and give incoherent values
|
||||
const Audio::Timestamp a = Audio::Timestamp(0, UINT_MAX, 1000);
|
||||
|
||||
int secs = UINT_MAX / 1000;
|
||||
int frames = UINT_MAX % 1000;
|
||||
|
||||
TS_ASSERT_EQUALS(a.secs(), secs);
|
||||
TS_ASSERT_EQUALS(a.numberOfFrames(), frames);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user