ruby-sox 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b3d0a858629f10877dee7bc1be0f707777f3215d
4
+ data.tar.gz: bae090b2b7124e2a37f15b1c9001bfa6ed79fced
5
+ SHA512:
6
+ metadata.gz: a532d4ab550278235dc139d9aa297f7494ba49b06d051a0c1e4e709cfbf78e837915f8f128b5482d6f6bbc83425020095b217f50fec6dcaf2e372c41692192e5
7
+ data.tar.gz: c428ddd99eb71e1b157d79b10c301f7a2dd320e4ed8fe332e924d0ec5e19cd6744c13ecec1142b9dd703e5cfd291d82433d01b057ba2f4f22f9f03f4c9d69bcf
data/LICENSE.txt ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2013 TMX Credit, author Potapov Sergey
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ The audio files are distributed under Creative Commons Attribution 3.0
23
+ Unported License.
data/README.markdown ADDED
@@ -0,0 +1,114 @@
1
+ # Ruby SoX
2
+
3
+ [![Build Status](https://travis-ci.org/TMXCredit/ruby-sox.png?branch=master)](https://travis-ci.org/TMXCredit/ruby-sox)
4
+
5
+ A Ruby wrapper for the `sox` command line tool to process sound.
6
+
7
+
8
+ ## Dependencies
9
+
10
+ * SoX
11
+ * Bash (for process substitution combiner strategy)
12
+ * Chromaprint (only to run tests)
13
+
14
+ ### Debian / Ubuntu
15
+
16
+ ```bash
17
+ apt-get install libsox-fmt-all sox libchromaprint-dev
18
+ ```
19
+
20
+ ### Mac
21
+
22
+ ```bash
23
+ # One of the following
24
+ # Notes:
25
+ # * chromaprint is not available in MacPorts as of this writing
26
+ # * flac must be installed before sox so it will link during compilation
27
+ sudo port install flac sox && brew install chromaprint
28
+ brew install flac sox chromaprint
29
+ ```
30
+
31
+ # Usage
32
+
33
+ Remember that it's a wrapper for `sox` to provide Ruby API.
34
+ It's assumed that you know the basics of sound computing theory and how
35
+ the `sox` tool works. Otherwise, `man sox` is your good friend.
36
+
37
+ ## Sox::Cmd
38
+
39
+ Allows you to do everything that the `sox` command does.
40
+
41
+ Mix 3 files into one (ruby-sox assumes that input files have same rate and number of channels):
42
+
43
+ ```ruby
44
+ # Build command
45
+ sox = Sox::Cmd.new(:combine => :mix)
46
+ .add_input("guitar1.flac")
47
+ .add_input("guitar2.flac")
48
+ .add_input("drums.flac")
49
+ .set_output("hell_rock-n-roll.mp3")
50
+ .set_effects(:rate => 44100, :channels => 2)
51
+
52
+ # Execute command
53
+ sox.run
54
+ ```
55
+
56
+ ## Sox::Combiner
57
+
58
+ Sox::Combiner combines files even if they have different rates or numbers
59
+ of channels. Under the hood, it converts the input files into temporary files
60
+ to have the same rate and number of channels, and then combines them.
61
+
62
+ Concatenate:
63
+
64
+ ```ruby
65
+ combiner = Sox::Combiner.new('in1.mp3', 'in2.ogg', 'in3.wav', :combine => :concatenate)
66
+ combiner.write('out.mp3')
67
+ ```
68
+
69
+ Mix 3 files into an MP3 with 2 channels and a rate of 1600:
70
+
71
+ ```ruby
72
+ combiner = Sox::Combiner.new('in1.mp3', 'in2.ogg', 'in3.wav', :combine => :mix, :rate => 1600, :channels => 2)
73
+ combiner.write('out.mp3')
74
+ ```
75
+
76
+ ## Run specs
77
+
78
+ ```bash
79
+ rake spec
80
+ ```
81
+
82
+ ## Credits
83
+
84
+ * [Sergey Potapov](https://github.com/greyblake)
85
+
86
+ ## License
87
+
88
+ Copyright (c) 2013 TMX Credit, author Potapov Sergey
89
+
90
+ Permission is hereby granted, free of charge, to any person obtaining
91
+ a copy of this software and associated documentation files (the
92
+ "Software"), to deal in the Software without restriction, including
93
+ without limitation the rights to use, copy, modify, merge, publish,
94
+ distribute, sublicense, and/or sell copies of the Software, and to
95
+ permit persons to whom the Software is furnished to do so, subject to
96
+ the following conditions:
97
+
98
+ The above copyright notice and this permission notice shall be
99
+ included in all copies or substantial portions of the Software.
100
+
101
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
102
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
103
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
104
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
105
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
106
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
107
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
108
+
109
+ The audio files are distributed under [Creative Commons Attribution 3.0
110
+ Unported License](http://creativecommons.org/licenses/by/3.0/legalcode).
111
+
112
+ ## Copyright
113
+
114
+ Copyright (c) 2013 TMX Credit.
data/lib/ruby-sox.rb ADDED
@@ -0,0 +1,2 @@
1
+ require File.expand_path('../sox', __FILE__)
2
+
data/lib/sox/cmd.rb ADDED
@@ -0,0 +1,85 @@
1
+ module Sox
2
+ # Process audio files using the +sox+ shell command.
3
+ #
4
+ # @example
5
+ # # Mix 3 files into one
6
+ # sox = Sox::Cmd.new(:combine => :mix)
7
+ # sox.add_input("guitar1.flac")
8
+ # sox.add_input("guitar2.flac")
9
+ # sox.add_input("drums.flac")
10
+ # sox.set_output("hell_rock-n-roll.mp3")
11
+ # sox.set_effects(:rate => 44100, :channels => 2)
12
+ # sox.run
13
+ class Cmd
14
+ include Sox::Shell
15
+
16
+ attr_reader :options, :inputs, :output, :effects
17
+
18
+ # @param options [Hash] global options for sox command
19
+ def initialize(options = {})
20
+ @options = options
21
+ @inputs = []
22
+ @effects = {}
23
+ end
24
+
25
+ # Add input file with its options.
26
+ #
27
+ # @param file_path [String] path to file
28
+ # @param input_options [Hash] options for input files, see +man sox+
29
+ #
30
+ # @return [Sox::Cmd] self
31
+ def add_input(file_path, input_options = {})
32
+ @inputs << Sox::File.new(file_path, input_options)
33
+ self
34
+ end
35
+
36
+ # Set output file and its options.
37
+ #
38
+ # @param file_path [String] ouput file path
39
+ # @param output_options [Hash] options for output file, see +man sox+
40
+ #
41
+ # @return [Sox::Cmd] self
42
+ def set_output(file_path, output_options = {})
43
+ @output = Sox::File.new(file_path, output_options)
44
+ self
45
+ end
46
+
47
+ # Set effects on the output file. See +man sox+ section +EFFECTS+.
48
+ # It receives the effect name as a hash key and the effect arguments as
49
+ # hash values which can be a string or an array of strings. If an effect
50
+ # has no arguments just pass +true+ as the value.
51
+ #
52
+ # @example
53
+ # # Normalize and use 2 channels for output
54
+ # sox_cmd.set_effects(:channels => 2, :norm => true)
55
+ #
56
+ # @param effects [Hash{Symbol, String => Symbol, String, Array<String>}]
57
+ #
58
+ # @return [Sox::Cmd] self
59
+ def set_effects(effects)
60
+ @effects = effects
61
+ self
62
+ end
63
+
64
+ # Set global options. See +man sox+ section +Global Options+.
65
+ #
66
+ # @param options [Hash] global options for +sox+ command
67
+ #
68
+ # @return [Sox::Cmd] self
69
+ def set_options(options)
70
+ @options = options
71
+ self
72
+ end
73
+
74
+ # Run `sox` command. Raise {Sox::Error} on fail.
75
+ #
76
+ # @return [Boolean] true in case of success
77
+ def run
78
+ raise(Sox::Error, "Output is missing, specify it with `set_output`") unless @output
79
+ raise(Sox::Error, "Inputs are missing, specify them with `add_input`") if @inputs.empty?
80
+
81
+ cmd = CommandBuilder.new(@inputs, @output, @options, @effects).build
82
+ sh(cmd)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,37 @@
1
+ module Sox
2
+ # Common parent class for combiner strategies.
3
+ class Combiner::BaseStrategy
4
+ include Sox::Shell
5
+
6
+ # @param input_files [Array<String>] input files
7
+ # @param options [Hash] see {Sox::Combiner#initialize}
8
+ def initialize(input_files, options)
9
+ @input_files = input_files
10
+ @options = options
11
+ end
12
+
13
+ # Run the command, and save output in the output file.
14
+ #
15
+ # @param output_file [String]
16
+ #
17
+ # @return [void]
18
+ def write(output_file)
19
+ raise NotImplementedError, __method__
20
+ end
21
+
22
+
23
+ # Build effects which will be applied on final output.
24
+ #
25
+ # @return [Hash]
26
+ def output_effects
27
+ {:norm => @options[:norm]}
28
+ end
29
+
30
+ # Build global options for +sox+ command.
31
+ #
32
+ # @return [Hash]
33
+ def output_options
34
+ {:combine => @options[:combine]}
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,78 @@
1
+ module Sox
2
+ # Combines files using process substitution to build and use mediate files.
3
+ # Process substitution is not supported by the standard shell, so we need
4
+ # to pass the final command to bash via shell.
5
+ #
6
+ # Read more about process substitution:
7
+ # http://en.wikipedia.org/wiki/Process_substitution
8
+ class Combiner::ProcessSubstitutionStrategy < Combiner::BaseStrategy
9
+ # Type of mediate files:
10
+ MEDIATE_TYPE = :sox
11
+
12
+ # Number of bits for mediate files:
13
+ MEDIATE_BITS = 32
14
+
15
+ # Encoding of mediate files:
16
+ MEDIATE_ENCODING = :signed
17
+
18
+ # Pseudo file which makes the `sox` command write to output to stdout:
19
+ SOX_PIPE = '-p'
20
+
21
+ # :nodoc:
22
+ def write(output_file)
23
+ inputs = @input_files.map { |file| build_input_file(file) }
24
+ output = Sox::File.new(output_file)
25
+
26
+ cmd = CommandBuilder.new(inputs, output, output_options, output_effects).build
27
+ bash(cmd)
28
+ end
29
+
30
+
31
+ # Build the input file which can be used in the command builder to get
32
+ # the final output.
33
+ #
34
+ # @param file_path [String] path to input file
35
+ #
36
+ # @return [Sox::File]
37
+ def build_input_file(file_path)
38
+ Sox::File.new(build_converted_input(file_path),
39
+ :type => MEDIATE_TYPE,
40
+ :encoding => MEDIATE_ENCODING,
41
+ :bits => MEDIATE_BITS,
42
+ :channels => @options[:channels],
43
+ :rate => @options[:rate]
44
+ ).tap { |file| file.escaped = true }
45
+ end
46
+ private :build_input_file
47
+
48
+ # Build the shell statement which can be used as the input file with
49
+ # the needed rate and number of channels.
50
+ #
51
+ # @param input_file [String]
52
+ #
53
+ # @return [String] shell statement which can be used as input file
54
+ #
55
+ # @example
56
+ # build_converted_input("in.mp3")
57
+ # # => "<(sox in.mp3 --encoding sox --bits 32 -p rate 22100 channels 1)"
58
+ def build_converted_input(input_file)
59
+ input = Sox::File.new(input_file)
60
+ output = Sox::File.new(SOX_PIPE, :encoding => MEDIATE_ENCODING, :bits => MEDIATE_BITS)
61
+ effects = {:channels => @options[:channels], :rate => @options[:rate]}
62
+ command = CommandBuilder.new([input], output, {}, effects).build
63
+ process_substitution_wrap(command)
64
+ end
65
+ private :build_converted_input
66
+
67
+ # Wrap shell command to make its output be used in process substitution.
68
+ # See http://en.wikipedia.org/wiki/Process_substitution for more info.
69
+ #
70
+ # @param command [String] shell command
71
+ #
72
+ # @return [String]
73
+ def process_substitution_wrap(command)
74
+ "<(#{command})"
75
+ end
76
+ private :process_substitution_wrap
77
+ end
78
+ end
@@ -0,0 +1,78 @@
1
+ module Sox
2
+ # Combines files using temporary files as mediate files.
3
+ class Combiner::TmpFileStrategy < Combiner::BaseStrategy
4
+ # Type of temporary mediate files:
5
+ MEDIATE_TYPE = :raw
6
+
7
+ # Number of bits for temporary mediate files:
8
+ MEDIATE_BITS = 16
9
+
10
+ # Encoding of temporary mediate files:
11
+ MEDIATE_ENCODING = :signed
12
+
13
+
14
+ # :nodoc:
15
+ def write(output_file)
16
+ tmp_files = []
17
+
18
+ @input_files.each do |input_file|
19
+ tmp_output_file = gen_tmp_filename
20
+ tmp_files << tmp_output_file
21
+
22
+ cmd = build_convert_command(input_file, tmp_output_file)
23
+ sh(cmd)
24
+ end
25
+
26
+ cmd = build_output_command(tmp_files, output_file)
27
+ sh(cmd)
28
+ ensure
29
+ # Remove temporary files
30
+ tmp_files.each { |file| FileUtils.rm(file) if ::File.exists?(file) }
31
+ end
32
+
33
+ # Build +sox+ command to get final output.
34
+ #
35
+ # @param input_files [Array<String>]
36
+ # @param output_file [String]
37
+ #
38
+ # @return [String] sox command
39
+ def build_output_command(input_files, output_file)
40
+ inputs = input_files.map do |path|
41
+ Sox::File.new(path,
42
+ :type => MEDIATE_TYPE,
43
+ :encoding => MEDIATE_ENCODING,
44
+ :bits => MEDIATE_BITS,
45
+ :channels => @options[:channels],
46
+ :rate => @options[:rate])
47
+ end
48
+
49
+ output = Sox::File.new(output_file)
50
+
51
+ builder = CommandBuilder.new(inputs, output, output_options, output_effects)
52
+ builder.build
53
+ end
54
+ private :build_output_command
55
+
56
+ # Build shell command which converts input file into temporary file with
57
+ # desired rate and channels.
58
+ #
59
+ # @param input_file [String] input file
60
+ # @param output_file [String] converted output with desired characteristics
61
+ #
62
+ # @return [String] shell command
63
+ def build_convert_command(input_file, output_file)
64
+ builder = CommandBuilder.new([Sox::File.new(input_file)], Sox::File.new(output_file))
65
+ builder.effects = {:channels => @options[:channels], :rate => @options[:rate]}
66
+ builder.build
67
+ end
68
+ private :build_convert_command
69
+
70
+ # Generate path to temporary file with unique name.
71
+ #
72
+ # @return [String] path to temporary file
73
+ def gen_tmp_filename
74
+ Dir::Tmpname.make_tmpname ['/tmp/ruby-sox', ".#{MEDIATE_TYPE}"], nil
75
+ end
76
+ private :gen_tmp_filename
77
+ end
78
+ end
@@ -0,0 +1,73 @@
1
+ module Sox
2
+ # Combines input files. Technically it calls +sox+ with +--combine+ option,
3
+ # but allows you not to care about the rates and numbers of channels in the
4
+ # input files. It converts them to the same rates/channels using temporary
5
+ # mediate files.
6
+ #
7
+ # @example
8
+ # # Concatenate
9
+ # combiner = Sox::Combiner.new('in1.mp3', 'in2.ogg', 'in3.wav', :combine => :concatenate)
10
+ # combiner.write('out.mp3')
11
+ class Combiner
12
+
13
+ autoload :BaseStrategy , 'sox/combiner/base_strategy'
14
+ autoload :TmpFileStrategy , 'sox/combiner/tmp_file_strategy'
15
+ autoload :ProcessSubstitutionStrategy, 'sox/combiner/process_substitution_strategy'
16
+
17
+ # Default options
18
+ DEFAULT_OPTIONS = {
19
+ # Method to be used for combining sounds. See --combine of sox tool.
20
+ :combine => :concatenate,
21
+
22
+ # Number of channels in the output file.
23
+ :channels => 1,
24
+
25
+ # Rate(samples per seconds) of the output file.
26
+ :rate => 22050,
27
+
28
+ # Apply norm effect on output.
29
+ :norm => false,
30
+
31
+ # Strategy to convert input files into files with the same rates
32
+ # and channels.
33
+ :strategy => :process_substitution
34
+ }
35
+
36
+ # Mapping of strategy names and their implementations
37
+ STRATEGIES = {
38
+ :tmp_file => TmpFileStrategy,
39
+ :process_substitution => ProcessSubstitutionStrategy
40
+ }
41
+
42
+
43
+ # @param input_files [Array<String>] input files
44
+ # @param options [Hash]
45
+ #
46
+ # @option options :combine [Symbol] value for +--combine+ sox option.
47
+ # Use underscore instead of hyphen, e.g. :mix_power.
48
+ # @option options :channels [Integer] number of channels in output file.
49
+ # @option options :rate [Integer] rate of output file
50
+ # @option options :norm [Boolean] apply +norm+ effect on output.
51
+ # @option options :strategy [Symbol] strategy to treat temporary files,
52
+ # default is :process_substitution which reduces disk IO.
53
+ def initialize(input_files, options = {})
54
+ raise(ArgumentError, "Input files are missing") if input_files.empty?
55
+
56
+ opts = DEFAULT_OPTIONS.merge(options)
57
+ strategy_name = opts.delete(:strategy)
58
+ strategy_class = STRATEGIES[strategy_name]
59
+ raise(ArgumentError, "Unknown strategy #{strategy_name.inspect}") unless strategy_class
60
+
61
+ @strategy = strategy_class.new(input_files, opts)
62
+ end
63
+
64
+ # Run +sox+ command and write output to file.
65
+ #
66
+ # @param output_file [String] path of output file
67
+ #
68
+ # @return [void]
69
+ def write(output_file)
70
+ @strategy.write(output_file)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,98 @@
1
+ module Sox
2
+ # Builds the +sox+ shell command from input files, an output file, options
3
+ # and effects.
4
+ #
5
+ # @example
6
+ # builder = Sox::CommandBuilder.new(['in1.mp3', 'in2.ogg'], 'out.wav',
7
+ # {:combine => :mix},
8
+ # {:rate => 44100, :channels => 2}
9
+ # )
10
+ # builder.build # => "sox --combine mix in1.mp3 in2.ogg out.wav rate 44100 channels 2"
11
+ class CommandBuilder
12
+ attr_accessor :input_files, :output_file, :options, :effects
13
+
14
+ # @param input_files [Array<Sox::File>]
15
+ # @param output_file [Sox::File]
16
+ # @param options [Hash{Symbol => Symbol}]
17
+ # @param effects [Hash{Symbol => Symbol}]
18
+ def initialize(input_files, output_file, options = {}, effects = {})
19
+ @input_files = input_files
20
+ @output_file = output_file
21
+ @options = options
22
+ @effects = effects
23
+ end
24
+
25
+ # Build shell command with all arguments and options.
26
+ #
27
+ # @return [String]
28
+ def build
29
+ [ Sox::SOX_COMMAND,
30
+ build_options(@options),
31
+ build_input_files,
32
+ build_file(@output_file),
33
+ build_effects
34
+ ].flatten.join(' ')
35
+ end
36
+
37
+
38
+ # Build input files with their options.
39
+ #
40
+ # @return [Array<String>]
41
+ def build_input_files
42
+ @input_files.map { |file| build_file(file) }
43
+ end
44
+ private :build_input_files
45
+
46
+ # Build part of SoX command which represents file(input or output).
47
+ #
48
+ # @param file [Sox::File] file
49
+ #
50
+ # @return [String]
51
+ def build_file(file)
52
+ opts = build_options(file.options)
53
+ file_path = file.escaped? ? file.path : Shellwords.escape(file.path)
54
+ [opts, file_path]
55
+ end
56
+ private :build_file
57
+
58
+ # Build options with their values (if present) to be used in shell command.
59
+ #
60
+ # @param options [Hash] options
61
+ #
62
+ # @return [Array<String>] options to be concatenated into string
63
+ def build_options(options)
64
+ options.inject([]) do |result, (opt, val)|
65
+ if val
66
+ result << "--#{shellify_opt(opt)}"
67
+ result << shellify_opt(val) if val != true
68
+ end
69
+ result
70
+ end
71
+ end
72
+ private :build_options
73
+
74
+ # Build effects with their arguments (if present) to be used in shell command.
75
+ #
76
+ # @return [Array<String>] effects to be concatenated into string
77
+ def build_effects
78
+ @effects.inject([]) do |result, (effect, val)|
79
+ if val
80
+ result << effect
81
+ result << val.to_s if val != true
82
+ end
83
+ result
84
+ end
85
+ end
86
+ private :build_effects
87
+
88
+ # Convert option or its value to shell style, separating words with "-".
89
+ #
90
+ # @param value [Symbol, String] option or value
91
+ #
92
+ # @return [String] shellified option
93
+ def shellify_opt(value)
94
+ value.to_s.gsub('_', '-')
95
+ end
96
+ private :shellify_opt
97
+ end
98
+ end
data/lib/sox/file.rb ADDED
@@ -0,0 +1,29 @@
1
+ module Sox
2
+ # Represents input or output file with its options for the `sox` command.
3
+ class File
4
+ # Path to file or whatever.
5
+ attr_reader :path
6
+
7
+ # File options which will be placed right before it.
8
+ attr_reader :options
9
+
10
+ # True if path doesn't need to be escaped.
11
+ attr_accessor :escaped
12
+
13
+
14
+ # @param path [String] path to file
15
+ # @param options [Hash{Symbol => Symbol,String,Numeric}] file options
16
+ def initialize(path, options = {})
17
+ @path = path
18
+ @options = options
19
+ @escaped = false
20
+ end
21
+
22
+ # Does the path need to be escaped?
23
+ #
24
+ # @return [Boolean]
25
+ def escaped?
26
+ @escaped
27
+ end
28
+ end
29
+ end
data/lib/sox/shell.rb ADDED
@@ -0,0 +1,45 @@
1
+ module Sox
2
+ # Provides methods to run the command in the +/bin/sh+ and +/bin/bash+
3
+ # interpreters. Ruby's `system` method runs +/bin/sh+ which doesn't support
4
+ # the process substitution feature. So sometimes we need to use bash with
5
+ # process substitution in order to avoid disk IO operations.
6
+ #
7
+ # Also this module takes care of error handling and raises {Sox::Error} when
8
+ # a failure message is returned by the shell command.
9
+ #
10
+ # See http://en.wikipedia.org/wiki/Process_substitution
11
+ module Shell
12
+ # Path to the +bash+ interpreter:
13
+ BASH_PATH = '/bin/bash'
14
+
15
+ # Run a shell command.
16
+ #
17
+ # @param command [String] shell command to execute
18
+ #
19
+ # @return [Boolean] true in case of success
20
+ def sh(command)
21
+ _, _, err_io, thread = Open3.popen3(command)
22
+ thread.join
23
+
24
+ process_status = thread.value
25
+ if process_status.success?
26
+ true
27
+ else
28
+ raise Error, err_io.read
29
+ end
30
+ rescue Errno::ENOENT => err
31
+ msg = "#{err.message}. Do you have `#{SOX_COMMAND}' installed?"
32
+ raise Error, msg
33
+ end
34
+
35
+ # Run bash command.
36
+ #
37
+ # @param command [String] bash command to execute
38
+ #
39
+ # @return [Boolean] true in case of success
40
+ def bash(command)
41
+ bash_command = "#{BASH_PATH} -c #{Shellwords.escape(command)}"
42
+ sh(bash_command)
43
+ end
44
+ end
45
+ end
data/lib/sox.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'shellwords'
2
+ require 'open3'
3
+ require 'tempfile'
4
+
5
+ # Wrapper around the +sox+ command line tool.
6
+ module Sox
7
+ # Basic SoX error:
8
+ class Error < StandardError
9
+ end
10
+
11
+ # The SoX command:
12
+ SOX_COMMAND = 'sox'.freeze
13
+ end
14
+
15
+ require 'sox/file'
16
+ require 'sox/shell'
17
+ require 'sox/command_builder'
18
+ require 'sox/cmd'
19
+ require 'sox/combiner'
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-sox
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Potapov Sergey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: jeweler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.7
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 1.8.7
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard-rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: metric_fu
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Wrapper around sox sound tool
84
+ email: blake131313@gmail.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files:
88
+ - LICENSE.txt
89
+ - README.markdown
90
+ files:
91
+ - LICENSE.txt
92
+ - README.markdown
93
+ - lib/ruby-sox.rb
94
+ - lib/sox.rb
95
+ - lib/sox/cmd.rb
96
+ - lib/sox/combiner.rb
97
+ - lib/sox/combiner/base_strategy.rb
98
+ - lib/sox/combiner/process_substitution_strategy.rb
99
+ - lib/sox/combiner/tmp_file_strategy.rb
100
+ - lib/sox/command_builder.rb
101
+ - lib/sox/file.rb
102
+ - lib/sox/shell.rb
103
+ homepage: http://github.com/greyblake/ruby-sox
104
+ licenses:
105
+ - MIT
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.0.3
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Wrapper around sox sound tool
127
+ test_files: []
128
+ has_rdoc: