function y = savewav(signal,filename,fs,bits)
%SAVEWAV  Write RIFF *.wav audio file.
%	SAVEWAV(X,'FILENAME',FS) writes the data in X to
%	a WAVE (*.wav) formatted audio file.  Data should 
%	be normalized for 8-bit (values 0 to 255) or
%	16-bit storage (values -32768 to +32767).  If 8-bit
%	data is given in the range -128 to 127, an offset
%	of 128 will be applied before storing data.  If X
%	is a matrix, the data will be store as multi-channel
%	with data along the longest dimension considered a 
%	single channel.  If the sampling frequency is not
%	specified, it defaults to FS = 11.025 kHz.
%
%	SAVEWAV(X,'FILENAME',FS,BITS) forces the number of
%	bits-per-sample to BITS.  Valid values for BITS are
%	8 or 16.  The default bits-per-sample is dependent
%	upon the data.  If the data is in the range 0 to 255
%	or -128 to 127, the default is 8-bits.  Data outside
%	these ranges is considered 16-bit.  An error message
%	is produced if the data is outside the range requested.
%	The sampling frequency must be specified.
%
%	SAVEWAV returns the number of bits-per-sample the 
%	data was stored in.
%
%	See also LOADWAV, LOADVOC, SAVEVOC, LOADAU, SAVEAU

%       Dennis W. Brown 6-14-94
%       Naval Postgraduate School, Monterey, CA
%       May be freely distributed.
%       Not for use in commercial products.

%	This code developed from code provided by
%	Copyright (c) 1994 by Charles W. Therrien

% arg check
if nargin == 2,
	fs = 11025;
end;

if nargin == 2 | nargin == 3,

	% compute range of data to decide number of bits
	low=min(min(signal));
	high=max(max(signal));

	if (low >= 0) & (high <= 255),
		bits = 8;
	elseif (low >= -128) & (high <= 127),
		bits = 8;
		signal = signal + 128;
	elseif (low >= -32768) & (high <= 32767),

		bits = 16;

		% offer warning if data is slightly out of 8-bit range
		if (low >= -100 & high <= 355) | (low >= -228 & high <= 227),
			disp('savewav: Writing data as 16-bit.');
		end;
	else,
		error('savewav: Data out of 16-bit range.  Adust and retry.');
	end;

elseif nargin == 4,

	% for check
	low=min(min(signal));
	high=max(max(signal));

	% range too
	if bits == 8,
		if (low >= 0) & (high <= 255),
			bits = 8;
		elseif (low >= -128) & (high <= 127),
			bits = 8;
			signal = signal + 128;
		else,
			error('savewav: Data out of 8-bit range.');
		end;
	elseif bits == 16,
		if (low < -32768 | high > 32767),
			error('savewav: Data out of 8-bit range.');
		end;
	else,
		error('savewav: Invalid number of bits/sample.');
	end;

else,
	error('savewav: Invalid number of input arguments.')
end;

% adjust filename if no extension
%if all(filename ~= '.')
%	filename=[filename,'.wav'];
%end;

% get number of channels and samples-per-channel
nchan = min(size(signal));
Ns = max(size(signal));

% make data row-wise to support interleaving of multi-channels
[m,n] = size(signal);
if n < m,
	signal = signal';
end;

% some more variables
byteps = bits/8;
totbytes = Ns * nchan * byteps;

% time to open the file
[fid,message]=fopen(filename,'wb','l');
if fid<0
	error(message)
end

% RIFF flag
fwrite(fid,'RIFF','uchar');

% filelength
fwrite(fid,36+totbytes,'ulong');

% identify as WAVE file
fwrite(fid,'WAVE','uchar');

% write format chunk
fwrite(fid,'fmt ','uchar');

fwrite(fid,16,'ulong');

% format category 1=PCM
fwrite(fid,1,'ushort');

% no. of channels
fwrite(fid,nchan,'ushort');

% sampling rate (Hz)
fwrite(fid,fs,'ulong');

% average bytes per second
fwrite(fid,fs*byteps*nchan,'ulong');

% block alignment
fwrite(fid,byteps*nchan,'ushort');

% bits per sample (specific to PCM)
fwrite(fid,bits,'ushort');

% write data chunk
fwrite(fid,'data','uchar');

% total number of bytes in signal
fwrite(fid,totbytes,'ulong');

% write the data
if bits == 8

	% write 8-bit data
	fwrite(fid,signal,'uchar');

	if rem(totbytes,2) ~= 0

		% write even number of bytes
		fwrite(fid,0,'uchar');
	end
else,
	% write 16-bit data
	fwrite(fid,signal,'short');
end

% done with file
fclose(fid);

% output requested?
if nargout == 1,
	y = bits;
elseif nargout > 1,
	error('savewav: Invalid number of output arguments.');
end;
