summaryrefslogtreecommitdiff
path: root/modules/sound/macros/auread.sci
blob: 5be614f5cd1a8a2ea84c588d191a9cf8dbdbb169 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
// Copyright (C) ???? - INRIA - Scilab
//
// This file must be used under the terms of the CeCILL.
// This source file is licensed as described in the file COPYING, which
// you should have received as part of this distribution.  The terms
// are also available at
// http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt

function [y,Fs,bits]=auread(aufile,ext)

    //Utility fct: reads .au sound file.
    //auread(aufile) loads a sound file specified by the string aufile,
    //returning the sampled data in y. The .au extension is appended
    //if no extension is given.  Amplitude values are in the range [-1,+1].
    //Supports multi-channel data in the following formats:
    //8-bit mu-law, 8-, 16-, and 32-bit linear, and floating point.

    //   [y,Fs,bits]=auread(aufile) returns the sample rate (Fs) in Hertz
    //   and the number of bits per sample used to encode the
    //   data in the file.

    //  auread(aufile,n) returns the first n samples from each
    //       channel in the file.
    //  auread(aufile,[n1,n2]) returns samples n1 through n2 from
    //       each channel in the file.
    //  siz=auread(aufile,'size') returns the size of the audio data contained
    //  in the file in place of the actual audio data, returning the
    //  vector siz=[samples channels].

    [nargout,nargin] = argn(0);

    if nargin>2 then
        error(msprintf(gettext("%s: Wrong number of input arguments: %d to %d expected.\n"),"auread",1,2));
    end
    // Append .au extension if it's missing:
    if strindex(aufile,".")==[] then
        aufile = aufile+".au";
    end

    [fid,junk] = mopen(aufile,"rb",0);
    if junk<0 then
        error(msprintf(gettext("%s: Cannot open file %s.\n"),"auread",aufile));
    end

    snd = read_sndhdr(fid);

    Fs = snd("rate")*snd("chans");
    bits = snd("bits");

    // Determine if caller wants data:
    if nargin<2 then
        ext = [];
    end
    // Default - read all samples
    exts = prod(size(ext));

    if ext <> [] then
        if convstr(ext)=="size" then
            // Caller doesn't want data - just data size:
            mclose(fid);
            y = [snd("samples"),snd("chans")];
            return
        elseif exts>2 then
            error(msprintf(gettext("%s: An error occurred: %s\n"),"auread",gettext("Index range must be specified as a scalar or a 2 elements vector.")));
        elseif exts==1 then
            ext = [1,ext];
        end
    end

    // Read data:

    snd = read_sndata(fid,snd,ext);
    y = snd("data");
    mclose(fid);

endfunction


function [new_snd]=read_sndata(fid,snd,ext)
    new_snd=[];
    SamplesPerChannel = snd("samples");
    BytesPerSample = snd("bits")/8;
    // format:
    if snd("format")==1 then
        dtype = "ucb";  // 8-bit mu-law
    elseif snd("format")==2 then
        dtype = "cb";  // 8-bit linear
    elseif snd("format")==3 then
        dtype = "sb";  // 16-bit linear
    elseif snd("format")==5 then
        dtype = "ib"; //  32-bit linear
    elseif snd("format")==6 then
        dtype = "fb";  // Single precision
    elseif snd("format")==7 then
        dtype = "db";  // Double-precision
    else
        error("Unrecognized data format.")
    end

    // sample range to read:
    if ext==[] then
        ext = [1,SamplesPerChannel];
        // all samples
    else
        if prod(size(ext))~=2 then
            error(msprintf(gettext("%s: An error occurred: %s\n"),"read_sndata",gettext("Sample limit vector must have 2 elements.")));
        end
        if ext(1)<1|ext(2)>SamplesPerChannel then
            error(msprintf(gettext("%s: An error occurred: %s\n"),"read_sndata",gettext("Sample limits out of range.")));
        end
        if ext(1)>ext(2) then
            error(msprintf(gettext("%s: An error occurred: %s\n"),"read_sndata",gettext("Sample limits must be given in ascending order.")));
        end
    end
    // Skip over leading samples:
    if ext(1)>1 then
        // Skip over leading samples, if specified:
        mseek(BytesPerSample*(ext(1)-1)*snd("chans"),fid,"cur");
        if (merror(fid) <> 0) then
            error(msprintf(gettext("%s: An error occurred: %s\n"),"read_sndata",gettext("Error in file format.")));
        end
    end

    // Read desired data:
    nSPCext = ext(2)-ext(1)+1;
    // # samples per channel in extraction range
    extSamples = snd("chans")*nSPCext;
    data=mget(snd("chans")*nSPCext,dtype,fid);
    // Rearrange data into a matrix with one channel per column:
    // XXXX A finir
    data = matrix(data,snd("chans"),nSPCext);
    // Convert and normalize data range:
    if snd("format")==1 then
        // 8-bit mu-law
        data = mu2lin(data);
    elseif snd("format")==2 then
        // 8-bit linear
        data = data*(2^(-7));
    elseif snd("format")==3 then
        // 16-bit linear
        data = data*(2^(-15));
    elseif snd("format")==5 then
        // 32-bit linear
        data = data*(2^(-31));
    elseif snd("format")==6|snd("format")==7 then
        // Float/Double
        //a = min(data);
        //b = max(data);
        //data = (data-a)/(b-a)*2-1;
    end
    new_snd = snd;
    new_snd("data")=data
    return
endfunction

function [snd]=read_sndhdr(fid)
    // Read file header:
    snd=tlist(["snd","offset","databytes","format","rate","chans","data","info","bits","samples","magic"])

    snd.magic = ascii(mget(4,"c",fid))
    if snd.magic~=".snd",
        error("Not a .au sound file.")
    end

    snd("offset")=mget(1,"uib",fid)
    snd("databytes")=mget(1,"uib",fid)
    snd("format")=mget(1,"uib",fid)
    snd("rate")=mget(1,"uib",fid)
    snd("chans")=mget(1,"uib",fid)

    // Directly determine how long info string is:
    info_len = snd("offset")-24;
    [info,cnt] = mtlb_fread(fid,info_len,"char");
    snd("info")=stripblanks(ascii(info'))
    if cnt~=info_len then
        error(msprintf(gettext("%s: An error occurred: %s\n"),"read_sndhdr",gettext("Error while reading sound file.")));
    end

    // Determine file length
    mseek(0,fid,"end");
    // Go to end of file
    file_len = mtell(fid);
    // Get position in bytes
    mseek(snd("offset"),fid,"set");
    // Reposition file pointer
    snd("databytes")=file_len-snd("offset")

    // Interpret format:
    if snd("format")==1 then
        snd("bits")=8
        // 8-bit mu-law
    elseif snd("format")==2 then
        snd("bits")=8
        // 8-bit linear
    elseif snd("format")==3 then
        snd("bits")=16
        // 16-bit linear
    elseif snd("format")==5 then
        snd("bits")=32
        // 32-bit linear
    elseif snd("format")==6 then
        snd("bits")=32
        // Single precision
    elseif snd("format")==7 then
        snd("bits")=64
        // Double-precision
    else
        error(msprintf(gettext("%s: An error occurred: %s\n"),"read_sndhdr",gettext("Unrecognized data format.")));
    end
    // Determine # of samples per channel:
    snd("samples")=snd("databytes")*8/snd("bits")/snd("chans")
    if snd("samples")~=fix(snd("samples")) then
        error(msprintf(gettext("%s: An error occurred: %s\n"),"read_sndhdr",gettext("Truncated data file.")));
    end
endfunction