wavread, wavwrite and sound

Nilesh Madhu <[email protected]> Wed, 19 Nov 2003 08:16:45 -0600
Newsgroups gmane.comp.gnu.octave.sources
Message-ID <[email protected]>
Hi,

I've read past postings regarding the wavread, wavwrite and the sound 
functions. I would like to offer my code for these functions. Also, i've 
modified the sound function so that it can be used like in matlab with 
variable sampling frequencies. Let me know if there are any queries/ doubts

Nilesh

-- 
Nilesh Madhu, M.Sc. (Communications Engineering),
Institute for Communications Acoustics,
Ruhr University Bochum,
D-44780, Bochum.

Tel.: +49 234 32 22496
Fax : +49 234 32 14165
Mail: [email protected]
Web : http://www.ika.ruhr-uni-bochum.de
sound.m (text/plain, 1.2 KB)
%SOUND Play a vector as a sound.
%  sound (s, Fs, NBits)
%  Plays the audio data stored in the vector s, at the sampling
%  frequency Fs and the number of bits per sample NBits to the speakers. 
%
%  Author: NM <Nilesh Madhu>
%  Created: 15 September 2003
%  Copyright (C) 2003 Nilesh Madhu
%
%  This file is part of Octave distribution at the Institute for 
%  Communications Acoustics (IKA) at the RU Bochum.
%

function sound(s, Fs, NBits)

% Handling the different sampling frequencies in linux is difficult using the 
% octave PLAYAUDIO command. As a result, a work around solution is to copy the 
% data into a '.wav' file temporarily and then play this wave file by issung a 
% SYSTEM call to PLAY. If no sampling frequency is mentioned, the default sampling
% frequency is 8kHz at 16 bits (2 bytes) per sample per channel.

SamplingFrequency = 8000;		% Sampling frequency.
BitspSamp = 16;				% number of bits per sample.
if nargin == 2
	SamplingFrequency = Fs;
	if nargin == 3
		BitspSamp = NBits;
	end
end
wavwrite("temp.wav", s, SamplingFrequency , BitspSamp);

commandstr = ['play -r ', int2str(SamplingFrequency),' temp.wav'];
system(commandstr);
cleanupstr = ('rm -f temp.wav');
system(cleanupstr);
wavread.m (text/plain, 2.4 KB)
%WAVREAD Simulates the matlab wavread command.
%  [S Fs NBits] = wavread(WAVEFILENAME)
 
%Information about WAVREAD
%  Wave files are in the Resource Interchange File Format (RIFF), 
%  which consists of a variable number of chunks containing either 
%  header information (for example, the wave format of sound samples) or 
%  data (the samples themselves). (See www.sonicspot.com/ for more information.)  

function [s, Fs, NBits] = wavread(WAVEFILENAME)

LName = length(WAVEFILENAME);

if (LName < 3)
	WAVEFILENAME = [WAVEFILENAME,'.wav'];
else
	file_ext = WAVEFILENAME(length(WAVEFILENAME)-2:end);
	if (file_ext~='wav')
		WAVEFILENAME = [WAVEFILENAME,'.wav'];
	end
end

fid = fopen(WAVEFILENAME, 'r', 'ieee-le');

if fid < 0
	disp('Error! Wave file does not exist or path is mis-spelled');
	return;
end

% Start reading in the RIFF data.

ChunkID = char(fread(fid,4,"uchar",0,"ieee-le").');
if (ChunkID~='RIFF')
	disp('Error! File is not in a RIFF format');
	return;
end

% Get the file size
fseek(fid, 0x04, SEEK_SET);	% Rewinding the file.
ChunkSize = fread(fid, 1, "uint", 0, "ieee-le");

% Check the RIFF Type ID. Should be 'WAVE'
RIFFTypeID = char(fread(fid, 4, "uchar", 0, "ieee-le").');
if (RIFFTypeID ~= 'WAVE')
	disp('Error! File is not a WAVE file');
	return;
end

ChunkID = fread(fid, 4, "uchar", 0, "ieee-le");			% Returns the string 'fmt'
ChunkSiz = fread(fid, 1, "uint", 0, "ieee-le");			% always 16 bytes
Compression = fread(fid, 1, "int16", 0, "ieee-le");		% Compression code
NumberofChannels = fread(fid, 1, "int16", 0, "ieee-le");	% Number of channels
Fs = fread(fid, 1, "int32", 0, "ieee-le");			% Sampling rate
Byps = fread(fid, 1, "int32", 0, "ieee-le");			% Bytes per second
BlockAlign = fread(fid, 1, "int16", 0, "ieee-le");		% Block Align
NBits = fread(fid, 1, "int16", 0, "ieee-le");			% NBits
ChunkData = char(fread(fid, 4, "uchar", 0, "ieee-le").');	% 'data'
NumberofDataBytes = (fread(fid, 1, "uint", 0, "ieee-le"));	
NumberofSamples = NumberofDataBytes/(NumberofChannels*(NBits/8)); % number of samples

% Enough data obtained for reading in the data based upon the number of
% significant bits per sample.
switch NBits
	case 8
		MultFact = 128;
		dataPrecision = 'uchar';
	case 16
		MultFact = 32768;
		dataPrecision = 'int16';
	case 24
		MultFact = 2^23;
		dataPrecision = 'int16';
end

s = fread(fid, [NumberofSamples NumberofChannels], dataPrecision, 0, 'ieee-le');

if NBits == 8
	s = (s/MultFact) - 1;
else
	s = s/MultFact;
end

fclose(fid);
wavwrite.m (text/plain, 3.2 KB)
%WAVWRITE Write a vector into a wave file.
%  wavwrite (FileName, s, Fs, NBits)
%  Writes the audio data stored in the vector s, at the sampling
%  frequency Fs and the number of bits per sample NBits to the file FileName. 
%
%  Author: NM <Nilesh Madhu>
%  Created: 15 September 2003
%  Copyright (C) 2003 Nilesh Madhu
%
%  This file is part of Octave distribution at the Institute for 
%  Communications Acoustics (IKA) at the RU Bochum.
%

function wavwrite(FileName, s, Fs, NBits)

% Handling the different sampling frequencies in linux is difficult using the 
% octave PLAYAUDIO command. As a result, a work around solution is to copy the 
% data into a '.wav' file temporarily and then play this wave file by issung a 
% SYSTEM call to PLAY. If no sampling frequency is mentioned, the default sampling
% frequency is 8kHz at 16 bits (2 bytes) per sample per channel.

SamplingFrequency = 8000;		% Sampling frequency.

if nargin > 2
	SamplingFrequency = Fs;
	if nargin < 4
		NBits = 16;		% number of significant bits per sample.
	end
end

% Setting the parameters for writing data depending upon the
% number of significant bits.
switch NBits
	case 8
		MultFact = 128;
		dataPrecision = 'uchar';
		s = (s+1)*MultFact;
	case 16
		MultFact = 32768;
		dataPrecision = 'int16';
		s = s*MultFact;
	case 24
		MultFact = 2^23;
		dataPrecision = 'int16';
		s = s*MultFact;
end

addExt = 0;

if length(FileName) < 3
	addExt = 1;
else
	file_ext = FileName(end-2:end);
	if file_ext~='wav' 
		addExt = 1;
	end
end

if addExt
	FileName = [FileName,'.wav'];
end
		
[fid msg] = fopen(FileName,"wb", "ieee-le");

if fid < 0
	disp(msg);
	return;
end

[NumSamples NumChannels] = size(s);
if NumSamples < NumChannels
	s = s.';
	[NumSamples NumChannels] = size(s);
end
 
% Writing into the '.wav' file. 

chunkDataSize = NumSamples*NumChannels*NBits/8;	 % Size of the samples in the wav file.

% The RIFF Chunk
RIFFChunkID = toascii("RIFF");	% 'RIFF'
countRIFFCkID = fwrite(fid, RIFFChunkID, 'uchar');
RIFFChunkSize = 36+chunkDataSize;

countRIFFCkSiz = fwrite(fid, RIFFChunkSize, 'uint');

% The WAVE type ID and the FORMAT Chunk.
RIFFTypeID = toascii("WAVE");	% 'WAVE'
countRIFFTypeID = fwrite(fid, RIFFTypeID, 'uchar'); 
ChunkFmt = toascii("fmt ");	% 'fmt '
countRIFFTypeID = fwrite(fid, ChunkFmt, 'uchar'); 
RIFFTypeSiz = 16;                       % always 16 bytes
countRIFFTypeSiz = fwrite(fid, RIFFTypeSiz, 'uint');		


% Specific data for the file
CompressionFormat = 1;			% Uncompressed/ PCM
NumberofChannels =  NumChannels;
BlockAlign = (NBits/8)*NumChannels;
AvgBytespSec = SamplingFrequency*BlockAlign;


countCompression = fwrite(fid, CompressionFormat, 'int16');
countNumChannels = fwrite(fid, NumChannels, 'int16');
countFs = fwrite(fid, SamplingFrequency, 'int32');
countAvgByps = fwrite(fid, AvgBytespSec, 'int32');
countBlockAlign = fwrite(fid, BlockAlign, 'int16');
countNBits = fwrite(fid, NBits, 'int16');

% Chunk DATA
chunkData = toascii("data");	% 'data'
countChunkData = fwrite(fid, chunkData);
countchunkDataSize = fwrite(fid, chunkDataSize, 'uint');

countAudioSamples = fwrite(fid, s, dataPrecision, 0, 'ieee-le');
%for i = 1:NumSamples
%	for j = NumChannels
%		fwrite(fid, s(i,j)*32768, 'int16');
%	end
%end
fclose(fid);
%command = ['play -r ',num2str(SamplingFrequency),' temp.wav'];
%system(command);