Giter Site home page Giter Site logo

wavefile's People

Contributors

henrikj242 avatar jstrait avatar samaaron avatar shanepelletier avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wavefile's Issues

Reference for older methods

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

Bufer from bytes & mulaw

Hi. I am receiving bytes for the linear16 wav file.
Can I somehow format it to mulaw/8000 without creating or saving a file?
And if not, is this format change possible at all?

no support for wave_format_extensible (0xfffe)

When trying to read a wav file with WAVEFORMATEX encoding (format code 0xfffe/65534), wavefile bails out with:

Audio format is 65534, but only format code 1 (PCM) or 3 (floating point) is supported. (WaveFile::UnsupportedFormatError)

Misleading error message if "fmt " chunk extension is too large to fit into chunk

As an example, suppose a "fmt " chunk has a stated size of 30 bytes, and the format code is not 1 (and therefore the chunk should have an extension). Since a "fmt " chunk extension body always starts at byte 18 (0-based), this means there are 12 bytes available for the chunk extension. If the extension has a reported size larger than 12 bytes, then the chunk extension will overflow out of the chunk.

In v1.1.1, this scenario will always cause InvalidFormatError to be raised. However, that happens by an accident of the implementation, and the error message will be misleading: "Not a supported wave file. The format chunk extension is shorter than expected." Although the extension could be shorter than expected, that's not guaranteed, and won't really be the source of the error.

What should happen in this scenario? If some of the bytes that overflow are part of required fields for the chunk extension (such as say, the first 22 bytes of a WAVE_FORMAT_EXTENSIBLE chunk extension), then it seems clear this should result in an error. If the overflowed bytes are just extra inert bytes, then you could argue that no error needs to be raised. However, that could lead to inconsistent behavior between different format codes, because the gem would have to understand the chunk extension format of every one of the many possible format codes in order to implement this in a consistent way. Also, always raising an error is how previous versions of the gem behave. Therefore, it seems preferable to always raise an error if the chunk extension overflows.

This is closely related to #33, because that bug and this one are caused by the same line of code. Despite the overlap, this bug is being opened since the two issues seem distinct from a behavior perspective.

Format Chunks With Extra Bytes at the End Sometimes Cause `InvalidFormatError` to be Raised

Normally, the "fmt " chunk has an expected size based on the format code. For example:

  • Format code 1 (Integer PCM): 16 bytes
  • Format code 3 (Floating point PCM): 18 bytes
  • Format code 65534 (WAVE_FORMAT_EXTENSIBLE): 40 bytes

When attempting to read a file using Reader.new(), an InvalidFormatError will be raised if the "fmt " chunk has fewer bytes than the expected size, because the chunk has incomplete data.

However (as of v1.1.1), if a "fmt " chunk has more bytes than expected, then an InvalidFormatError will also sometimes be raised with the message "Not a supported wave file. The format chunk extension is shorter than expected.". This error message is misleading, because the problem is that the chunk is longer than expected, not shorter. If the format code is 1, it's doubly misleading because the "fmt " chunk won't even have an extension.

Why is this error only sometimes raised? There is a scenario in which this error won't be raised if the "fmt " chunk is larger than the normal expected size: if the format code is 1, and the value of bytes 16 and 17 (0-based) when interpreted as a 16-bit unsigned little endian integer is the same as the subsequent number of bytes in the chunk body, no error will be raised. For example, if the "fmt " chunk size is 22, the format code is 1, and the value of bytes 16 and 17 is 4 (when interpreted as a 16-bit unsigned little endian integer), the file can be opened correctly. Note that this implies that if the format code is not 1, the required chunk extension can contain extra bytes, but there can't be extra bytes following the extension. (However, if the file is in WAVE_FORMAT_EXTENSIBLE format (i.e. format code 65534) and the extension has extra bytes, the "sub format GUID" field won't be read correctly; see #37 for more info on that issue).

In general, it seems like an error shouldn't be raised if the "fmt " chunk is larger than the default expected size. Page 60 of the original "Multimedia Programming Interface and Data Specifications 1.0" document with the original definition of the *.wav file spec states:

"The < format-specific-fields> consists of zero or more bytes of parameters. Which parameters occur depends on the WAVE format category–see the following section for details. Playback software should be written to allow for (and ignore) any unknown < format-specific-fields> parameters that occur at the end of this field."

Which seems like it could be interpreted as meaning extra bytes at the end of a format chunk should be ignored without raising an error.

See #24 for more info on the background of this issue.

Writer not always writing when buffer has changed

Thank you for your work on this. I really like this project. I have however noticed some odd behavior. When I write a file, if I attempt to overwrite, no changes are recorded. Oddly, even if I delete the file and allow the application to recreate it, the data from the previous file is recreated. However, if I change the file name, the new data is written to file. I'm not sure if I'm doing something wrong or if there's a bug.

Here is the application I'm working on:

require 'wavefile'
include WaveFile

sample_rate = 44100
buffer_size = sample_rate * 5
buffer_data = Array.new(buffer_size)

class Frequency_node
    def initialize(sample_rate, frequency)
        @sample_rate = sample_rate
        @frequency = sample_rate/frequency.to_f
        @current_frame = 0
    end
    def next()
        return_tone = Math.sin(((@current_frame % @frequency)/@frequency) * 2 * Math::PI)
        @current_frame += 1
        return return_tone
    end
end

f = Frequency_node.new(sample_rate, 440.0)

(0...buffer_size).each do |frame|
    buffer_data[frame] = f.next
end

format = Format.new(:mono, :pcm_16, 44100)
writer = Writer.new("a_440.wav", format)
buffer = Buffer.new(buffer_data, Format.new(:mono, :float, sample_rate))

writer.write(buffer)
writer.close()

After recording the 440 tone, if I then change it, the old tone is still recorded, even if I delete the file and allow the application to recreate it. However, if I rename the file i.e. "a_440_2.wav", the new tone will be recorded.

I'm using Ruby 1.9.3 and wavefile 0.5.0 on OSX 10.8.2

Thanks again.

Example here - https://github.com/jstrait/wavefile/wiki/WaveFile-Tutorial#copying-a-wave-file-to-different-format working correctly?

@jstrait sorry if this is a total newbie issue, but when I run the example here - https://github.com/jstrait/wavefile/wiki/WaveFile-Tutorial#copying-a-wave-file-to-different-format with a voice recording, the resulting audio file sound like chipmunks. Here's my code example. Any clue on what I am doing wrong? Great gem, love working with it so far.

require 'wavefile'
include WaveFile

new_file = 'data/copy.wav'

Writer.new(new_file, Format.new(:mono, :pcm_16, 16000)) do |writer|
  Reader.new('data/twilio_recording.wav').each_buffer(8000) do |buffer|
    writer.write(buffer)
  end
end

UnsupportedFormatError

Hi!

Thank you for working on this excellent library!

I am getting an UnsupportedFormatError when reading the included file. Is this truly an unsupported file format, or am I maybe doing something wrong when reading it?

wav.zip

The exception I get does not include a message with any details of the format. That would be nice.

Possible bug when no block is given to the writer?

If I'm not wrong, both examples below are supposed to work just as well. However, the second test produces a WAV file with the correct size, but somehow it's corrupted.

require "wavefile"

# Test 1, this works

reader = WaveFile::Reader.new "test.wav"
WaveFile::Writer.new("output1.wav", reader.format) do |writer|
  reader.each_buffer(4096) do |buffer|
    writer.write WaveFile::Buffer.new(buffer.samples, reader.format)
  end
end

# Test 2, output corrupted

reader = WaveFile::Reader.new "test.wav"
writer = WaveFile::Writer.new("output2.wav", reader.format)
reader.each_buffer(4096) do |buffer|
  writer.write WaveFile::Buffer.new(buffer.samples, reader.format)
end

Append mode for Writer class

It would be quite nice to be able to append with the Writer class, instead of always overriding an existing file.

Checking out the Writer class, it's hard-coded to open the given file with "wb" access mode. This could surely be extended a bit?

`Reader` instances can be created for WAVE_FORMAT_EXTENSIBLE files that have an incomplete/missing format chunk extension

When a fmt chunk has the format code 65534 (i.e. WAVE_FORMAT_EXTENSIBLE) it is required to have a chunk extension of 22 bytes containing 3 fields. These fields, especially the final 16 byte "audio format GUID" field, are required in order to correctly read the file's sample data, and don't have sensible default values.

In v1.1.1 of the gem a Reader instance can be created, without any error being raised, for some WAVE_FORMAT_EXTENSIBLE files in which the fmt chunk has a missing/truncated extension. The readable_format? field on the Reader instance will be correctly set to false, so no sample data will be able to be read out of it. However, the object attached to format and native_format will contain invalid values (i.e. either nil or "") for the missing extension fields.

It seems like a bug that Reader instances can be created from files like this. These are malformed files, and some of the information shown in the objects returned by format and native_format will not necessarily be meaningful/accurate. It seems like better behavior would be to instead raise an InvalidFormatError when trying to read this type of file, and not allow a Reader instance to be created.

Enable resampling

Consider the following code:

require 'wavefile'
include WaveFile

#1 second 440 Hz square wave
format = Format.new(:mono, 16, 44100)
writer = Writer.new("square.wav", format)
cycle = ([2**15] * 50) + ([-2**15] * 50)
buffer = Buffer.new(cycle, format)
441.times do 
  writer.write(buffer)
end
writer.close()

# square.wav now has 44100 samples

# read square wave in at half the sampling rate
samples = []
format = Format.new(:mono, 16, 22050)
reader = Reader.new("square.wav", format).each_buffer(1024) do |buffer|
  samples += buffer.samples
end

puts "#{samples.length} samples read"
# outputs "44100 samples read"

I would assume to get 22050 samples instead of 44100, thus a resampled version of the file. Am i the only one feeling this way?

Mix 2 wav files.

Hello,

This gem is useful and I'm very thanks to you.
I have one question.
Using your gem, can I mix 2 wave files and set the volume for each track?
Looking forward your answer.

@file_name not set for Writer class

The Writer class has an attr_reader for :file_name, but the @file_name instance variable never gets set. So a Writer instance returns nil when file_name is called.

Method to obtain markers/cue points

Is wavefile able to read cue/marker points from wave files. I have seen very little on this topic and am curious if wavefile would support this.

support reading from a file or stream

It would be nice if the interface would allow streaming when reading a wave file.

e.g.

wav_reader = WaveFile::Reader.new(File.open("some.wav"))

or even more generically from any Ruby IO object:

wav_reader = WaveFile::Reader.new(StringIO.new(".... wave bytes..."))

No Header Is Written When Exception Occurs While Writing Inside a Block

For example:

Writer.new("error.wav", format) do |writer|
  writer.write(buffer)
  x = 1 / 0
end

When this is run, the error.wav will exist on disk, but will not be playable because the Writer was never closed.

Adding an ensure clause to the block_given? section of Writer.new should resolve this.

odd number size riff chunk

I think you may not be handling adding or reading an extra pad byte when a chunk has a size that is an odd number of bytes. Not all wav creators seem to do this but adobe audition does, and it leads to misaligned parsing of the riff chunks.

I tested such a file with your gem and it choked on it.

Here is more info from a similarly reported issue:

http://forums.adobe.com/message/3798778

new gem release

A new release of the wavefile gem would be great! Not sure what the current plans are. Joel? Need help?

No high-level duration info

Feature request: I'd love to be able to ask some high-level questions about a file, like:

sound = WaveFile::Reader.new('StartUp.wav')
puts "Duration in milliseconds: #{sound.duration}",
     "Stereo? #{sound.channels==2}"

How to work with 24 bits per sample .wav files?

Hi All,

Is there strictly no way that WaveInfo will support 24 bits per sample .wav audio tracks? I am pretty deep into the process of building a web application that needs to be able to convert 24 bits per sample files into 192/320 MP3's. At the moment I am using LAME as my Encoder of choice.

I have tried to research into this a bit further but I am no audio expert so it's all a bit confusing!

Any help on the matter would be greatly received :)

Edit: I have tested the process of reading a 24-bit file as a 32-bit file, but this simply throws an "UnsupportedFormatError" exception.

WaveFile::Reader doesn't work with pipe IO

Hello!

I was trying to use this gem to record a wav file to STDOUT and then feed it to WaveFile::Reader to analyze in realtime. If I recall correctly, it was something along the lines of

IO.popen("rec -c 1 -t wav - 2>/dev/null") do |stdout|
  WaveFile::Reader.new(stdout) do |reader|
    # do stuff
  end
end

However, this results in the following exception:

.../wavefile-1.1.1/lib/wavefile/chunk_readers/riff_reader.rb:31:in `pos': Illegal seek (Errno::ESPIPE)
	from .../wavefile-1.1.1/lib/wavefile/chunk_readers/riff_reader.rb:31:in `read_until_data_chunk'
	from .../wavefile-1.1.1/lib/wavefile/chunk_readers/riff_reader.rb:10:in `initialize'
	from .../wavefile-1.1.1/lib/wavefile/reader.rb:45:in `new'
	from .../wavefile-1.1.1/lib/wavefile/reader.rb:45:in `initialize'
	...

which is because it's trying to seek on the IO, which is an invalid operation on a pipe.

I did also try record to a file instead of STDOUT and calling WaveFile::Reader on that, but because the file size kept increasing, that also resulted in something going wrong (I think because WaveFile::Reader#read_until_data_chunk tries to read until the end of the file). Also that means that the file keeps growing while the recording is ongoing, which is not ideal.

I ended up calling IO.popen("rec -c 1 -t s32 - 2>/dev/null") which outputs the audio amplitudes as signed 32-bit integers, and analyzing that directly.

The reason I'm opening this ticket is because I'm wondering whether analyzing an audio recording in realtime is an aim of this project, and if so, whether it's a planned feature or something that can be done now and I just missed something?

Thank you!

Rewind the IO object

How can I rewind the Reader so that I can go back and read the first buffer? I'm trying to loop a wave file but currently the only way is to recreate the Reader object once I get to the end of the samples, which is expensive.

Sample Data Can't Be Read From a WAVE_FORMAT_EXTENSIBLE File With an Oversized Format Chunk Extension

If a *.wav file's fmt chunk has a format code of 65534 (i.e. WAVE_FORMAT_EXTENSIBLE), it should have a fmt chunk extension at least 22 bytes long. However, as of v1.1.1 sample data can't be read from a WAVE_FORMAT_EXTENSIBLE file where the chunk extension is larger than 22 bytes. Although a Reader instance can be created for such a file, the Reader.format.sub_audio_format_guid field will have an incorrect value, and Reader.readable_format? will be set to false. Any attempts to read sample data will raise an error.

The "sub format GUID" field is 16 bytes long and exists at bytes 6-21 (0-based) of the chunk extension. The bug is that the gem reads from byte 6 until the end of the chunk extension to get this value, instead of just bytes 6-21. If the extension is larger than 22 bytes, this results in a value that is larger than 16 bytes, and is not recognized as valid. Since this value is needed to know how to read sample data out of the data chunk, no sample data can be read from the file.

You might ask, is a WAVE_FORMAT_EXTENSIBLE chunk extension larger than 22 bytes even valid? Yes, according to the document that defines the WAVE_FORMAT_EXTENSIBLE format (https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn653308(v=vs.85)). It states that the chunk extension must be at least 22 bytes long. (Search for the "cbSize is at Least 22" heading in that document for more info). This implies that a WAVE_FORMAT_EXTENSIBLE file with a format chunk extension larger than 22 bytes should be valid and readable, with the extra bytes beyond the first 22 being ignored. (As long as the main fmt chunk size also correctly accounts for the oversized extension).

Note that this is similar to the bug described in #34, but not the same. That bug refers to Reader instances incorrectly being able to be created for WAVE_FORMAT_EXTENSIBLE files with a format chunk extension shorter than 22 bytes, instead of raising InvalidFormatError.

This is also similar but not the same as the bug described in #33. That bug refers to issues caused by extra bytes occurring after the format chunk extension, while this issue refers to extra bytes inside the format chunk extension. The behavior is not the same for these two cases.

each_buffer causes ReaderClosedError

each_buffer closes the reader which causes some unintuitive errors:

reader = WaveFile::Reader.new(ARGV.first)

reader.each_buffer do |buffer|
  puts "Reading buffer ..."
end

reader.close # throws errors since reader is already closed

This also means you can never use each_buffer in a Reader block:

WaveFile::Reader.new(ARGV.first) do |reader|
  reader.each_buffer do |buffer|
    puts "Reading buffer ..."
  end 
end # error thrown when block completes

I personally don't think each_buffer should close the reader. What if I want to make a second pass?

If it is important that each_block closes the Reader, then it should be renamed each_block! since it has destructive side-effects. If each_block is going to continue to close the Reader, then you also won't wantReader#close to throw an error when called on a closed Reader or you'll never be able to use each_block in a Reader block.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.