waveform 0.1.1 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +12 -2
- data/bin/waveform +7 -3
- data/lib/waveform/version.rb +1 -1
- data/lib/waveform.rb +48 -37
- data/test/waveform_test.rb +73 -58
- metadata +52 -71
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6ce38fd32793bd0e734bdd4a4d5fc35d1b23fd61bc7b3336b7cf2e4a3fedfe76
|
4
|
+
data.tar.gz: ed342c1ad243cab828bd48e85ded1d68ef837c5ca7a845779a81cc1d0f1debc5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5de7b29d02d0d8fc2890c4dd6e685e3140067c7b24bc48d3a97327d1c3b2dbb75fd386878da0f31035a7f9ba567f1293003d3ccb4119732fb717fedf412e7b3c
|
7
|
+
data.tar.gz: 3c02222c54dbc8561b7ddf5c41c47caebe93e45d8e3e298a32d2737d9e04152b256da595fdcb740a47aeb192f1d8bf30a5a4295aff364b70868f4ba774903aa0
|
data/README.md
CHANGED
@@ -14,10 +14,12 @@ Then:
|
|
14
14
|
|
15
15
|
$ sudo gem install waveform
|
16
16
|
|
17
|
-
Image creation depends on `chunky_png`, which has a faster native library called `oily_png` which will be used if
|
17
|
+
Image creation depends on `chunky_png`, which has a faster native library called `oily_png` which will be used if available.
|
18
18
|
|
19
19
|
$ sudo gem install oily_png
|
20
20
|
|
21
|
+
NOTE: If `ruby-audio` fails to compile and you have `libsndfile` available, it may be because of this: http://stackoverflow.com/questions/19919640/ruby-audio-1-6-1-install-error-with-installed-libsndfile-1-0-25
|
22
|
+
|
21
23
|
CLI Usage
|
22
24
|
=========
|
23
25
|
|
@@ -76,7 +78,7 @@ Tests
|
|
76
78
|
=====
|
77
79
|
|
78
80
|
$ rake
|
79
|
-
|
81
|
+
|
80
82
|
If you get an error about not being able to find ruby-audio gem (and you have ruby-audio gem) you might need to let rake know how to load your gems -- if you're using rubygems:
|
81
83
|
|
82
84
|
$ export RUBYOPT="rubygems"
|
@@ -87,6 +89,14 @@ Sample sound file used in tests is in the Public Domain from soundbible.com: <ht
|
|
87
89
|
Changes
|
88
90
|
=======
|
89
91
|
|
92
|
+
0.1.3
|
93
|
+
-----
|
94
|
+
* Update for ruby 3.2 (replace `File.exists?` w/ `File.exist?`)
|
95
|
+
|
96
|
+
0.1.2
|
97
|
+
-----
|
98
|
+
* Added more helpful deprecation notice for non-WAV audio files
|
99
|
+
|
90
100
|
0.1.1
|
91
101
|
-----
|
92
102
|
* Fixed RMS calculation (was calculating RMSD instead of RMS before) -- thanks, cviedmai
|
data/bin/waveform
CHANGED
@@ -4,9 +4,9 @@ require "optparse"
|
|
4
4
|
|
5
5
|
options = Waveform::DefaultOptions
|
6
6
|
optparse = OptionParser.new do |o|
|
7
|
-
o.banner = "Usage: waveform [options] source_audio [
|
7
|
+
o.banner = "Usage: waveform [options] source_audio [output.png]"
|
8
8
|
o.version = Waveform::VERSION
|
9
|
-
|
9
|
+
|
10
10
|
o.on("-W", "--width WIDTH", "Width (in pixels) of generated waveform image -- Default #{Waveform::DefaultOptions[:width]}.") do |width|
|
11
11
|
options[:width] = width.to_i
|
12
12
|
end
|
@@ -15,6 +15,10 @@ optparse = OptionParser.new do |o|
|
|
15
15
|
options[:height] = height.to_i
|
16
16
|
end
|
17
17
|
|
18
|
+
o.on("-a", "--autowidth MSEC", "Sets the width of the waveform based on the audio length, using a resolution of the given msec per pixel.") do |msec|
|
19
|
+
options[:auto_width] = msec.to_i
|
20
|
+
end
|
21
|
+
|
18
22
|
o.on("-c", "--color COLOR", "Color (hex code) to draw the waveform. Can also pass 'transparent' to cut it out of the background -- Default #{Waveform::DefaultOptions[:color]}.") do |color|
|
19
23
|
if color == "transparent"
|
20
24
|
options[:color] = :transparent
|
@@ -41,7 +45,7 @@ optparse = OptionParser.new do |o|
|
|
41
45
|
end
|
42
46
|
|
43
47
|
options[:force] = false
|
44
|
-
o.on("-F", "--force", "Force
|
48
|
+
o.on("-F", "--force", "Force generation of waveform if file exists") do
|
45
49
|
options[:force] = true
|
46
50
|
end
|
47
51
|
|
data/lib/waveform/version.rb
CHANGED
data/lib/waveform.rb
CHANGED
@@ -17,38 +17,43 @@ class Waveform
|
|
17
17
|
:force => false,
|
18
18
|
:logger => nil
|
19
19
|
}
|
20
|
-
|
20
|
+
|
21
21
|
TransparencyMask = "#00ff00"
|
22
22
|
TransparencyAlternate = "#ffff00" # in case the mask is the background color!
|
23
|
-
|
23
|
+
|
24
24
|
attr_reader :source
|
25
|
-
|
25
|
+
|
26
26
|
# Scope these under Waveform so you can catch the ones generated by just this
|
27
27
|
# class.
|
28
28
|
class RuntimeError < ::RuntimeError;end;
|
29
29
|
class ArgumentError < ::ArgumentError;end;
|
30
|
-
|
31
|
-
class << self
|
30
|
+
|
31
|
+
class << self
|
32
32
|
# Generate a Waveform image at the given filename with the given options.
|
33
|
-
#
|
33
|
+
#
|
34
34
|
# Available options (all optional) are:
|
35
|
-
#
|
35
|
+
#
|
36
36
|
# :method => The method used to read sample frames, available methods
|
37
37
|
# are peak and rms. peak is probably what you're used to seeing, it uses
|
38
38
|
# the maximum amplitude per sample to generate the waveform, so the
|
39
39
|
# waveform looks more dynamic. RMS gives a more fluid waveform and
|
40
40
|
# probably more accurately reflects what you hear, but isn't as
|
41
41
|
# pronounced (typically).
|
42
|
-
#
|
42
|
+
#
|
43
43
|
# Can be :rms or :peak
|
44
44
|
# Default is :peak.
|
45
|
-
#
|
45
|
+
#
|
46
46
|
# :width => The width (in pixels) of the final waveform image.
|
47
47
|
# Default is 1800.
|
48
|
-
#
|
48
|
+
#
|
49
49
|
# :height => The height (in pixels) of the final waveform image.
|
50
50
|
# Default is 280.
|
51
|
-
#
|
51
|
+
#
|
52
|
+
# :auto_width => msec per pixel. This will overwrite the width of the
|
53
|
+
# final waveform image depending on the length of the audio file.
|
54
|
+
# Example:
|
55
|
+
# 100 => 1 pixel per 100 msec; a one minute audio file will result in a width of 600 pixels
|
56
|
+
#
|
52
57
|
# :background_color => Hex code of the background color of the generated
|
53
58
|
# waveform image.
|
54
59
|
# Default is #666666 (gray).
|
@@ -59,7 +64,7 @@ class Waveform
|
|
59
64
|
# Default is #00ccff (cyan-ish).
|
60
65
|
#
|
61
66
|
# :force => Force generation of waveform, overwriting WAV or PNG file.
|
62
|
-
#
|
67
|
+
#
|
63
68
|
# :logger => IOStream to log progress to.
|
64
69
|
#
|
65
70
|
# Example:
|
@@ -69,15 +74,21 @@ class Waveform
|
|
69
74
|
#
|
70
75
|
def generate(source, filename, options={})
|
71
76
|
options = DefaultOptions.merge(options)
|
72
|
-
|
77
|
+
|
73
78
|
raise ArgumentError.new("No source audio filename given, must be an existing sound file.") unless source
|
74
79
|
raise ArgumentError.new("No destination filename given for waveform") unless filename
|
75
80
|
raise RuntimeError.new("Source audio file '#{source}' not found.") unless File.exist?(source)
|
76
|
-
raise RuntimeError.new("Destination file #{filename} exists. Use --force if you want to automatically remove it.") if File.
|
81
|
+
raise RuntimeError.new("Destination file #{filename} exists. Use --force if you want to automatically remove it.") if File.exist?(filename) && !options[:force] === true
|
77
82
|
|
78
83
|
@log = Log.new(options[:logger])
|
79
84
|
@log.start!
|
80
|
-
|
85
|
+
|
86
|
+
if options[:auto_width]
|
87
|
+
RubyAudio::Sound.open(source) do |audio|
|
88
|
+
options[:width] = (audio.info.length * 1000 / options[:auto_width].to_i).ceil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
81
92
|
# Frames gives the amplitudes for each channel, for our waveform we're
|
82
93
|
# saying the "visual" amplitude is the average of the amplitude across all
|
83
94
|
# the channels. This might be a little weird w/ the "peak" method if the
|
@@ -87,30 +98,30 @@ class Waveform
|
|
87
98
|
samples = frames(source, options[:width], options[:method]).collect do |frame|
|
88
99
|
frame.inject(0.0) { |sum, peak| sum + peak } / frame.size
|
89
100
|
end
|
90
|
-
|
101
|
+
|
91
102
|
@log.timed("\nDrawing...") do
|
92
103
|
# Don't remove the file even if force is true until we're sure the
|
93
104
|
# source was readable
|
94
|
-
if File.
|
105
|
+
if File.exist?(filename) && options[:force] === true
|
95
106
|
@log.out("Output file #{filename} encountered. Removing.")
|
96
107
|
File.unlink(filename)
|
97
108
|
end
|
98
|
-
|
109
|
+
|
99
110
|
image = draw samples, options
|
100
111
|
image.save filename
|
101
112
|
end
|
102
|
-
|
103
|
-
@log.done!("Generated waveform '#{filename}'")
|
113
|
+
|
114
|
+
@log.done!("Generated waveform '#{filename}'")
|
104
115
|
end
|
105
|
-
|
116
|
+
|
106
117
|
private
|
107
|
-
|
118
|
+
|
108
119
|
# Returns a sampling of frames from the given RubyAudio::Sound using the
|
109
120
|
# given method the sample size is determined by the given pixel width --
|
110
121
|
# we want one sample frame per horizontal pixel.
|
111
122
|
def frames(source, width, method = :peak)
|
112
123
|
raise ArgumentError.new("Unknown sampling method #{method}") unless [ :peak, :rms ].include?(method)
|
113
|
-
|
124
|
+
|
114
125
|
frames = []
|
115
126
|
|
116
127
|
RubyAudio::Sound.open(source) do |audio|
|
@@ -125,19 +136,19 @@ class Waveform
|
|
125
136
|
end
|
126
137
|
end
|
127
138
|
end
|
128
|
-
|
139
|
+
|
129
140
|
frames
|
130
141
|
rescue RubyAudio::Error => e
|
131
142
|
raise e unless e.message == "File contains data in an unknown format."
|
132
|
-
raise Waveform::RuntimeError.new("Source audio file #{source} could not be read by RubyAudio library --
|
143
|
+
raise Waveform::RuntimeError.new("Source audio file #{source} could not be read by RubyAudio library -- Hint: non-WAV files are no longer supported, convert to WAV first using something like ffmpeg (RubyAudio: #{e.message})")
|
133
144
|
end
|
134
|
-
|
145
|
+
|
135
146
|
# Draws the given samples using the given options, returns a ChunkyPNG::Image.
|
136
|
-
def draw(samples, options)
|
147
|
+
def draw(samples, options)
|
137
148
|
image = ChunkyPNG::Image.new(options[:width], options[:height],
|
138
149
|
options[:background_color] == :transparent ? ChunkyPNG::Color::TRANSPARENT : options[:background_color]
|
139
150
|
)
|
140
|
-
|
151
|
+
|
141
152
|
if options[:color] == :transparent
|
142
153
|
color = transparent = ChunkyPNG::Color.from_hex(
|
143
154
|
# Have to do this little bit because it's possible the color we were
|
@@ -152,7 +163,7 @@ class Waveform
|
|
152
163
|
# Calling "zero" the middle of the waveform, like there's positive and
|
153
164
|
# negative amplitude
|
154
165
|
zero = options[:height] / 2.0
|
155
|
-
|
166
|
+
|
156
167
|
samples.each_with_index do |sample, x|
|
157
168
|
# Half the amplitude goes above zero, half below
|
158
169
|
amplitude = sample * options[:height].to_f / 2.0
|
@@ -160,7 +171,7 @@ class Waveform
|
|
160
171
|
# go haywire.
|
161
172
|
image.line(x, (zero - amplitude).round, x, (zero + amplitude).round, color)
|
162
173
|
end
|
163
|
-
|
174
|
+
|
164
175
|
# Simple transparency masking, it just loops over every pixel and makes
|
165
176
|
# ones which match the transparency mask color completely clear.
|
166
177
|
if transparent
|
@@ -170,10 +181,10 @@ class Waveform
|
|
170
181
|
end
|
171
182
|
end
|
172
183
|
end
|
173
|
-
|
184
|
+
|
174
185
|
image
|
175
186
|
end
|
176
|
-
|
187
|
+
|
177
188
|
# Returns an array of the peak of each channel for the given collection of
|
178
189
|
# frames -- the peak is individual to the channel, and the returned collection
|
179
190
|
# of peaks are not (necessarily) from the same frame(s).
|
@@ -194,10 +205,10 @@ class Waveform
|
|
194
205
|
end
|
195
206
|
rms_frame
|
196
207
|
end
|
197
|
-
|
208
|
+
|
198
209
|
# Returns the peak voltage reached on the given channel in the given collection
|
199
210
|
# of frames.
|
200
|
-
#
|
211
|
+
#
|
201
212
|
# TODO: Could lose some resolution and only sample every other frame, would
|
202
213
|
# likely still generate the same waveform as the waveform is so comparitively
|
203
214
|
# low resolution to the original input (in most cases), and would increase
|
@@ -223,7 +234,7 @@ end
|
|
223
234
|
class Waveform
|
224
235
|
# A simple class for logging + benchmarking, nice to have good feedback on a
|
225
236
|
# long batch operation.
|
226
|
-
#
|
237
|
+
#
|
227
238
|
# There's probably 10,000,000 other bechmarking classes, but writing this was
|
228
239
|
# easier than using Google.
|
229
240
|
class Log
|
@@ -245,7 +256,7 @@ class Waveform
|
|
245
256
|
end
|
246
257
|
|
247
258
|
# Starts a new benchmark clock and returns the index of the new clock.
|
248
|
-
#
|
259
|
+
#
|
249
260
|
# If .start! is called again before .end! then the time returned will be
|
250
261
|
# the elapsed time from the next call to start!, and calling .end! again
|
251
262
|
# will return the time from *this* call to start! (that is, the clocks are
|
@@ -279,4 +290,4 @@ class Waveform
|
|
279
290
|
done!
|
280
291
|
end
|
281
292
|
end
|
282
|
-
end
|
293
|
+
end
|
data/test/waveform_test.rb
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "waveform"))
|
2
2
|
|
3
3
|
require "test/unit"
|
4
|
-
require "ruby-debug"
|
5
4
|
require "fileutils"
|
6
5
|
|
7
6
|
module Helpers
|
8
|
-
def
|
7
|
+
def fixture_asset(file)
|
9
8
|
File.join(File.dirname(__FILE__), "fixtures", file)
|
10
9
|
end
|
11
|
-
|
10
|
+
|
12
11
|
def output(file)
|
13
12
|
File.join(File.dirname(__FILE__), "output", file)
|
14
13
|
end
|
15
|
-
|
14
|
+
|
16
15
|
def open_png(file)
|
17
16
|
ChunkyPNG::Image.from_datastream(ChunkyPNG::Datastream.from_file(file))
|
18
17
|
end
|
@@ -27,19 +26,19 @@ class WaveformTest < Test::Unit::TestCase
|
|
27
26
|
Dir[output("*.*")].each{ |f| FileUtils.rm(f) }
|
28
27
|
FileUtils.mkdir_p(output(""))
|
29
28
|
end
|
30
|
-
|
29
|
+
|
31
30
|
def test_generates_waveform
|
32
|
-
Waveform.generate(
|
33
|
-
assert File.
|
34
|
-
|
31
|
+
Waveform.generate(fixture_asset("sample.wav"), output("waveform_from_audio_source.png"))
|
32
|
+
assert File.exist?(output("waveform_from_audio_source.png"))
|
33
|
+
|
35
34
|
image = open_png(output("waveform_from_audio_source.png"))
|
36
35
|
assert_equal ChunkyPNG::Color.from_hex(Waveform::DefaultOptions[:color]), image[60, 120]
|
37
36
|
assert_equal ChunkyPNG::Color.from_hex(Waveform::DefaultOptions[:background_color]), image[0, 0]
|
38
37
|
end
|
39
|
-
|
38
|
+
|
40
39
|
def test_generates_waveform_from_mono_audio_source_via_peak
|
41
|
-
Waveform.generate(
|
42
|
-
assert File.
|
40
|
+
Waveform.generate(fixture_asset("mono_sample.wav"), output("waveform_from_mono_audio_source_via_peak.png"))
|
41
|
+
assert File.exist?(output("waveform_from_mono_audio_source_via_peak.png"))
|
43
42
|
|
44
43
|
image = open_png(output("waveform_from_mono_audio_source_via_peak.png"))
|
45
44
|
assert_equal ChunkyPNG::Color.from_hex(Waveform::DefaultOptions[:color]), image[60, 120]
|
@@ -47,122 +46,138 @@ class WaveformTest < Test::Unit::TestCase
|
|
47
46
|
end
|
48
47
|
|
49
48
|
def test_generates_waveform_from_mono_audio_source_via_rms
|
50
|
-
Waveform.generate(
|
51
|
-
assert File.
|
49
|
+
Waveform.generate(fixture_asset("mono_sample.wav"), output("waveform_from_mono_audio_source_via_rms.png"), :method => :rms)
|
50
|
+
assert File.exist?(output("waveform_from_mono_audio_source_via_rms.png"))
|
52
51
|
|
53
52
|
image = open_png(output("waveform_from_mono_audio_source_via_rms.png"))
|
54
53
|
assert_equal ChunkyPNG::Color.from_hex(Waveform::DefaultOptions[:color]), image[60, 120]
|
55
54
|
assert_equal ChunkyPNG::Color.from_hex(Waveform::DefaultOptions[:background_color]), image[0, 0]
|
56
55
|
end
|
57
|
-
|
56
|
+
|
58
57
|
def test_logs_to_given_io
|
59
58
|
File.open(output("waveform.log"), "w") do |io|
|
60
|
-
Waveform.generate(
|
59
|
+
Waveform.generate(fixture_asset("sample.wav"), output("logged.png"), :logger => io)
|
61
60
|
end
|
62
|
-
|
61
|
+
|
63
62
|
assert_match /Generated waveform/, File.read(output("waveform.log"))
|
64
63
|
end
|
65
|
-
|
64
|
+
|
66
65
|
def test_uses_rms_instead_of_peak
|
67
|
-
Waveform.generate(
|
68
|
-
Waveform.generate(
|
66
|
+
Waveform.generate(fixture_asset("sample.wav"), output("peak.png"))
|
67
|
+
Waveform.generate(fixture_asset("sample.wav"), output("rms.png"), :method => :rms)
|
69
68
|
|
70
69
|
rms = open_png(output("rms.png"))
|
71
70
|
peak = open_png(output("peak.png"))
|
72
|
-
|
71
|
+
|
73
72
|
assert_equal ChunkyPNG::Color.from_hex(Waveform::DefaultOptions[:color]), peak[44, 43]
|
74
73
|
assert_equal ChunkyPNG::Color.from_hex(Waveform::DefaultOptions[:background_color]), rms[44, 43]
|
75
74
|
assert_equal ChunkyPNG::Color.from_hex(Waveform::DefaultOptions[:color]), rms[60, 120]
|
76
75
|
end
|
77
|
-
|
76
|
+
|
78
77
|
def test_is_900px_wide
|
79
|
-
Waveform.generate(
|
80
|
-
|
78
|
+
Waveform.generate(fixture_asset("sample.wav"), output("width-900.png"), :width => 900)
|
79
|
+
|
81
80
|
image = open_png(output("width-900.png"))
|
82
|
-
|
81
|
+
|
83
82
|
assert_equal 900, image.width
|
84
83
|
end
|
85
|
-
|
84
|
+
|
86
85
|
def test_is_100px_tall
|
87
|
-
Waveform.generate(
|
88
|
-
|
86
|
+
Waveform.generate(fixture_asset("sample.wav"), output("height-100.png"), :height => 100)
|
87
|
+
|
89
88
|
image = open_png(output("height-100.png"))
|
90
|
-
|
89
|
+
|
91
90
|
assert_equal 100, image.height
|
92
91
|
end
|
93
|
-
|
92
|
+
|
93
|
+
def test_has_auto_width
|
94
|
+
Waveform.generate(fixture_asset("sample.wav"), output("width-auto.png"), :auto_width => 10)
|
95
|
+
|
96
|
+
image = open_png(output("width-auto.png"))
|
97
|
+
|
98
|
+
assert_equal 209, image.width
|
99
|
+
end
|
100
|
+
|
94
101
|
def test_has_red_background_color
|
95
|
-
Waveform.generate(
|
96
|
-
|
102
|
+
Waveform.generate(fixture_asset("sample.wav"), output("background_color-#ff0000.png"), :background_color => "#ff0000")
|
103
|
+
|
97
104
|
image = open_png(output("background_color-#ff0000.png"))
|
98
|
-
|
105
|
+
|
99
106
|
assert_equal ChunkyPNG::Color.from_hex("#ff0000"), image[0, 0]
|
100
107
|
end
|
101
|
-
|
108
|
+
|
102
109
|
def test_has_transparent_background_color
|
103
|
-
Waveform.generate(
|
104
|
-
|
110
|
+
Waveform.generate(fixture_asset("sample.wav"), output("background_color-transparent.png"), :background_color => :transparent)
|
111
|
+
|
105
112
|
image = open_png(output("background_color-transparent.png"))
|
106
|
-
|
113
|
+
|
107
114
|
assert_equal ChunkyPNG::Color::TRANSPARENT, image[0, 0]
|
108
115
|
end
|
109
|
-
|
116
|
+
|
110
117
|
def test_has_black_foreground_color
|
111
|
-
Waveform.generate(
|
112
|
-
|
118
|
+
Waveform.generate(fixture_asset("sample.wav"), output("color-#000000.png"), :color => "#000000")
|
119
|
+
|
113
120
|
image = open_png(output("color-#000000.png"))
|
114
|
-
|
121
|
+
|
115
122
|
assert_equal ChunkyPNG::Color.from_hex("#000000"), image[60, 120]
|
116
123
|
end
|
117
|
-
|
124
|
+
|
118
125
|
def test_has_red_background_color_with_transparent_foreground_cutout
|
119
|
-
Waveform.generate(
|
120
|
-
|
126
|
+
Waveform.generate(fixture_asset("sample.wav"), output("background_color-#ff0000+color-transparent.png"), :background_color => "#ff0000", :color => :transparent)
|
127
|
+
|
121
128
|
image = open_png(output("background_color-#ff0000+color-transparent.png"))
|
122
|
-
|
129
|
+
|
123
130
|
assert_equal ChunkyPNG::Color.from_hex("#ff0000"), image[0, 0]
|
124
131
|
assert_equal ChunkyPNG::Color::TRANSPARENT, image[60, 120]
|
125
132
|
end
|
126
|
-
|
133
|
+
|
127
134
|
# Bright green is our transparency mask color, so this test ensures that we
|
128
135
|
# don't destroy the image if the background also uses the transparency mask
|
129
136
|
# color
|
130
137
|
def test_has_transparent_foreground_on_bright_green_background
|
131
|
-
Waveform.generate(
|
132
|
-
|
138
|
+
Waveform.generate(fixture_asset("sample.wav"), output("background_color-#00ff00+color-transparent.png"), :background_color => "#00ff00", :color => :transparent)
|
139
|
+
|
133
140
|
image = open_png(output("background_color-#00ff00+color-transparent.png"))
|
134
|
-
|
141
|
+
|
135
142
|
assert_equal ChunkyPNG::Color.from_hex("#00ff00"), image[0, 0]
|
136
143
|
assert_equal ChunkyPNG::Color::TRANSPARENT, image[60, 120]
|
137
144
|
end
|
138
|
-
|
145
|
+
|
139
146
|
def test_raises_error_if_not_given_readable_audio_source
|
140
147
|
assert_raise(Waveform::RuntimeError) do
|
141
|
-
Waveform.generate(
|
148
|
+
Waveform.generate(fixture_asset("sample.txt"), output("shouldnt_exist.png"))
|
142
149
|
end
|
143
150
|
end
|
144
|
-
|
151
|
+
|
145
152
|
def test_overwrites_existing_waveform_if_force_is_true_and_file_exists
|
146
153
|
FileUtils.touch output("overwritten.png")
|
147
154
|
|
148
|
-
Waveform.generate(
|
155
|
+
Waveform.generate(fixture_asset("sample.wav"), output("overwritten.png"), :force => true)
|
149
156
|
end
|
150
157
|
|
151
158
|
def test_raises_exception_if_waveform_exists_and_force_is_false
|
152
159
|
FileUtils.touch output("wont_be_overwritten.png")
|
153
|
-
|
160
|
+
|
154
161
|
assert_raises Waveform::RuntimeError do
|
155
|
-
Waveform.generate(
|
162
|
+
Waveform.generate(fixture_asset("sample.wav"), output("wont_be_overwritten.png"), :force => false)
|
156
163
|
end
|
157
164
|
end
|
158
|
-
|
165
|
+
|
159
166
|
def test_raises_exception_if_waveform_exists
|
160
167
|
FileUtils.touch output("wont_be_overwritten_by_default.png")
|
161
|
-
|
168
|
+
|
162
169
|
assert_raises Waveform::RuntimeError do
|
163
|
-
Waveform.generate(
|
170
|
+
Waveform.generate(fixture_asset("sample.wav"), output("wont_be_overwritten_by_default.png"))
|
164
171
|
end
|
165
|
-
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_raises_deprecation_exception_if_ruby_audio_fails_to_read_source_file
|
175
|
+
begin
|
176
|
+
Waveform.generate(fixture_asset("sample.txt"), output("shouldnt_exist.png"))
|
177
|
+
rescue Waveform::RuntimeError => e
|
178
|
+
assert_match /Hint: non-WAV files are no longer supported, convert to WAV first using something like ffmpeg/, e.message
|
179
|
+
end
|
180
|
+
end
|
166
181
|
end
|
167
182
|
|
168
183
|
WaveformTest.cleanup
|
metadata
CHANGED
@@ -1,99 +1,80 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: waveform
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 1
|
10
|
-
version: 0.1.1
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.3
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Ben Alavi
|
14
|
-
autorequire:
|
8
|
+
autorequire:
|
15
9
|
bindir: bin
|
16
10
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2023-03-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
21
14
|
name: ruby-audio
|
22
|
-
|
23
|
-
|
24
|
-
none: false
|
25
|
-
requirements:
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
26
17
|
- - ">="
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
segments:
|
30
|
-
- 0
|
31
|
-
version: "0"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
32
20
|
type: :runtime
|
33
|
-
version_requirements: *id001
|
34
|
-
- !ruby/object:Gem::Dependency
|
35
|
-
name: chunky_png
|
36
21
|
prerelease: false
|
37
|
-
|
38
|
-
|
39
|
-
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: chunky_png
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
40
31
|
- - ">="
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
|
43
|
-
segments:
|
44
|
-
- 0
|
45
|
-
version: "0"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
46
34
|
type: :runtime
|
47
|
-
|
48
|
-
|
49
|
-
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Generate waveform images from audio files. Includes a Waveform class
|
42
|
+
for generating waveforms in your code as well as a simple command-line program called
|
43
|
+
'waveform' for generating on the command line.
|
44
|
+
email:
|
50
45
|
- benalavi@gmail.com
|
51
|
-
executables:
|
46
|
+
executables:
|
52
47
|
- waveform
|
53
48
|
extensions: []
|
54
|
-
|
55
49
|
extra_rdoc_files: []
|
56
|
-
|
57
|
-
files:
|
50
|
+
files:
|
58
51
|
- README.md
|
59
52
|
- Rakefile
|
60
|
-
-
|
53
|
+
- bin/waveform
|
61
54
|
- lib/waveform.rb
|
62
|
-
- waveform.
|
55
|
+
- lib/waveform/version.rb
|
63
56
|
- test/waveform_test.rb
|
64
|
-
-
|
57
|
+
- waveform.gemspec
|
65
58
|
homepage: http://github.com/benalavi/waveform
|
66
59
|
licenses: []
|
67
|
-
|
68
|
-
post_install_message:
|
60
|
+
metadata: {}
|
61
|
+
post_install_message:
|
69
62
|
rdoc_options: []
|
70
|
-
|
71
|
-
require_paths:
|
63
|
+
require_paths:
|
72
64
|
- lib
|
73
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
-
|
75
|
-
requirements:
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
76
67
|
- - ">="
|
77
|
-
- !ruby/object:Gem::Version
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
version: "0"
|
82
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
-
none: false
|
84
|
-
requirements:
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
85
72
|
- - ">="
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
|
88
|
-
segments:
|
89
|
-
- 0
|
90
|
-
version: "0"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
91
75
|
requirements: []
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
signing_key:
|
96
|
-
specification_version: 3
|
76
|
+
rubygems_version: 3.3.26
|
77
|
+
signing_key:
|
78
|
+
specification_version: 4
|
97
79
|
summary: Generate waveform images from audio files
|
98
80
|
test_files: []
|
99
|
-
|