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