1 /*---------------------------------------------------------------------------- 2 * 3 * File: 4 * eas_wave.c 5 * 6 * Contents and purpose: 7 * This module contains .WAV file functions for the EAS synthesizer 8 * test harness. 9 * 10 * Copyright Sonic Network Inc. 2005 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 * Revision Control: 25 * $Revision: 658 $ 26 * $Date: 2007-04-24 13:35:49 -0700 (Tue, 24 Apr 2007) $ 27 *---------------------------------------------------------------------------- 28 */ 29 30 /* lint complaints about most C library headers, so we use our own during lint step */ 31 #ifdef _lint 32 #include "lint_stdlib.h" 33 #else 34 #include <stdio.h> 35 #include <stdlib.h> 36 #endif 37 38 #include "eas_wave.h" 39 40 /* .WAV file format tags */ 41 const EAS_U32 riffTag = 0x46464952; 42 const EAS_U32 waveTag = 0x45564157; 43 const EAS_U32 fmtTag = 0x20746d66; 44 const EAS_U32 dataTag = 0x61746164; 45 46 #ifdef _BIG_ENDIAN 47 /*---------------------------------------------------------------------------- 48 * FlipDWord() 49 *---------------------------------------------------------------------------- 50 * Purpose: Endian flip a DWORD for big-endian processors 51 * 52 * Inputs: 53 * 54 * Outputs: 55 * 56 *---------------------------------------------------------------------------- 57 */ 58 static void FlipDWord (EAS_U32 *pValue) 59 { 60 EAS_U8 *p; 61 EAS_U32 temp; 62 63 p = (EAS_U8*) pValue; 64 temp = (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0]; 65 *pValue = temp; 66 } 67 68 /*---------------------------------------------------------------------------- 69 * FlipWord() 70 *---------------------------------------------------------------------------- 71 * Purpose: Endian flip a WORD for big-endian processors 72 * 73 * Inputs: 74 * 75 * Outputs: 76 * 77 *---------------------------------------------------------------------------- 78 */ 79 static void FlipWord (EAS_U16 *pValue) 80 { 81 EAS_U8 *p; 82 EAS_U16 temp; 83 84 p = (EAS_U8*) pValue; 85 temp = (p[1] << 8) | p[0]; 86 *pValue = temp; 87 } 88 89 /*---------------------------------------------------------------------------- 90 * FlipWaveHeader() 91 *---------------------------------------------------------------------------- 92 * Purpose: Endian flip the wave header for big-endian processors 93 * 94 * Inputs: 95 * 96 * Outputs: 97 * 98 *---------------------------------------------------------------------------- 99 */ 100 static void FlipWaveHeader (WAVE_HEADER *p) 101 { 102 103 FlipDWord(&p->nRiffTag); 104 FlipDWord(&p->nRiffSize); 105 FlipDWord(&p->nWaveTag); 106 FlipDWord(&p->nFmtTag); 107 FlipDWord(&p->nFmtSize); 108 FlipDWord(&p->nDataTag); 109 FlipDWord(&p->nDataSize); 110 FlipWord(&p->fc.wFormatTag); 111 FlipWord(&p->fc.nChannels); 112 FlipDWord(&p->fc.nSamplesPerSec); 113 FlipDWord(&p->fc.nAvgBytesPerSec); 114 FlipWord(&p->fc.nBlockAlign); 115 FlipWord(&p->fc.wBitsPerSample); 116 117 } 118 #endif 119 120 /*---------------------------------------------------------------------------- 121 * WaveFileCreate() 122 *---------------------------------------------------------------------------- 123 * Purpose: Opens a wave file for writing and writes the header 124 * 125 * Inputs: 126 * 127 * Outputs: 128 * 129 *---------------------------------------------------------------------------- 130 */ 131 132 WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample) 133 { 134 WAVE_FILE *wFile; 135 136 /* allocate memory */ 137 wFile = malloc(sizeof(WAVE_FILE)); 138 if (!wFile) 139 return NULL; 140 wFile->write = EAS_TRUE; 141 142 /* create the file */ 143 wFile->file = fopen(filename,"wb"); 144 if (!wFile->file) 145 { 146 free(wFile); 147 return NULL; 148 } 149 150 /* initialize PCM format .WAV file header */ 151 wFile->wh.nRiffTag = riffTag; 152 wFile->wh.nRiffSize = sizeof(WAVE_HEADER) - 8; 153 wFile->wh.nWaveTag = waveTag; 154 wFile->wh.nFmtTag = fmtTag; 155 wFile->wh.nFmtSize = sizeof(FMT_CHUNK); 156 157 /* initalize 'fmt' chunk */ 158 wFile->wh.fc.wFormatTag = 1; 159 wFile->wh.fc.nChannels = (EAS_U16) nChannels; 160 wFile->wh.fc.nSamplesPerSec = (EAS_U32) nSamplesPerSec; 161 wFile->wh.fc.wBitsPerSample = (EAS_U16) wBitsPerSample; 162 wFile->wh.fc.nBlockAlign = (EAS_U16) (nChannels * (EAS_U16) (wBitsPerSample / 8)); 163 wFile->wh.fc.nAvgBytesPerSec = wFile->wh.fc.nBlockAlign * (EAS_U32) nSamplesPerSec; 164 165 /* initialize 'data' chunk */ 166 wFile->wh.nDataTag = dataTag; 167 wFile->wh.nDataSize = 0; 168 169 #ifdef _BIG_ENDIAN 170 FlipWaveHeader(&wFile->wh); 171 #endif 172 173 /* write the header */ 174 if (fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file) != 1) 175 { 176 fclose(wFile->file); 177 free(wFile); 178 return NULL; 179 } 180 181 #ifdef _BIG_ENDIAN 182 FlipWaveHeader(&wFile->wh); 183 #endif 184 185 /* return the file handle */ 186 return wFile; 187 } /* end WaveFileCreate */ 188 189 /*---------------------------------------------------------------------------- 190 * WaveFileWrite() 191 *---------------------------------------------------------------------------- 192 * Purpose: Writes data to the wave file 193 * 194 * Inputs: 195 * 196 * Outputs: 197 * 198 *---------------------------------------------------------------------------- 199 */ 200 EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n) 201 { 202 EAS_I32 count; 203 204 /* make sure we have an open file */ 205 if (wFile == NULL) 206 { 207 return 0; 208 } 209 210 #ifdef _BIG_ENDIAN 211 { 212 EAS_I32 i; 213 EAS_U16 *p; 214 p = buffer; 215 i = n >> 1; 216 while (i--) 217 FlipWord(p++); 218 } 219 #endif 220 221 /* write the data */ 222 count = (EAS_I32) fwrite(buffer, 1, (size_t) n, wFile->file); 223 224 /* add the number of bytes written */ 225 wFile->wh.nRiffSize += (EAS_U32) count; 226 wFile->wh.nDataSize += (EAS_U32) count; 227 228 /* return the count of bytes written */ 229 return count; 230 } /* end WriteWaveHeader */ 231 232 /*---------------------------------------------------------------------------- 233 * WaveFileClose() 234 *---------------------------------------------------------------------------- 235 * Purpose: Opens a wave file for writing and writes the header 236 * 237 * Inputs: 238 * 239 * Outputs: 240 * 241 *---------------------------------------------------------------------------- 242 */ 243 244 EAS_BOOL WaveFileClose (WAVE_FILE *wFile) 245 { 246 EAS_I32 count = 1; 247 248 /* return to beginning of file and write the header */ 249 if (wFile->write) 250 { 251 if (fseek(wFile->file, 0L, SEEK_SET) == 0) 252 { 253 254 #ifdef _BIG_ENDIAN 255 FlipWaveHeader(&wFile->wh); 256 #endif 257 count = (EAS_I32) fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file); 258 #ifdef _BIG_ENDIAN 259 FlipWaveHeader(&wFile->wh); 260 #endif 261 } 262 } 263 264 /* close the file */ 265 if (fclose(wFile->file) != 0) 266 count = 0; 267 268 /* free the memory */ 269 free(wFile); 270 271 /* return the file handle */ 272 return (count == 1 ? EAS_TRUE : EAS_FALSE); 273 } /* end WaveFileClose */ 274 275 #ifdef _WAVE_FILE_READ 276 #ifdef _BIG_ENDIAN 277 #error "WaveFileOpen not currently supported on big-endian processors" 278 #endif 279 /*---------------------------------------------------------------------------- 280 * WaveFileOpen() 281 *---------------------------------------------------------------------------- 282 * Purpose: Opens a wave file for reading and reads the header 283 * 284 * Inputs: 285 * 286 * Outputs: 287 * 288 *---------------------------------------------------------------------------- 289 */ 290 291 WAVE_FILE *WaveFileOpen (const char *filename) 292 { 293 WAVE_FILE *wFile; 294 struct 295 { 296 EAS_U32 tag; 297 EAS_U32 size; 298 } chunk; 299 EAS_U32 tag; 300 EAS_I32 startChunkPos; 301 EAS_INT state; 302 EAS_BOOL done; 303 304 /* allocate memory */ 305 wFile = malloc(sizeof(WAVE_FILE)); 306 if (!wFile) 307 return NULL; 308 309 /* open the file */ 310 wFile->write = EAS_FALSE; 311 wFile->file = fopen(filename,"rb"); 312 if (!wFile->file) 313 { 314 free(wFile); 315 return NULL; 316 } 317 318 /* make lint happy */ 319 chunk.tag = chunk.size = 0; 320 startChunkPos = 0; 321 322 /* read the RIFF tag and file size */ 323 state = 0; 324 done = EAS_FALSE; 325 while (!done) 326 { 327 328 switch(state) 329 { 330 /* read the RIFF tag */ 331 case 0: 332 if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) 333 done = EAS_TRUE; 334 else 335 { 336 if (chunk.tag != riffTag) 337 done = EAS_TRUE; 338 else 339 state++; 340 } 341 break; 342 343 /* read the WAVE tag */ 344 case 1: 345 if (fread(&tag, sizeof(tag), 1, wFile->file) != 1) 346 done = EAS_TRUE; 347 else 348 { 349 if (tag != waveTag) 350 done = EAS_TRUE; 351 else 352 state++; 353 } 354 break; 355 356 /* looking for fmt chunk */ 357 case 2: 358 if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) 359 done = EAS_TRUE; 360 else 361 { 362 startChunkPos = ftell(wFile->file); 363 364 /* not fmt tag, skip it */ 365 if (chunk.tag != fmtTag) 366 fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); 367 else 368 state++; 369 } 370 break; 371 372 /* read fmt chunk */ 373 case 3: 374 if (fread(&wFile->wh.fc, sizeof(FMT_CHUNK), 1, wFile->file) != 1) 375 done = EAS_TRUE; 376 else 377 { 378 fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); 379 state++; 380 } 381 break; 382 383 /* looking for data chunk */ 384 case 4: 385 if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) 386 done = EAS_TRUE; 387 else 388 { 389 startChunkPos = ftell(wFile->file); 390 391 /* not data tag, skip it */ 392 if (chunk.tag != dataTag) 393 fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); 394 else 395 { 396 wFile->dataSize = chunk.size; 397 state++; 398 done = EAS_TRUE; 399 } 400 } 401 break; 402 403 default: 404 done = EAS_TRUE; 405 break; 406 } 407 } 408 409 /* if not final state, an error occurred */ 410 if (state != 5) 411 { 412 fclose(wFile->file); 413 free(wFile); 414 return NULL; 415 } 416 417 /* return the file handle */ 418 return wFile; 419 } /* end WaveFileOpen */ 420 #endif 421 422 423 424