1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /***************************************************************************
3  *            audiocachefiletest.cc
4  *
5  *  Thu Jan  7 15:43:12 CET 2016
6  *  Copyright 2016 Bent Bisballe Nyeng
7  *  deva@aasimon.org
8  ****************************************************************************/
9 
10 /*
11  *  This file is part of DrumGizmo.
12  *
13  *  DrumGizmo is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU Lesser General Public License as published by
15  *  the Free Software Foundation; either version 3 of the License, or
16  *  (at your option) any later version.
17  *
18  *  DrumGizmo is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU Lesser General Public License for more details.
22  *
23  *  You should have received a copy of the GNU Lesser General Public License
24  *  along with DrumGizmo; if not, write to the Free Software
25  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
26  */
27 #include <uunit.h>
28 
29 #include <cstring>
30 
31 #include <audiocachefile.h>
32 #include <audiofile.h>
33 
34 #include "drumkit_creator.h"
35 
36 class TestableAudioCacheFiles
37 	: public AudioCacheFiles
38 {
39 public:
40 	//CacheAudioFile& getAudioFile(const std::string& filename);
41 	//void release(const std::string& filename);
getRef(const std::string & filename)42 	int getRef(const std::string& filename)
43 	{
44 		auto it = audiofiles.find(filename);
45 
46 		if(it == audiofiles.end())
47 		{
48 			return -1;
49 		}
50 
51 		return (it->second).ref;
52 	}
53 };
54 
55 class AudioCacheFileTest
56 	: public uUnit
57 {
58 public:
AudioCacheFileTest()59 	AudioCacheFileTest()
60 	{
61 		uUNIT_TEST(AudioCacheFileTest::refTest);
62 		uUNIT_TEST(AudioCacheFileTest::readTest);
63 		uUNIT_TEST(AudioCacheFileTest::noFileTest);
64 	}
65 
66 	DrumkitCreator drumkit_creator;
67 
refTest()68 	void refTest()
69 	{
70 		// Create the audio file
71 		auto filename = drumkit_creator.createSingleChannelWav("single_channel.wav");
72 
73 		// Conduct tests
74 		TestableAudioCacheFiles audiofiles;
75 		uUNIT_ASSERT_EQUAL(-1, audiofiles.getRef(filename));
76 
77 		audiofiles.getFile(filename);
78 		uUNIT_ASSERT_EQUAL(1, audiofiles.getRef(filename));
79 
80 		audiofiles.getFile(filename);
81 		uUNIT_ASSERT_EQUAL(2, audiofiles.getRef(filename));
82 
83 		audiofiles.releaseFile(filename);
84 		uUNIT_ASSERT_EQUAL(1, audiofiles.getRef(filename));
85 
86 		audiofiles.releaseFile(filename);
87 		uUNIT_ASSERT_EQUAL(-1, audiofiles.getRef(filename));
88 	}
89 
readTestHelper(size_t buffer_size)90 	void readTestHelper(size_t buffer_size)
91 	{
92 		printf("Test buffer size: %d samples\n", (int)buffer_size);
93 
94 		// Create the audio file
95 		auto filename = drumkit_creator.createMultiChannelWav("multi_channel.wav");
96 
97 		// Conduct tests
98 		AudioFile* ref_file[13];
99 		for(size_t c = 0; c < 13; ++c)
100 		{
101 			ref_file[c] = new AudioFile(filename, c);
102 			ref_file[c]->load(nullptr);
103 		}
104 
105 		std::vector<sample_t> read_buffer;
106 
107 		AudioCacheFile file(filename, read_buffer);
108 		uUNIT_ASSERT_EQUAL(filename, file.getFilename());
109 		uUNIT_ASSERT_EQUAL(13, (int)file.getChannelCount()); // Sanity check
110 
111 		CacheChannels channels;
112 
113 		sample_t samples[13][buffer_size];
114 		volatile bool ready[13];
115 		for(size_t c = 0; c < 13; ++c)
116 		{
117 			for(size_t i = 0; i < buffer_size; ++i)
118 			{
119 				samples[c][i] = 42;
120 			}
121 
122 			channels.push_back(
123 				{
124 					c, // channel
125 					samples[c], // samples
126 					buffer_size, // max_num_samples
127 					&ready[c] // ready
128 				}
129 			);
130 		}
131 
132 		for(size_t offset = 0; offset < file.getSize(); offset += buffer_size)
133 		{
134 			for(size_t c = 0; c < 13; ++c)
135 			{
136 				ready[c] = false;
137 			}
138 
139 			size_t read_size = file.getSize() - offset;
140 			if(read_size > buffer_size)
141 			{
142 				read_size = buffer_size;
143 			}
144 			else
145 			{
146 				printf("Last read: %d samples\n", (int)read_size);
147 			}
148 
149 			file.readChunk(channels, offset, read_size);
150 
151 			for(size_t c = 0; c < 13; ++c)
152 			{
153 				uUNIT_ASSERT_EQUAL(true, ready[c]?true:false);
154 			}
155 
156 			sample_t diff[13] = {0.0};
157 			for(size_t c = 0; c < 13; ++c)
158 			{
159 				for(size_t i = 0; i < read_size; ++i)
160 				{
161 					diff[c] += abs((long)(ref_file[c]->data[i + offset] - samples[c][i]));
162 				}
163 			}
164 
165 			for(int c = 0; c < 13; ++c)
166 			{
167 				uUNIT_ASSERT_EQUAL((sample_t)0.0, diff[c]);
168 			}
169 		}
170 
171 		for(size_t c = 0; c < 13; ++c)
172 		{
173 			delete ref_file[c];
174 		}
175 	}
176 
readTest()177 	void readTest()
178 	{
179 		// Exhaustive test for 1...64
180 		for(size_t buffer_size = 1; buffer_size < 64; ++buffer_size)
181 		{
182 			readTestHelper(buffer_size);
183 		}
184 
185 		// Binary test for 64 .. 4096
186 		for(size_t buffer_size = 64; buffer_size < 4096; buffer_size *= 2)
187 		{
188 			readTestHelper(buffer_size);
189 		}
190 
191 		// And some sporadic tests for some "wierd" sizes.
192 		for(size_t buffer_size = 65; buffer_size < 4096; buffer_size *= 1.1)
193 		{
194 			readTestHelper(buffer_size);
195 		}
196 	}
197 
noFileTest()198 	void noFileTest()
199 	{
200 		size_t buffer_size = 64;
201 		std::string filename = "kits/no-such-file.wav";
202 
203 		std::vector<sample_t> read_buffer;
204 
205 		AudioCacheFile file(filename, read_buffer);
206 		uUNIT_ASSERT_EQUAL(filename, file.getFilename());
207 		uUNIT_ASSERT_EQUAL(0u, (unsigned int)file.getSize());
208 		uUNIT_ASSERT_EQUAL(0u, (unsigned int)file.getChannelCount());
209 
210 		CacheChannels channels;
211 
212 		sample_t samples[13][buffer_size];
213 		volatile bool ready[13];
214 		for(size_t c = 0; c < 13; ++c)
215 		{
216 			for(size_t i = 0; i < buffer_size; ++i)
217 			{
218 				samples[c][i] = 42.0f;
219 			}
220 
221 			channels.push_back(
222 				{
223 					c, // channel
224 					samples[c], // samples
225 					buffer_size, // max_num_samples
226 					&ready[c] // ready
227 				}
228 			);
229 		}
230 
231 		for(size_t c = 0; c < 13; ++c)
232 		{
233 			ready[c] = false;
234 		}
235 
236 		file.readChunk(channels, 0, buffer_size);
237 
238 		for(size_t c = 0; c < 13; ++c)
239 		{
240 			uUNIT_ASSERT_EQUAL(false, ready[c]?true:false);
241 		}
242 
243 		for(size_t c = 0; c < 13; ++c)
244 		{
245 			for(size_t i = 0; i < buffer_size; ++i)
246 			{
247 				uUNIT_ASSERT_EQUAL(42.0f, samples[c][i]);
248 			}
249 		}
250 	}
251 };
252 
253 // Registers the fixture into the 'registry'
254 static AudioCacheFileTest test;
255