waveform 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -46,7 +46,8 @@ There are some nifty options you can supply to switch things up:
46
46
  There are also some less-nifty options:
47
47
 
48
48
  -q will generate your waveform without printing out a bunch of stuff.
49
- -h will prit out a help screen with all this info.
49
+ -h will print out a help screen with all this info.
50
+ -F will automatically overwrite destination file.
50
51
 
51
52
  Generating a small waveform "cut out" of a white background is pretty useful,
52
53
  then you can overlay it on a web-gradient on the website for your new startup
@@ -39,6 +39,11 @@ optparse = OptionParser.new do |o|
39
39
  options[:quiet] = true
40
40
  end
41
41
 
42
+ options[:force] = false
43
+ o.on("-F", "--force", "Force generationg of waveform if file exists") do
44
+ options[:force] = true
45
+ end
46
+
42
47
  o.on("-h", "--help", "Display this screen") do
43
48
  puts o
44
49
  exit
@@ -1,4 +1,5 @@
1
1
  require "ruby-audio"
2
+ require "tempfile"
2
3
 
3
4
  begin
4
5
  require "oily_png"
@@ -7,20 +8,21 @@ rescue LoadError
7
8
  end
8
9
 
9
10
  class Waveform
10
- VERSION = "0.0.2"
11
+ VERSION = "0.0.3"
11
12
 
12
13
  DefaultOptions = {
13
14
  :method => :peak,
14
15
  :width => 1800,
15
16
  :height => 280,
16
17
  :background_color => "#666666",
17
- :color => "#00ccff"
18
+ :color => "#00ccff",
19
+ :force => false
18
20
  }
19
21
 
20
22
  TransparencyMask = "#00ff00"
21
23
  TransparencyAlternate = "#ffff00" # in case the mask is the background color!
22
24
 
23
- attr_reader :audio
25
+ attr_reader :source
24
26
 
25
27
  # Scope these under Waveform so you can catch the ones generated by just this
26
28
  # class.
@@ -42,18 +44,30 @@ class Waveform
42
44
  # Waveform.new("mp3s/Kickstart My Heart.mp3")
43
45
  # Waveform.new("mp3s/Kickstart My Heart.mp3", $stdout)
44
46
  #
45
- def initialize(audio, log=nil)
46
- raise ArgumentError.new("No source audio filename given, must be an existing sound file.") unless audio
47
- raise RuntimeError.new("Source audio file '#{audio}' not found.") unless File.exist?(audio)
47
+ def initialize(source, log=nil)
48
+ raise ArgumentError.new("No source audio filename given, must be an existing sound file.") unless source
49
+ raise RuntimeError.new("Source audio file '#{source}' not found.") unless File.exist?(source)
48
50
 
49
51
  @log = Log.new(log)
50
-
51
- if File.extname(audio) != ".wav"
52
- @audio = audio.sub /(.+)\.(.+)/, "\\1.wav"
53
- raise RuntimeError.new("Unable to decode source '#{audio}' to WAV. Do you have ffmpeg installed with an appropriate decoder for your source file?") unless to_wav(audio, @audio)
52
+ @log.start!
53
+
54
+ # @source is the path to the given source file, whatever it may be
55
+ @source = source
56
+
57
+ # @audio is the path to the actual audio file we will process, always wav
58
+ if File.extname(source) == ".wav"
59
+ @audio = File.open(source, "rb")
54
60
  else
55
- @audio = audio
61
+ # This happens in initialize so you can generate multiple waveforms from
62
+ # the same audio without decoding multiple times
63
+ #
64
+ # Note that we're leaving it up to the ruby/system GC to clean up these
65
+ # tempfiles because someone may be generating multiple waveform images
66
+ # from a single audio source so we can't explicitly unlink the tempfile.
67
+ @audio = to_wav(source)
56
68
  end
69
+
70
+ raise RuntimeError.new("Unable to decode source \'#{@source}\' to WAV. Do you have ffmpeg installed with an appropriate decoder for your source file?") unless @audio
57
71
  end
58
72
 
59
73
  # Generate a Waveform image at the given filename with the given options.
@@ -85,21 +99,29 @@ class Waveform
85
99
  # color background to achieve a "cutout" effect).
86
100
  # Default is #00ccff (cyan-ish).
87
101
  #
102
+ # :force => Force generation of waveform, overwriting WAV or PNG file.
103
+ #
88
104
  # Example:
89
105
  # waveform = Waveform.new("mp3s/Kickstart My Heart.mp3")
90
- #
106
+ #
91
107
  # waveform.generate("waves/Kickstart My Heart.png")
92
108
  # waveform.generate("waves/Kickstart My Heart.png", :method => :rms)
93
109
  # waveform.generate("waves/Kickstart My Heart.png", :color => "#ff00ff")
94
- #
110
+ #
95
111
  def generate(filename, options={})
96
112
  raise ArgumentError.new("No destination filename given for waveform") unless filename
97
- raise RuntimeError.new("Destination file #{filename} exists") if File.exists?(filename)
113
+
114
+ if File.exists?(filename)
115
+ if options[:force]
116
+ @log.out("Output file #{filename} encountered. Removing.")
117
+ File.unlink(filename)
118
+ else
119
+ raise RuntimeError.new("Destination file #{filename} exists. Use --force if you want to automatically remove it.")
120
+ end
121
+ end
98
122
 
99
123
  options = DefaultOptions.merge(options)
100
-
101
- @log.start!
102
-
124
+
103
125
  # Frames gives the amplitudes for each channel, for our waveform we're
104
126
  # saying the "visual" amplitude is the average of the amplitude across all
105
127
  # the channels. This might be a little weird w/ the "peak" method if the
@@ -161,7 +183,7 @@ class Waveform
161
183
 
162
184
  frames = []
163
185
 
164
- RubyAudio::Sound.open(audio) do |snd|
186
+ RubyAudio::Sound.open(@audio.path) do |snd|
165
187
  frames_read = 0
166
188
  frames_per_sample = (snd.info.frames.to_f / width.to_f).to_i
167
189
  sample = RubyAudio::Buffer.new("float", frames_per_sample, snd.info.channels)
@@ -179,18 +201,17 @@ class Waveform
179
201
 
180
202
  private
181
203
 
182
- # Decode audio to a wav file, returns true if the decode succeeded or false
183
- # otherwise.
184
- def to_wav(src, dest)
185
- @log.start!
186
- @log.out("Decoding source audio '#{src}' to WAV...")
187
-
188
- raise RuntimeError.new("Destination WAV file '#{dest}' exists!") if File.exists?(dest)
204
+ # Decode given src file to a wav Tempfile. Returns the Tempfile if the decode
205
+ # succeeded, or false if the decode failed.
206
+ def to_wav(src, force=false)
207
+ wav = nil
189
208
 
190
- system %Q{ffmpeg -i "#{src}" -f wav "#{dest}" > /dev/null 2>&1}
191
- @log.done!
209
+ @log.timed("Decoding source audio '#{src}' to WAV...") do
210
+ wav = Tempfile.new(File.basename(src))
211
+ system %Q{ffmpeg -y -i "#{src}" -f wav "#{wav.path}" > /dev/null 2>&1}
212
+ end
192
213
 
193
- File.exists?(dest)
214
+ return wav.size == 0 ? false : wav
194
215
  end
195
216
 
196
217
  # Returns an array of the peak of each channel for the given collection of
@@ -115,5 +115,60 @@ class WaveformTest < Test::Unit::TestCase
115
115
  assert_equal ChunkyPNG::Color.from_hex("#00ff00"), image[0, 0]
116
116
  assert_equal ChunkyPNG::Color::TRANSPARENT, image[60, 120]
117
117
  end
118
+
119
+ # Not sure how to best test this as it's totally dependent on the ruby and
120
+ # system GC when the tempfiles are removed (as we're not explicitly
121
+ # unlinking them).
122
+ # should "use a tempfile when generating a temporary wav" do
123
+ # tempfiles = Dir[File.join(Dir.tmpdir(), "sample_mp3*")].size
124
+ # Waveform.new(fixture("sample_mp3.mp3")).generate(output("cleanup_temporary_wav.png"))
125
+ # assert_equal tempfiles + 1, Dir[File.join(Dir.tmpdir(), "sample_mp3*")].size
126
+ # end
127
+
128
+ should "not delete source wav file if one was given" do
129
+ assert File.exists?(fixture("sample.wav"))
130
+ Waveform.new(fixture("sample.wav")).generate(output("keep_source_wav.png"))
131
+ assert File.exists?(fixture("sample.wav"))
132
+ end
133
+
134
+ should "raise an error if unable to decode to wav" do
135
+ assert_raise(Waveform::RuntimeError) do
136
+ Waveform.new(fixture("sample.txt")).generate(output("shouldnt_exist.png"))
137
+ end
138
+ end
139
+
140
+ context "with existing PNG files" do
141
+ setup do
142
+ @existing = output("existing.png")
143
+ FileUtils.touch @existing
144
+ end
145
+
146
+ should "generate waveform if :force is true and PNG exists" do
147
+ @waveform.generate(@existing, :force => true)
148
+ end
149
+
150
+ should "raise an exception if PNG exists and :force is false" do
151
+ assert_raises Waveform::RuntimeError do
152
+ @waveform.generate(@existing, :force => false)
153
+ end
154
+ end
155
+ end
156
+
157
+ context "with existing WAV files" do
158
+ setup do
159
+ @existing = output("existing.wav")
160
+ FileUtils.touch @existing
161
+ end
162
+
163
+ should "generate waveform if :force is true and WAV exists" do
164
+ @waveform.generate(@existing, :force => true)
165
+ end
166
+
167
+ should "raise an exception if WAV exists and :force is false" do
168
+ assert_raises Waveform::RuntimeError do
169
+ @waveform.generate(@existing, :force => false)
170
+ end
171
+ end
172
+ end
118
173
  end
119
174
  end
@@ -3,8 +3,8 @@ require "./lib/waveform"
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "waveform"
5
5
  s.version = Waveform::VERSION
6
- s.summary = "Generate waveform images from WAV and MP3 files"
7
- s.description = "Generate waveform images from WAV and MP3 files -- in your code or via included CLI."
6
+ s.summary = "Generate waveform images from WAV, MP3, etc... files"
7
+ s.description = "Generate waveform images from WAV, MP3, etc... files - as a gem or via CLI."
8
8
  s.authors = ["Ben Alavi"]
9
9
  s.email = ["benalavi@gmail.com"]
10
10
  s.homepage = "http://github.com/benalavi/waveform"
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: waveform
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.2
5
+ version: 0.0.3
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ben Alavi
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-07-18 00:00:00 Z
13
+ date: 2011-07-28 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: ruby-audio
@@ -45,7 +45,7 @@ dependencies:
45
45
  version: "0"
46
46
  type: :development
47
47
  version_requirements: *id003
48
- description: Generate waveform images from WAV and MP3 files -- in your code or via included CLI.
48
+ description: Generate waveform images from WAV, MP3, etc... files - as a gem or via CLI.
49
49
  email:
50
50
  - benalavi@gmail.com
51
51
  executables:
@@ -84,9 +84,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
84
  requirements: []
85
85
 
86
86
  rubyforge_project:
87
- rubygems_version: 1.8.5
87
+ rubygems_version: 1.8.6
88
88
  signing_key:
89
89
  specification_version: 3
90
- summary: Generate waveform images from WAV and MP3 files
90
+ summary: Generate waveform images from WAV, MP3, etc... files
91
91
  test_files: []
92
92