eas_main.c revision e442bb7cd6a085b33a4dd52c0e20a157ada7feb1
1/*----------------------------------------------------------------------------
2 *
3 * File:
4 * eas_main.c
5 *
6 * Contents and purpose:
7 * The entry point and high-level functions for the EAS Synthesizer test
8 * harness.
9 *
10 * Copyright Sonic Network Inc. 2004
11
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 *      http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 *----------------------------------------------------------------------------
25 * Revision Control:
26 *   $Revision: 775 $
27 *   $Date: 2007-07-20 10:11:11 -0700 (Fri, 20 Jul 2007) $
28 *----------------------------------------------------------------------------
29*/
30
31#ifdef _lint
32#include "lint_stdlib.h"
33#else
34#include <stdio.h>
35#include <string.h>
36#include <stdlib.h>
37#include <time.h>
38#endif
39
40#include "eas.h"
41#include "eas_wave.h"
42#include "eas_report.h"
43
44/* determines how many EAS buffers to fill a host buffer */
45#define NUM_BUFFERS			8
46
47/* default file to play if no filename is specified on the command line */
48static const char defaultTestFile[] = "test.mid";
49
50EAS_I32 polyphony;
51
52/* prototypes for helper functions */
53static void StrCopy(char *dest, const char *src, EAS_I32 size);
54static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size);
55static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize);
56static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig);
57
58/* main is defined after playfile to avoid the need for two passes through lint */
59
60/*----------------------------------------------------------------------------
61 * PlayFile()
62 *----------------------------------------------------------------------------
63 * Purpose:
64 * This function plays the file requested by filename
65 *
66 * Inputs:
67 *
68 * Outputs:
69 *
70 *----------------------------------------------------------------------------
71*/
72
73static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize)
74{
75	EAS_HANDLE handle;
76	EAS_RESULT result, reportResult;
77	EAS_I32 count;
78	EAS_STATE state;
79	EAS_I32 playTime;
80	char waveFilename[256];
81	WAVE_FILE *wFile;
82	EAS_INT i;
83	EAS_PCM *p;
84	EAS_FILE file;
85
86	/* determine the name of the output file */
87	wFile = NULL;
88	if (outputFile == NULL)
89	{
90		StrCopy(waveFilename, filename, sizeof(waveFilename));
91		if (!ChangeFileExt(waveFilename, "wav", sizeof(waveFilename)))
92		{
93			{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error in output filename %s\n", waveFilename); */ }
94			return EAS_FAILURE;
95		}
96		outputFile = waveFilename;
97	}
98
99	/* call EAS library to open file */
100	file.path = filename;
101	file.fd = 0;
102	if ((reportResult = EAS_OpenFile(easData, &file, &handle, NULL)) != EAS_SUCCESS)
103	{
104		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_OpenFile returned %ld\n", reportResult); */ }
105		return reportResult;
106	}
107
108	/* prepare to play the file */
109	if ((result = EAS_Prepare(easData, handle)) != EAS_SUCCESS)
110	{
111		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Prepare returned %ld\n", result); */ }
112		reportResult = result;
113	}
114
115	/* get play length */
116	if ((result = EAS_ParseMetaData(easData, handle, &playTime)) != EAS_SUCCESS)
117	{
118		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_ParseMetaData returned %ld\n", result); */ }
119		return result;
120	}
121	EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0xe624f4d9, 0x00000005 , playTime / 1000, playTime % 1000);
122
123	if (reportResult == EAS_SUCCESS)
124	{
125		/* create the output file */
126		wFile = WaveFileCreate(outputFile, pLibConfig->numChannels, pLibConfig->sampleRate, sizeof(EAS_PCM) * 8);
127		if (!wFile)
128		{
129			{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to create output file %s\n", waveFilename); */ }
130			reportResult = EAS_FAILURE;
131		}
132	}
133
134	/* rendering loop */
135	while (reportResult == EAS_SUCCESS)
136	{
137
138		/* we may render several buffers here to fill one host buffer */
139		for (i = 0, p = buffer; i < NUM_BUFFERS; i++, p+= pLibConfig->mixBufferSize * pLibConfig->numChannels)
140		{
141
142			/* get the current time */
143			if ((result = EAS_GetLocation(easData, handle, &playTime)) != EAS_SUCCESS)
144			{
145				{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_GetLocation returned %d\n",result); */ }
146				if (reportResult == EAS_SUCCESS)
147					reportResult = result;
148				break;
149			}
150			{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Parser time: %d.%03d\n", playTime / 1000, playTime % 1000); */ }
151
152			/* render a buffer of audio */
153			if ((result = EAS_Render(easData, p, pLibConfig->mixBufferSize, &count)) != EAS_SUCCESS)
154			{
155				{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Render returned %d\n",result); */ }
156				if (reportResult == EAS_SUCCESS)
157					reportResult = result;
158			}
159		}
160
161		if (result == EAS_SUCCESS)
162		{
163			/* write it to the wave file */
164			if (WaveFileWrite(wFile, buffer, bufferSize) != bufferSize)
165			{
166				{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "WaveFileWrite failed\n"); */ }
167				reportResult = EAS_FAILURE;
168			}
169		}
170
171		if (reportResult == EAS_SUCCESS)
172		{
173			/* check stream state */
174			if ((result = EAS_State(easData, handle, &state)) != EAS_SUCCESS)
175			{
176				{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_State returned %d\n", result); */ }
177				reportResult = result;
178			}
179
180			/* is playback complete */
181			if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR))
182				break;
183		}
184	}
185
186	/* close the output file */
187	if (wFile)
188	{
189		if (!WaveFileClose(wFile))
190		{
191			{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error closing wave file %s\n", waveFilename); */ }
192			if (reportResult == EAS_SUCCESS)
193				result = EAS_FAILURE;
194		}
195	}
196
197	/* close the input file */
198	if ((result = EAS_CloseFile(easData,handle)) != EAS_SUCCESS)
199	{
200		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Close returned %ld\n", result); */ }
201		if (reportResult == EAS_SUCCESS)
202			result = EAS_FAILURE;
203	}
204
205	return reportResult;
206} /* end PlayFile */
207
208/*----------------------------------------------------------------------------
209 * main()
210 *----------------------------------------------------------------------------
211 * Purpose: The entry point for the EAS sample application
212 *
213 * Inputs:
214 *
215 * Outputs:
216 *
217 *----------------------------------------------------------------------------
218*/
219int main( int argc, char **argv )
220{
221	EAS_DATA_HANDLE easData;
222	const S_EAS_LIB_CONFIG *pLibConfig;
223	void *buffer;
224	EAS_RESULT result, playResult;
225	EAS_I32 bufferSize;
226	int i;
227	int temp;
228	FILE *debugFile;
229	char *outputFile = NULL;
230
231	/* set the error reporting level */
232	EAS_SetDebugLevel(_EAS_SEVERITY_INFO);
233	debugFile = NULL;
234
235	/* process command-line arguments */
236	for (i = 1; i < argc; i++)
237	{
238		/* check for switch */
239		if (argv[i][0] == '-')
240		{
241			switch (argv[i][1])
242			{
243			case 'd':
244				temp = argv[i][2];
245				if ((temp >= '0') || (temp <= '9'))
246					EAS_SetDebugLevel(temp);
247				else
248					{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid debug level %d\n", temp); */ }
249				break;
250			case 'f':
251				if ((debugFile = fopen(&argv[i][2],"w")) == NULL)
252					{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unable to create debug file %s\n", &argv[i][2]); */ }
253				else
254					EAS_SetDebugFile(debugFile, EAS_TRUE);
255				break;
256			case 'o':
257				outputFile = &argv[i][2];
258				break;
259			case 'p':
260				polyphony = atoi(&argv[i][2]);
261				if (polyphony < 1)
262					polyphony = 1;
263				{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Polyphony set to %d\n", polyphony); */ }
264				break;
265			default:
266				break;
267			}
268			continue;
269		}
270	}
271
272	/* assume success */
273	playResult = EAS_SUCCESS;
274
275	/* get the library configuration */
276	pLibConfig = EAS_Config();
277	if (!EASLibraryCheck(pLibConfig))
278		return -1;
279	if (polyphony > pLibConfig->maxVoices)
280		polyphony = pLibConfig->maxVoices;
281
282	/* calculate buffer size */
283	bufferSize = pLibConfig->mixBufferSize * pLibConfig->numChannels * (EAS_I32)sizeof(EAS_PCM) * NUM_BUFFERS;
284
285	/* allocate output buffer memory */
286	buffer = malloc((EAS_U32)bufferSize);
287	if (!buffer)
288	{
289		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Error allocating memory for audio buffer\n"); */ }
290		return EAS_FAILURE;
291	}
292
293	/* initialize the EAS library */
294	polyphony = pLibConfig->maxVoices;
295	if ((result = EAS_Init(&easData)) != EAS_SUCCESS)
296	{
297		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Init returned %ld - aborting!\n", result); */ }
298		free(buffer);
299		return result;
300	}
301
302	/*
303	 * Some debugging environments don't allow for passed parameters.
304	 * In this case, just play the default MIDI file "test.mid"
305	 */
306	if (argc < 2)
307	{
308		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", defaultTestFile); */ }
309		if ((playResult = PlayFile(easData, defaultTestFile, NULL, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS)
310		{
311			{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, defaultTestFile); */ }
312		}
313	}
314	/* iterate through the list of files to be played */
315	else
316	{
317		for (i = 1; i < argc; i++)
318		{
319			/* check for switch */
320			if (argv[i][0] != '-')
321			{
322
323				{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", argv[i]); */ }
324				if ((playResult = PlayFile(easData, argv[i], outputFile, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS)
325				{
326					{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, argv[i]); */ }
327					break;
328				}
329			}
330		}
331	}
332
333	/* shutdown the EAS library */
334	if ((result = EAS_Shutdown(easData)) != EAS_SUCCESS)
335	{
336		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Shutdown returned %ld\n", result); */ }
337	}
338
339	/* free the output buffer */
340	free(buffer);
341
342	/* close the debug file */
343	if (debugFile)
344		fclose(debugFile);
345
346	/* play errors take precedence over shutdown errors */
347	if (playResult != EAS_SUCCESS)
348		return playResult;
349	return result;
350} /* end main */
351
352/*----------------------------------------------------------------------------
353 * StrCopy()
354 *----------------------------------------------------------------------------
355 * Purpose:
356 * Safe string copy
357 *
358 * Inputs:
359 *
360 * Outputs:
361 *
362 *----------------------------------------------------------------------------
363*/
364static void StrCopy(char *dest, const char *src, EAS_I32 size)
365{
366	int len;
367
368	strncpy(dest, src, (size_t) size-1);
369	len = (int) strlen(src);
370	if (len < size)
371		dest[len] = 0;
372} /* end StrCopy */
373
374/*----------------------------------------------------------------------------
375 * ChangeFileExt()
376 *----------------------------------------------------------------------------
377 * Purpose:
378 * Changes the file extension of a filename
379 *
380 * Inputs:
381 *
382 * Outputs:
383 *
384 *----------------------------------------------------------------------------
385*/
386static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size)
387{
388	char *p;
389
390	/* find the extension, if any */
391	p = strrchr(str,'.');
392	if (!p)
393	{
394		if ((EAS_I32)(strlen(str) + 5) > size)
395			return EAS_FALSE;
396		strcat(str,".");
397		strcat(str,ext);
398		return EAS_TRUE;
399	}
400
401	/* make sure there's room for the extension */
402	p++;
403	*p = 0;
404	if ((EAS_I32)(strlen(str) + 4) > size)
405		return EAS_FALSE;
406	strcat(str,ext);
407	return EAS_TRUE;
408} /* end ChangeFileExt */
409
410/*----------------------------------------------------------------------------
411 * EASLibraryCheck()
412 *----------------------------------------------------------------------------
413 * Purpose:
414 * Displays the library version and checks it against the header
415 * file used to build this code.
416 *
417 * Inputs:
418 * pLibConfig		- library configuration retrieved from the library
419 *
420 * Outputs:
421 * returns EAS_TRUE if matched
422 *
423 * Side Effects:
424 *
425 *----------------------------------------------------------------------------
426*/
427static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig)
428{
429
430	/* display the library version */
431	{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "EAS Library Version %d.%d.%d.%d\n",
432		pLibConfig->libVersion >> 24,
433		(pLibConfig->libVersion >> 16) & 0x0f,
434		(pLibConfig->libVersion >> 8) & 0x0f,
435		pLibConfig->libVersion & 0x0f); */ }
436
437	/* display some info about the library build */
438	if (pLibConfig->checkedVersion)
439		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tChecked library\n"); */ }
440	{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMaximum polyphony: %d\n", pLibConfig->maxVoices); */ }
441	{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tNumber of channels: %d\n", pLibConfig->numChannels); */ }
442	{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tSample rate: %d\n", pLibConfig->sampleRate); */ }
443	{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMix buffer size: %d\n", pLibConfig->mixBufferSize); */ }
444	if (pLibConfig->filterEnabled)
445		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tFilter enabled\n"); */ }
446#ifndef _WIN32_WCE
447	{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build Timestamp: %s", ctime((time_t*)&pLibConfig->buildTimeStamp)); */ }
448#endif
449	{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build ID: %s\n", pLibConfig->buildGUID); */ }
450
451	/* check it against the header file used to build this code */
452	/*lint -e{778} constant expression used for display purposes may evaluate to zero */
453	if (LIB_VERSION != pLibConfig->libVersion)
454	{
455		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Library version does not match header files. EAS Header Version %d.%d.%d.%d\n",
456			LIB_VERSION >> 24,
457			(LIB_VERSION >> 16) & 0x0f,
458			(LIB_VERSION >> 8) & 0x0f,
459			LIB_VERSION & 0x0f); */ }
460		return EAS_FALSE;
461	}
462	return EAS_TRUE;
463} /* end EASLibraryCheck */
464
465