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 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 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 */ 216 int 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 */ 361 static 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 */ 383 static 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 */ 424 static 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