Class: CarrierWave::AudioWaveform::Waveformer

Inherits:
Object
  • Object
show all
Defined in:
lib/carrierwave/audio_waveform/waveformer.rb,
lib/carrierwave/audio_waveform/waveformer.rb

Defined Under Namespace

Classes: ArgumentError, Log, RuntimeError

Constant Summary collapse

DefaultOptions =
{
  :method => :peak,
  :width => 1800,
  :height => 280,
  :background_color => "#666666",
  :color => "#00ccff",
  :logger => nil,
  :type => :png
}
TransparencyMask =
"#00ff00"
TransparencyAlternate =

in case the mask is the background color!

"#ffff00"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Attribute Details

#sourceObject (readonly)

Returns the value of attribute source.



22
23
24
# File 'lib/carrierwave/audio_waveform/waveformer.rb', line 22

def source
  @source
end

Class Method Details

.generate(source, options = {}) ⇒ Object

Generate a Waveform image at the given filename with the given options.

Available options (all optional) are:

:method => The method used to read sample frames, available methods
  are peak and rms. peak is probably what you're used to seeing, it uses
  the maximum amplitude per sample to generate the waveform, so the
  waveform looks more dynamic. RMS gives a more fluid waveform and
  probably more accurately reflects what you hear, but isn't as
  pronounced (typically).

  Can be :rms or :peak
  Default is :peak.

:width => The width (in pixels) of the final waveform image.
  Default is 1800.

:height => The height (in pixels) of the final waveform image.
  Default is 280.

:auto_width => msec per pixel. This will overwrite the width of the
  final waveform image depending on the length of the audio file.
  Example:
    100 => 1 pixel per 100 msec; a one minute audio file will result in a width of 600 pixels

:background_color => Hex code of the background color of the generated
  waveform image. Pass :transparent for transparent background.
  Default is #666666 (gray).

:color => Hex code of the color to draw the waveform, or can pass
  :transparent to render the waveform transparent (use w/ a solid
  color background to achieve a "cutout" effect).
  Default is #00ccff (cyan-ish).

:sample_width => Integer specifying the sample width. If this
  is specified, there will be gaps (minimum of 1px wide, as specified
  by :gap_width) between samples that are this wide in pixels.
  Default is nil
  Minimum is 1 (for anything other than nil)

:gap_width => Integer specifying the gap width. If sample_width
  is specified, this will be the size of the gaps between samples in pixels.
  Default is nil
  Minimum is 1 (for anything other than nil, or when sample_width is present but gap_width is not)

:logger => IOStream to log progress to.

Example:

CarrierWave::AudioWaveform::Waveformer.generate("Kickstart My Heart.wav")
CarrierWave::AudioWaveform::Waveformer.generate("Kickstart My Heart.wav", :method => :rms)
CarrierWave::AudioWaveform::Waveformer.generate("Kickstart My Heart.wav", :color => "#ff00ff", :logger => $stdout)

Raises:



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/carrierwave/audio_waveform/waveformer.rb', line 82

def generate(source, options={})
  options = DefaultOptions.merge(options)
  filename = options[:filename] || self.generate_image_filename(source, options[:type])

  raise ArgumentError.new("No source audio filename given, must be an existing sound file.") unless source
  raise ArgumentError.new("No destination filename given for waveform") unless filename
  raise RuntimeError.new("Source audio file '#{source}' not found.") unless File.exist?(source)

  old_source = source
  source = generate_wav_source(source)

  @log = Log.new(options[:logger])
  @log.start!

  if options[:auto_width]
    RubyAudio::Sound.open(source) do |audio|
      options[:width] = (audio.info.length * 1000 / options[:auto_width].to_i).ceil
    end
  end

  # Frames gives the amplitudes for each channel, for our waveform we're
  # saying the "visual" amplitude is the average of the amplitude across all
  # the channels. This might be a little weird w/ the "peak" method if the
  # frames are very wide (i.e. the image width is very small) -- I *think*
  # the larger the frames are, the more "peaky" the waveform should get,
  # perhaps to the point of inaccurately reflecting the actual sound.
  samples = frames(source, options[:width], options[:method]).collect do |frame|
    frame.inject(0.0) { |sum, peak| sum + peak } / frame.size      
  end

  @log.timed("\nDrawing...") do
    # Don't remove the file until we're sure the
    # source was readable
    if File.exists?(filename)
      @log.out("Output file #{filename} encountered. Removing.")
      File.unlink(filename)
    end

    image = draw samples, options

    if options[:type] == :svg
      File.open(filename, 'w') do |f|
        f.puts image
      end
    else
      image.save filename
    end
  end

  if source != old_source
    @log.out("Removing temporary file at #{source}")
    FileUtils.rm(source)
  end

  @log.done!("Generated waveform '#{filename}'")

  filename
end

.generate_image_filename(source, image_type) ⇒ Object



141
142
143
144
145
146
147
148
149
150
# File 'lib/carrierwave/audio_waveform/waveformer.rb', line 141

def generate_image_filename(source, image_type)
  ext = File.extname(source)
  source_file_path_without_extension = File.join File.dirname(source), File.basename(source, ext)

  if image_type == :svg
    "#{source_file_path_without_extension}.svg"
  else
    "#{source_file_path_without_extension}.png"
  end
end