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 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 */ 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 */ 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 */ 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 */ 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