@@ -14,7 +14,7 @@ use std::cmp;
14
14
use std:: error;
15
15
use std:: fmt;
16
16
use std:: io;
17
- use std:: io:: { Seek , Write } ;
17
+ use std:: io:: { Seek , SeekFrom , Write } ;
18
18
use std:: result;
19
19
20
20
use byteorder:: { LittleEndian , WriteBytesExt } ;
@@ -150,15 +150,15 @@ trait WriteWaveExt: Write + Seek {
150
150
try!( self . write_u32_l ( 0 ) ) ; // Size of data subchunk.
151
151
152
152
Ok ( ( ) )
153
- }
153
+ }
154
154
155
155
fn write_u16_l ( & mut self , n : u16 ) -> io:: Result < ( ) > {
156
156
self . write_u16 :: < LittleEndian > ( n)
157
157
}
158
158
159
159
fn write_u32_l ( & mut self , n : u32 ) -> io:: Result < ( ) > {
160
160
self . write_u32 :: < LittleEndian > ( n)
161
- }
161
+ }
162
162
}
163
163
164
164
impl < T > WriteWaveExt for T where T : Seek + Write { }
@@ -176,6 +176,9 @@ pub struct WaveWriter<T>
176
176
/// Represents the PCM format for this wave file.
177
177
pub pcm_format : PcmFormat ,
178
178
179
+ // How many samples have been written.
180
+ written_samples : u32 ,
181
+
179
182
// The underlying writer that we'll use to read data.
180
183
writer : T ,
181
184
}
@@ -200,20 +203,20 @@ impl<T> WaveWriter<T>
200
203
201
204
Ok ( WaveWriter {
202
205
pcm_format : pcm_format,
206
+ written_samples : 0 ,
203
207
writer : writer,
204
208
} )
205
209
}
206
210
207
-
208
211
/// Writes a single sample as an unsigned 8-bit value.
209
212
pub fn write_sample_u8 ( & mut self , sample : u8 ) -> io:: Result < ( ) > {
210
213
self . write_sample ( sample, |writer, sample| writer. write_u8 ( sample) )
211
214
}
212
215
213
216
/// Writes a single sample as a signed 16-bit value.
214
217
pub fn write_sample_i16 ( & mut self , sample : i16 ) -> io:: Result < ( ) > {
215
- self . write_sample ( sample,
216
- |writer , sample| writer. write_i16 :: < LittleEndian > ( sample) )
218
+ self . write_sample ( sample, |writer , sample|
219
+ writer. write_i16 :: < LittleEndian > ( sample) )
217
220
}
218
221
219
222
/// Writes a single sample as a signed 24-bit value. The value will be truncated
@@ -227,14 +230,35 @@ impl<T> WaveWriter<T>
227
230
228
231
/// Writes a single sample as a signed 32-bit value.
229
232
pub fn write_sample_i32 ( & mut self , sample : i32 ) -> io:: Result < ( ) > {
230
- self . write_sample ( sample,
231
- |writer , sample| writer. write_i32 :: < LittleEndian > ( sample) )
233
+ self . write_sample ( sample, |writer , sample|
234
+ writer. write_i32 :: < LittleEndian > ( sample) )
232
235
}
233
236
234
237
fn write_sample < F , S > ( & mut self , sample : S , write_data : F ) -> io:: Result < ( ) >
235
238
where F : Fn ( & mut T , S ) -> io:: Result < ( ) >
236
239
{
237
- Ok ( try!( write_data ( & mut self . writer , sample) ) )
240
+ try!( write_data ( & mut self . writer , sample) ) ;
241
+ self . written_samples = self . written_samples + 1 ;
242
+ Ok ( ( ) )
243
+ }
244
+
245
+ /// Updates the header at the beginning of the file with the new chunk sizes.
246
+ pub fn sync_header ( & mut self ) -> io:: Result < ( ) > {
247
+ let data_chunk_size = self . written_samples * self . pcm_format . bits_per_sample as u32 / 8 ;
248
+ let riff_chunk_size = 36 + data_chunk_size;
249
+
250
+ // File size minus eight bytes
251
+ try!( self . writer . seek ( SeekFrom :: Start ( 4 ) ) ) ;
252
+ try!( self . writer . write_u32_l ( riff_chunk_size) ) ;
253
+
254
+ // Data size minus eight bytes
255
+ try!( self . writer . seek ( SeekFrom :: Start ( 40 ) ) ) ;
256
+ try!( self . writer . write_u32_l ( data_chunk_size) ) ;
257
+
258
+ // Seek back to the end so we can continue writing
259
+ try!( self . writer . seek ( SeekFrom :: End ( 0 ) ) ) ;
260
+
261
+ Ok ( ( ) )
238
262
}
239
263
240
264
/// Consumes this writer, returning the underlying value.
@@ -300,5 +324,63 @@ mod tests {
300
324
assert_eq ! ( 16 , wave_reader. pcm_format. bits_per_sample) ;
301
325
}
302
326
327
+ // Write validation tests
328
+
329
+ #[ test]
330
+ fn test_header_sync_when_no_data_written ( ) {
331
+ let data = Vec :: new ( ) ;
332
+ let mut cursor = Cursor :: new ( data) ;
333
+ let mut wave_writer = WaveWriter :: new ( 1 , 44100 , 16 , cursor) . unwrap ( ) ;
334
+ wave_writer. sync_header ( ) . unwrap ( ) ;
335
+ let mut cursor = wave_writer. into_inner ( ) ;
336
+
337
+ cursor. set_position ( 0 ) ;
338
+
339
+ let wave_reader = WaveReader :: new ( cursor) . unwrap ( ) ;
340
+ let cursor = wave_reader. into_inner ( ) ;
341
+ let data = cursor. into_inner ( ) ;
342
+
343
+ assert_eq ! ( 44 , data. len( ) ) ;
344
+ // We're not currently surfacing the chunk/subchunk info in the reader
345
+ // so just access the data directly.
346
+
347
+ // Should match 36 in little-endian format.
348
+ assert_eq ! ( b"\x24 \x00 \x00 \x00 " , & data[ 4 ..8 ] ) ;
349
+
350
+ // Should match 0 in little-endian format.
351
+ assert_eq ! ( b"\x00 \x00 \x00 \x00 " , & data[ 40 ..44 ] ) ;
352
+ }
353
+
354
+ #[ test]
355
+ fn test_header_sync_when_ten_samples_written ( ) {
356
+ let data = Vec :: new ( ) ;
357
+ let mut cursor = Cursor :: new ( data) ;
358
+ let mut wave_writer = WaveWriter :: new ( 1 , 44100 , 16 , cursor) . unwrap ( ) ;
359
+
360
+ for i in 0 ..10 {
361
+ wave_writer. write_sample_i16 ( i as i16 ) . unwrap ( ) ;
362
+ }
363
+
364
+ wave_writer. sync_header ( ) . unwrap ( ) ;
365
+
366
+ let mut cursor = wave_writer. into_inner ( ) ;
367
+
368
+ cursor. set_position ( 0 ) ;
369
+
370
+ let wave_reader = WaveReader :: new ( cursor) . unwrap ( ) ;
371
+ let cursor = wave_reader. into_inner ( ) ;
372
+ let data = cursor. into_inner ( ) ;
373
+
374
+ assert_eq ! ( 64 , data. len( ) ) ;
375
+ // We're not currently surfacing the chunk/subchunk info in the reader
376
+ // so just access the data directly.
377
+
378
+ // Should match 56 in little-endian format.
379
+ assert_eq ! ( b"\x38 \x00 \x00 \x00 " , & data[ 4 ..8 ] ) ;
380
+
381
+ // Should match 20 in little-endian format.
382
+ assert_eq ! ( b"\x14 \x00 \x00 \x00 " , & data[ 40 ..44 ] ) ;
383
+ }
384
+
303
385
// TODO test header
304
386
}
0 commit comments