waveform 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
-
|