Mercurial > hg > octave-lyh
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 |