package uk.co.mmscomputing.sound; import java.io.*; import javax.sound.sampled.*; public class WaveOutputFile extends RandomAccessFile{ byte[] h=new byte[58]; public WaveOutputFile(File file,AudioFormat format)throws FileNotFoundException,IOException{ super(file,"rw"); write(getHeader(format)); } public WaveOutputFile(String file,AudioFormat format)throws FileNotFoundException,IOException{ super(file,"rw"); write(getHeader(format)); } private byte[] getHeader(AudioFormat format){ /* riff chunk = [format chunk, fact chunk, data chunk] We don't know the length of the data chunk yet. Need fact chunk for compressed data. */ // start riff chunk int i=0; h[i++]='R'; h[i++]='I'; h[i++]='F'; h[i++]='F'; // 0 : 'RIFF' h[i++]= 50; h[i++]= 0 ; h[i++]= 0 ; h[i++]= 0 ; // 4 : length of riff chunk [8..(data size+58)] h[i++]='W'; h[i++]='A'; h[i++]='V'; h[i++]='E'; // 8 : 'WAVE' // start format chunk h[i++]='f'; h[i++]='m'; h[i++]='t'; h[i++]=' '; // 12: 'fmt ' h[i++]= 18; h[i++]= 0 ; h[i++]= 0 ; h[i++]= 0 ; // 16 : length of format chunk = 0x12 = 18 [20..38] AudioFormat.Encoding encoding=format.getEncoding(); if(encoding.equals(AudioFormat.Encoding.PCM_SIGNED)){ h[i++]= 1 ; h[i++]= 0 ; // 20 : PCM = 1 }else if(encoding.equals(AudioFormat.Encoding.PCM_UNSIGNED)){ throw new IllegalArgumentException(getClass().getName() +".getHeader(AudioFormat format)\n\tDo not support PCM unsigned data" ); }else if(encoding.equals(AudioFormat.Encoding.ALAW)){ h[i++]= 6 ; h[i++]= 0 ; // 20 : A-Law = 6 }else if(encoding.equals(AudioFormat.Encoding.ULAW)){ h[i++]= 7 ; h[i++]= 0 ; // 20 : u-Law = 7 }else{ throw new IllegalArgumentException(getClass().getName() +".getHeader(AudioFormat format)\n\tDo not support encoding ["+encoding+"]" ); } int channels=format.getChannels(); if(channels==1){ h[i++]= 1 ; h[i++]= 0 ; // 22 : mono = 1 }else if(channels==2){ h[i++]= 2 ; h[i++]= 0 ; // 22 : stereo = 2 }else{ throw new IllegalArgumentException(getClass().getName() +".getHeader(AudioFormat format)\n\tDo not support "+channels+" channels" ); } int sr = (int)format.getFrameRate(); h[i++]=(byte)( sr & 0x000000FF); // 24 : sample rate h[i++]=(byte)((sr>>8) & 0x000000FF); h[i++]=(byte)((sr>>16) & 0x000000FF); h[i++]=(byte)((sr>>24) & 0x000000FF); int ss = format.getFrameSize(); int bs = sr * ss; h[i++]=(byte)( bs & 0x000000FF); // 28 : bytes per second h[i++]=(byte)((bs>>8) & 0x000000FF); h[i++]=(byte)((bs>>16) & 0x000000FF); h[i++]=(byte)((bs>>24) & 0x000000FF); h[i++]=(byte)( ss & 0x000000FF); // 32 : bytes per sample h[i++]=(byte)((ss>>8) & 0x000000FF); int ssib = format.getSampleSizeInBits(); h[i++]=(byte)( ssib & 0x000000FF); // 34 : bits per sample h[i++]=(byte)((ssib>>8)& 0x000000FF); h[i++]= 0 ; h[i++]= 0 ; // 36 : number of bytes of additional compressor-specific information // end format chunk // 38 // start fact chunk // 38 h[i++]='f'; h[i++]='a'; h[i++]='c'; h[i++]='t'; // 38: 'fact' h[i++]= 4 ; h[i++]= 0 ; h[i++]= 0 ; h[i++]= 0 ; // 42 : length of fact chunk = 0x04 = 4 [46..50] h[i++]= 0 ; h[i++]= 0 ; h[i++]= 0 ; h[i++]= 0 ; // 46 : data size // end fact chunk // 50 // start data chunk // 50 h[i++]='d'; h[i++]='a'; h[i++]='t'; h[i++]='a'; // 50: 'data' h[i++]= 0 ; h[i++]= 0 ; h[i++]= 0 ; h[i++]= 0 ; // 54 : length of data chunk [58..(data size+58)] // data size bytes // end data chunk // data size + 58 // end riff chunk // data size + 58 return h; } public void close()throws IOException{ long size = length(); if(size>=0x7FFFFFFFl){ throw new IOException(getClass().getName()+".close()\n\tData size ["+size+"] is too big for WAV file."); } int i=4; int len=(int)size-8; h[i++]=(byte)( len & 0x000000FF); // 4 : length of riff chunk [8..(data size+58)] h[i++]=(byte)((len>>8) & 0x000000FF); h[i++]=(byte)((len>>16) & 0x000000FF); h[i++]=(byte)((len>>24) & 0x000000FF); i=46; len=(int)size-58; // data size h[i++]=(byte)( len & 0x000000FF); // 46 : 'fact' data size h[i++]=(byte)((len>>8) & 0x000000FF); h[i++]=(byte)((len>>16) & 0x000000FF); h[i++]=(byte)((len>>24) & 0x000000FF); i=54; h[i++]=(byte)( len & 0x000000FF); // 54 : length of data chunk [58..(data size+58)] h[i++]=(byte)((len>>8) & 0x000000FF); h[i++]=(byte)((len>>16) & 0x000000FF); h[i++]=(byte)((len>>24) & 0x000000FF); seek(0); write(h); // write header at beginning of file super.close(); } }