~ubuntu-branches/ubuntu/karmic/scilab/karmic

« back to all changes in this revision

Viewing changes to macros/sound/wavwrite.sci

  • Committer: Bazaar Package Importer
  • Author(s): Torsten Werner
  • Date: 2002-03-21 16:57:43 UTC
  • Revision ID: james.westby@ubuntu.com-20020321165743-e9mv12c1tb1plztg
Tags: upstream-2.6
ImportĀ upstreamĀ versionĀ 2.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
function []=wavwrite(y,Fs,nbits,wavefile)
 
2
[nargout,nargin] = argn(0)
 
3
//WAVWRITE Write Microsoft WAVE ("""".wav"""") sound file.
 
4
//   WAVWRITE(Y,WAVEFILE) writes a WAVE file specified by the
 
5
//   string WAVEFILE.  The data should be arranged with one channel
 
6
//   per column.  Amplitude values outside the range [-1,+1] are
 
7
//   clipped prior to writing.
 
8
// 
 
9
//   WAVWRITE(Y,FS,WAVEFILE) specifies the sample rate FS of the data
 
10
//   in Hertz.
 
11
// 
 
12
//   WAVWRITE(Y,FS,NBITS,WAVEFILE) forces an NBITS-bit file format to
 
13
//   be written, where NBITS<=16.
 
14
// 
 
15
//   Supports multi-channel 8- or 16-bit WAVE data.
 
16
// 
 
17
//   See also WAVREAD, AUWRITE.
 
18
 
 
19
//   Copyright (c) 1984-98 by The MathWorks, Inc.
 
20
//   $Revision: 5.6 $  $Date: 1997/11/21 23:24:12 $
 
21
 
 
22
//   D. Orofino, 11/95
 
23
 
 
24
// Get user default preferences:
 
25
Fs_pref = 8000;
 
26
nbits_pref = 16;
 
27
 
 
28
// Parse inputs:
 
29
if nargin<2|nargin>4 then
 
30
  error('Incorrect number of input arguments.');
 
31
elseif nargin<3 then
 
32
  wavefile = Fs;
 
33
  Fs = Fs_pref;
 
34
  nbits = nbits_pref;
 
35
elseif nargin<4 then
 
36
  wavefile = nbits;
 
37
  nbits = nbits_pref;
 
38
end
 
39
 
 
40
// Open file for output:
 
41
if ~(type(wavefile)==10) then
 
42
  error('wavefile must be a string.');
 
43
end
 
44
if mtlb_findstr(wavefile,'.')==[] then
 
45
  wavefile = wavefile+'.wav';
 
46
end
 
47
[fid,%v] = mopen(wavefile,'wb',1)
 
48
if %v<0 then fid = -1;end
 
49
// Little-endian
 
50
if fid==(-1) then
 
51
  error('Can''t open WAVE file for output.');
 
52
end
 
53
 
 
54
// If input is a vector, force it to be a column:
 
55
 
 
56
if size(y,2) > 2 then
 
57
  error('Data array must have 1- or 2-dimensions, only.');
 
58
end
 
59
[samples,channels] = size(y);
 
60
if samples==1 then
 
61
  y = y(:);
 
62
  [samples,channels] = size(y);
 
63
end
 
64
 
 
65
// Clip data to normalized range [-1,+1]:
 
66
i = matrix(find(abs(y)>1),1,-1);
 
67
if ~(i==[]) then
 
68
  y(i) = sign(y(i)) 
 
69
  warning('Data clipped during write to file.');
 
70
end
 
71
 
 
72
// # bytes per sample to write
 
73
bytes_per_sample = ceil(nbits/8);
 
74
total_samples = samples*channels;
 
75
total_bytes = total_samples*bytes_per_sample;
 
76
 
 
77
// Determine number of bytes in RIFF chunk
 
78
// (not including pad bytes, if needed):
 
79
// ----------------------------------
 
80
//  'RIFF'           4 bytes
 
81
//  size             4 bytes (ulong)
 
82
//  'WAVE'           4 bytes
 
83
//  'fmt '           4 bytes
 
84
//  size             4 bytes (ulong)
 
85
// <wave-format>     14 bytes
 
86
// <format_specific> 2 bytes (PCM)
 
87
//  'data'           4 bytes
 
88
//  size             4 bytes (ulong)
 
89
// <wave-data>       N bytes
 
90
// ----------------------------------
 
91
riff_cksize = 36+total_bytes;
 
92
// Don't include 'RIFF' or its size field
 
93
fmt_cksize = 16;
 
94
// Don't include 'fmt ' or its size field
 
95
data_cksize = total_bytes;
 
96
// Don't include 'data' or its size field
 
97
 
 
98
// Determine pad bytes:
 
99
data_pad = data_cksize-fix(data_cksize./2).*2;
 
100
riff_cksize = riff_cksize+data_pad;
 
101
// + fmt_pad, always 0
 
102
 
 
103
ck= tlist(['ck','fid','Size','ID']) 
 
104
// Write RIFF chunk:
 
105
ck('fid')=fid
 
106
ck('Size')=riff_cksize
 
107
ck('ID')='RIFF';
 
108
write_ckinfo(ck);
 
109
 
 
110
// Write WAVE:
 
111
ck('ID')='WAVE';
 
112
write_ckinfo(ck,1);
 
113
 
 
114
// Write <fmt-ck>:
 
115
ck('ID')='fmt ';
 
116
ck('Size')=fmt_cksize
 
117
write_ckinfo(ck);
 
118
// Write <wave-format>:
 
119
fmt=tlist(['fmt','wFormatTag','nChannels','nSamplesPerSec','nAvgBytesPerSec','nBlockAlign','nBitsPerSample'])
 
120
fmt('wFormatTag')=1
 
121
// Data encoding format = PCM
 
122
fmt('nChannels')=channels
 
123
// Number of channels
 
124
fmt('nSamplesPerSec')=Fs
 
125
// Samples per second
 
126
fmt('nAvgBytesPerSec')=channels*bytes_per_sample*Fs
 
127
// Avg transfer rate
 
128
fmt('nBlockAlign')=channels*bytes_per_sample
 
129
// Block alignment
 
130
fmt('nBitsPerSample')=nbits
 
131
// standard <PCM-format-specific> info
 
132
status = write_wavefmt(fid,fmt);
 
133
 
 
134
// Write <data-ck>:
 
135
ck('ID') = 'data';
 
136
ck('Size')=data_cksize
 
137
write_ckinfo(ck);
 
138
 
 
139
// Write <wave-data>, and its pad byte if needed:
 
140
status = write_wavedat(fid,fmt,y);
 
141
mclose(fid);
 
142
// Close file
 
143
// end of wavwrite()
 
144
 
 
145
function write_ckinfo(ck,sflg)
 
146
[nargout,nargin] = argn(0)
 
147
// WRITE_CKINFO: Writes next RIFF chunk, but not the chunk data.
 
148
//   If optional sflg is set to nonzero, write SUBchunk info instead.
 
149
//   Expects an open FID pointing to first byte of chunk header,
 
150
//   and a chunk structure.
 
151
//   ck.fid, ck.ID, ck.Size, ck.Data
 
152
if length(ck('ID'))<>4 then error('write_ckinfo: ck has a wrong length');end
 
153
mput(ascii(ck('ID')),'c',ck('fid'))
 
154
// Error condition
 
155
if nargin==1 then
 
156
  // Write chunk size (skip if subchunk):
 
157
  mput(ck('Size'),'ui',ck('fid'))
 
158
end
 
159
 
 
160
 
 
161
function [status]=write_wavedat(fid,fmt,data)
 
162
status=[];
 
163
// WRITE_WAVEDAT: Write WAVE data chunk
 
164
//   Assumes fid points to the wave-data chunk
 
165
//   Requires <wave-format> structure to be passed.
 
166
 
 
167
status = 0;
 
168
 
 
169
if fmt('wFormatTag')==1 then
 
170
  // PCM Format:
 
171
  // Determine # bytes/sample - format requires rounding
 
172
  //  to next integer number of bytes:
 
173
  BytesPerSample = ceil(fmt('nBitsPerSample')/8);
 
174
  if BytesPerSample==1 then
 
175
    dtype = 'uc';
 
176
    // unsigned 8-bit
 
177
    // Scale data according to bits/samples: [-1,+1] -> [0,255]
 
178
    data = round((data+1)*255/2);
 
179
  elseif BytesPerSample==2 then
 
180
    dtype = 's';
 
181
    // signed 16-bit
 
182
    // Scale data according to bits/samples: [-1,+1] -> [-32768,+32767]
 
183
    data = round((data+1)*65535/2)-32768;
 
184
  else
 
185
    error('Cannot write WAVE files with more than 16 bits/sample.');
 
186
  end
 
187
   
 
188
  // Write data, one row at a time (one sample from each channel):
 
189
  [samples,channels] = size(data);
 
190
  total_samples = samples*channels;
 
191
  if mput(matrix(data',total_samples,1),dtype,fid)~=0 then
 
192
    status = -1;
 
193
    return
 
194
  end
 
195
  // Error condition
 
196
   
 
197
  // Determine if a pad-byte is appended to data chunk:
 
198
  %v2_1$1 = total_samples*BytesPerSample
 
199
  if %v2_1$1-fix(%v2_1$1./2).*2 then
 
200
    mtlb_fwrite(fid,0,'uchar');
 
201
  end
 
202
   
 
203
   
 
204
else
 
205
  // Unknown wave-format for data.
 
206
  error('Unknown data format.');
 
207
end
 
208
return
 
209
 
 
210
 
 
211
function [status]=write_wavefmt(fid,fmt)
 
212
status = 0;
 
213
// WRITE_WAVEFMT: Write WAVE format chunk.
 
214
//   Assumes fid points to the wave-format subchunk.
 
215
//   Requires chunk structure to be passed, indicating
 
216
//   the length of the chunk.
 
217
 
 
218
// Create <wave-format> data:
 
219
 
 
220
mput(fmt('wFormatTag'),'us',fid);
 
221
mput(fmt('nChannels'),'us',fid);
 
222
mput(fmt('nSamplesPerSec'),'ui',fid);
 
223
mput(fmt('nAvgBytesPerSec'),'ui',fid);
 
224
mput(fmt('nBlockAlign'),'us',fid);
 
225
 
 
226
// Write format-specific info:
 
227
if fmt('wFormatTag')==1 then
 
228
  // Write standard <PCM-format-specific> info:
 
229
  mput(fmt('nBitsPerSample'),'us',fid)
 
230
else
 
231
  error('Unknown data format.');
 
232
end
 
233
 
 
234
 
 
235
 
 
236
 
 
237
 
 
238
 
 
239