jstrait / wavefile

A Ruby gem for reading and writing sound files in Wave format (*.wav)
https://wavefilegem.com
MIT License
208 stars 24 forks source link

Reference for older methods #29

Closed arjunmenon closed 5 years ago

arjunmenon commented 5 years ago

Hey I found a small gist to get fft values of sound files. It used these methods, samples = w.sample_data[0, [w.sample_rate * 10, w.sample_data.size].min]

Now, the sample_data was available in the very first release of this gem.

What is the equivalent newer version to these methods.

Simple generating

reader.each_buffer do |buffer|
  puts buffer.samples
end

returns different result

jstrait commented 5 years ago

Thanks for the question - after looking at the gist, I think I might see the problem.

It seems like the gist relies on having the sample data for the entire file in the sample_data array. Older versions of the WaveFile gem read the entire file into memory, which meant that the sample_data field would contain the file's entire sample data. However, more recent versions instead allow reading a *.wav file in a buffered way. Calling each_buffer will normally only return a portion of the file's sample data at a time.

If you want to read the entire file with the current version of the WaveFile gem, you could do:

all_samples_in_file = reader.read(reader.total_sample_frames)

Or:

reader.each_buffer(reader.total_sample_frames) do |buffer|
  # `buffer` will contain all samples in the file
end

Hope this helps!

arjunmenon commented 5 years ago

Ok, so if I omit reader.total_sample_frames does that mean we can use it for continuous stream, like from a mic or from a streaming source?

jstrait commented 5 years ago

In theory I think it should be possible to read sample data from a .wav file in a streaming way, using Reader.read, if you construct it with the relevant IO instance. However, this will only work if the sample data being read from the IO instance is wrapped in a `.wav` file. If the stream only contains raw sample data, then the WaveFile gem won't know how to read it.

Raw sample data coming from a microphone will probably not be wrapped inside a *.wav file.

If you're trying to get sample data in real time from a microphone or other sound source, you might want to look into something like a PortAudio wrapper gem for Ruby, such as https://rubygems.org/gems/ffi-portaudio or https://rubygems.org/gems/easy_audio. I haven't used these myself, but I found them from searching on rubygems.org.

Here's an example of how to read a *.wav file from a stream using the WaveFile gem, adapted from the example at http://wavefilegem.com/examples.html:

SAMPLES_PER_BUFFER = 4096
streaming_io = <construct IO instance here>

reader = Reader.new(streaming_io)
begin
  while true do
    buffer = reader.read(SAMPLES_PER_BUFFER)
    puts "Read #{buffer.samples.length} samples."
  end
rescue EOFError
  reader.close
end

Hope this helps!

jstrait commented 5 years ago

Closing this issue, hope this helped!