aboutsummaryrefslogtreecommitdiff
path: root/test/sound/audiostream.h
blob: e0d3ece059e1633b47e6003726486fe87f5b5dba (plain)
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
#include <cxxtest/TestSuite.h>

#include "sound/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_fixed_iter() {
		testLoopingAudioStreamFixedIter(22050, false);
	}

	void test_looping_audio_stream_stereo_fixed_iter() {
		testLoopingAudioStreamFixedIter(22050, true);
	}

private:
	void testSubLoopingAudioStreamFixedIter(const int sampleRate, const bool isStereo) {
		const int secondLength = sampleRate * (isStereo ? 2 : 1);
		const Audio::Timestamp loopStart(500, 1000), loopEnd(1000, 1000);
		const int32 loopOffset = Audio::convertTimeToStreamPos(loopStart, sampleRate, isStereo).totalNumberOfFrames();
		const int32 loopIteration = Audio::convertTimeToStreamPos((loopEnd - loopStart), sampleRate, isStereo).totalNumberOfFrames();

		int16 *sine = 0;
		Audio::SeekableAudioStream *s = createSineStream<int16>(sampleRate, 3, &sine, false, isStereo);
		Audio::SubLoopingAudioStream *loop = new Audio::SubLoopingAudioStream(s, 5, loopStart, loopEnd);

		int16 *buffer = new int16[secondLength * 2];

		// Check parameters
		TS_ASSERT_EQUALS(loop->isStereo(), isStereo);
		TS_ASSERT_EQUALS(loop->getRate(), sampleRate);
		TS_ASSERT_EQUALS(loop->endOfData(), false);

		// Read one sceond (this is the non-looped part + one iteration)
		TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength), secondLength);
		TS_ASSERT_EQUALS(memcmp(buffer, sine, secondLength * 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 + loopOffset, 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 + loopOffset, loopIteration * sizeof(int16)), 0);
		TS_ASSERT_EQUALS(memcmp(buffer + loopIteration * 1, sine + loopOffset, loopIteration * sizeof(int16)), 0);
		TS_ASSERT_EQUALS(memcmp(buffer + loopIteration * 2, sine + loopOffset, 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_fixed_iter() {
		testSubLoopingAudioStreamFixedIter(22050, false);
	}

	void test_sub_looping_audio_stream_stereo_fixed_iter() {
		testSubLoopingAudioStreamFixedIter(22050, true);
	}
};