/*---------------------------------------------------------------------------- * * File: * eas_main.c * * Contents and purpose: * The entry point and high-level functions for the EAS Synthesizer test * harness. * * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *---------------------------------------------------------------------------- * Revision Control: * $Revision: 775 $ * $Date: 2007-07-20 10:11:11 -0700 (Fri, 20 Jul 2007) $ *---------------------------------------------------------------------------- */ #ifdef _lint #include "lint_stdlib.h" #else #include #include #include #include #endif #include "eas.h" #include "eas_wave.h" #include "eas_report.h" /* determines how many EAS buffers to fill a host buffer */ #define NUM_BUFFERS 8 /* default file to play if no filename is specified on the command line */ static const char defaultTestFile[] = "test.mid"; EAS_I32 polyphony; /* prototypes for helper functions */ static void StrCopy(char *dest, const char *src, EAS_I32 size); static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size); 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); static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig); /* main is defined after playfile to avoid the need for two passes through lint */ /*---------------------------------------------------------------------------- * PlayFile() *---------------------------------------------------------------------------- * Purpose: * This function plays the file requested by filename * * Inputs: * * Outputs: * *---------------------------------------------------------------------------- */ 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) { EAS_HANDLE handle; EAS_RESULT result, reportResult; EAS_I32 count; EAS_STATE state; EAS_I32 playTime; char waveFilename[256]; WAVE_FILE *wFile; EAS_INT i; EAS_PCM *p; /* determine the name of the output file */ wFile = NULL; if (outputFile == NULL) { StrCopy(waveFilename, filename, sizeof(waveFilename)); if (!ChangeFileExt(waveFilename, "wav", sizeof(waveFilename))) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error in output filename %s\n", waveFilename); */ } return EAS_FAILURE; } outputFile = waveFilename; } /* call EAS library to open file */ if ((reportResult = EAS_OpenFile(easData, filename, &handle)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_OpenFile returned %ld\n", reportResult); */ } return reportResult; } /* prepare to play the file */ if ((result = EAS_Prepare(easData, handle)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Prepare returned %ld\n", result); */ } reportResult = result; } /* get play length */ if ((result = EAS_ParseMetaData(easData, handle, &playTime)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_ParseMetaData returned %ld\n", result); */ } return result; } EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0xe624f4d9, 0x00000005 , playTime / 1000, playTime % 1000); if (reportResult == EAS_SUCCESS) { /* create the output file */ wFile = WaveFileCreate(outputFile, pLibConfig->numChannels, pLibConfig->sampleRate, sizeof(EAS_PCM) * 8); if (!wFile) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to create output file %s\n", waveFilename); */ } reportResult = EAS_FAILURE; } } /* rendering loop */ while (reportResult == EAS_SUCCESS) { /* we may render several buffers here to fill one host buffer */ for (i = 0, p = buffer; i < NUM_BUFFERS; i++, p+= pLibConfig->mixBufferSize * pLibConfig->numChannels) { /* get the current time */ if ((result = EAS_GetLocation(easData, handle, &playTime)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_GetLocation returned %d\n",result); */ } if (reportResult == EAS_SUCCESS) reportResult = result; break; } { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Parser time: %d.%03d\n", playTime / 1000, playTime % 1000); */ } /* render a buffer of audio */ if ((result = EAS_Render(easData, p, pLibConfig->mixBufferSize, &count)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Render returned %d\n",result); */ } if (reportResult == EAS_SUCCESS) reportResult = result; } } if (result == EAS_SUCCESS) { /* write it to the wave file */ if (WaveFileWrite(wFile, buffer, bufferSize) != bufferSize) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "WaveFileWrite failed\n"); */ } reportResult = EAS_FAILURE; } } if (reportResult == EAS_SUCCESS) { /* check stream state */ if ((result = EAS_State(easData, handle, &state)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_State returned %d\n", result); */ } reportResult = result; } /* is playback complete */ if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) break; } } /* close the output file */ if (wFile) { if (!WaveFileClose(wFile)) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error closing wave file %s\n", waveFilename); */ } if (reportResult == EAS_SUCCESS) result = EAS_FAILURE; } } /* close the input file */ if ((result = EAS_CloseFile(easData,handle)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Close returned %ld\n", result); */ } if (reportResult == EAS_SUCCESS) result = EAS_FAILURE; } return reportResult; } /* end PlayFile */ /*---------------------------------------------------------------------------- * main() *---------------------------------------------------------------------------- * Purpose: The entry point for the EAS sample application * * Inputs: * * Outputs: * *---------------------------------------------------------------------------- */ int main( int argc, char **argv ) { EAS_DATA_HANDLE easData; const S_EAS_LIB_CONFIG *pLibConfig; void *buffer; EAS_RESULT result, playResult; EAS_I32 bufferSize; int i; int temp; FILE *debugFile; char *outputFile = NULL; /* set the error reporting level */ EAS_SetDebugLevel(_EAS_SEVERITY_INFO); debugFile = NULL; /* process command-line arguments */ for (i = 1; i < argc; i++) { /* check for switch */ if (argv[i][0] == '-') { switch (argv[i][1]) { case 'd': temp = argv[i][2]; if ((temp >= '0') || (temp <= '9')) EAS_SetDebugLevel(temp); else { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid debug level %d\n", temp); */ } break; case 'f': if ((debugFile = fopen(&argv[i][2],"w")) == NULL) { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unable to create debug file %s\n", &argv[i][2]); */ } else EAS_SetDebugFile(debugFile, EAS_TRUE); break; case 'o': outputFile = &argv[i][2]; break; case 'p': polyphony = atoi(&argv[i][2]); if (polyphony < 1) polyphony = 1; { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Polyphony set to %d\n", polyphony); */ } break; default: break; } continue; } } /* assume success */ playResult = EAS_SUCCESS; /* get the library configuration */ pLibConfig = EAS_Config(); if (!EASLibraryCheck(pLibConfig)) return -1; if (polyphony > pLibConfig->maxVoices) polyphony = pLibConfig->maxVoices; /* calculate buffer size */ bufferSize = pLibConfig->mixBufferSize * pLibConfig->numChannels * (EAS_I32)sizeof(EAS_PCM) * NUM_BUFFERS; /* allocate output buffer memory */ buffer = malloc((EAS_U32)bufferSize); if (!buffer) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Error allocating memory for audio buffer\n"); */ } return EAS_FAILURE; } /* initialize the EAS library */ polyphony = pLibConfig->maxVoices; if ((result = EAS_Init(&easData)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Init returned %ld - aborting!\n", result); */ } free(buffer); return result; } /* * Some debugging environments don't allow for passed parameters. * In this case, just play the default MIDI file "test.mid" */ if (argc < 2) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", defaultTestFile); */ } if ((playResult = PlayFile(easData, defaultTestFile, NULL, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, defaultTestFile); */ } } } /* iterate through the list of files to be played */ else { for (i = 1; i < argc; i++) { /* check for switch */ if (argv[i][0] != '-') { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", argv[i]); */ } if ((playResult = PlayFile(easData, argv[i], outputFile, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, argv[i]); */ } break; } } } } /* shutdown the EAS library */ if ((result = EAS_Shutdown(easData)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Shutdown returned %ld\n", result); */ } } /* free the output buffer */ free(buffer); /* close the debug file */ if (debugFile) fclose(debugFile); /* play errors take precedence over shutdown errors */ if (playResult != EAS_SUCCESS) return playResult; return result; } /* end main */ /*---------------------------------------------------------------------------- * StrCopy() *---------------------------------------------------------------------------- * Purpose: * Safe string copy * * Inputs: * * Outputs: * *---------------------------------------------------------------------------- */ static void StrCopy(char *dest, const char *src, EAS_I32 size) { int len; strncpy(dest, src, (size_t) size-1); len = (int) strlen(src); if (len < size) dest[len] = 0; } /* end StrCopy */ /*---------------------------------------------------------------------------- * ChangeFileExt() *---------------------------------------------------------------------------- * Purpose: * Changes the file extension of a filename * * Inputs: * * Outputs: * *---------------------------------------------------------------------------- */ static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size) { char *p; /* find the extension, if any */ p = strrchr(str,'.'); if (!p) { if ((EAS_I32)(strlen(str) + 5) > size) return EAS_FALSE; strcat(str,"."); strcat(str,ext); return EAS_TRUE; } /* make sure there's room for the extension */ p++; *p = 0; if ((EAS_I32)(strlen(str) + 4) > size) return EAS_FALSE; strcat(str,ext); return EAS_TRUE; } /* end ChangeFileExt */ /*---------------------------------------------------------------------------- * EASLibraryCheck() *---------------------------------------------------------------------------- * Purpose: * Displays the library version and checks it against the header * file used to build this code. * * Inputs: * pLibConfig - library configuration retrieved from the library * * Outputs: * returns EAS_TRUE if matched * * Side Effects: * *---------------------------------------------------------------------------- */ static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig) { /* display the library version */ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "EAS Library Version %d.%d.%d.%d\n", pLibConfig->libVersion >> 24, (pLibConfig->libVersion >> 16) & 0x0f, (pLibConfig->libVersion >> 8) & 0x0f, pLibConfig->libVersion & 0x0f); */ } /* display some info about the library build */ if (pLibConfig->checkedVersion) { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tChecked library\n"); */ } { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMaximum polyphony: %d\n", pLibConfig->maxVoices); */ } { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tNumber of channels: %d\n", pLibConfig->numChannels); */ } { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tSample rate: %d\n", pLibConfig->sampleRate); */ } { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMix buffer size: %d\n", pLibConfig->mixBufferSize); */ } if (pLibConfig->filterEnabled) { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tFilter enabled\n"); */ } #ifndef _WIN32_WCE { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build Timestamp: %s", ctime((time_t*)&pLibConfig->buildTimeStamp)); */ } #endif { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build ID: %s\n", pLibConfig->buildGUID); */ } /* check it against the header file used to build this code */ /*lint -e{778} constant expression used for display purposes may evaluate to zero */ if (LIB_VERSION != pLibConfig->libVersion) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Library version does not match header files. EAS Header Version %d.%d.%d.%d\n", LIB_VERSION >> 24, (LIB_VERSION >> 16) & 0x0f, (LIB_VERSION >> 8) & 0x0f, LIB_VERSION & 0x0f); */ } return EAS_FALSE; } return EAS_TRUE; } /* end EASLibraryCheck */