carrierwave-audio-waveform 1.0.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b817a62eeaac43003254b3790fdc864faf0a0980
4
- data.tar.gz: 84176297d0547e499d84bedef2e22585618e1e8e
3
+ metadata.gz: 9b978937b699c8840ed808da400cc75406b850c7
4
+ data.tar.gz: e8ea1146faf2a37a1fcdb7c98172c1a241008bfc
5
5
  SHA512:
6
- metadata.gz: c321c0dcaf6d14e6a8c6526c532eca40cb30ecf5690fae3896c1185d308344621974d310fff12cda3446ff210a8747c536de918fed7d13cacca7262e8851f49f
7
- data.tar.gz: 42ce80dacf18c25b68f7732e5983f4547a505bd991c50b9b7eddcaf62fce51c549e200c2dd7af6b5e8b41fbdd592456a16733ffb4ee13f88d437e526a1490dd2
6
+ metadata.gz: 763f2a8d2b40333712f256cf8f8cac5e2a75559a30d24857a3075f1f8cb30f5ee1ac825b97d719b8d7bf46f09542fcf1432ba67f2d34a327a1ccf75062e5ff42
7
+ data.tar.gz: 377f117014e72cc62fb6c3dafb1a1882a77ce43100b548c10690da7c2f6f79c6564b5f80ca95c4f34503f6df2cf51f1afbb718e30ea7d8c956e2b12de2a116c7
@@ -1,5 +1,6 @@
1
1
  require 'carrierwave'
2
2
  require 'carrierwave/audio_waveform/waveformer'
3
+ require 'carrierwave/audio_waveform/waveform_data'
3
4
 
4
5
  module CarrierWave
5
6
  module AudioWaveform
@@ -9,6 +10,10 @@ module CarrierWave
9
10
  def waveform options={}
10
11
  process waveform: [ options ]
11
12
  end
13
+
14
+ def waveform_data options={}
15
+ process waveform_data: [ options ]
16
+ end
12
17
  end
13
18
 
14
19
  def waveform options={}
@@ -16,6 +21,15 @@ module CarrierWave
16
21
 
17
22
  image_filename = Waveformer.generate(current_path, options)
18
23
  File.rename image_filename, current_path
24
+ self.file.instance_variable_set(:@content_type, "image/png")
25
+ end
26
+
27
+ def waveform_data options={}
28
+ cache_stored_file! if !cached?
29
+
30
+ data_filename = WaveformData.generate(current_path, options)
31
+ File.rename data_filename, current_path
32
+ self.file.instance_variable_set(:@content_type, "application/json")
19
33
  end
20
34
  end
21
- end
35
+ end
@@ -1,5 +1,5 @@
1
1
  module CarrierWave
2
2
  module AudioWaveform
3
- VERSION = '1.0.0'
3
+ VERSION = '1.0.3'
4
4
  end
5
5
  end
@@ -0,0 +1,197 @@
1
+ require 'ruby-sox'
2
+ require 'fileutils'
3
+
4
+ module CarrierWave
5
+ module AudioWaveform
6
+ class WaveformData
7
+ DefaultOptions = {
8
+ pixels_per_second: 10,
9
+ bits: 16
10
+ }
11
+
12
+ # Scope these under Waveform so you can catch the ones generated by just this
13
+ # class.
14
+ class RuntimeError < ::RuntimeError;end;
15
+ class ArgumentError < ::ArgumentError;end;
16
+
17
+ class << self
18
+ # Generate a Waveform image at the given filename with the given options.
19
+ #
20
+ # Available options (all optional) are:
21
+ #
22
+ # :convert_to_extension_before_processing => Symbolized extension (:wav, :mp3, etc.)
23
+ # Useful if .wav or .mp3 isn't being passed in--you can convert to that format first.
24
+ #
25
+ # :set_extension_before_processing => Symbolized extension (:wav, :mp3, etc.)
26
+ # This is useful because CarrierWave will send files in with the wrong extension sometimes.
27
+ # For instance, if this is nested under a version, that version may be an .mp3, but its parent
28
+ #
29
+ # :pixels_per_second => The number of pixels per second to evaluate.
30
+ #
31
+ # :bits => 8 or 16 bit precision
32
+ #
33
+ # :logger => IOStream to log progress to.
34
+ #
35
+ # Example:
36
+ # CarrierWave::AudioWaveform::Waveformer.generate("Kickstart My Heart.wav")
37
+ # CarrierWave::AudioWaveform::Waveformer.generate("Kickstart My Heart.wav", :method => :rms)
38
+ # CarrierWave::AudioWaveform::Waveformer.generate("Kickstart My Heart.wav", :color => "#ff00ff", :logger => $stdout)
39
+ #
40
+ def generate(source, options={})
41
+ options = DefaultOptions.merge(options)
42
+ options[:filename] ||= self.generate_json_filename(source)
43
+ old_source = source
44
+ if options[:convert_to_extension_before_processing]
45
+ source = generate_valid_source(source, options[:convert_to_extension_before_processing])
46
+ elsif options[:set_extension_before_processing]
47
+ source = generate_proper_source(source, options[:set_extension_before_processing])
48
+ end
49
+
50
+ raise ArgumentError.new("No source audio filename given, must be an existing sound file.") unless source
51
+ raise ArgumentError.new("No destination filename given for waveform") unless options[:filename]
52
+ raise RuntimeError.new("Source audio file '#{source}' not found.") unless File.exist?(source)
53
+
54
+ @log = Log.new(options[:logger])
55
+ @log.start!
56
+
57
+ @log.timed("\nGenerating...") do
58
+ stdout_str, stderr_str, status = self.generate_waveform_data(source, options)
59
+ if stderr_str.present? && !stderr_str.include?("Recoverable")
60
+ raise RuntimeError.new(stderr_str)
61
+ end
62
+ end
63
+
64
+ if source != old_source && options[:convert_to_extension_before_processing]
65
+ @log.out("Removing temporary file at #{source}")
66
+ FileUtils.rm(source)
67
+ elsif source != old_source && options[:set_extension_before_processing]
68
+ @log.out("Renaming file at #{source}")
69
+ old_ext = File.extname(source).gsub(/\./, '').to_sym
70
+ generate_proper_source(source, old_ext)
71
+ end
72
+
73
+ @log.done!("Generated waveform data '#{options[:filename]}'")
74
+
75
+ options[:filename]
76
+ end
77
+
78
+ def generate_json_filename(source)
79
+ ext = File.extname(source)
80
+ source_file_path_without_extension = File.join File.dirname(source), File.basename(source, ext)
81
+ "#{source_file_path_without_extension}.json"
82
+ end
83
+
84
+ def generate_waveform_data(source, options = DefaultOptions)
85
+ options[:filename] ||= self.generate_json_filename(source)
86
+ Open3.capture3(
87
+ "audiowaveform -i #{source} --pixels-per-second #{options[:pixels_per_second]} -b #{options[:bits]} -o #{options[:filename]}"
88
+ )
89
+ end
90
+
91
+ private
92
+
93
+ # Returns the proper file type if the one passed in was
94
+ # wrong, or the original if it wasn't.
95
+ def generate_proper_source(source, proper_ext)
96
+ ext = File.extname(source)
97
+ ext_gsubbed = ext.gsub(/\./, '')
98
+
99
+ if ext_gsubbed != proper_ext.to_s
100
+ filename_with_proper_extension = "#{source.chomp(File.extname(source))}.#{proper_ext}"
101
+ File.rename source, filename_with_proper_extension
102
+ filename_with_proper_extension
103
+ else
104
+ source
105
+ end
106
+ rescue Sox::Error => e
107
+ raise e unless e.message.include?("FAIL formats:")
108
+ raise RuntimeError.new("Source file #{source} could not be converted to .wav by Sox (Sox: #{e.message})")
109
+ end
110
+
111
+ # Returns a converted file.
112
+ def generate_valid_source(source, proper_ext)
113
+ ext = File.extname(source)
114
+ ext_gsubbed = ext.gsub(/\./, '')
115
+
116
+ if ext_gsubbed != proper_ext.to_s
117
+ input_options = { type: ext_gsubbed }
118
+ output_options = { type: proper_ext.to_s }
119
+ source_filename_without_extension = File.basename(source, ext)
120
+ output_file_path = File.join File.dirname(source), "tmp_#{source_filename_without_extension}_#{Time.now.to_i}.#{proper_ext}"
121
+ converter = Sox::Cmd.new
122
+ converter.add_input source, input_options
123
+ converter.set_output output_file_path, output_options
124
+ converter.run
125
+ output_file_path
126
+ else
127
+ source
128
+ end
129
+ rescue Sox::Error => e
130
+ raise e unless e.message.include?("FAIL formats:")
131
+ raise RuntimeError.new("Source file #{source} could not be converted to .wav by Sox (Sox: #{e.message})")
132
+ end
133
+ end
134
+ end
135
+
136
+ class WaveformData
137
+ # A simple class for logging + benchmarking, nice to have good feedback on a
138
+ # long batch operation.
139
+ #
140
+ # There's probably 10,000,000 other bechmarking classes, but writing this was
141
+ # easier than using Google.
142
+ class Log
143
+ attr_accessor :io
144
+
145
+ def initialize(io=$stdout)
146
+ @io = io
147
+ end
148
+
149
+ # Prints the given message to the log
150
+ def out(msg)
151
+ io.print(msg) if io
152
+ end
153
+
154
+ # Prints the given message to the log followed by the most recent benchmark
155
+ # (note that it calls .end! which will stop the benchmark)
156
+ def done!(msg="")
157
+ out "#{msg} (#{self.end!}s)\n"
158
+ end
159
+
160
+ # Starts a new benchmark clock and returns the index of the new clock.
161
+ #
162
+ # If .start! is called again before .end! then the time returned will be
163
+ # the elapsed time from the next call to start!, and calling .end! again
164
+ # will return the time from *this* call to start! (that is, the clocks are
165
+ # LIFO)
166
+ def start!
167
+ (@benchmarks ||= []) << Time.now
168
+ @current = @benchmarks.size - 1
169
+ end
170
+
171
+ # Returns the elapsed time from the most recently started benchmark clock
172
+ # and ends the benchmark, so that a subsequent call to .end! will return
173
+ # the elapsed time from the previously started benchmark clock.
174
+ def end!
175
+ elapsed = (Time.now - @benchmarks[@current])
176
+ @current -= 1
177
+ elapsed
178
+ end
179
+
180
+ # Returns the elapsed time from the benchmark clock w/ the given index (as
181
+ # returned from when .start! was called).
182
+ def time?(index)
183
+ Time.now - @benchmarks[index]
184
+ end
185
+
186
+ # Benchmarks the given block, printing out the given message first (if
187
+ # given).
188
+ def timed(message=nil, &block)
189
+ start!
190
+ out(message) if message
191
+ yield
192
+ done!
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carrierwave-audio-waveform
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Trevor Hinesley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-20 00:00:00.000000000 Z
11
+ date: 2017-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: carrierwave
@@ -120,6 +120,7 @@ files:
120
120
  - lib/carrierwave-audio-waveform.rb
121
121
  - lib/carrierwave/audio_waveform.rb
122
122
  - lib/carrierwave/audio_waveform/version.rb
123
+ - lib/carrierwave/audio_waveform/waveform_data.rb
123
124
  - lib/carrierwave/audio_waveform/waveformer.rb
124
125
  homepage: https://github.com/TrevorHinesley/carrierwave-audio-waveform
125
126
  licenses:
@@ -146,3 +147,4 @@ signing_key:
146
147
  specification_version: 4
147
148
  summary: Generate waveform images from audio files within Carrierwave
148
149
  test_files: []
150
+ has_rdoc: