1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) ???? - INRIA - Scilab
3 // Copyright (C) ???? - ENPC
4 // Copyright (C) 2008-2011 - DIGITEO - Allan CORNET
5 // Copyright (C) 2012 - 2016 - Scilab Enterprises
6 // Copyright (C) 2019 - Samuel GOUGEON
8 // This file is hereby licensed under the terms of the GNU GPL v2.0,
9 // pursuant to article 5.3.4 of the CeCILL v.2.1.
10 // This file was originally licensed under the terms of the CeCILL v2.1,
11 // and continues to be available under such terms.
12 // For more information, see the COPYING file which you should have received
13 // along with this program.
15 // =============================================================================
16 function [y, Fs, bits] = wavread(wavfile, ext)
22 // Read Microsoft .wav sound file.
23 // y=wavread(wavfile) reads a .wav file specified by the string wavfile,
24 // returning the sampled data in y. The .wav extension is appended
25 // if no extension is given.
26 // Amplitude values are in the range [-1,+1].
27 // [y,fs,bits]=wavread(wavfile) returns the sample rate (fs) in Hertz
28 // and the number of bits per sample (bits) used to encode the
30 // [...]=wavread(wavfile,n) returns only the first n samples from each
31 // channel in the file.
32 // [...]=wavread(wavfile,[n1 n2]) returns only samples n1 through n2 from
33 // each channel in the file.
34 // siz=wavread(wavfile,"size") returns the size of the audio data contained
35 // in the file in place of the actual audio data, returning the
36 // vector siz=[samples channels].
37 // infos=wavread(wavfile,"size") returns a vector with the information about actual
39 // vector infos = [wFormatTag, nChannels, nSamplesPerSec,
40 // nAvgBytesPerSec, nBlockAlign,
41 // nBitsPerSample, cbSize, nChannels, samples]
44 // INPUT ARGUMENTS CHECKING
45 // ========================
46 // Append .wav extension if necessary
47 tmp = fileparts(wavfile,"extension")
48 if tmp=="" | (~isfile(wavfile) & tmp<>".wav")
49 wavfile = wavfile + ".wav";
52 // Handle ext optional argument
57 if (type(ext) == 10) then
59 if (ext <> "size") & (ext <> "info") then
60 msg = gettext("%s: Wrong value for input argument #%d: Must be ""%s"" or ""%s"", an integer or a vector of %d integers.\n")
61 error(msprintf(msg, "wavread", 2, "size", "info", 2));
63 elseif (type(ext) == 1) then
64 exts = size(ext, "*");
66 msg = gettext("%s: Wrong value for input argument: Index range must be specified as a scalar or %d-element vector.\n")
67 error(msprintf(msg, "wavread", 2));
71 ext = "size"; // synonym for size
77 msg = gettext("%s: Wrong value for input argument #%d: Must be ""%s"" or ""%s"", an integer or a vector of %d integers.\n")
78 error(msprintf(msg, "wavread", 2, "size", "info", 2));
83 if ~isfile(wavfile) then
84 msg = _("%s: The file ''%s'' does not exist.\n")
85 error(msprintf(msg, "wavread", wavfile));
87 [fid, err] = mopen(wavfile, "rb", 1); // Little-endian
89 error(msprintf(gettext("%s: Cannot open file %s.\n"), "wavread", wavfile));
92 // Checking for the RIFF and wav identifiers
93 // -----------------------------------------
95 ID = stripblanks(ascii(mget(4, "c", fid)));
96 Size = mget(1, "ui", fid);
97 if (convstr(ID) ~= "riff") then
99 msg2 = gettext(".wav file does not contain the RIFF identifier.")
100 error(msprintf(gettext("%s: An error occurred: %s\n"), "wavread", msg2));
102 rifftype = mget(4, "c", fid);
103 dtype = convstr(ascii(rifftype)');
104 if (dtype ~= "wave") then
106 msg2 = gettext(".wav file does not contain the wave identifier.")
107 error(msprintf(gettext("%s: An error occurred: %s\n"), "wavread", msg2));
110 // Find optional chunks
111 // --------------------
114 while ~found_data then
115 [ID, Size] = find_cktype(fid);
119 orig_pos = mtell(fid);
121 // # of required bytes in <fact-ck> header
122 if total_bytes < nbytes then
124 msg2 = gettext("Error reading .wav file.")
125 error(msprintf(gettext("%s: An error occurred: %s\n"), "wavread", msg2));
127 factdata = mget(1, "ui", fid); // Samples per second
128 rbytes = total_bytes - (mtell(fid) - orig_pos);
130 mseek(rbytes, fid, "cur");
131 if (merror(fid) <> 0) then
133 msg2 = gettext("Error reading <fact-ck> chunk.")
134 error(msprintf(gettext("%s: An error occurred: %s\n"), "wavread", msg2));
141 msg = gettext("%s: An error occurred: %s is not supported.\n")
142 error(msprintf(msg, "wavread", "Broadcast Wave Format"));
144 // bug 4832 - Sampler Chunk
147 msg = gettext("%s: An error occurred: invalid file format. Error reading <%s> chunk.\n")
148 error(msprintf(msg, "wavread", ID));
152 [wFormatTag, nChannels, nSamplesPerSec, nAvgBytesPerSec, nBlockAlign, nBitsPerSample, cbSize] = read_wavefmt(fid, Size);
159 msg2 = gettext("Invalid .wav file: found data before format information.")
160 error(msprintf(gettext("%s: An error occurred: %s\n"), "wavread", msg2));
162 if (ext == "size") | (ext == "info") | (~(ext == [])) & and(ext == 0) then
163 // Caller just wants data size:
164 samples = read_wavedat(fid, Size ,wFormatTag, nChannels, nBitsPerSample, -1);
165 if (ext == "info") then
166 y = [wFormatTag, nChannels, nSamplesPerSec, nAvgBytesPerSec, nBlockAlign, nBitsPerSample, cbSize, nChannels, samples];
168 y = [nChannels, samples];
171 y = read_wavedat(fid, Size ,wFormatTag, nChannels, nBitsPerSample, ext);
176 mseek(Size, fid, "cur")
177 if (merror(fid) <> 0) then
179 msg2 = gettext("Incorrect chunk size information in RIFF file.")
180 error(msprintf(gettext("%s: An error occurred: %s\n"), "wavread", msg2))
185 if ( wFormatTag == 1 | wFormatTag == 3) then
186 bits = (nBlockAlign / nChannels) * 8;
192 // =============================================================================
193 function [ID, Size] = find_cktype(fid)
194 ID = stripblanks(ascii(mget(4, "c", fid)));
195 Size = mget(1, "ui", fid);
197 // =============================================================================
198 function [wFormatTag, nChannels, nSamplesPerSec, nAvgBytesPerSec, nBlockAlign, nBitsPerSample, cbSize] = read_wavefmt(fid, total_bytes)
199 orig_pos = mtell(fid);
200 nbytes = 14; // # of required bytes in header
202 if total_bytes < nbytes then
204 msg2 = gettext("Error reading .wav file.")
205 error(msprintf(gettext("%s: An error occurred: %s\n"), "read_wavefmt", msg2));
209 wFormatTag = mget(1, "us", fid); // Data encoding format
210 nChannels = mget(1, "us", fid); // Number of channels
211 nSamplesPerSec = mget(1, "ui", fid); // Samples per second
212 nAvgBytesPerSec = mget(1, "ui", fid); // Avg transfer rate
213 nBlockAlign = mget(1, "us", fid); // Block alignment
214 supportedFormats = [1 3]; // codes of supported wav formats
215 if (and(wFormatTag ~= supportedFormats)) then
217 msg = gettext("%s: wav format #%d detected. Only wav formats #%s are supported.\n")
218 error(msprintf(msg, "read_wavefmt", wFormatTag, strcat(msprintf("%d\n",supportedFormats'),"|")));
220 [cbSize, nBitsPerSample] = read_fmt_pcm(fid, total_bytes);
223 rbytes = total_bytes - (mtell(fid) - orig_pos);
225 mseek(rbytes, fid, "cur")
226 if (merror(fid) <> 0) then
228 msg2 = gettext("Error reading .wav file.")
229 error(msprintf(gettext("%s: An error occurred: %s\n"), "read_wavefmt", msg2));
233 // =============================================================================
234 function [cbSize, nBitsPerSample] = read_fmt_pcm(fid, total_bytes)
238 // # of bytes already read
239 if (total_bytes < nbytes + 2) then
241 msg2 = gettext("Error reading wav file.")
242 error(msprintf(gettext("%s: An error occurred: %s\n"), "read_fmt_pcm", msg2));
244 nBitsPerSample = mget(1, "us", fid);
246 if (total_bytes > nbytes) then
247 if (total_bytes >= nbytes + 2) then
248 cbSize = mget(1, "us", fid);
251 if (total_bytes > nbytes) then
252 mseek(total_bytes - nbytes, fid, "cur")
253 if (merror(fid) <> 0) then
255 msg2 = gettext("Error reading wav file.")
256 error(msprintf(gettext("%s: An error occurred: %s\n"), "read_fmt_pcm", msg2));
261 // =============================================================================
262 function Data = read_wavedat(fid, Size, wFormatTag, nChannels, nBitsPerSample, ext)
267 Data = read_dat_pcm(fid, Size, nChannels, nBitsPerSample, ext, wFormatTag);
269 fmt_msg = "Microsoft ADPCM";
271 // normalized floating-point
272 Data = read_dat_pcm(fid, Size, nChannels, nBitsPerSample, ext, wFormatTag);
274 fmt_msg = "CCITT a-law";
276 fmt_msg = "CCITT mu-law";
278 fmt_msg = "IMA ADPCM";
280 fmt_msg = "DSP Group TrueSpeech TM";
282 fmt_msg = "GSM 6.10";
284 fmt_msg = "MSN Audio";
286 fmt_msg = "IBM Mu-law";
288 fmt_msg = "IBM A-law";
290 fmt_msg = "IBM AVC Adaptive Differential";
292 fmt_msg = "Format #" + string(wFormatTag);
294 if ~(fmt_msg == []) then
296 msg = gettext("%s: An error occurred: Data compression format %s is not supported.\n")
297 error(msprintf(msg, "read_wavedat", fmt_msg));
300 // =============================================================================
301 function Data = read_dat_pcm(fid, total_bytes , nChannels, nBitsPerSample, ext, wFormatTag)
302 // Determine # bytes/sample - format requires rounding
303 // to next integer number of bytes:
304 BytesPerSample = ceil(nBitsPerSample / 8);
306 select BytesPerSample
307 case 1 then // unsigned 8-bit
309 case 2 then // signed 16-bit
311 case 3 then // signed 24-bit
313 case 4 then // signed 32-bit (long)
314 if wFormatTag == 3 then
321 msg2 = gettext("Cannot read .wav file with more than 16 bits per sample.")
322 error(msprintf(gettext("%s: An error occurred: %s\n"), "read_dat_pcm", msg2));
323 end// select BytesPerSample
325 // # bytes in this chunk
326 total_samples = total_bytes / BytesPerSample;
327 SamplesPerChannel = total_samples / nChannels;
328 if ((~(ext == [])) & (ext == -1)) then
329 // Just return the samples per channel, and seek past data:
330 Data = SamplesPerChannel;
331 mseek(total_bytes, fid, "cur");
335 ext = [1, SamplesPerChannel];
337 if (prod(size(ext)) ~= 2) then
339 msg2 = gettext("Sample limit vector must have 2 entries.")
340 error(msprintf(gettext("%s: An error occurred: %s\n"), "read_dat_pcm", msg2));
342 if (ext(1) < 1) | (ext(2) > SamplesPerChannel) then
344 msg2 = gettext("Sample limits out of range.")
345 error(msprintf(gettext("%s: An error occurred: %s\n"), "read_dat_pcm", msg2));
347 if (ext(1) > ext(2)) then
349 msg2 = gettext("Invalid sample limits (use ascending order).")
350 error(msprintf(gettext("%s: An error occurred: %s\n"), "read_dat_pcm", msg2));
355 // Skip if specified:
356 mseek(BytesPerSample * (ext(1) - 1) * nChannels, fid, "cur");
360 nSPCext = ext(2) - ext(1) + 1;
361 // # samples per channel in extraction range
362 extSamples = nChannels * nSPCext;
364 //24-bits files need special treatment
365 if ( BytesPerSample == 3 ) then
367 Data_tmp = (mget(3 * nChannels * nSPCext, dtype, fid));
368 oct1 = uint8(Data_tmp(1:3:$-1));
369 oct2 = uint8(Data_tmp(2:3:$));
370 oct3 = Data_tmp(3:3:$);
371 Data_tmp2 = (double(oct1) * (2^0) + double(oct2) * (2^8) + double(oct3) * (2^16));
372 Data = matrix(Data_tmp2, [nChannels, nSPCext]);
374 Data = matrix(mget(nChannels * nSPCext, dtype, fid), [nChannels, nSPCext]);
377 // Skip trailing samples:
379 mseek(BytesPerSample * (SamplesPerChannel - ext(2)) * nChannels, fid, "cur");
381 // Determine if a pad-byte is appended and skip if present:
383 if ( junk - fix(junk./2).*2 ) then
384 mseek(1, fid, "cur");
386 // Normalize data range in [-1 1] (min will hit -1)
387 select BytesPerSample
389 Data = (Data - 128) / 128;
393 Data = Data / (2^23);
395 // wFormatTag == 3 already normalized
396 if wFormatTag <> 3 then
397 Data = Data / (2^31);
399 end; //normalization in range [-1 +1]
401 // =============================================================================