1 //-----------------------------------------------------------------------------
2 // Copyright (c) 2015-2018 Marcelo Fernandez
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to
6 // deal in the Software without restriction, including without limitation the
7 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 // sell copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 // IN THE SOFTWARE.
21 //-----------------------------------------------------------------------------
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "oamlCommon.h"
28 
29 
30 oamlAudioFile::oamlAudioFile(std::string _filename, oamlBase *_base, oamlFileCallbacks *cbs, bool _verbose) {
31 	base = _base;
32 	filename = _filename;
33 	layer = "";
34 	randomChance = -1;
35 	gain = 1.f;
36 	fcbs = cbs;
37 	verbose = _verbose;
38 
39 #ifdef __HAVE_SOXR
40 	soxr = NULL;
41 #endif
42 	handle = NULL;
43 
44 	format = 0;
45 	bytesPerSample = 0;
46 	samplesPerSec = 0;
47 	totalSamples = 0;
48 	channelCount = 0;
49 	samplesToEnd = 0;
50 	fileBytesPerSample = 0;
51 
main(int argc,char ** argv)52 	chance = false;
53 	lastChance = false;
54 }
55 
56 oamlAudioFile::~oamlAudioFile() {
57 	if (handle) {
58 		delete handle;
59 		handle = NULL;
60 	}
61 
62 #ifdef __HAVE_SOXR
63 	if (soxr) {
64 		soxr_delete(soxr);
65 		soxr = NULL;
66 	}
67 #endif
68 }
69 
70 oamlRC oamlAudioFile::OpenFile() {
71 	std::string ext = filename.substr(filename.find_last_of(".") + 1);
72 	if (ext == "wav" || ext == "wave") {
73 		handle = new wavFile(fcbs);
74 	} else if (ext == "aif" || ext == "aiff") {
75 		handle = (audioFile*)new aifFile(fcbs);
76 #ifdef __HAVE_OGG
77 	} else if (ext == "ogg") {
78 		handle = (audioFile*)new oggFile(fcbs);
79 #endif
80 	} else {
81 		fprintf(stderr, "liboaml: Unknown audio format: '%s'\n", GetFilenameStr());
82 		return OAML_ERROR;
83 	}
84 
85 	if (handle->Open(GetFilenameStr()) == -1) {
86 		fprintf(stderr, "liboaml: Error opening: '%s'\n", GetFilenameStr());
87 		return OAML_ERROR;
88 	}
89 
90 	format = handle->GetFormat();
91 	bytesPerSample = handle->GetBytesPerSample();
92 	samplesPerSec = handle->GetSamplesPerSec();
93 	totalSamples = handle->GetTotalSamples();
94 	channelCount = handle->GetChannels();
95 
96 	fileFormat = format;
97 	fileBytesPerSample = bytesPerSample;
98 
99 #ifdef __HAVE_SOXR
100 	unsigned int sampleRate = base->GetSampleRate();
101 	if (sampleRate != samplesPerSec) {
102 		if (soxr == NULL) {
find_entry_for_token(char * token)103 			soxr_io_spec_t spec;
104 
105 			switch (format) {
106 				case AF_FORMAT_SINT8:
107 				case AF_FORMAT_SINT16:
108 				case AF_FORMAT_SINT24:
109 					spec.itype = SOXR_INT16_I;
110 					break;
111 
112 				case AF_FORMAT_SINT32:
113 					spec.itype = SOXR_INT32_I;
114 					break;
115 
116 				case AF_FORMAT_FLOAT32:
117 					spec.itype = SOXR_FLOAT32_I;
parse_line(char * line,SourceType type)118 					break;
119 			}
120 			spec.otype = SOXR_INT16_I;
121 			spec.scale = 1;
122 			spec.e = NULL;
123 			spec.flags = 0;
124 
125 			soxr = soxr_create(double(samplesPerSec), double(sampleRate), channelCount, NULL, &spec, NULL, NULL);
126 		}
127 
128 		totalSamples = (double)totalSamples * sampleRate / samplesPerSec;
129 		samplesToEnd = (double)samplesToEnd * sampleRate / samplesPerSec;
130 		samplesPerSec = sampleRate;
131 		format = AF_FORMAT_SINT16;
132 		bytesPerSample = 2;
133 	}
134 #endif
135 
136 	return OAML_OK;
137 }
138 
139 oamlRC oamlAudioFile::Open() {
140 	if (verbose) __oamlLog("%s %s\n", __FUNCTION__, GetFilenameStr());
141 	if (buffer.size() == 0) {
142 		oamlRC rc = OpenFile();
143 		if (rc != OAML_OK) return rc;
144 	}
145 
146 	if (GetRandomChance() != -1) {
147 		chance = __oamlRandom(0, 100) > GetRandomChance();
148 	} else {
parse_contents(FILE * stream,SourceType type)149 		lastChance = true;
150 		chance = true;
151 	}
152 
153 	return OAML_OK;
154 }
155 
156 oamlRC oamlAudioFile::Load() {
157 	int ret;
158 	do {
159 		ret = Read();
160 	} while (ret > 0);
161 
162 	if (ret == -1) return OAML_ERROR;
163 	return OAML_OK;
164 }
165 
166 int oamlAudioFile::LoadProgress() {
167 	if (handle == NULL) {
168 		return buffer.size()/bytesPerSample;
169 	}
170 
171 	int ret = Read();
172 	if (ret == -1) {
173 		return -1;
174 	}
175 
176 	return buffer.size()/bytesPerSample;
177 }
178 
179 int oamlAudioFile::Read() {
180 	if (handle == NULL)
181 		return -1;
182 
183 	char buf[4096];
184 	int frames = 4096 / fileBytesPerSample / channelCount;
185 	int readSize = frames * fileBytesPerSample * channelCount;
186 	int bytes = handle->Read(buf, readSize);
187 	if (bytes <= 0) {
188 		handle->Close();
189 		delete handle;
190 		handle = NULL;
191 	}
192 
193 #ifdef __HAVE_SOXR
194 	if (soxr != NULL) {
195 		// Re-sample through libsoxr
196 		char obuf[4096*4];
197 
198 		size_t ilen = bytes / fileBytesPerSample / channelCount;
199 		size_t idone = 0;
200 		size_t olen = 4096*4 / bytesPerSample / channelCount;
201 		size_t odone = 0;
202 		soxr_error_t err;
203 
204 		switch (fileFormat) {
205 			case AF_FORMAT_SINT8:
206 				// 8-bit is not directly supported by libsoxr, convert the buffer to 16-bit and then process
207 				{
208 					int16_t buf16[4096];
209 					for (int i=0; i<bytes; i++) {
210 						buf16[i] = (int16_t)buf[i] << 8;
211 					}
212 
213 					err = soxr_process(soxr, (char*)buf16, ilen, &idone, obuf, olen, &odone);
214 				}
215 				break;
216 
217 			case AF_FORMAT_SINT24:
218 				// 24-bit is not directly supported by libsoxr, convert the buffer to 16-bit and then process
219 				{
220 					int16_t buf16[4096];
221 					for (int i=0; i<bytes/3; i++) {
222 						buf16[i] = (((int16_t)buf[i*3+2] & 0xFF) << 8) | ((int16_t)buf[i*3+1] & 0xFF);
223 					}
224 
225 					err = soxr_process(soxr, (char*)buf16, ilen, &idone, obuf, olen, &odone);
226 				}
227 				break;
228 
229 			default:
230 				// Input format is supported by libsoxr, process out buffers
231 				err = soxr_process(soxr, buf, ilen, &idone, obuf, olen, &odone);
232 				break;
233 		}
234 
235 		if (err != NULL) {
236 			fprintf(stderr, "liboaml: Error on soxr_process\n");
237 			return -1;
238 		} else if (odone > 0) {
239 			buffer.putBytes((uint8_t*)obuf, odone * bytesPerSample * channelCount);
240 		}
241 
242 		return odone;
243 	}
244 #endif
245 
246 	if (bytes > 0) {
247 		buffer.putBytes((uint8_t*)buf, bytes);
248 	}
249 
250 	return bytes;
251 }
252 
253 int oamlAudioFile::Read32(unsigned int pos) {
254 	int ret = 0;
255 
256 	if (pos > totalSamples)
257 		return 0;
258 
259 	pos*= bytesPerSample;
260 	while ((pos+bytesPerSample) > buffer.size()) {
261 		if (Read() == -1)
262 			return 0;
263 	}
264 
265 	switch (format) {
266 		case AF_FORMAT_FLOAT32:
267 			ret|= ((uint32_t)buffer.get(pos));
268 			ret|= ((uint32_t)buffer.get(pos+1))<<8;
269 			ret|= ((uint32_t)buffer.get(pos+2))<<16;
270 			ret|= ((uint32_t)buffer.get(pos+3))<<24;
271 			ret = uint32_t(*(float*)&ret * 32768.f) << 16;
272 			break;
273 
274 		case AF_FORMAT_SINT32:
275 			break;
276 
277 		case AF_FORMAT_SINT24:
278 			ret|= ((uint32_t)buffer.get(pos))<<8;
279 			ret|= ((uint32_t)buffer.get(pos+1))<<16;
280 			ret|= ((uint32_t)buffer.get(pos+2))<<24;
281 			break;
282 
283 		case AF_FORMAT_SINT16:
284 			ret|= ((uint32_t)buffer.get(pos))<<16;
285 			ret|= ((uint32_t)buffer.get(pos+1))<<24;
286 			break;
287 
288 		case AF_FORMAT_SINT8:
289 			ret|= ((uint32_t)buffer.get(pos))<<23;
290 			break;
291 	}
292 
293 	return ret;
294 }
295 
296 float oamlAudioFile::ReadFloat(unsigned int pos, bool isTail) {
297 	if (isTail) {
298 		if (lastChance == false)
299 			return 0.f;
300 	} else {
301 		if (pos == (samplesToEnd-1)) {
302 			lastChance = chance;
303 		}
304 
305 		if (chance == false)
306 			return 0.f;
307 	}
308 
309 	float sample = __oamlInteger24ToFloat(Read32(pos)>>8);
310 	if (GetGain() != 1.f) {
311 		sample*= GetGain();
312 	}
313 	return sample;
314 }
315 
316 void oamlAudioFile::FreeMemory() {
317 	if (buffer.size() > 0 || handle != NULL) {
318 		if (verbose) __oamlLog("%s %s\n", __FUNCTION__, GetFilenameStr());
319 	}
320 
321 	buffer.clear();
322 	buffer.free();
323 
324 	if (handle) {
325 		delete handle;
326 		handle = NULL;
327 	}
328 
329 	format = 0;
330 	bytesPerSample = 0;
331 	samplesPerSec = 0;
332 	totalSamples = 0;
333 	channelCount = 0;
334 }
335