1 package com.hammurapi.jcapture; 2 3 // This file was taken from http://www.labbookpages.co.uk/audio/javaWavFiles.html 4 5 // Wav file IO class 6 // A.Greensted 7 // http://www.labbookpages.co.uk 8 9 // File format is based on the information from 10 // http://www.sonicspot.com/guide/wavefiles.html 11 // http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/wave.htm 12 13 // Version 1.0 14 15 import java.io.*; 16 17 public class WavFile { 18 private enum IOState { 19 READING, WRITING, CLOSED 20 }; 21 22 private final static int BUFFER_SIZE = 4096; 23 24 private final static int FMT_CHUNK_ID = 0x20746D66; 25 private final static int DATA_CHUNK_ID = 0x61746164; 26 private final static int RIFF_CHUNK_ID = 0x46464952; 27 private final static int RIFF_TYPE_ID = 0x45564157; 28 29 private File file; // File that will be read from or written to 30 private IOState ioState; // Specifies the IO State of the Wav File (used for 31 // snaity checking) 32 private int bytesPerSample; // Number of bytes required to store a single 33 // sample 34 private long numFrames; // Number of frames within the data section 35 private FileOutputStream oStream; // Output stream used for writting data 36 private FileInputStream iStream; // Input stream used for reading data 37 private double floatScale; // Scaling factor used for int <-> float 38 // conversion 39 private double floatOffset; // Offset factor used for int <-> float 40 // conversion 41 private boolean wordAlignAdjust; // Specify if an extra byte at the end of 42 // the data chunk is required for word 43 // alignment 44 45 // Wav Header 46 private int numChannels; // 2 bytes unsigned, 0x0001 (1) to 0xFFFF (65,535) 47 private long sampleRate; // 4 bytes unsigned, 0x00000001 (1) to 0xFFFFFFFF 48 // (4,294,967,295) 49 // Although a java int is 4 bytes, it is signed, 50 // so need to use a long 51 private int blockAlign; // 2 bytes unsigned, 0x0001 (1) to 0xFFFF (65,535) 52 private int validBits; // 2 bytes unsigned, 0x0002 (2) to 0xFFFF (65,535) 53 54 // Buffering 55 private byte[] buffer; // Local buffer used for IO 56 private int bufferPointer; // Points to the current position in local buffer 57 private int bytesRead; // Bytes read after last read into local buffer 58 private long frameCounter; // Current number of frames read or written 59 60 // Cannot instantiate WavFile directly, must either use newWavFile() or 61 // openWavFile() WavFile()62 private WavFile() { 63 buffer = new byte[BUFFER_SIZE]; 64 } 65 getNumChannels()66 public int getNumChannels() { 67 return numChannels; 68 } 69 getNumFrames()70 public long getNumFrames() { 71 return numFrames; 72 } 73 getFramesRemaining()74 public long getFramesRemaining() { 75 return numFrames - frameCounter; 76 } 77 getSampleRate()78 public long getSampleRate() { 79 return sampleRate; 80 } 81 getValidBits()82 public int getValidBits() { 83 return validBits; 84 } 85 newWavFile(File file, int numChannels, long numFrames, int validBits, long sampleRate)86 public static WavFile newWavFile(File file, int numChannels, 87 long numFrames, int validBits, long sampleRate) throws IOException, 88 WavFileException { 89 // Instantiate new Wavfile and initialise 90 WavFile wavFile = new WavFile(); 91 wavFile.file = file; 92 wavFile.numChannels = numChannels; 93 wavFile.numFrames = numFrames; 94 wavFile.sampleRate = sampleRate; 95 wavFile.bytesPerSample = (validBits + 7) / 8; 96 wavFile.blockAlign = wavFile.bytesPerSample * numChannels; 97 wavFile.validBits = validBits; 98 99 // Sanity check arguments 100 if (numChannels < 1 || numChannels > 65535) 101 throw new WavFileException( 102 "Illegal number of channels, valid range 1 to 65536"); 103 if (numFrames < 0) 104 throw new WavFileException("Number of frames must be positive"); 105 if (validBits < 2 || validBits > 65535) 106 throw new WavFileException( 107 "Illegal number of valid bits, valid range 2 to 65536"); 108 if (sampleRate < 0) 109 throw new WavFileException("Sample rate must be positive"); 110 111 // Create output stream for writing data 112 wavFile.oStream = new FileOutputStream(file); 113 114 // Calculate the chunk sizes 115 long dataChunkSize = wavFile.blockAlign * numFrames; 116 long mainChunkSize = 4 + // Riff Type 117 8 + // Format ID and size 118 16 + // Format data 119 8 + // Data ID and size 120 dataChunkSize; 121 122 // Chunks must be word aligned, so if odd number of audio data bytes 123 // adjust the main chunk size 124 if (dataChunkSize % 2 == 1) { 125 mainChunkSize += 1; 126 wavFile.wordAlignAdjust = true; 127 } else { 128 wavFile.wordAlignAdjust = false; 129 } 130 131 // Set the main chunk size 132 putLE(RIFF_CHUNK_ID, wavFile.buffer, 0, 4); 133 putLE(mainChunkSize, wavFile.buffer, 4, 4); 134 putLE(RIFF_TYPE_ID, wavFile.buffer, 8, 4); 135 136 // Write out the header 137 wavFile.oStream.write(wavFile.buffer, 0, 12); 138 139 // Put format data in buffer 140 long averageBytesPerSecond = sampleRate * wavFile.blockAlign; 141 142 putLE(FMT_CHUNK_ID, wavFile.buffer, 0, 4); // Chunk ID 143 putLE(16, wavFile.buffer, 4, 4); // Chunk Data Size 144 putLE(1, wavFile.buffer, 8, 2); // Compression Code (Uncompressed) 145 putLE(numChannels, wavFile.buffer, 10, 2); // Number of channels 146 putLE(sampleRate, wavFile.buffer, 12, 4); // Sample Rate 147 putLE(averageBytesPerSecond, wavFile.buffer, 16, 4); // Average Bytes 148 // Per Second 149 putLE(wavFile.blockAlign, wavFile.buffer, 20, 2); // Block Align 150 putLE(validBits, wavFile.buffer, 22, 2); // Valid Bits 151 152 // Write Format Chunk 153 wavFile.oStream.write(wavFile.buffer, 0, 24); 154 155 // Start Data Chunk 156 putLE(DATA_CHUNK_ID, wavFile.buffer, 0, 4); // Chunk ID 157 putLE(dataChunkSize, wavFile.buffer, 4, 4); // Chunk Data Size 158 159 // Write Format Chunk 160 wavFile.oStream.write(wavFile.buffer, 0, 8); 161 162 // Calculate the scaling factor for converting to a normalised double 163 if (wavFile.validBits > 8) { 164 // If more than 8 validBits, data is signed 165 // Conversion required multiplying by magnitude of max positive 166 // value 167 wavFile.floatOffset = 0; 168 wavFile.floatScale = Long.MAX_VALUE >> (64 - wavFile.validBits); 169 } else { 170 // Else if 8 or less validBits, data is unsigned 171 // Conversion required dividing by max positive value 172 wavFile.floatOffset = 1; 173 wavFile.floatScale = 0.5 * ((1 << wavFile.validBits) - 1); 174 } 175 176 // Finally, set the IO State 177 wavFile.bufferPointer = 0; 178 wavFile.bytesRead = 0; 179 wavFile.frameCounter = 0; 180 wavFile.ioState = IOState.WRITING; 181 182 return wavFile; 183 } 184 openWavFile(File file)185 public static WavFile openWavFile(File file) throws IOException, 186 WavFileException { 187 // Instantiate new Wavfile and store the file reference 188 WavFile wavFile = new WavFile(); 189 wavFile.file = file; 190 191 // Create a new file input stream for reading file data 192 wavFile.iStream = new FileInputStream(file); 193 194 // Read the first 12 bytes of the file 195 int bytesRead = wavFile.iStream.read(wavFile.buffer, 0, 12); 196 if (bytesRead != 12) 197 throw new WavFileException("Not enough wav file bytes for header"); 198 199 // Extract parts from the header 200 long riffChunkID = getLE(wavFile.buffer, 0, 4); 201 long chunkSize = getLE(wavFile.buffer, 4, 4); 202 long riffTypeID = getLE(wavFile.buffer, 8, 4); 203 204 // Check the header bytes contains the correct signature 205 if (riffChunkID != RIFF_CHUNK_ID) 206 throw new WavFileException( 207 "Invalid Wav Header data, incorrect riff chunk ID"); 208 if (riffTypeID != RIFF_TYPE_ID) 209 throw new WavFileException( 210 "Invalid Wav Header data, incorrect riff type ID"); 211 212 // Check that the file size matches the number of bytes listed in header 213 if (file.length() != chunkSize + 8) { 214 throw new WavFileException("Header chunk size (" + chunkSize 215 + ") does not match file size (" + file.length() + ")"); 216 } 217 218 boolean foundFormat = false; 219 boolean foundData = false; 220 221 // Search for the Format and Data Chunks 222 while (true) { 223 // Read the first 8 bytes of the chunk (ID and chunk size) 224 bytesRead = wavFile.iStream.read(wavFile.buffer, 0, 8); 225 if (bytesRead == -1) 226 throw new WavFileException( 227 "Reached end of file without finding format chunk"); 228 if (bytesRead != 8) 229 throw new WavFileException("Could not read chunk header"); 230 231 // Extract the chunk ID and Size 232 long chunkID = getLE(wavFile.buffer, 0, 4); 233 chunkSize = getLE(wavFile.buffer, 4, 4); 234 235 // Word align the chunk size 236 // chunkSize specifies the number of bytes holding data. However, 237 // the data should be word aligned (2 bytes) so we need to calculate 238 // the actual number of bytes in the chunk 239 long numChunkBytes = (chunkSize % 2 == 1) ? chunkSize + 1 240 : chunkSize; 241 242 if (chunkID == FMT_CHUNK_ID) { 243 // Flag that the format chunk has been found 244 foundFormat = true; 245 246 // Read in the header info 247 bytesRead = wavFile.iStream.read(wavFile.buffer, 0, 16); 248 249 // Check this is uncompressed data 250 int compressionCode = (int) getLE(wavFile.buffer, 0, 2); 251 if (compressionCode != 1) 252 throw new WavFileException("Compression Code " 253 + compressionCode + " not supported"); 254 255 // Extract the format information 256 wavFile.numChannels = (int) getLE(wavFile.buffer, 2, 2); 257 wavFile.sampleRate = getLE(wavFile.buffer, 4, 4); 258 wavFile.blockAlign = (int) getLE(wavFile.buffer, 12, 2); 259 wavFile.validBits = (int) getLE(wavFile.buffer, 14, 2); 260 261 if (wavFile.numChannels == 0) 262 throw new WavFileException( 263 "Number of channels specified in header is equal to zero"); 264 if (wavFile.blockAlign == 0) 265 throw new WavFileException( 266 "Block Align specified in header is equal to zero"); 267 if (wavFile.validBits < 2) 268 throw new WavFileException( 269 "Valid Bits specified in header is less than 2"); 270 if (wavFile.validBits > 64) 271 throw new WavFileException( 272 "Valid Bits specified in header is greater than 64, this is greater than a long can hold"); 273 274 // Calculate the number of bytes required to hold 1 sample 275 wavFile.bytesPerSample = (wavFile.validBits + 7) / 8; 276 if (wavFile.bytesPerSample * wavFile.numChannels != wavFile.blockAlign) 277 throw new WavFileException( 278 "Block Align does not agree with bytes required for validBits and number of channels"); 279 280 // Account for number of format bytes and then skip over 281 // any extra format bytes 282 numChunkBytes -= 16; 283 if (numChunkBytes > 0) 284 wavFile.iStream.skip(numChunkBytes); 285 } else if (chunkID == DATA_CHUNK_ID) { 286 // Check if we've found the format chunk, 287 // If not, throw an exception as we need the format information 288 // before we can read the data chunk 289 if (foundFormat == false) 290 throw new WavFileException( 291 "Data chunk found before Format chunk"); 292 293 // Check that the chunkSize (wav data length) is a multiple of 294 // the 295 // block align (bytes per frame) 296 if (chunkSize % wavFile.blockAlign != 0) 297 throw new WavFileException( 298 "Data Chunk size is not multiple of Block Align"); 299 300 // Calculate the number of frames 301 wavFile.numFrames = chunkSize / wavFile.blockAlign; 302 303 // Flag that we've found the wave data chunk 304 foundData = true; 305 306 break; 307 } else { 308 // If an unknown chunk ID is found, just skip over the chunk 309 // data 310 wavFile.iStream.skip(numChunkBytes); 311 } 312 } 313 314 // Throw an exception if no data chunk has been found 315 if (foundData == false) 316 throw new WavFileException("Did not find a data chunk"); 317 318 // Calculate the scaling factor for converting to a normalised double 319 if (wavFile.validBits > 8) { 320 // If more than 8 validBits, data is signed 321 // Conversion required dividing by magnitude of max negative value 322 wavFile.floatOffset = 0; 323 wavFile.floatScale = 1 << (wavFile.validBits - 1); 324 } else { 325 // Else if 8 or less validBits, data is unsigned 326 // Conversion required dividing by max positive value 327 wavFile.floatOffset = -1; 328 wavFile.floatScale = 0.5 * ((1 << wavFile.validBits) - 1); 329 } 330 331 wavFile.bufferPointer = 0; 332 wavFile.bytesRead = 0; 333 wavFile.frameCounter = 0; 334 wavFile.ioState = IOState.READING; 335 336 return wavFile; 337 } 338 339 // Get and Put little endian data from local buffer 340 // ------------------------------------------------ getLE(byte[] buffer, int pos, int numBytes)341 private static long getLE(byte[] buffer, int pos, int numBytes) { 342 numBytes--; 343 pos += numBytes; 344 345 long val = buffer[pos] & 0xFF; 346 for (int b = 0; b < numBytes; b++) 347 val = (val << 8) + (buffer[--pos] & 0xFF); 348 349 return val; 350 } 351 putLE(long val, byte[] buffer, int pos, int numBytes)352 private static void putLE(long val, byte[] buffer, int pos, int numBytes) { 353 for (int b = 0; b < numBytes; b++) { 354 buffer[pos] = (byte) (val & 0xFF); 355 val >>= 8; 356 pos++; 357 } 358 } 359 360 // Sample Writing and Reading 361 // -------------------------- writeSample(long val)362 private void writeSample(long val) throws IOException { 363 for (int b = 0; b < bytesPerSample; b++) { 364 if (bufferPointer == BUFFER_SIZE) { 365 oStream.write(buffer, 0, BUFFER_SIZE); 366 bufferPointer = 0; 367 } 368 369 buffer[bufferPointer] = (byte) (val & 0xFF); 370 val >>= 8; 371 bufferPointer++; 372 } 373 } 374 readSample()375 private long readSample() throws IOException, WavFileException { 376 long val = 0; 377 378 for (int b = 0; b < bytesPerSample; b++) { 379 if (bufferPointer == bytesRead) { 380 int read = iStream.read(buffer, 0, BUFFER_SIZE); 381 if (read == -1) 382 throw new WavFileException("Not enough data available"); 383 bytesRead = read; 384 bufferPointer = 0; 385 } 386 387 int v = buffer[bufferPointer]; 388 if (b < bytesPerSample - 1 || bytesPerSample == 1) 389 v &= 0xFF; 390 val += v << (b * 8); 391 392 bufferPointer++; 393 } 394 395 return val; 396 } 397 398 // Integer 399 // ------- readFrames(int[] sampleBuffer, int numFramesToRead)400 public int readFrames(int[] sampleBuffer, int numFramesToRead) 401 throws IOException, WavFileException { 402 return readFrames(sampleBuffer, 0, numFramesToRead); 403 } 404 readFrames(int[] sampleBuffer, int offset, int numFramesToRead)405 public int readFrames(int[] sampleBuffer, int offset, int numFramesToRead) 406 throws IOException, WavFileException { 407 if (ioState != IOState.READING) 408 throw new IOException("Cannot read from WavFile instance"); 409 410 for (int f = 0; f < numFramesToRead; f++) { 411 if (frameCounter == numFrames) 412 return f; 413 414 for (int c = 0; c < numChannels; c++) { 415 sampleBuffer[offset] = (int) readSample(); 416 offset++; 417 } 418 419 frameCounter++; 420 } 421 422 return numFramesToRead; 423 } 424 readFrames(int[][] sampleBuffer, int numFramesToRead)425 public int readFrames(int[][] sampleBuffer, int numFramesToRead) 426 throws IOException, WavFileException { 427 return readFrames(sampleBuffer, 0, numFramesToRead); 428 } 429 readFrames(int[][] sampleBuffer, int offset, int numFramesToRead)430 public int readFrames(int[][] sampleBuffer, int offset, int numFramesToRead) 431 throws IOException, WavFileException { 432 if (ioState != IOState.READING) 433 throw new IOException("Cannot read from WavFile instance"); 434 435 for (int f = 0; f < numFramesToRead; f++) { 436 if (frameCounter == numFrames) 437 return f; 438 439 for (int c = 0; c < numChannels; c++) 440 sampleBuffer[c][offset] = (int) readSample(); 441 442 offset++; 443 frameCounter++; 444 } 445 446 return numFramesToRead; 447 } 448 writeFrames(int[] sampleBuffer, int numFramesToWrite)449 public int writeFrames(int[] sampleBuffer, int numFramesToWrite) 450 throws IOException, WavFileException { 451 return writeFrames(sampleBuffer, 0, numFramesToWrite); 452 } 453 writeFrames(int[] sampleBuffer, int offset, int numFramesToWrite)454 public int writeFrames(int[] sampleBuffer, int offset, int numFramesToWrite) 455 throws IOException, WavFileException { 456 if (ioState != IOState.WRITING) 457 throw new IOException("Cannot write to WavFile instance"); 458 459 for (int f = 0; f < numFramesToWrite; f++) { 460 if (frameCounter == numFrames) 461 return f; 462 463 for (int c = 0; c < numChannels; c++) { 464 writeSample(sampleBuffer[offset]); 465 offset++; 466 } 467 468 frameCounter++; 469 } 470 471 return numFramesToWrite; 472 } 473 writeFrames(int[][] sampleBuffer, int numFramesToWrite)474 public int writeFrames(int[][] sampleBuffer, int numFramesToWrite) 475 throws IOException, WavFileException { 476 return writeFrames(sampleBuffer, 0, numFramesToWrite); 477 } 478 writeFrames(int[][] sampleBuffer, int offset, int numFramesToWrite)479 public int writeFrames(int[][] sampleBuffer, int offset, 480 int numFramesToWrite) throws IOException, WavFileException { 481 if (ioState != IOState.WRITING) 482 throw new IOException("Cannot write to WavFile instance"); 483 484 for (int f = 0; f < numFramesToWrite; f++) { 485 if (frameCounter == numFrames) 486 return f; 487 488 for (int c = 0; c < numChannels; c++) 489 writeSample(sampleBuffer[c][offset]); 490 491 offset++; 492 frameCounter++; 493 } 494 495 return numFramesToWrite; 496 } 497 498 // Long 499 // ---- readFrames(long[] sampleBuffer, int numFramesToRead)500 public int readFrames(long[] sampleBuffer, int numFramesToRead) 501 throws IOException, WavFileException { 502 return readFrames(sampleBuffer, 0, numFramesToRead); 503 } 504 readFrames(long[] sampleBuffer, int offset, int numFramesToRead)505 public int readFrames(long[] sampleBuffer, int offset, int numFramesToRead) 506 throws IOException, WavFileException { 507 if (ioState != IOState.READING) 508 throw new IOException("Cannot read from WavFile instance"); 509 510 for (int f = 0; f < numFramesToRead; f++) { 511 if (frameCounter == numFrames) 512 return f; 513 514 for (int c = 0; c < numChannels; c++) { 515 sampleBuffer[offset] = readSample(); 516 offset++; 517 } 518 519 frameCounter++; 520 } 521 522 return numFramesToRead; 523 } 524 readFrames(long[][] sampleBuffer, int numFramesToRead)525 public int readFrames(long[][] sampleBuffer, int numFramesToRead) 526 throws IOException, WavFileException { 527 return readFrames(sampleBuffer, 0, numFramesToRead); 528 } 529 readFrames(long[][] sampleBuffer, int offset, int numFramesToRead)530 public int readFrames(long[][] sampleBuffer, int offset, int numFramesToRead) 531 throws IOException, WavFileException { 532 if (ioState != IOState.READING) 533 throw new IOException("Cannot read from WavFile instance"); 534 535 for (int f = 0; f < numFramesToRead; f++) { 536 if (frameCounter == numFrames) 537 return f; 538 539 for (int c = 0; c < numChannels; c++) 540 sampleBuffer[c][offset] = readSample(); 541 542 offset++; 543 frameCounter++; 544 } 545 546 return numFramesToRead; 547 } 548 writeFrames(long[] sampleBuffer, int numFramesToWrite)549 public int writeFrames(long[] sampleBuffer, int numFramesToWrite) 550 throws IOException, WavFileException { 551 return writeFrames(sampleBuffer, 0, numFramesToWrite); 552 } 553 writeFrames(long[] sampleBuffer, int offset, int numFramesToWrite)554 public int writeFrames(long[] sampleBuffer, int offset, int numFramesToWrite) 555 throws IOException, WavFileException { 556 if (ioState != IOState.WRITING) 557 throw new IOException("Cannot write to WavFile instance"); 558 559 for (int f = 0; f < numFramesToWrite; f++) { 560 if (frameCounter == numFrames) 561 return f; 562 563 for (int c = 0; c < numChannels; c++) { 564 writeSample(sampleBuffer[offset]); 565 offset++; 566 } 567 568 frameCounter++; 569 } 570 571 return numFramesToWrite; 572 } 573 writeFrames(long[][] sampleBuffer, int numFramesToWrite)574 public int writeFrames(long[][] sampleBuffer, int numFramesToWrite) 575 throws IOException, WavFileException { 576 return writeFrames(sampleBuffer, 0, numFramesToWrite); 577 } 578 writeFrames(long[][] sampleBuffer, int offset, int numFramesToWrite)579 public int writeFrames(long[][] sampleBuffer, int offset, 580 int numFramesToWrite) throws IOException, WavFileException { 581 if (ioState != IOState.WRITING) 582 throw new IOException("Cannot write to WavFile instance"); 583 584 for (int f = 0; f < numFramesToWrite; f++) { 585 if (frameCounter == numFrames) 586 return f; 587 588 for (int c = 0; c < numChannels; c++) 589 writeSample(sampleBuffer[c][offset]); 590 591 offset++; 592 frameCounter++; 593 } 594 595 return numFramesToWrite; 596 } 597 598 // Double 599 // ------ readFrames(double[] sampleBuffer, int numFramesToRead)600 public int readFrames(double[] sampleBuffer, int numFramesToRead) 601 throws IOException, WavFileException { 602 return readFrames(sampleBuffer, 0, numFramesToRead); 603 } 604 readFrames(double[] sampleBuffer, int offset, int numFramesToRead)605 public int readFrames(double[] sampleBuffer, int offset, int numFramesToRead) 606 throws IOException, WavFileException { 607 if (ioState != IOState.READING) 608 throw new IOException("Cannot read from WavFile instance"); 609 610 for (int f = 0; f < numFramesToRead; f++) { 611 if (frameCounter == numFrames) 612 return f; 613 614 for (int c = 0; c < numChannels; c++) { 615 sampleBuffer[offset] = floatOffset + (double) readSample() 616 / floatScale; 617 offset++; 618 } 619 620 frameCounter++; 621 } 622 623 return numFramesToRead; 624 } 625 readFrames(double[][] sampleBuffer, int numFramesToRead)626 public int readFrames(double[][] sampleBuffer, int numFramesToRead) 627 throws IOException, WavFileException { 628 return readFrames(sampleBuffer, 0, numFramesToRead); 629 } 630 readFrames(double[][] sampleBuffer, int offset, int numFramesToRead)631 public int readFrames(double[][] sampleBuffer, int offset, 632 int numFramesToRead) throws IOException, WavFileException { 633 if (ioState != IOState.READING) 634 throw new IOException("Cannot read from WavFile instance"); 635 636 for (int f = 0; f < numFramesToRead; f++) { 637 if (frameCounter == numFrames) 638 return f; 639 640 for (int c = 0; c < numChannels; c++) 641 sampleBuffer[c][offset] = floatOffset + (double) readSample() 642 / floatScale; 643 644 offset++; 645 frameCounter++; 646 } 647 648 return numFramesToRead; 649 } 650 writeFrames(double[] sampleBuffer, int numFramesToWrite)651 public int writeFrames(double[] sampleBuffer, int numFramesToWrite) 652 throws IOException, WavFileException { 653 return writeFrames(sampleBuffer, 0, numFramesToWrite); 654 } 655 writeFrames(double[] sampleBuffer, int offset, int numFramesToWrite)656 public int writeFrames(double[] sampleBuffer, int offset, 657 int numFramesToWrite) throws IOException, WavFileException { 658 if (ioState != IOState.WRITING) 659 throw new IOException("Cannot write to WavFile instance"); 660 661 for (int f = 0; f < numFramesToWrite; f++) { 662 if (frameCounter == numFrames) 663 return f; 664 665 for (int c = 0; c < numChannels; c++) { 666 writeSample((long) (floatScale * (floatOffset + sampleBuffer[offset]))); 667 offset++; 668 } 669 670 frameCounter++; 671 } 672 673 return numFramesToWrite; 674 } 675 writeFrames(double[][] sampleBuffer, int numFramesToWrite)676 public int writeFrames(double[][] sampleBuffer, int numFramesToWrite) 677 throws IOException, WavFileException { 678 return writeFrames(sampleBuffer, 0, numFramesToWrite); 679 } 680 writeFrames(double[][] sampleBuffer, int offset, int numFramesToWrite)681 public int writeFrames(double[][] sampleBuffer, int offset, 682 int numFramesToWrite) throws IOException, WavFileException { 683 if (ioState != IOState.WRITING) 684 throw new IOException("Cannot write to WavFile instance"); 685 686 for (int f = 0; f < numFramesToWrite; f++) { 687 if (frameCounter == numFrames) 688 return f; 689 690 for (int c = 0; c < numChannels; c++) 691 writeSample((long) (floatScale * (floatOffset + sampleBuffer[c][offset]))); 692 693 offset++; 694 frameCounter++; 695 } 696 697 return numFramesToWrite; 698 } 699 close()700 public void close() throws IOException { 701 // Close the input stream and set to null 702 if (iStream != null) { 703 iStream.close(); 704 iStream = null; 705 } 706 707 if (oStream != null) { 708 // Write out anything still in the local buffer 709 if (bufferPointer > 0) 710 oStream.write(buffer, 0, bufferPointer); 711 712 // If an extra byte is required for word alignment, add it to the 713 // end 714 if (wordAlignAdjust) 715 oStream.write(0); 716 717 // Close the stream and set to null 718 oStream.close(); 719 oStream = null; 720 } 721 722 // Flag that the stream is closed 723 ioState = IOState.CLOSED; 724 } 725 display()726 public void display() { 727 display(System.out); 728 } 729 display(PrintStream out)730 public void display(PrintStream out) { 731 out.printf("File: %s\n", file); 732 out.printf("Channels: %d, Frames: %d\n", numChannels, numFrames); 733 out.printf("IO State: %s\n", ioState); 734 out.printf("Sample Rate: %d, Block Align: %d\n", sampleRate, blockAlign); 735 out.printf("Valid Bits: %d, Bytes per sample: %d\n", validBits, 736 bytesPerSample); 737 } 738 main(String[] args)739 public static void main(String[] args) { 740 if (args.length < 1) { 741 System.err.println("Must supply filename"); 742 System.exit(1); 743 } 744 745 try { 746 for (String filename : args) { 747 WavFile readWavFile = openWavFile(new File(filename)); 748 readWavFile.display(); 749 750 long numFrames = readWavFile.getNumFrames(); 751 int numChannels = readWavFile.getNumChannels(); 752 int validBits = readWavFile.getValidBits(); 753 long sampleRate = readWavFile.getSampleRate(); 754 755 WavFile writeWavFile = newWavFile(new File("out.wav"), 756 numChannels, numFrames, validBits, sampleRate); 757 758 final int BUF_SIZE = 5001; 759 760 // int[] buffer = new int[BUF_SIZE * numChannels]; 761 // long[] buffer = new long[BUF_SIZE * numChannels]; 762 double[] buffer = new double[BUF_SIZE * numChannels]; 763 764 int framesRead = 0; 765 int framesWritten = 0; 766 767 do { 768 framesRead = readWavFile.readFrames(buffer, BUF_SIZE); 769 framesWritten = writeWavFile.writeFrames(buffer, BUF_SIZE); 770 System.out.printf("%d %d\n", framesRead, framesWritten); 771 } while (framesRead != 0); 772 773 readWavFile.close(); 774 writeWavFile.close(); 775 } 776 777 WavFile writeWavFile = newWavFile(new File("out2.wav"), 1, 10, 23, 778 44100); 779 double[] buffer = new double[10]; 780 writeWavFile.writeFrames(buffer, 10); 781 writeWavFile.close(); 782 } catch (Exception e) { 783 System.err.println(e); 784 e.printStackTrace(); 785 } 786 } 787 } 788