Class: WaveFile::Writer
- Inherits:
-
Object
- Object
- WaveFile::Writer
- Defined in:
- lib/wavefile/writer.rb
Overview
Provides the ability to write data to a wave file.
When a Writer is constructed it can be given a block. All samples should be written inside this block, and when the block exits the file will automatically be closed:
Writer.new("my_file.wav", Format.new(:mono, :pcm_16, 44100)) do |writer|
# Write sample data here
end
If no block is given, you’ll need to manually close the Writer when done. The underlaying file will not be valid or playable until close is called.
writer = Writer.new("my_file.wav", Format.new(:mono, :pcm_16, 44100))
# Write sample data here
writer.close
Instance Attribute Summary collapse
-
#file_name ⇒ Object
readonly
Returns the name of the Wave file that is being written to.
-
#format ⇒ Object
readonly
Returns a Format object describing the Wave file being written (number of channels, sample format and bits per sample, sample rate, etc.).
-
#total_sample_frames ⇒ Object
readonly
Returns the number of samples (per channel) that have been written to the file so far.
Instance Method Summary collapse
-
#close ⇒ Object
Closes the Writer.
-
#closed? ⇒ Boolean
Returns true if the Writer is closed, and false if it is open and available for writing.
-
#initialize(file_name, format) ⇒ Writer
constructor
Returns a constructed Writer object which is available for writing sample data to the specified file (via the write method).
-
#total_duration ⇒ Object
Returns a Duration instance for the number of sample frames that have been written so far.
-
#write(buffer) ⇒ Object
Appends the sample data in the given Buffer to the end of the wave file.
Constructor Details
#initialize(file_name, format) ⇒ Writer
Returns a constructed Writer object which is available for writing sample data to the specified file (via the write method). When all sample data has been written, the Writer should be closed. Note that the wave file being written to will NOT be valid (and playable in other programs) until the Writer has been closed.
If a block is given to this method, sample data can be written inside the given block. When the block terminates, the Writer will be automatically closed (and no more sample data can be written).
If no block is given, then sample data can be written until the close method is called.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/wavefile/writer.rb', line 28 def initialize(file_name, format) @file_name = file_name @file = File.open(file_name, "wb") @format = format @total_sample_frames = 0 @pack_code = PACK_CODES[format.sample_format][format.bits_per_sample] # Note that the correct sizes for the RIFF and data chunks can't be determined # until all samples have been written, so this header as written will be incorrect. # When close is called, the correct sizes will be re-written. write_header(0) if block_given? begin yield(self) ensure close end end end |
Instance Attribute Details
#file_name ⇒ Object (readonly)
Returns the name of the Wave file that is being written to
112 113 114 |
# File 'lib/wavefile/writer.rb', line 112 def file_name @file_name end |
#format ⇒ Object (readonly)
Returns a Format object describing the Wave file being written (number of channels, sample format and bits per sample, sample rate, etc.)
116 117 118 |
# File 'lib/wavefile/writer.rb', line 116 def format @format end |
#total_sample_frames ⇒ Object (readonly)
Returns the number of samples (per channel) that have been written to the file so far. For example, if 1000 “left” samples and 1000 “right” samples have been written to a stereo file, this will return 1000.
121 122 123 |
# File 'lib/wavefile/writer.rb', line 121 def total_sample_frames @total_sample_frames end |
Instance Method Details
#close ⇒ Object
Closes the Writer. After a Writer is closed, no more sample data can be written to it.
Note that the wave file will NOT be valid until this method is called. The wave file format requires certain information about the amount of sample data, and this can’t be determined until all samples have been written. (This method doesn’t need to be called when passing a block to Writer.new, as this method will automatically be called when the block exits).
Returns nothing. Raises IOError if the Writer is already closed.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/wavefile/writer.rb', line 86 def close # The RIFF specification requires that each chunk be aligned to an even number of bytes, # even if the byte count is an odd number. Therefore if an odd number of bytes has been # written, write an empty padding byte. # # See http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/riffmci.pdf, page 11. bytes_written = @total_sample_frames * @format.block_align if bytes_written.odd? @file.syswrite(EMPTY_BYTE) end # We can't know what chunk sizes to write for the RIFF and data chunks until all # samples have been written, so go back to the beginning of the file and re-write # those chunk headers with the correct sizes. @file.sysseek(0) write_header(@total_sample_frames) @file.close end |
#closed? ⇒ Boolean
Returns true if the Writer is closed, and false if it is open and available for writing.
71 72 73 |
# File 'lib/wavefile/writer.rb', line 71 def closed? @file.closed? end |
#total_duration ⇒ Object
Returns a Duration instance for the number of sample frames that have been written so far
107 108 109 |
# File 'lib/wavefile/writer.rb', line 107 def total_duration Duration.new(@total_sample_frames, @format.sample_rate) end |
#write(buffer) ⇒ Object
Appends the sample data in the given Buffer to the end of the wave file.
Returns the number of sample frames that have been written to the file so far. Raises IOError if the Writer has been closed.
55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/wavefile/writer.rb', line 55 def write(buffer) samples = buffer.convert(@format).samples if @format.bits_per_sample == 24 && @format.sample_format == :pcm samples.flatten.each do |sample| @file.syswrite([sample].pack("l<X")) end else @file.syswrite(samples.flatten.pack(@pack_code)) end @total_sample_frames += samples.length end |