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 */
48 static const char defaultTestFile[] = "test.mid";
49
50 EAS_I32 polyphony;
51
52 /* prototypes for helper functions */
53 static void StrCopy(char *dest, const char *src, EAS_I32 size);
54 static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size);
55 static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize);
56 static 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
PlayFile(EAS_DATA_HANDLE easData,const char * filename,const char * outputFile,const S_EAS_LIB_CONFIG * pLibConfig,void * buffer,EAS_I32 bufferSize)73 static 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)) != 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 */
main(int argc,char ** argv)219 int 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 */
StrCopy(char * dest,const char * src,EAS_I32 size)364 static 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 */
ChangeFileExt(char * str,const char * ext,EAS_I32 size)386 static 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 */
EASLibraryCheck(const S_EAS_LIB_CONFIG * pLibConfig)427 static 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