Bump version numbers to 6.2.0
[scilab.git] / scilab / modules / sound / macros / auread.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) ???? - INRIA - Scilab
3 //
4 // Copyright (C) 2012 - 2016 - Scilab Enterprises
5 //
6 // This file is hereby licensed under the terms of the GNU GPL v2.0,
7 // pursuant to article 5.3.4 of the CeCILL v.2.1.
8 // This file was originally licensed under the terms of the CeCILL v2.1,
9 // and continues to be available under such terms.
10 // For more information, see the COPYING file which you should have received
11 // along with this program.
12
13 function [y,Fs,bits]=auread(aufile, ext)
14
15     //Utility fct: reads .au sound file.
16     //auread(aufile) loads a sound file specified by the string aufile,
17     //returning the sampled data in y. The .au extension is appended
18     //if no extension is given.  Amplitude values are in the range [-1,+1].
19     //Supports multi-channel data in the following formats:
20     //8-bit mu-law, 8-, 16-, and 32-bit linear, and floating point.
21
22     //   [y,Fs,bits]=auread(aufile) returns the sample rate (Fs) in Hertz
23     //   and the number of bits per sample used to encode the
24     //   data in the file.
25
26     //  auread(aufile,n) returns the first n samples from each
27     //       channel in the file.
28     //  auread(aufile,[n1,n2]) returns samples n1 through n2 from
29     //       each channel in the file.
30     //  siz=auread(aufile,'size') returns the size of the audio data contained
31     //  in the file in place of the actual audio data, returning the
32     //  vector siz=[samples channels].
33
34     [nargout,nargin] = argn(0);
35
36     if nargin>2 then
37         error(msprintf(gettext("%s: Wrong number of input arguments: %d to %d expected.\n"),"auread",1,2));
38     end
39     // Append .au extension if it's missing
40     tmp = convstr(fileparts(aufile,"extension"))
41     if tmp=="" | (~isfile(aufile) & tmp<>".au")
42         aufile = aufile + ".au";
43     end
44
45     [fid,junk] = mopen(aufile,"rb",0);
46     if junk<0 then
47         error(msprintf(gettext("%s: Cannot open file %s.\n"),"auread",aufile));
48     end
49
50     snd = read_sndhdr(fid);
51
52     Fs = snd("rate")*snd("chans");
53     bits = snd("bits");
54
55     // Determine if caller wants data:
56     if nargin<2 then
57         ext = [];
58     end
59     // Default - read all samples
60     exts = prod(size(ext));
61
62     if ext <> [] then
63         if convstr(ext)=="size" then
64             // Caller doesn't want data - just data size:
65             mclose(fid);
66             y = [snd("samples"),snd("chans")];
67             return
68         elseif exts>2 then
69             mclose(fid)
70             error(msprintf(gettext("%s: An error occurred: %s\n"),"auread",gettext("Index range must be specified as a scalar or a 2 elements vector.")));
71         elseif exts==1 then
72             ext = [1,ext];
73         end
74     end
75
76     // Read data:
77
78     snd = read_sndata(fid,snd,ext);
79     y = snd("data");
80     mclose(fid);
81
82 endfunction
83
84
85 function new_snd = read_sndata(fid,snd,ext)
86     new_snd = [];
87     SamplesPerChannel = snd("samples");
88     BytesPerSample = snd("bits")/8;
89     // format:
90     if snd("format")==1 then
91         dtype = "ucb";  // 8-bit mu-law
92     elseif snd("format")==2 then
93         dtype = "cb";  // 8-bit linear
94     elseif snd("format")==3 then
95         dtype = "sb";  // 16-bit linear
96     elseif snd("format")==5 then
97         dtype = "ib"; //  32-bit linear
98     elseif snd("format")==6 then
99         dtype = "fb";  // Single precision
100     elseif snd("format")==7 then
101         dtype = "db";  // Double-precision
102     else
103         mclose(fid)
104         msg = gettext("%s: File ''%s'': Unrecognized data format.\n")
105         error(msprintf(msg, "auread/read_sndata", aufile));
106     end
107
108     // sample range to read:
109     if ext==[] then
110         ext = [1,SamplesPerChannel];
111         // all samples
112     else
113         if prod(size(ext))~=2 then
114             mclose(fid)
115             error(msprintf(gettext("%s: An error occurred: %s\n"),"auread/read_sndata",gettext("Sample limit vector must have 2 elements.")));
116         end
117         if ext(1)<1|ext(2)>SamplesPerChannel then
118             mclose(fid)
119             error(msprintf(gettext("%s: An error occurred: %s\n"),"auread/read_sndata",gettext("Sample limits out of range.")));
120         end
121         if ext(1)>ext(2) then
122             mclose(fid)
123             error(msprintf(gettext("%s: An error occurred: %s\n"),"auread/read_sndata",gettext("Sample limits must be given in ascending order.")));
124         end
125     end
126     // Skip over leading samples:
127     if ext(1)>1 then
128         // Skip over leading samples, if specified:
129         mseek(BytesPerSample*(ext(1)-1)*snd("chans"),fid,"cur");
130         if merror(fid) <> 0 then
131             mclose(fid)
132             error(msprintf(gettext("%s: An error occurred: %s\n"),"auread/read_sndata",gettext("Error in file format.")));
133         end
134     end
135
136     // Read desired data:
137     nSPCext = ext(2)-ext(1)+1;
138     // # samples per channel in extraction range
139     extSamples = snd("chans")*nSPCext;
140     data=mget(snd("chans")*nSPCext,dtype,fid);
141     // Rearrange data into a matrix with one channel per column:
142     // XXXX A finir
143     data = matrix(data,snd("chans"),nSPCext);
144     // Convert and normalize data range:
145     if snd("format")==1 then
146         // 8-bit mu-law
147         data = mu2lin(data);
148     elseif snd("format")==2 then
149         // 8-bit linear
150         data = data*(2^(-7));
151     elseif snd("format")==3 then
152         // 16-bit linear
153         data = data*(2^(-15));
154     elseif snd("format")==5 then
155         // 32-bit linear
156         data = data*(2^(-31));
157     elseif snd("format")==6|snd("format")==7 then
158         // Float/Double
159         //a = min(data);
160         //b = max(data);
161         //data = (data-a)/(b-a)*2-1;
162     end
163     new_snd = snd;
164     new_snd("data") = data
165 endfunction
166
167 function snd = read_sndhdr(fid)
168     // Read file header:
169     snd = tlist(["snd","offset","databytes","format","rate","chans","data","info","bits","samples","magic"])
170
171     snd.magic = ascii(mget(4,"c",fid))
172     if snd.magic~=".snd",
173         mclose(fid)
174         msg = gettext("%s: File ''%s'' is not a .au sound file.\n")
175         error(msprintf(msg, "auread/read_sndhdr", aufile));
176     end
177
178     snd("offset")=mget(1,"uib",fid)
179     snd("databytes")=mget(1,"uib",fid)
180     snd("format")=mget(1,"uib",fid)
181     snd("rate")=mget(1,"uib",fid)
182     snd("chans")=mget(1,"uib",fid)
183
184     // Directly determine how long info string is:
185     info_len = snd("offset")-24;
186     [info,cnt] = mtlb_fread(fid,info_len,"char");
187     snd("info")=stripblanks(ascii(info'))
188     if cnt~=info_len then
189         mclose(fid)
190         error(msprintf(gettext("%s: An error occurred: %s\n"),"auread/read_sndhdr",gettext("Error while reading sound file.")));
191     end
192
193     // Determine file length
194     mseek(0,fid,"end");
195     // Go to end of file
196     file_len = mtell(fid);
197     // Get position in bytes
198     mseek(snd("offset"),fid,"set");
199     // Reposition file pointer
200     snd("databytes")=file_len-snd("offset")
201
202     // Interpret format:
203     if snd("format")==1 then
204         snd("bits")=8
205         // 8-bit mu-law
206     elseif snd("format")==2 then
207         snd("bits")=8
208         // 8-bit linear
209     elseif snd("format")==3 then
210         snd("bits")=16
211         // 16-bit linear
212     elseif snd("format")==5 then
213         snd("bits")=32
214         // 32-bit linear
215     elseif snd("format")==6 then
216         snd("bits")=32
217         // Single precision
218     elseif snd("format")==7 then
219         snd("bits")=64
220         // Double-precision
221     else
222         mclose(fid)
223         error(msprintf(gettext("%s: An error occurred: %s\n"),"auread/read_sndhdr",gettext("Unrecognized data format.")));
224     end
225     // Determine # of samples per channel:
226     snd("samples")=snd("databytes")*8/snd("bits")/snd("chans")
227     if snd("samples")~=fix(snd("samples")) then
228         mclose(fid)
229         error(msprintf(gettext("%s: An error occurred: %s\n"),"auread/read_sndhdr",gettext("Truncated data file.")));
230     end
231 endfunction