comparison scripts/audio/wavwrite.m @ 12701:de3e90a420e3 stable

Overhaul wavwrite, wavread and fix normalization problem (Bug #33420). * wavwrite.m: Remove ancient non-Matlab calling form of function. Update tests and add test to verify proper clipping of out-of-range values. * wavread.m: Use correct normalization constant to put values in range [-1,1). Add test to stop fntests.m from reporting this as untested function.
author Rik <octave@nomad.inbox5.com>
date Sat, 04 Jun 2011 07:20:42 -0700
parents c792872f8942
children e9c23efe6fff
comparison
equal deleted inserted replaced
12700:9843b3b055e0 12701:de3e90a420e3
16 ## along with Octave; see the file COPYING. If not, see 16 ## along with Octave; see the file COPYING. If not, see
17 ## <http://www.gnu.org/licenses/>. 17 ## <http://www.gnu.org/licenses/>.
18 18
19 ## -*- texinfo -*- 19 ## -*- texinfo -*-
20 ## @deftypefn {Function File} {} wavwrite (@var{y}, @var{filename}) 20 ## @deftypefn {Function File} {} wavwrite (@var{y}, @var{filename})
21 ## @deftypefnx {Function File} {} wavwrite (@var{y}, @var{fs}, @var{filename}) 21 ## @deftypefnx {Function File} {} wavwrite (@var{y}, @var{Fs}, @var{filename})
22 ## @deftypefnx {Function File} {} wavwrite (@var{y}, @var{fs}, @var{bits}, @var{filename}) 22 ## @deftypefnx {Function File} {} wavwrite (@var{y}, @var{Fs}, @var{bps}, @var{filename})
23 ## Write @var{y} to the canonical RIFF/WAVE sound file @var{filename} 23 ## Write @var{y} to the canonical RIFF/WAVE sound file @var{filename}
24 ## with sample rate @var{fs} and bits per sample @var{bits}. The 24 ## with sample rate @var{Fs} and bits per sample @var{bps}. The
25 ## default sample rate is 8000 Hz with 16-bits per sample. Each column 25 ## default sample rate is 8000 Hz with 16-bits per sample. Each column
26 ## of the data represents a separate channel. 26 ## of the data represents a separate channel.
27 ## @seealso{wavread} 27 ## @seealso{wavread}
28 ## @end deftypefn 28 ## @end deftypefn
29 29
32 32
33 function wavwrite (y, varargin) 33 function wavwrite (y, varargin)
34 34
35 BYTEORDER = "ieee-le"; 35 BYTEORDER = "ieee-le";
36 36
37 ## For backward compatibility with previous versions of Octave, also
38 ## accept the inputs
39 ##
40 ## wavwrite (filename, y)
41 ## wavwrite (filename, y, fs)
42 ## wavwrite (filename, y, fs, bits)
43
44 if (nargin < 2 || nargin > 4) 37 if (nargin < 2 || nargin > 4)
45 print_usage (); 38 print_usage ();
46 endif 39 endif
47 40
48 ## Defaults. 41 ## Defaults.
49 samples_per_sec = 8000; 42 samples_per_sec = 8000;
50 bits_per_sample = 16; 43 bits_per_sample = 16;
51 44
52 if (ischar (y)) 45 filename = varargin{end};
53 filename = y; 46 if (nargin > 2)
54 y = varargin{1}; 47 samples_per_sec = varargin{1};
55 if (nargin > 2) 48 if (nargin > 3)
56 samples_per_sec = varargin{2}; 49 bits_per_sample = varargin{2};
57 if (nargin > 3)
58 bits_per_sample = varargin{3};
59 endif
60 endif
61 else
62 filename = varargin{end};
63 if (nargin > 2)
64 samples_per_sec = varargin{1};
65 if (nargin > 3)
66 bits_per_sample = varargin{2};
67 endif
68 endif 50 endif
69 endif 51 endif
70 52
71 ## test arguments 53 ## test arguments
72 if (columns (y) < 1) 54 if (columns (y) < 1)
73 error ("wavwrite: Y must have at least one column"); 55 error ("wavwrite: Y must have at least one column");
74 endif 56 endif
75 if (columns (y) > 2^15-1) 57 if (columns (y) > 0x7FFF)
76 error ("wavwrite: Y has more than 32767 columns (too many for a WAV-file)"); 58 error ("wavwrite: Y has more than 32767 columns (too many for a WAV-file)");
77 endif 59 endif
78 60
79 ## determine sample format 61 ## determine sample format
80 switch (bits_per_sample) 62 switch (bits_per_sample)
87 otherwise 69 otherwise
88 error ("wavwrite: sample resolution not supported"); 70 error ("wavwrite: sample resolution not supported");
89 endswitch 71 endswitch
90 72
91 ## calculate filesize 73 ## calculate filesize
92 [n, channels] = size(y); 74 [n, channels] = size (y);
93 75
94 ## size of data chunk 76 ## size of data chunk
95 ck_size = n*channels*(bits_per_sample/8); 77 ck_size = n*channels*(bits_per_sample/8);
96
97 ## open file for writing binary
98 78
99 if (! ischar (filename)) 79 if (! ischar (filename))
100 error ("wavwrite: expecting FILENAME to be a character string"); 80 error ("wavwrite: expecting FILENAME to be a character string");
101 endif 81 endif
102 82
83 ## open file for writing binary
103 [fid, msg] = fopen (filename, "wb"); 84 [fid, msg] = fopen (filename, "wb");
104 if (fid < 0) 85 if (fid < 0)
105 error ("wavwrite: %s", msg); 86 error ("wavwrite: %s", msg);
106 endif 87 endif
107 88
124 105
125 ## sample rate 106 ## sample rate
126 c += fwrite (fid, samples_per_sec, "uint32", 0, BYTEORDER); 107 c += fwrite (fid, samples_per_sec, "uint32", 0, BYTEORDER);
127 108
128 ## bytes per second 109 ## bytes per second
129 bps = samples_per_sec*channels*bits_per_sample/8; 110 byteps = samples_per_sec*channels*bits_per_sample/8;
130 c += fwrite (fid, bps, "uint32", 0, BYTEORDER); 111 c += fwrite (fid, byteps, "uint32", 0, BYTEORDER);
131 112
132 ## block align 113 ## block align
133 c += fwrite (fid, channels*bits_per_sample/8, "uint16", 0, BYTEORDER); 114 c += fwrite (fid, channels*bits_per_sample/8, "uint16", 0, BYTEORDER);
134 115
135 c += fwrite (fid, bits_per_sample, "uint16", 0, BYTEORDER); 116 c += fwrite (fid, bits_per_sample, "uint16", 0, BYTEORDER);
145 yi = reshape (y', n*channels, 1); 126 yi = reshape (y', n*channels, 1);
146 127
147 ## scale samples 128 ## scale samples
148 switch (bits_per_sample) 129 switch (bits_per_sample)
149 case 8 130 case 8
150 yi = round (yi*127 + 128); 131 yi = round (yi*128 + 128);
151 case 16 132 case 16
152 yi = round (yi*32767); 133 yi = round (yi*32768);
153 case 32 134 case 32
154 yi = round (yi*2147483647); 135 yi = round (yi*2147483648);
155 endswitch 136 endswitch
156 137
157 ## write to file 138 ## write to file
158 c = fwrite (fid, yi, format, 0, BYTEORDER); 139 c = fwrite (fid, yi, format, 0, BYTEORDER);
159 140
160 fclose (fid); 141 fclose (fid);
161 142
162 endfunction 143 endfunction
163 144
145
164 %!test 146 %!test
165 %! A = [1:10; 1:10]/10; 147 %! A = [-1:0.1:1; -1:0.1:1];
166 %! wavwrite("a.wav", A); 148 %! wavwrite (A, "a.wav");
167 %! [B, samples_per_sec, bits_per_sample] = wavread("a.wav"); 149 %! [B, samples_per_sec, bits_per_sample] = wavread ("a.wav");
168 %! assert(A,B, 10^(-4)); 150 %! assert(A,B, 1/2^15);
169 %! assert(samples_per_sec, 8000); 151 %! assert(samples_per_sec, 8000);
170 %! assert(bits_per_sample, 16); 152 %! assert(bits_per_sample, 16);
171 %! delete ("a.wav"); 153 %! delete ("a.wav");
172 % 154 %
173 %!test 155 %!test
174 %! A=[1:10; 1:10] / 10; 156 %! A = [-1:0.1:1; -1:0.1:1];
175 %! wavwrite("a.wav", A, 4000); 157 %! wavwrite (A, 4000, "a.wav");
176 %! [B, samples_per_sec, bits_per_sample] = wavread("a.wav"); 158 %! [B, samples_per_sec, bits_per_sample] = wavread ("a.wav");
177 %! assert(A,B, 10^(-4)); 159 %! assert(A,B, 1/2^15);
178 %! assert(samples_per_sec, 4000); 160 %! assert(samples_per_sec, 4000);
179 %! assert(bits_per_sample, 16); 161 %! assert(bits_per_sample, 16);
180 %! delete ("a.wav"); 162 %! delete ("a.wav");
181 % 163 %
182 %!test 164 %!test
183 %! A=[1:10; 1:10] / 10; 165 %! A = [-1:0.1:1; -1:0.1:1];
184 %! wavwrite("a.wav", A, 4000, 8); 166 %! wavwrite (A, 4000, 8, "a.wav");
185 %! [B, samples_per_sec, bits_per_sample] = wavread("a.wav"); 167 %! [B, samples_per_sec, bits_per_sample] = wavread ("a.wav");
186 %! assert(A,B, 10^(-2)); 168 %! assert(A,B, 1/128);
187 %! assert(samples_per_sec, 4000); 169 %! assert(samples_per_sec, 4000);
188 %! assert(bits_per_sample, 8); 170 %! assert(bits_per_sample, 8);
189 %! delete ("a.wav"); 171 %! delete ("a.wav");
172 %
173 %!test
174 %! A = [-2:2];
175 %! wavwrite (A, "a.wav");
176 %! B = wavread ("a.wav");
177 %! B *= 32768;
178 %! assert(B, [-32768 -32768 0 32767 32767]);
179 %! delete ("a.wav");
180