eas_main.c revision 56c99cd2c2c1e6ab038dac5fced5b92ccf11ff6c
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
85    /* determine the name of the output file */
86    wFile = NULL;
87    if (outputFile == NULL)
88    {
89        StrCopy(waveFilename, filename, sizeof(waveFilename));
90        if (!ChangeFileExt(waveFilename, "wav", sizeof(waveFilename)))
91        {
92            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error in output filename %s\n", waveFilename); */ }
93            return EAS_FAILURE;
94        }
95        outputFile = waveFilename;
96    }
97
98    /* call EAS library to open file */
99    if ((reportResult = EAS_OpenFile(easData, filename, &handle)) != EAS_SUCCESS)
100    {
101        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_OpenFile returned %ld\n", reportResult); */ }
102        return reportResult;
103    }
104
105    /* prepare to play the file */
106    if ((result = EAS_Prepare(easData, handle)) != EAS_SUCCESS)
107    {
108        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Prepare returned %ld\n", result); */ }
109        reportResult = result;
110    }
111
112    /* get play length */
113    if ((result = EAS_ParseMetaData(easData, handle, &playTime)) != EAS_SUCCESS)
114    {
115        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_ParseMetaData returned %ld\n", result); */ }
116        return result;
117    }
118    EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0xe624f4d9, 0x00000005 , playTime / 1000, playTime % 1000);
119
120    if (reportResult == EAS_SUCCESS)
121    {
122        /* create the output file */
123        wFile = WaveFileCreate(outputFile, pLibConfig->numChannels, pLibConfig->sampleRate, sizeof(EAS_PCM) * 8);
124        if (!wFile)
125        {
126            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to create output file %s\n", waveFilename); */ }
127            reportResult = EAS_FAILURE;
128        }
129    }
130
131    /* rendering loop */
132    while (reportResult == EAS_SUCCESS)
133    {
134
135        /* we may render several buffers here to fill one host buffer */
136        for (i = 0, p = buffer; i < NUM_BUFFERS; i++, p+= pLibConfig->mixBufferSize * pLibConfig->numChannels)
137        {
138
139            /* get the current time */
140            if ((result = EAS_GetLocation(easData, handle, &playTime)) != EAS_SUCCESS)
141            {
142                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_GetLocation returned %d\n",result); */ }
143                if (reportResult == EAS_SUCCESS)
144                    reportResult = result;
145                break;
146            }
147            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Parser time: %d.%03d\n", playTime / 1000, playTime % 1000); */ }
148
149            /* render a buffer of audio */
150            if ((result = EAS_Render(easData, p, pLibConfig->mixBufferSize, &count)) != EAS_SUCCESS)
151            {
152                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Render returned %d\n",result); */ }
153                if (reportResult == EAS_SUCCESS)
154                    reportResult = result;
155            }
156        }
157
158        if (result == EAS_SUCCESS)
159        {
160            /* write it to the wave file */
161            if (WaveFileWrite(wFile, buffer, bufferSize) != bufferSize)
162            {
163                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "WaveFileWrite failed\n"); */ }
164                reportResult = EAS_FAILURE;
165            }
166        }
167
168        if (reportResult == EAS_SUCCESS)
169        {
170            /* check stream state */
171            if ((result = EAS_State(easData, handle, &state)) != EAS_SUCCESS)
172            {
173                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_State returned %d\n", result); */ }
174                reportResult = result;
175            }
176
177            /* is playback complete */
178            if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR))
179                break;
180        }
181    }
182
183    /* close the output file */
184    if (wFile)
185    {
186        if (!WaveFileClose(wFile))
187        {
188            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error closing wave file %s\n", waveFilename); */ }
189            if (reportResult == EAS_SUCCESS)
190                result = EAS_FAILURE;
191        }
192    }
193
194    /* close the input file */
195    if ((result = EAS_CloseFile(easData,handle)) != EAS_SUCCESS)
196    {
197        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Close returned %ld\n", result); */ }
198        if (reportResult == EAS_SUCCESS)
199            result = EAS_FAILURE;
200    }
201
202    return reportResult;
203} /* end PlayFile */
204
205/*----------------------------------------------------------------------------
206 * main()
207 *----------------------------------------------------------------------------
208 * Purpose: The entry point for the EAS sample application
209 *
210 * Inputs:
211 *
212 * Outputs:
213 *
214 *----------------------------------------------------------------------------
215*/
216int main( int argc, char **argv )
217{
218    EAS_DATA_HANDLE easData;
219    const S_EAS_LIB_CONFIG *pLibConfig;
220    void *buffer;
221    EAS_RESULT result, playResult;
222    EAS_I32 bufferSize;
223    int i;
224    int temp;
225    FILE *debugFile;
226    char *outputFile = NULL;
227
228    /* set the error reporting level */
229    EAS_SetDebugLevel(_EAS_SEVERITY_INFO);
230    debugFile = NULL;
231
232    /* process command-line arguments */
233    for (i = 1; i < argc; i++)
234    {
235        /* check for switch */
236        if (argv[i][0] == '-')
237        {
238            switch (argv[i][1])
239            {
240            case 'd':
241                temp = argv[i][2];
242                if ((temp >= '0') || (temp <= '9'))
243                    EAS_SetDebugLevel(temp);
244                else
245                    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid debug level %d\n", temp); */ }
246                break;
247            case 'f':
248                if ((debugFile = fopen(&argv[i][2],"w")) == NULL)
249                    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unable to create debug file %s\n", &argv[i][2]); */ }
250                else
251                    EAS_SetDebugFile(debugFile, EAS_TRUE);
252                break;
253            case 'o':
254                outputFile = &argv[i][2];
255                break;
256            case 'p':
257                polyphony = atoi(&argv[i][2]);
258                if (polyphony < 1)
259                    polyphony = 1;
260                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Polyphony set to %d\n", polyphony); */ }
261                break;
262            default:
263                break;
264            }
265            continue;
266        }
267    }
268
269    /* assume success */
270    playResult = EAS_SUCCESS;
271
272    /* get the library configuration */
273    pLibConfig = EAS_Config();
274    if (!EASLibraryCheck(pLibConfig))
275        return -1;
276    if (polyphony > pLibConfig->maxVoices)
277        polyphony = pLibConfig->maxVoices;
278
279    /* calculate buffer size */
280    bufferSize = pLibConfig->mixBufferSize * pLibConfig->numChannels * (EAS_I32)sizeof(EAS_PCM) * NUM_BUFFERS;
281
282    /* allocate output buffer memory */
283    buffer = malloc((EAS_U32)bufferSize);
284    if (!buffer)
285    {
286        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Error allocating memory for audio buffer\n"); */ }
287        return EAS_FAILURE;
288    }
289
290    /* initialize the EAS library */
291    polyphony = pLibConfig->maxVoices;
292    if ((result = EAS_Init(&easData)) != EAS_SUCCESS)
293    {
294        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Init returned %ld - aborting!\n", result); */ }
295        free(buffer);
296        return result;
297    }
298
299    /*
300     * Some debugging environments don't allow for passed parameters.
301     * In this case, just play the default MIDI file "test.mid"
302     */
303    if (argc < 2)
304    {
305        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", defaultTestFile); */ }
306        if ((playResult = PlayFile(easData, defaultTestFile, NULL, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS)
307        {
308            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, defaultTestFile); */ }
309        }
310    }
311    /* iterate through the list of files to be played */
312    else
313    {
314        for (i = 1; i < argc; i++)
315        {
316            /* check for switch */
317            if (argv[i][0] != '-')
318            {
319
320                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", argv[i]); */ }
321                if ((playResult = PlayFile(easData, argv[i], outputFile, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS)
322                {
323                    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, argv[i]); */ }
324                    break;
325                }
326            }
327        }
328    }
329
330    /* shutdown the EAS library */
331    if ((result = EAS_Shutdown(easData)) != EAS_SUCCESS)
332    {
333        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Shutdown returned %ld\n", result); */ }
334    }
335
336    /* free the output buffer */
337    free(buffer);
338
339    /* close the debug file */
340    if (debugFile)
341        fclose(debugFile);
342
343    /* play errors take precedence over shutdown errors */
344    if (playResult != EAS_SUCCESS)
345        return playResult;
346    return result;
347} /* end main */
348
349/*----------------------------------------------------------------------------
350 * StrCopy()
351 *----------------------------------------------------------------------------
352 * Purpose:
353 * Safe string copy
354 *
355 * Inputs:
356 *
357 * Outputs:
358 *
359 *----------------------------------------------------------------------------
360*/
361static void StrCopy(char *dest, const char *src, EAS_I32 size)
362{
363    int len;
364
365    strncpy(dest, src, (size_t) size-1);
366    len = (int) strlen(src);
367    if (len < size)
368        dest[len] = 0;
369} /* end StrCopy */
370
371/*----------------------------------------------------------------------------
372 * ChangeFileExt()
373 *----------------------------------------------------------------------------
374 * Purpose:
375 * Changes the file extension of a filename
376 *
377 * Inputs:
378 *
379 * Outputs:
380 *
381 *----------------------------------------------------------------------------
382*/
383static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size)
384{
385    char *p;
386
387    /* find the extension, if any */
388    p = strrchr(str,'.');
389    if (!p)
390    {
391        if ((EAS_I32)(strlen(str) + 5) > size)
392            return EAS_FALSE;
393        strcat(str,".");
394        strcat(str,ext);
395        return EAS_TRUE;
396    }
397
398    /* make sure there's room for the extension */
399    p++;
400    *p = 0;
401    if ((EAS_I32)(strlen(str) + 4) > size)
402        return EAS_FALSE;
403    strcat(str,ext);
404    return EAS_TRUE;
405} /* end ChangeFileExt */
406
407/*----------------------------------------------------------------------------
408 * EASLibraryCheck()
409 *----------------------------------------------------------------------------
410 * Purpose:
411 * Displays the library version and checks it against the header
412 * file used to build this code.
413 *
414 * Inputs:
415 * pLibConfig       - library configuration retrieved from the library
416 *
417 * Outputs:
418 * returns EAS_TRUE if matched
419 *
420 * Side Effects:
421 *
422 *----------------------------------------------------------------------------
423*/
424static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig)
425{
426
427    /* display the library version */
428    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "EAS Library Version %d.%d.%d.%d\n",
429        pLibConfig->libVersion >> 24,
430        (pLibConfig->libVersion >> 16) & 0x0f,
431        (pLibConfig->libVersion >> 8) & 0x0f,
432        pLibConfig->libVersion & 0x0f); */ }
433
434    /* display some info about the library build */
435    if (pLibConfig->checkedVersion)
436        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tChecked library\n"); */ }
437    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMaximum polyphony: %d\n", pLibConfig->maxVoices); */ }
438    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tNumber of channels: %d\n", pLibConfig->numChannels); */ }
439    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tSample rate: %d\n", pLibConfig->sampleRate); */ }
440    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMix buffer size: %d\n", pLibConfig->mixBufferSize); */ }
441    if (pLibConfig->filterEnabled)
442        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tFilter enabled\n"); */ }
443#ifndef _WIN32_WCE
444    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build Timestamp: %s", ctime((time_t*)&pLibConfig->buildTimeStamp)); */ }
445#endif
446    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build ID: %s\n", pLibConfig->buildGUID); */ }
447
448    /* check it against the header file used to build this code */
449    /*lint -e{778} constant expression used for display purposes may evaluate to zero */
450    if (LIB_VERSION != pLibConfig->libVersion)
451    {
452        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Library version does not match header files. EAS Header Version %d.%d.%d.%d\n",
453            LIB_VERSION >> 24,
454            (LIB_VERSION >> 16) & 0x0f,
455            (LIB_VERSION >> 8) & 0x0f,
456            LIB_VERSION & 0x0f); */ }
457        return EAS_FALSE;
458    }
459    return EAS_TRUE;
460} /* end EASLibraryCheck */
461
462