aboutsummaryrefslogtreecommitdiff
path: root/test/audio/audiostream.h
blob: b94ee087d02c3f79e888daba8e470272e12cee01 (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
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
#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);
	}
};