wolffd@0
|
1 function seq_wavwrite(in_files,wavefile,varargin)
|
wolffd@0
|
2 % Combines wav-data from folder or specific files in one file.
|
wolffd@0
|
3 %
|
wolffd@0
|
4 % seq_wavwrite(path_string,wavefile) combines all .wav files in
|
wolffd@0
|
5 % path_string in the file wavefile.
|
wolffd@0
|
6 % i.e.: seq_wavwrite('C:\wav\','C:\combined.wav')
|
wolffd@0
|
7 %
|
wolffd@0
|
8 % The file format will depend on the first file processed, the other
|
wolffd@0
|
9 % files will be transfered to this format by resampling, dithering and
|
wolffd@0
|
10 % channel repetition/rejection. You may use some of the extra-options 'Fs','nbits'
|
wolffd@0
|
11 % or 'channels' to override these settings.
|
wolffd@0
|
12 % i.e.: seq_wavwrite('C:\wav\','C:\combined.wav','Fs',44100,'nbits',16,'channels',1)
|
wolffd@0
|
13 % will produce a mono file with 44.1 kHz samle rate and 16bits per sample
|
wolffd@0
|
14 %
|
wolffd@0
|
15 % seq_wavwrite(files_cellarray,wavefile) only combines the files specified
|
wolffd@0
|
16 % in files_cellarray.
|
wolffd@0
|
17 % i.e.: files={'C:\wav\test1.wav','C:\other_wav\test2.wav'};
|
wolffd@0
|
18 % seq_wavwrite(files,'C:\combined.wav');
|
wolffd@0
|
19 %
|
wolffd@0
|
20 % You may want to copy only some parts of the files.
|
wolffd@0
|
21 % Therefore use the extra-option 'sequences':
|
wolffd@0
|
22 % seq_wavwrite(files,'C:\combined','sequences',segments);
|
wolffd@0
|
23 % ,where segments is an cell array the same size as the files_cellarray,
|
wolffd@0
|
24 % witch contains the position of the parts for every file.
|
wolffd@0
|
25 % Every cell row contains a struct array with the following fields:
|
wolffd@0
|
26 % abs_startspl and abs_stopspl
|
wolffd@0
|
27 % or
|
wolffd@0
|
28 % abs_startms and abs_stopms
|
wolffd@0
|
29 % You may also specify the channels that are to be copied in the field
|
wolffd@0
|
30 % channels
|
wolffd@0
|
31 % i.e.: files={'C:\wav\test1.wav','C:\other_wav\test2.wav'};
|
wolffd@0
|
32 % segsforfile1(1).abs_startspl=1;
|
wolffd@0
|
33 % segsforfile1(1).abs_stopspl=44100;
|
wolffd@0
|
34 % segsforfile1(2).abs_startspl=88200;
|
wolffd@0
|
35 % segsforfile1(2).abs_stopspl=200000;
|
wolffd@0
|
36 % segsforfile2(1).abs_startms=1;
|
wolffd@0
|
37 % segsforfile2(1).abs_stopms=2000;
|
wolffd@0
|
38 % segsforfile2(1).channels=[1 2]; <- use the first two channels
|
wolffd@0
|
39 % segments={segsforfile1,segsforfile2};
|
wolffd@0
|
40 % seq_wavwrite(files,'C:\combined','sequences',segments);
|
wolffd@0
|
41 %
|
wolffd@0
|
42 % If you want to copy specific files as a whole, just omit their abs_...
|
wolffd@0
|
43 % values.
|
wolffd@0
|
44 %
|
wolffd@0
|
45 % seq_wavwrite uses blockwise file processing to be able to copy large
|
wolffd@0
|
46 % amounts of data. The option 'max_chunksize' allows you to specify the
|
wolffd@0
|
47 % blocksize in samples. Keep in mind that in multichannel mode the actual
|
wolffd@0
|
48 % blocksize will be chunksize times channels.
|
wolffd@0
|
49 % i.e.: seq_wavwrite('C:\wav\','C:\combined.wav','max_chunksize',44100*60)
|
wolffd@0
|
50
|
wolffd@0
|
51 % Parse inputs:
|
wolffd@0
|
52
|
wolffd@0
|
53 [slash,leftargs]=process_options(varargin,'systemslash','\');
|
wolffd@0
|
54
|
wolffd@0
|
55 if ischar(in_files)
|
wolffd@0
|
56 data_names=dir(strcat(in_files,slash,'*.wav'));
|
wolffd@0
|
57 in_files=strcat(in_files,{data_names.name});
|
wolffd@0
|
58 end
|
wolffd@0
|
59
|
wolffd@0
|
60 [tmp_sig,tmp_Fs,tmp_nbits]=wavread(char(in_files{1}),[1 2]);
|
wolffd@0
|
61 tmp_channels=size(tmp_sig,2);
|
wolffd@0
|
62
|
wolffd@0
|
63 def_max_chunk_size = 44100*60*2;%chunksize nearly one minute at 44,1 khz sample rate
|
wolffd@0
|
64 [sequences,Fs,nbits,channels,max_chunk_size]=process_options(leftargs,'sequences',[],'Fs',...
|
wolffd@0
|
65 tmp_Fs,'nbits',tmp_nbits,'channels',tmp_channels,'max_chunksize',def_max_chunk_size);
|
wolffd@0
|
66
|
wolffd@0
|
67 if ischar(in_files) && ~isempty(sequences)
|
wolffd@0
|
68 warning('segment parameters ignored in directory-input mode')
|
wolffd@0
|
69 sequences=[];
|
wolffd@0
|
70 end
|
wolffd@0
|
71
|
wolffd@0
|
72 % Determine number of bytes in chunks
|
wolffd@0
|
73 % (not including pad bytes, if needed):
|
wolffd@0
|
74 % ----------------------------------
|
wolffd@0
|
75 % 'RIFF' 4 bytes
|
wolffd@0
|
76 % size 4 bytes
|
wolffd@0
|
77 % 'WAVE' 4 bytes
|
wolffd@0
|
78 % 'fmt ' 4 bytes
|
wolffd@0
|
79 % size 4 bytes
|
wolffd@0
|
80 % <wave-format> 14 bytes
|
wolffd@0
|
81 % <format_specific> 2 bytes (PCM)
|
wolffd@0
|
82 % 'data' 4 bytes
|
wolffd@0
|
83 % size 4 bytes
|
wolffd@0
|
84 % <wave-data> N bytes
|
wolffd@0
|
85 % ----------------------------------
|
wolffd@0
|
86
|
wolffd@0
|
87 bytes_per_sample = ceil(nbits/8);
|
wolffd@0
|
88 fmt_cksize = 16; % Don't include 'fmt ' or its size field
|
wolffd@0
|
89
|
wolffd@0
|
90 % Open file for output:
|
wolffd@0
|
91 [fid,err] = OpenWaveWrite(wavefile);
|
wolffd@0
|
92 error(err);
|
wolffd@0
|
93 try
|
wolffd@0
|
94 % Prepare basic chunk structure fields:
|
wolffd@0
|
95 ck=[]; ck.fid=fid; ck.filename = wavefile;
|
wolffd@0
|
96
|
wolffd@0
|
97 fwrite(fid,zeros(1,20),'uchar'); %skip previous chunks
|
wolffd@0
|
98 % Write <wave-format>:
|
wolffd@0
|
99 fmt.filename = wavefile;
|
wolffd@0
|
100 if nbits == 32,
|
wolffd@0
|
101 fmt.wFormatTag = 3; % Data encoding format (1=PCM, 3=Type 3 32-bit)
|
wolffd@0
|
102 else
|
wolffd@0
|
103 fmt.wFormatTag = 1;
|
wolffd@0
|
104 end
|
wolffd@0
|
105 fmt.nSamplesPerSec = Fs; % Samples per second
|
wolffd@0
|
106 fmt.nAvgBytesPerSec = channels*bytes_per_sample*Fs; % Avg transfer rate
|
wolffd@0
|
107 fmt.nBlockAlign = channels*bytes_per_sample; % Block alignment
|
wolffd@0
|
108 fmt.nBitsPerSample = nbits; % standard <PCM-format-specific> info
|
wolffd@0
|
109 fmt.nChannels = channels; % Number of channels
|
wolffd@0
|
110 error(write_wavefmt(fid,fmt));
|
wolffd@0
|
111
|
wolffd@0
|
112 fwrite(fid,zeros(1,8),'uchar'); %skip following chunks
|
wolffd@0
|
113
|
wolffd@0
|
114 % Write all audio data
|
wolffd@0
|
115 sample_sum=0;
|
wolffd@0
|
116 for filei=1:size(in_files,2)
|
wolffd@0
|
117 resamplewarn=0;
|
wolffd@0
|
118 channelwarn=0;
|
wolffd@0
|
119 if ~isempty(sequences)&& ~isempty(sequences{filei})
|
wolffd@0
|
120 numsegs=size(sequences{filei},2);
|
wolffd@0
|
121 else numsegs=1;
|
wolffd@0
|
122 end
|
wolffd@0
|
123 for seqi=1:numsegs;
|
wolffd@0
|
124 tmp_fsiz=wavread(char(in_files{filei}),'size');
|
wolffd@0
|
125 tmp_fsiz=tmp_fsiz(1);
|
wolffd@0
|
126 [y,tmp_fs,null]=wavread(char(in_files{filei}),[1 2]);%read data
|
wolffd@0
|
127 if ~isempty(sequences) && ~isempty(sequences{filei})
|
wolffd@0
|
128 if isfield(sequences{filei}(seqi),'abs_startspl')
|
wolffd@0
|
129 spl_seq=[sequences{filei}(seqi).abs_startspl sequences{filei}(seqi).abs_stopspl];
|
wolffd@0
|
130 elseif isfield(sequences{filei}(seqi),'abs_startms')
|
wolffd@0
|
131 spl_seq=floor([sequences{filei}(seqi).abs_startms sequences{filei}(seqi).abs_stopms].*tmp_fs./1000);
|
wolffd@0
|
132 else
|
wolffd@0
|
133 spl_seq=[1 tmp_fsiz];
|
wolffd@0
|
134 end
|
wolffd@0
|
135 if (spl_seq(1)< 1) || (spl_seq(2) > tmp_fsiz)
|
wolffd@0
|
136 warning('correcting segment range, not necessary critical in miliseconds-mode')
|
wolffd@0
|
137 spl_seq(1)=max(spl_seq(1),1);
|
wolffd@0
|
138 spl_seq(2)=min(spl_seq(2),tmp_fsiz);
|
wolffd@0
|
139 end
|
wolffd@0
|
140 else
|
wolffd@0
|
141 spl_seq=[1 tmp_fsiz];
|
wolffd@0
|
142 end
|
wolffd@0
|
143 win_start=spl_seq(1);
|
wolffd@0
|
144 win_stop=(min(spl_seq(2),spl_seq(1)+max_chunk_size-1));
|
wolffd@0
|
145 while win_stop <= spl_seq(2)
|
wolffd@0
|
146 [y,tmp_fs,null]=wavread(char(in_files{filei}),[win_start win_stop]);%read data
|
wolffd@0
|
147 if (size(y,2) > 1) && ~isempty(sequences) && isfield(sequences{filei}(seqi),'channels') %choose channel
|
wolffd@0
|
148 if size(y,2) >= max(sequences{filei}(seqi).channels)
|
wolffd@0
|
149 y=y(:,sequences{filei}(seqi).channels);
|
wolffd@0
|
150 else
|
wolffd@0
|
151 if ~channelwarn
|
wolffd@0
|
152 warning('ignoring errorneous channel field');
|
wolffd@0
|
153 channelwarn=1;
|
wolffd@0
|
154 end
|
wolffd@0
|
155 end
|
wolffd@0
|
156 end
|
wolffd@0
|
157 if (tmp_fs ~= Fs) %resample data if necessary
|
wolffd@0
|
158 if ~resamplewarn
|
wolffd@0
|
159 fprintf('seq_wavwrite.m: resampling from %d to %d Hz. \n',tmp_fs,Fs);
|
wolffd@0
|
160 resamplewarn=1;
|
wolffd@0
|
161 end
|
wolffd@0
|
162 y=resample(y,Fs,tmp_fs);
|
wolffd@0
|
163 end
|
wolffd@0
|
164 [samples,akt_channels] = size(y);
|
wolffd@0
|
165 if akt_channels > channels % if necessary make equivalent channelnum
|
wolffd@0
|
166 y=y(:,1:channels);
|
wolffd@0
|
167 elseif akt_channels < channels
|
wolffd@0
|
168 y=[y repmat(y(:,end),1,channels-akt_channels)];
|
wolffd@0
|
169 end
|
wolffd@0
|
170 error(write_wavedat(fid,fmt,y));
|
wolffd@0
|
171 sample_sum=sample_sum+samples;
|
wolffd@0
|
172
|
wolffd@0
|
173 if win_stop == spl_seq(2), break;
|
wolffd@0
|
174 end
|
wolffd@0
|
175 win_start=win_start+max_chunk_size;
|
wolffd@0
|
176 win_stop=(min(spl_seq(2),win_stop+max_chunk_size));
|
wolffd@0
|
177 end
|
wolffd@0
|
178 end
|
wolffd@0
|
179 end
|
wolffd@0
|
180 clear y;
|
wolffd@0
|
181
|
wolffd@0
|
182 total_samples = sample_sum * channels;
|
wolffd@0
|
183 total_bytes = total_samples * bytes_per_sample;
|
wolffd@0
|
184 data_cksize = total_bytes;
|
wolffd@0
|
185
|
wolffd@0
|
186 riff_cksize = 36+total_bytes;
|
wolffd@0
|
187
|
wolffd@0
|
188 % Determine pad bytes:
|
wolffd@0
|
189 % Determine if a pad-byte must be appended to data chunk:
|
wolffd@0
|
190 if rem(data_cksize, 2) ~= 0,
|
wolffd@0
|
191 fwrite(fid,0,'uchar');
|
wolffd@0
|
192 end
|
wolffd@0
|
193 data_pad = rem(data_cksize,2);
|
wolffd@0
|
194 riff_cksize = riff_cksize + data_pad; % + fmt_pad, always 0
|
wolffd@0
|
195
|
wolffd@0
|
196 % Write RIFF chunk:
|
wolffd@0
|
197 fseek(fid,0,'bof');
|
wolffd@0
|
198 ck.ID = 'RIFF';
|
wolffd@0
|
199 ck.Size = riff_cksize;
|
wolffd@0
|
200 error(write_ckinfo(ck));
|
wolffd@0
|
201
|
wolffd@0
|
202 % Write WAVE subchunk:
|
wolffd@0
|
203 ck.ID = 'WAVE';
|
wolffd@0
|
204 ck.Size = []; % Indicate a subchunk (no chunk size)
|
wolffd@0
|
205 error(write_ckinfo(ck));
|
wolffd@0
|
206
|
wolffd@0
|
207 % Write <fmt-ck>:
|
wolffd@0
|
208 ck.ID = 'fmt ';
|
wolffd@0
|
209 ck.Size = fmt_cksize;
|
wolffd@0
|
210 error(write_ckinfo(ck));
|
wolffd@0
|
211
|
wolffd@0
|
212 % Write <data-ck>:
|
wolffd@0
|
213 fseek(fid,36,'bof');
|
wolffd@0
|
214 ck.ID = 'data';
|
wolffd@0
|
215 ck.Size = data_cksize;
|
wolffd@0
|
216 error(write_ckinfo(ck));
|
wolffd@0
|
217 err='';
|
wolffd@0
|
218 catch
|
wolffd@0
|
219 err=lasterr;
|
wolffd@0
|
220 end
|
wolffd@0
|
221 % Close file:
|
wolffd@0
|
222 fclose(fid);
|
wolffd@0
|
223
|
wolffd@0
|
224 error(err);
|
wolffd@0
|
225 % end of wavwrite()
|
wolffd@0
|
226
|
wolffd@0
|
227
|
wolffd@0
|
228 % ------------------------------------------------------------------------
|
wolffd@0
|
229 % Private functions:
|
wolffd@0
|
230 % ------------------------------------------------------------------------
|
wolffd@0
|
231
|
wolffd@0
|
232
|
wolffd@0
|
233 % ------------------------------------------------------------------------
|
wolffd@0
|
234 function [fid,err] = OpenWaveWrite(wavefile)
|
wolffd@0
|
235 % OpenWaveWrite
|
wolffd@0
|
236 % Open WAV file for writing.
|
wolffd@0
|
237 % If filename does not contain an extension, add ".wav"
|
wolffd@0
|
238
|
wolffd@0
|
239 fid = [];
|
wolffd@0
|
240 err = '';
|
wolffd@0
|
241 if ~isstr(wavefile),
|
wolffd@0
|
242 err='Wave file name must be a string.'; return;
|
wolffd@0
|
243 end
|
wolffd@0
|
244 if isempty(findstr(wavefile,'.')),
|
wolffd@0
|
245 wavefile=[wavefile '.wav'];
|
wolffd@0
|
246 end
|
wolffd@0
|
247 % Open file, little-endian:
|
wolffd@0
|
248 [fid,err] = fopen(wavefile,'wb','l');
|
wolffd@0
|
249
|
wolffd@0
|
250 return
|
wolffd@0
|
251
|
wolffd@0
|
252
|
wolffd@0
|
253 % ------------------------------------------------------------------------
|
wolffd@0
|
254 function err = write_ckinfo(ck)
|
wolffd@0
|
255 % WRITE_CKINFO: Writes next RIFF chunk, but not the chunk data.
|
wolffd@0
|
256 % Assumes the following fields in ck:
|
wolffd@0
|
257 % .fid File ID to an open file
|
wolffd@0
|
258 % .ID 4-character string chunk identifier
|
wolffd@0
|
259 % .Size Size of chunk (empty if subchunk)
|
wolffd@0
|
260 %
|
wolffd@0
|
261 %
|
wolffd@0
|
262 % Expects an open FID pointing to first byte of chunk header,
|
wolffd@0
|
263 % and a chunk structure.
|
wolffd@0
|
264 % ck.fid, ck.ID, ck.Size, ck.Data
|
wolffd@0
|
265
|
wolffd@0
|
266 errmsg = ['Failed to write ' ck.ID ' chunk to WAVE file: ' ck.filename];
|
wolffd@0
|
267 err = '';
|
wolffd@0
|
268
|
wolffd@0
|
269 if (fwrite(ck.fid, ck.ID, 'char') ~= 4),
|
wolffd@0
|
270 err=errmsg; return;
|
wolffd@0
|
271 end
|
wolffd@0
|
272
|
wolffd@0
|
273 if ~isempty(ck.Size),
|
wolffd@0
|
274 % Write chunk size:
|
wolffd@0
|
275 if (fwrite(ck.fid, ck.Size, 'uint32') ~= 1),
|
wolffd@0
|
276 err=errmsg; return;
|
wolffd@0
|
277 end
|
wolffd@0
|
278 end
|
wolffd@0
|
279
|
wolffd@0
|
280 return
|
wolffd@0
|
281
|
wolffd@0
|
282 % ------------------------------------------------------------------------
|
wolffd@0
|
283 function err = write_wavefmt(fid, fmt)
|
wolffd@0
|
284 % WRITE_WAVEFMT: Write WAVE format chunk.
|
wolffd@0
|
285 % Assumes fid points to the wave-format subchunk.
|
wolffd@0
|
286 % Requires chunk structure to be passed, indicating
|
wolffd@0
|
287 % the length of the chunk.
|
wolffd@0
|
288
|
wolffd@0
|
289 errmsg = ['Failed to write WAVE format chunk to file' fmt.filename];
|
wolffd@0
|
290 err = '';
|
wolffd@0
|
291
|
wolffd@0
|
292 % Create <wave-format> data:
|
wolffd@0
|
293 if (fwrite(fid, fmt.wFormatTag, 'uint16') ~= 1) | ...
|
wolffd@0
|
294 (fwrite(fid, fmt.nChannels, 'uint16') ~= 1) | ...
|
wolffd@0
|
295 (fwrite(fid, fmt.nSamplesPerSec, 'uint32' ) ~= 1) | ...
|
wolffd@0
|
296 (fwrite(fid, fmt.nAvgBytesPerSec, 'uint32' ) ~= 1) | ...
|
wolffd@0
|
297 (fwrite(fid, fmt.nBlockAlign, 'uint16') ~= 1),
|
wolffd@0
|
298 err=errmsg; return;
|
wolffd@0
|
299 end
|
wolffd@0
|
300
|
wolffd@0
|
301 % Write format-specific info:
|
wolffd@0
|
302 if fmt.wFormatTag==1 | fmt.wFormatTag==3,
|
wolffd@0
|
303 % Write standard <PCM-format-specific> info:
|
wolffd@0
|
304 if (fwrite(fid, fmt.nBitsPerSample, 'uint16') ~= 1),
|
wolffd@0
|
305 err=errmsg; return;
|
wolffd@0
|
306 end
|
wolffd@0
|
307
|
wolffd@0
|
308 else
|
wolffd@0
|
309 err='Unknown data format.';
|
wolffd@0
|
310 end
|
wolffd@0
|
311
|
wolffd@0
|
312 return
|
wolffd@0
|
313
|
wolffd@0
|
314
|
wolffd@0
|
315 % -----------------------------------------------------------------------
|
wolffd@0
|
316 function y = PCM_Quantize(x, fmt)
|
wolffd@0
|
317 % PCM_Quantize:
|
wolffd@0
|
318 % Scale and quantize input data, from [-1, +1] range to
|
wolffd@0
|
319 % either an 8-, 16-, or 24-bit data range.
|
wolffd@0
|
320
|
wolffd@0
|
321 % Clip data to normalized range [-1,+1]:
|
wolffd@0
|
322 ClipMsg = ['Data clipped during write to file:' fmt.filename];
|
wolffd@0
|
323 ClipWarn = 0;
|
wolffd@0
|
324
|
wolffd@0
|
325 % Determine slope (m) and bias (b) for data scaling:
|
wolffd@0
|
326 nbits = fmt.nBitsPerSample;
|
wolffd@0
|
327 m = 2.^(nbits-1);
|
wolffd@0
|
328
|
wolffd@0
|
329 switch nbits
|
wolffd@0
|
330 case 8,
|
wolffd@0
|
331 b=128;
|
wolffd@0
|
332 case {16,24},
|
wolffd@0
|
333 b=0;
|
wolffd@0
|
334 otherwise,
|
wolffd@0
|
335 error('Invalid number of bits specified.');
|
wolffd@0
|
336 end
|
wolffd@0
|
337
|
wolffd@0
|
338 y = round(m .* x + b);
|
wolffd@0
|
339
|
wolffd@0
|
340 % Determine quantized data limits, based on the
|
wolffd@0
|
341 % presumed input data limits of [-1, +1]:
|
wolffd@0
|
342 ylim = [-1 +1];
|
wolffd@0
|
343 qlim = m * ylim + b;
|
wolffd@0
|
344 qlim(2) = qlim(2)-1;
|
wolffd@0
|
345
|
wolffd@0
|
346 % Clip data to quantizer limits:
|
wolffd@0
|
347 i = find(y < qlim(1));
|
wolffd@0
|
348 if ~isempty(i),
|
wolffd@0
|
349 warning(ClipMsg); ClipWarn=1;
|
wolffd@0
|
350 y(i) = qlim(1);
|
wolffd@0
|
351 end
|
wolffd@0
|
352
|
wolffd@0
|
353 i = find(y > qlim(2));
|
wolffd@0
|
354 if ~isempty(i),
|
wolffd@0
|
355 if ~ClipWarn, warning(ClipMsg); end
|
wolffd@0
|
356 y(i) = qlim(2);
|
wolffd@0
|
357 end
|
wolffd@0
|
358
|
wolffd@0
|
359 return
|
wolffd@0
|
360
|
wolffd@0
|
361
|
wolffd@0
|
362 % -----------------------------------------------------------------------
|
wolffd@0
|
363 function err = write_wavedat(fid,fmt,data)
|
wolffd@0
|
364 % WRITE_WAVEDAT: Write WAVE data chunk
|
wolffd@0
|
365 % Assumes fid points to the wave-data chunk
|
wolffd@0
|
366 % Requires <wave-format> structure to be passed.
|
wolffd@0
|
367
|
wolffd@0
|
368 err = '';
|
wolffd@0
|
369
|
wolffd@0
|
370 if fmt.wFormatTag==1 | fmt.wFormatTag==3,
|
wolffd@0
|
371 % PCM Format
|
wolffd@0
|
372
|
wolffd@0
|
373 % 32-bit Type 3 is normalized, so no scaling needed.
|
wolffd@0
|
374 if fmt.nBitsPerSample ~= 32,
|
wolffd@0
|
375 data = PCM_Quantize(data, fmt);
|
wolffd@0
|
376 end
|
wolffd@0
|
377
|
wolffd@0
|
378 switch fmt.nBitsPerSample
|
wolffd@0
|
379 case 8,
|
wolffd@0
|
380 dtype='uchar'; % unsigned 8-bit
|
wolffd@0
|
381 case 16,
|
wolffd@0
|
382 dtype='int16'; % signed 16-bit
|
wolffd@0
|
383 case 24,
|
wolffd@0
|
384 dtype='bit24'; % signed 24-bit
|
wolffd@0
|
385 case 32,
|
wolffd@0
|
386 dtype='float'; % normalized 32-bit floating point
|
wolffd@0
|
387 otherwise,
|
wolffd@0
|
388 err = 'Invalid number of bits specified.'; return;
|
wolffd@0
|
389 end
|
wolffd@0
|
390
|
wolffd@0
|
391 % Write data, one row at a time (one sample from each channel):
|
wolffd@0
|
392 [samples,channels] = size(data);
|
wolffd@0
|
393 total_samples = samples*channels;
|
wolffd@0
|
394
|
wolffd@0
|
395 if (fwrite(fid, reshape(data',total_samples,1), dtype) ~= total_samples),
|
wolffd@0
|
396 err = 'Failed to write PCM data samples.'; return;
|
wolffd@0
|
397 end
|
wolffd@0
|
398
|
wolffd@0
|
399
|
wolffd@0
|
400 else
|
wolffd@0
|
401 % Unknown wave-format for data.
|
wolffd@0
|
402 err = 'Unsupported data format.';
|
wolffd@0
|
403 end
|
wolffd@0
|
404
|
wolffd@0
|
405 return
|
wolffd@0
|
406
|
wolffd@0
|
407 % end of wavwrite.m
|