/*---------------------------------------------------------------------------- | |
* | |
* 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 <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#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 */ | |