Mercurial > hg > octave-nkf
annotate scripts/audio/wavread.m @ 10635:d1978e7364ad
Print name of function in error() string messages.
author | Rik <octave@nomad.inbox5.com> |
---|---|
date | Sun, 16 May 2010 22:26:54 -0700 |
parents | 95c3e38098bf |
children | a4b8364e04c7 |
rev | line source |
---|---|
8920 | 1 ## Copyright (C) 2005, 2006, 2007, 2008, 2009 Michael Zeising |
5565 | 2 ## |
3 ## This file is part of Octave. | |
4 ## | |
5 ## Octave is free software; you can redistribute it and/or modify it | |
6 ## under the terms of the GNU General Public License as published by | |
7016 | 7 ## the Free Software Foundation; either version 3 of the License, or (at |
8 ## your option) any later version. | |
5565 | 9 ## |
10 ## Octave is distributed in the hope that it will be useful, but | |
11 ## WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 ## General Public License for more details. | |
14 ## | |
15 ## You should have received a copy of the GNU General Public License | |
7016 | 16 ## along with Octave; see the file COPYING. If not, see |
17 ## <http://www.gnu.org/licenses/>. | |
5565 | 18 |
19 ## -*- texinfo -*- | |
6547 | 20 ## @deftypefn {Function File} {@var{y} =} wavread (@var{filename}) |
5567 | 21 ## Load the RIFF/WAVE sound file @var{filename}, and return the samples |
22 ## in vector @var{y}. If the file contains multichannel data, then | |
23 ## @var{y} is a matrix with the channels represented as columns. | |
5565 | 24 ## |
6547 | 25 ## @deftypefnx {Function File} {[@var{y}, @var{Fs}, @var{bits}] =} wavread (@var{filename}) |
5565 | 26 ## Additionally return the sample rate (@var{fs}) in Hz and the number of bits |
27 ## per sample (@var{bits}). | |
28 ## | |
6547 | 29 ## @deftypefnx {Function File} {[@dots{}] =} wavread (@var{filename}, @var{n}) |
5565 | 30 ## Read only the first @var{n} samples from each channel. |
31 ## | |
6549 | 32 ## @deftypefnx {Function File} {[@dots{}] =} wavread (@var{filename},[@var{n1} @var{n2}]) |
5565 | 33 ## Read only samples @var{n1} through @var{n2} from each channel. |
34 ## | |
6547 | 35 ## @deftypefnx {Function File} {[@var{samples}, @var{channels}] =} wavread (@var{filename}, "size") |
5567 | 36 ## Return the number of samples (@var{n}) and channels (@var{ch}) |
37 ## instead of the audio data. | |
5642 | 38 ## @seealso{wavwrite} |
5565 | 39 ## @end deftypefn |
40 | |
7117 | 41 ## Author: Michael Zeising <michael@michaels-website.de> |
5565 | 42 ## Created: 06 December 2005 |
43 | |
5567 | 44 function [y, samples_per_sec, bits_per_sample] = wavread (filename, param) |
45 | |
5565 | 46 FORMAT_PCM = 0x0001; # PCM (8/16/32 bit) |
47 FORMAT_IEEE_FLOAT = 0x0003; # IEEE float (32/64 bit) | |
48 BYTEORDER = "ieee-le"; | |
49 | |
5567 | 50 if (nargin < 1 || nargin > 2) |
6046 | 51 print_usage (); |
5567 | 52 endif |
53 | |
54 if (! ischar (filename)) | |
10635
d1978e7364ad
Print name of function in error() string messages.
Rik <octave@nomad.inbox5.com>
parents:
10549
diff
changeset
|
55 error ("wavread: expecting filename to be a character string"); |
5567 | 56 endif |
57 | |
8796
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
58 # Open file for binary reading. |
5565 | 59 [fid, msg] = fopen (filename, "rb"); |
60 if (fid < 0) | |
5572 | 61 error ("wavread: %s", msg); |
5565 | 62 endif |
8796
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
63 |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
64 ## Get file size. |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
65 fseek (fid, 0, "eof"); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
66 file_size = ftell (fid); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
67 fseek (fid, 0, "bof"); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
68 |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
69 ## Find RIFF chunk. |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
70 riff_size = find_chunk (fid, "RIFF", file_size); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
71 riff_pos = ftell (fid); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
72 if (riff_size == -1) |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
73 fclose (fid); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
74 error ("wavread: file contains no RIFF chunk"); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
75 endif |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
76 |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
77 riff_type = char (fread (fid, 4))'; |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
78 if(! strcmp (riff_type, "WAVE")) |
5565 | 79 fclose (fid); |
8796
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
80 error ("wavread: file contains no WAVE signature"); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
81 endif |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
82 riff_pos = riff_pos + 4; |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
83 riff_size = riff_size - 4; |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
84 |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
85 ## Find format chunk inside the RIFF chunk. |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
86 fseek (fid, riff_pos, "bof"); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
87 fmt_size = find_chunk (fid, "fmt ", riff_size); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
88 fmt_pos = ftell(fid); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
89 if (fmt_size == -1) |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
90 fclose (fid); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
91 error ("wavread: file contains no format chunk"); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
92 endif |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
93 |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
94 ## Find data chunk inside the RIFF chunk. |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
95 ## We don't assume that it comes after the format chunk. |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
96 fseek (fid, riff_pos, "bof"); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
97 data_size = find_chunk (fid, "data", riff_size); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
98 data_pos = ftell (fid); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
99 if (data_size == -1) |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
100 fclose (fid); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
101 error ("wavread: file contains no data chunk"); |
5565 | 102 endif |
103 | |
8796
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
104 ### Read format chunk. |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
105 fseek (fid, fmt_pos, "bof"); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
106 |
8506 | 107 ## Sample format code. |
6304 | 108 format_tag = fread (fid, 1, "uint16", 0, BYTEORDER); |
5567 | 109 if (format_tag != FORMAT_PCM && format_tag != FORMAT_IEEE_FLOAT) |
110 fclose (fid); | |
111 error ("wavread: sample format %#x is not supported", format_tag); | |
112 endif | |
113 | |
8506 | 114 ## Number of interleaved channels. |
6304 | 115 channels = fread (fid, 1, "uint16", 0, BYTEORDER); |
5567 | 116 |
8506 | 117 ## Sample rate. |
6304 | 118 samples_per_sec = fread (fid, 1, "uint32", 0, BYTEORDER); |
5567 | 119 |
8506 | 120 ## Bits per sample. |
8796
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
121 fseek (fid, 6, "cof"); |
6304 | 122 bits_per_sample = fread (fid, 1, "uint16", 0, BYTEORDER); |
5567 | 123 |
8796
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
124 ### Read data chunk. |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
125 fseek (fid, data_pos, "bof"); |
5565 | 126 |
8506 | 127 ## Determine sample data type. |
5567 | 128 if (format_tag == FORMAT_PCM) |
5839 | 129 switch (bits_per_sample) |
5565 | 130 case 8 |
5572 | 131 format = "uint8"; |
5565 | 132 case 16 |
133 format = "int16"; | |
5839 | 134 case 24 |
10549 | 135 format = "uint8"; |
5565 | 136 case 32 |
137 format = "int32"; | |
138 otherwise | |
139 fclose (fid); | |
6304 | 140 error ("wavread: %d bits sample resolution is not supported with PCM", |
10549 | 141 bits_per_sample); |
5565 | 142 endswitch |
143 else | |
5567 | 144 switch (bits_per_sample) |
5565 | 145 case 32 |
146 format = "float32"; | |
147 case 64 | |
148 format = "float64"; | |
149 otherwise | |
150 fclose (fid); | |
6304 | 151 error ("wavread: %d bits sample resolution is not supported with IEEE float", |
10549 | 152 bits_per_sample); |
5565 | 153 endswitch |
154 endif | |
155 | |
8506 | 156 ## Parse arguments. |
5567 | 157 if (nargin == 1) |
8796
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
158 length = 8 * data_size / bits_per_sample; |
5565 | 159 else |
5567 | 160 if (size (param, 2) == 1) |
8506 | 161 ## Number of samples is given. |
5565 | 162 length = param * channels; |
5567 | 163 elseif (size (param, 2) == 2) |
8506 | 164 ## Sample range is given. |
8796
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
165 if (fseek (fid, (param(1)-1) * channels * (bits_per_sample/8), "cof") < 0) |
5567 | 166 warning ("wavread: seeking failed"); |
5565 | 167 endif |
5839 | 168 length = (param(2)-param(1)+1) * channels; |
5567 | 169 elseif (size (param, 2) == 4 && char (param) == "size") |
8506 | 170 ## Size of the file is requested. |
5565 | 171 fclose (fid); |
9598
70de69177370
wavread.m: rename data_size from obsolete ck_size
Christophe Tournery <christophe.tournery@illusonic.com>
parents:
8920
diff
changeset
|
172 y = [data_size/channels/(bits_per_sample/8), channels]; |
5565 | 173 return |
174 else | |
175 fclose (fid); | |
176 error ("wavread: invalid argument 2"); | |
177 endif | |
178 endif | |
5839 | 179 |
8506 | 180 ## Read samples and close file. |
5839 | 181 if (bits_per_sample == 24) |
182 length *= 3; | |
183 endif | |
5565 | 184 [yi, n] = fread (fid, length, format, 0, BYTEORDER); |
185 fclose (fid); | |
5839 | 186 |
8506 | 187 ## Check data. |
6304 | 188 if (mod (numel (yi), channels) != 0) |
189 error ("wavread: data in %s doesn't match the number of channels", | |
10549 | 190 filename); |
6304 | 191 endif |
192 | |
5839 | 193 if (bits_per_sample == 24) |
194 yi = reshape (yi, 3, rows(yi)/3)'; | |
195 yi(yi(:,3) >= 128, 3) -= 256; | |
196 yi = yi * [1; 256; 65536]; | |
7151 | 197 endif |
198 | |
5567 | 199 if (format_tag == FORMAT_PCM) |
8506 | 200 ## Normalize samples. |
5567 | 201 switch (bits_per_sample) |
5565 | 202 case 8 |
7117 | 203 yi = (yi - 128)/127; |
5572 | 204 case 16 |
7117 | 205 yi /= 32767; |
5839 | 206 case 24 |
10549 | 207 yi /= 8388607; |
5572 | 208 case 32 |
7117 | 209 yi /= 2147483647; |
5565 | 210 endswitch |
211 endif | |
212 | |
8506 | 213 ## Deinterleave. |
5567 | 214 nr = numel (yi) / channels; |
215 y = reshape (yi, channels, nr)'; | |
5565 | 216 |
217 endfunction | |
8796
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
218 |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
219 ## Given a chunk_id, scan through chunks from the current file position |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
220 ## though at most size bytes. Return the size of the found chunk, with |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
221 ## file position pointing to the start of the chunk data. Return -1 for |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
222 ## size if chunk is not found. |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
223 |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
224 function chunk_size = find_chunk (fid, chunk_id, size) |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
225 id = ""; |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
226 offset = 8; |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
227 chunk_size = 0; |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
228 |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
229 while (! strcmp (id, chunk_id) && (offset < size)) |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
230 fseek (fid, chunk_size, "cof"); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
231 id = char (fread (fid, 4))'; |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
232 chunk_size = fread (fid, 1, "uint32", 0, "ieee-le"); |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
233 offset = offset + 8 + chunk_size; |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
234 endwhile |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
235 if (! strcmp (id, chunk_id)) |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
236 chunk_size = -1; |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
237 endif |
9662dfb26652
wavread.m: improve search for data chunks
Frederick Umminger <Frederick_Umminger@playstation.sony.com>
parents:
8506
diff
changeset
|
238 endfunction |