audio_glue 0.1.0
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/LICENSE.txt +20 -0
- data/README.markdown +148 -0
- data/lib/audio_glue.rb +35 -0
- data/lib/audio_glue/base_adapter.rb +21 -0
- data/lib/audio_glue/builder.rb +40 -0
- data/lib/audio_glue/snippet.rb +36 -0
- data/lib/audio_glue/snippet_packet.rb +25 -0
- data/lib/audio_glue/template.rb +152 -0
- data/lib/audio_glue/template/head_context.rb +40 -0
- data/lib/audio_glue/template_loader.rb +78 -0
- metadata +129 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 1c31ccdeefe481d8de76901107ceba5892ddbaac
|
|
4
|
+
data.tar.gz: 2b91e5f9b841f4a6f6bd19aabe790e227f91e5d0
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c30e801164ff09e7b0295a8f4b84a5e5c10ab9cc7e11d4b8eaa38d0d01439664df941463064b52d133a0adc1a24ac21846adc1297b91ecdcf22e063eaf881dfd
|
|
7
|
+
data.tar.gz: d1b7c8166a480ae8a67ee2dac987056f25258bfea178476d09a8daf5f80bdc1c26a612ea669f0d159eb2e9fc7057870f775099d277343e51585a547544466da3
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
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.
|
data/README.markdown
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# AudioGlue
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/TMXCredit/audio_glue)
|
|
4
|
+
|
|
5
|
+
Audio template engine (aka ERB/HAML for audio).
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
An example:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
require 'audio_glue'
|
|
13
|
+
|
|
14
|
+
# We need to use one of the adapters.
|
|
15
|
+
# This one comes from the audio_glue-sox_adapter gem:
|
|
16
|
+
require 'audio_glue/sox_adapter'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Create a template class:
|
|
20
|
+
class HelloWorldTemplate < AudioGlue::Template
|
|
21
|
+
# Specify the characteristics of an output audio file:
|
|
22
|
+
head do
|
|
23
|
+
format :mp3
|
|
24
|
+
rate 44100
|
|
25
|
+
channels 2
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Lets concatenate 2 mp3 files:
|
|
29
|
+
body do
|
|
30
|
+
- file("/sounds/hello.mp3") # Local file
|
|
31
|
+
|
|
32
|
+
if @say_name
|
|
33
|
+
- url("http://some-service.com/my-name-is-glue.mp3") # Remote file
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Initialize a template:
|
|
39
|
+
template = HelloWorldTemplate.new(:say_name => true)
|
|
40
|
+
|
|
41
|
+
# Optionally, build using an adapter:
|
|
42
|
+
adapter = AudioGlue::PlainSoxAdapter.new
|
|
43
|
+
builder = AudioGlue::Builder.new(adapter)
|
|
44
|
+
|
|
45
|
+
# Process a template to get audio data:
|
|
46
|
+
audio = builder.build(template) # => audio as a binary string
|
|
47
|
+
|
|
48
|
+
# Write the result to a local file:
|
|
49
|
+
File.binwrite("/hello_world.mp3", audio)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Templates
|
|
53
|
+
|
|
54
|
+
A glue template is a template file (e.g. like ERB or HAML) which defines how
|
|
55
|
+
the output audio should be built.
|
|
56
|
+
In Ruby terms, it's a subclass of `AudioGlue::Template`.
|
|
57
|
+
|
|
58
|
+
#### Glue templates
|
|
59
|
+
|
|
60
|
+
In the example above, the template inherits from `AudioGlue::Template`.
|
|
61
|
+
But you can also store templates in `.glue` files.
|
|
62
|
+
For example `/path/to/templates/hello_world.glue`:
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
head {
|
|
66
|
+
format :mp3
|
|
67
|
+
rate 44100
|
|
68
|
+
channels 2
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
body {
|
|
72
|
+
- file("/sounds/hello.mp3")
|
|
73
|
+
if @say_name
|
|
74
|
+
- url("http://some-service.com/my-name-is-glue.mp3")
|
|
75
|
+
end
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
And then we can load it with `AudioGlue::TemplateLoader`:
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
# Create an instance of the loader with a basic directory,
|
|
83
|
+
# where templates are located:
|
|
84
|
+
loader = TemplateLoader.new("/path/to/templates")
|
|
85
|
+
|
|
86
|
+
# Load and cache the template:
|
|
87
|
+
loader.get("hello_world") # => anonymous subclass of AudioGlue::Template
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### Glue Syntax
|
|
91
|
+
|
|
92
|
+
Each glue template has 2 sections:
|
|
93
|
+
|
|
94
|
+
* `head` - contains the parameters of the output file (`format`, `rate`, `channels`)
|
|
95
|
+
* `body` - specifies how to build the output
|
|
96
|
+
|
|
97
|
+
The `body` references the audio snippets that will be used to build the output
|
|
98
|
+
audio. There a few types of snippets:
|
|
99
|
+
|
|
100
|
+
* `file` - points to an audio file in the local file system
|
|
101
|
+
* `url` - contains a URL to a remote audio file
|
|
102
|
+
|
|
103
|
+
To make a snippet be added to the output it should have a dash prefix (`-`).
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
### Custom adapters
|
|
107
|
+
|
|
108
|
+
You may want to create your own adapter to concatenate audio files, if you
|
|
109
|
+
think the existing one is not efficient, or if you want to add some caching.
|
|
110
|
+
|
|
111
|
+
The responsibility of adapters is to build audio data from
|
|
112
|
+
`AudioGlue::SnippetPacket`. The snippet packet is a collection of audio
|
|
113
|
+
snippets and output file characteristics(format, rate, channels).
|
|
114
|
+
|
|
115
|
+
A very simple adapter could look like this:
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
# Doesn't support :url snippets, only files in local file system.
|
|
119
|
+
# Doesn't handle rate and channels.
|
|
120
|
+
class SimpleAdapter < AudioGlue::BaseAdapter
|
|
121
|
+
# Only this method is required to be implemented.
|
|
122
|
+
def build(snippet_packet)
|
|
123
|
+
# Extract file paths from snippets.
|
|
124
|
+
# Ensure only :file snippets are present.
|
|
125
|
+
file_paths = snippet_packet.snippets.map do |snippet|
|
|
126
|
+
unless snippet.type == :file
|
|
127
|
+
raise(AudioGlue::Error, "Only file snippets are supported")
|
|
128
|
+
end
|
|
129
|
+
snippets.source
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Build cat command
|
|
133
|
+
command = "cat #{file_paths.join(' ')}"
|
|
134
|
+
|
|
135
|
+
# Concatenate files and return result
|
|
136
|
+
%{command}
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
## Credits
|
|
143
|
+
|
|
144
|
+
* [Sergey Potapov](https://github.com/greyblake)
|
|
145
|
+
|
|
146
|
+
## Copyright
|
|
147
|
+
|
|
148
|
+
Copyright (c) 2013 TMX Credit.
|
data/lib/audio_glue.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'tempfile'
|
|
4
|
+
|
|
5
|
+
require 'audio_glue/snippet'
|
|
6
|
+
require 'audio_glue/snippet_packet'
|
|
7
|
+
require 'audio_glue/template/head_context'
|
|
8
|
+
require 'audio_glue/template'
|
|
9
|
+
require 'audio_glue/base_adapter'
|
|
10
|
+
require 'audio_glue/builder'
|
|
11
|
+
|
|
12
|
+
require 'audio_glue/template_loader'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# AudioGlue is a library to concatenate audio snippets using templates.
|
|
16
|
+
# Consider it like ERB or HAML for audio files, where input is not text
|
|
17
|
+
# snippets, but audio snippets, and output is not text, but audio.
|
|
18
|
+
module AudioGlue
|
|
19
|
+
# Basic error for AudioGlue errors.
|
|
20
|
+
class Error < StandardError
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Raised on an attempt to call an unimplemented method of an object which
|
|
24
|
+
# a class inherits from an abstract class.
|
|
25
|
+
class AbstractMethodCallError < Error
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Raised on a failed attempt to load a glue template.
|
|
29
|
+
class LoadTemplateError < Error
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Raised when audio data fails to be built.
|
|
33
|
+
class BuildError < Error
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module AudioGlue
|
|
2
|
+
# Base adapter that specifies interface for all adapters.
|
|
3
|
+
# The responsibility of an adapter is to build an output audio file
|
|
4
|
+
# from a {AudioGlue::SnippetPacket snippet packet}, which provides
|
|
5
|
+
# a collection of input audio sources and some parameters for the output file
|
|
6
|
+
# (rate, number of channels).
|
|
7
|
+
#
|
|
8
|
+
# An adapter can rely on different tools and libraries to process audio
|
|
9
|
+
# files. Also an adapter is responsible for correctly processing remote files
|
|
10
|
+
# (e.g. downloading them as temporary files if necessary).
|
|
11
|
+
class BaseAdapter
|
|
12
|
+
# Build audio file from a snippet packet and return result as binary string.
|
|
13
|
+
#
|
|
14
|
+
# @param snippet_packet [AudioGlue::SnippetPacket]
|
|
15
|
+
#
|
|
16
|
+
# @return [String]
|
|
17
|
+
def build(snippet_packet)
|
|
18
|
+
raise AbstractMethodCallError, __method__
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module AudioGlue
|
|
2
|
+
# Builds audio from a {AudioGlue::Template template} instance.
|
|
3
|
+
#
|
|
4
|
+
# @example
|
|
5
|
+
# # Instantiate the builder with an adapter:
|
|
6
|
+
# builder = AudioGlue::Builder.new(AudioGlue::PlainSoxAdapter.new)
|
|
7
|
+
#
|
|
8
|
+
# # Create the template instance:
|
|
9
|
+
# template = HiTemplate.new(:with_smalltalk => true)
|
|
10
|
+
#
|
|
11
|
+
# # Build the output audio:
|
|
12
|
+
# builder.build(template) # => audio as a binary string
|
|
13
|
+
class Builder
|
|
14
|
+
# @param adapter [AudioGlue::BaseAdapter] instance of an adapter
|
|
15
|
+
def initialize(adapter)
|
|
16
|
+
@adapter = adapter
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Build an audio file and return the result as a binary string.
|
|
20
|
+
#
|
|
21
|
+
# @param template [AudioGlue::Template]
|
|
22
|
+
# @param opts [Hash]
|
|
23
|
+
#
|
|
24
|
+
# @option opts :format [Symbol, String]
|
|
25
|
+
# @option opts :rate [Integer, String]
|
|
26
|
+
# @option opts :channels [Integer, String]
|
|
27
|
+
#
|
|
28
|
+
# @return [String]
|
|
29
|
+
def build(template, opts = {})
|
|
30
|
+
format, rate, channels = opts[:format], opts[:rate], opts[:channels]
|
|
31
|
+
|
|
32
|
+
packet = template.build_snippet_packet
|
|
33
|
+
packet.format = format if format
|
|
34
|
+
packet.rate = rate if rate
|
|
35
|
+
packet.channels = channels if channels
|
|
36
|
+
|
|
37
|
+
@adapter.build(packet)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module AudioGlue
|
|
2
|
+
# Represents an audio partial which will be used to build an output audio.
|
|
3
|
+
# There are a few types of snippets:
|
|
4
|
+
# * :file - represents audio file in local file system
|
|
5
|
+
# * :url - represents remote audio file
|
|
6
|
+
#
|
|
7
|
+
# Other custom types can be created if custom adapter will support them.
|
|
8
|
+
#
|
|
9
|
+
# {AudioGlue::BaseAdapter adapters} are responsible for processing every
|
|
10
|
+
# particular snippet type.
|
|
11
|
+
class Snippet
|
|
12
|
+
attr_reader :type, :source, :snippet_packet, :opts
|
|
13
|
+
|
|
14
|
+
# @param type [Symbol] :file, :url or anything else that can be handled by
|
|
15
|
+
# the adapter
|
|
16
|
+
# @param source [String] Can be location, URL, or whatever depending on type
|
|
17
|
+
# @param snippet_packet [AudioGlue::SnippetPacket] the snippet packet used
|
|
18
|
+
# to add the audio snippet to the packet when `-` unary method is called
|
|
19
|
+
# @param opts [Hash] any specific options which are supported by adapter
|
|
20
|
+
def initialize(type, source, snippet_packet, opts = {})
|
|
21
|
+
@type = type
|
|
22
|
+
@source = source
|
|
23
|
+
@snippet_packet = snippet_packet
|
|
24
|
+
@opts = opts
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Add self to the snippet packet.
|
|
28
|
+
# It's used to support dash syntax in +.glue+ files, like:
|
|
29
|
+
# - file('/audio.mp3')
|
|
30
|
+
#
|
|
31
|
+
# @return [void]
|
|
32
|
+
def -@
|
|
33
|
+
@snippet_packet << self
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module AudioGlue
|
|
2
|
+
# SnippetPacket is a collection of {AudioGlue::Snippet snippets} with
|
|
3
|
+
# some additional info about the output file
|
|
4
|
+
# (format, rate, number of channels).
|
|
5
|
+
#
|
|
6
|
+
# It's supposed to be built by {AudioGlue::Template}. And then it's passed
|
|
7
|
+
# to an adapter which builds the audio output.
|
|
8
|
+
class SnippetPacket
|
|
9
|
+
extend Forwardable
|
|
10
|
+
def_delegators :@snippets, :<<
|
|
11
|
+
|
|
12
|
+
attr_accessor :format, :rate, :channels
|
|
13
|
+
attr_reader :snippets
|
|
14
|
+
|
|
15
|
+
# @param format [Symbol, String]
|
|
16
|
+
# @param rate [Numeric, String]
|
|
17
|
+
# @param channels [Numeric, String]
|
|
18
|
+
def initialize(format, rate, channels)
|
|
19
|
+
@format = format
|
|
20
|
+
@rate = rate
|
|
21
|
+
@channels = channels
|
|
22
|
+
@snippets = []
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
module AudioGlue
|
|
2
|
+
# Represents an audio template.
|
|
3
|
+
# Every particular template is a subclass of {AudioGlue::Template}.
|
|
4
|
+
# Quite often the classes can be anonymous. (That's why +inspect+ is redefined
|
|
5
|
+
# to provide more information.)
|
|
6
|
+
#
|
|
7
|
+
# The Template class owns +format+, +rate+, +channels+, and also a block used
|
|
8
|
+
# to create an {AudioGlue::SnippetPacket}
|
|
9
|
+
# ("render", in terms of the view templates).
|
|
10
|
+
#
|
|
11
|
+
# A Template instance differs from the Template class. It has instance
|
|
12
|
+
# variables, that can be used in the +body+ block.
|
|
13
|
+
#
|
|
14
|
+
# @example
|
|
15
|
+
# class HiTemplate < AudioGlue::Template
|
|
16
|
+
# # Output file information
|
|
17
|
+
# head do
|
|
18
|
+
# format :mo3
|
|
19
|
+
# rate 22050
|
|
20
|
+
# channels 2
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# # Block to "render" template
|
|
24
|
+
# body do
|
|
25
|
+
# - file('/hi.mp3')
|
|
26
|
+
# if @with_smalltalk
|
|
27
|
+
# - url('http://say.it/how-are-you.mp3')
|
|
28
|
+
# end
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# # Create an instance of Template. We wonder how our friend is doing so
|
|
33
|
+
# # we pass ":with_smalltalk => true", to add a remote URL snippet.
|
|
34
|
+
# template = HiTemplate.new(:with_smalltalk => true)
|
|
35
|
+
#
|
|
36
|
+
# # Let's create a snippet packet:
|
|
37
|
+
# packet = template.build_snippet_packet => # <AudioGlue::SnippetPacket ..>
|
|
38
|
+
# # Now we can pass a snippet packet to the adapter to build output audio.
|
|
39
|
+
class Template
|
|
40
|
+
extend Forwardable
|
|
41
|
+
def_delegators 'self.class', :format, :rate, :channels, :path, :body_proc
|
|
42
|
+
|
|
43
|
+
class << self
|
|
44
|
+
attr_accessor :format, :rate, :channels, :path, :body_proc
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Process the +head+ block in a +.glue+ template.
|
|
48
|
+
#
|
|
49
|
+
# @yield block which will be executed in context of
|
|
50
|
+
# {AudioGlue::Template::HeadContext} object.
|
|
51
|
+
#
|
|
52
|
+
# @return [void]
|
|
53
|
+
def self.head(&block)
|
|
54
|
+
HeadContext.new(self).instance_eval(&block)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Process the +body+ block in a +.glue+ template.
|
|
58
|
+
#
|
|
59
|
+
# @yield block which will be executed in context of
|
|
60
|
+
# {AudioGlue::Template::BodyContext} object. It should define body of
|
|
61
|
+
# audio template.
|
|
62
|
+
# @return [void]
|
|
63
|
+
def self.body(&block)
|
|
64
|
+
self.body_proc = block
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Redefine the +inspect+ method to provide more information when the
|
|
68
|
+
# template is an anonymous class.
|
|
69
|
+
#
|
|
70
|
+
# @return [String]
|
|
71
|
+
def self.inspect
|
|
72
|
+
if self.name
|
|
73
|
+
super
|
|
74
|
+
else
|
|
75
|
+
info = "<AudioGlue::Template(class)"
|
|
76
|
+
info << " path=#{path.inspect}" if path
|
|
77
|
+
info << ">"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# @param variables [Hash] hash of parameters which can be used as instance
|
|
83
|
+
# variables in +body+ statement of +.glue+ template.
|
|
84
|
+
def initialize(variables = {})
|
|
85
|
+
variables.each do |var, value|
|
|
86
|
+
instance_variable_set("@#{var}", value)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Execute the body of the template to build a snippet packet.
|
|
91
|
+
#
|
|
92
|
+
# @return [AudioGlue::SnippetPacket]
|
|
93
|
+
def build_snippet_packet
|
|
94
|
+
@__packet__ = SnippetPacket.new(format, rate, channels)
|
|
95
|
+
instance_eval(&body_proc)
|
|
96
|
+
@__packet__
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Redefine +inspect+ to provide more information if the class of the
|
|
100
|
+
# template object is anonymous.
|
|
101
|
+
#
|
|
102
|
+
# @return [String]
|
|
103
|
+
def inspect
|
|
104
|
+
if self.class.name
|
|
105
|
+
super
|
|
106
|
+
else
|
|
107
|
+
info = "<AudioGlue::Template"
|
|
108
|
+
info << "(path=#{path.inspect})" if path
|
|
109
|
+
|
|
110
|
+
instance_variables.each do |var|
|
|
111
|
+
info << " #{var}="
|
|
112
|
+
info << instance_variable_get(var).inspect
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
info << ">"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# Create a snippet (with the +:file+ type) for the given audio file.
|
|
121
|
+
#
|
|
122
|
+
# @param file_path [String] path to an audio file in local file system
|
|
123
|
+
#
|
|
124
|
+
# @return [AudioGlue::Snippet]
|
|
125
|
+
def file(file_path)
|
|
126
|
+
create_snippet(:file, file_path)
|
|
127
|
+
end
|
|
128
|
+
private :file
|
|
129
|
+
|
|
130
|
+
# Create a snippet (with +:url+ type) for the given audio URL.
|
|
131
|
+
#
|
|
132
|
+
# @param remote_url [String] remote location of audio file
|
|
133
|
+
#
|
|
134
|
+
# @return [AudioGlue::Snippet]
|
|
135
|
+
def url(remote_url)
|
|
136
|
+
create_snippet(:url, remote_url)
|
|
137
|
+
end
|
|
138
|
+
private :url
|
|
139
|
+
|
|
140
|
+
# Create snippet.
|
|
141
|
+
#
|
|
142
|
+
# @param type [Symbol] snippet type
|
|
143
|
+
# @param source [String]
|
|
144
|
+
# @param opts [Hash] any options supported by adapter
|
|
145
|
+
#
|
|
146
|
+
# @return [AudioGlue::Snippet]
|
|
147
|
+
def create_snippet(type, source, opts = {})
|
|
148
|
+
Snippet.new(type, source, @__packet__, opts)
|
|
149
|
+
end
|
|
150
|
+
private :create_snippet
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module AudioGlue
|
|
2
|
+
class Template
|
|
3
|
+
# The context in which the +head+ statement of a +.glue+ template is
|
|
4
|
+
# executed. It's used to set the +format+, +rate+ and +channels+ on
|
|
5
|
+
# the template.
|
|
6
|
+
class HeadContext
|
|
7
|
+
# @param template [Class] subclass of {AudioGlue::Template}
|
|
8
|
+
def initialize(template)
|
|
9
|
+
@template = template
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Set the audio format on the template ("mp3", "ogg", "wav", etc).
|
|
13
|
+
#
|
|
14
|
+
# @param format_value [Symbol, String]
|
|
15
|
+
#
|
|
16
|
+
# @return [void]
|
|
17
|
+
def format(format_value)
|
|
18
|
+
@template.format = format_value
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Set the audio bitrate on the template.
|
|
22
|
+
#
|
|
23
|
+
# @param rate_value [Integer, String]
|
|
24
|
+
#
|
|
25
|
+
# @return [void]
|
|
26
|
+
def rate(rate_value)
|
|
27
|
+
@template.rate = rate_value
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Set the number of channels on the template.
|
|
31
|
+
#
|
|
32
|
+
# @param channels_value [Integer, String]
|
|
33
|
+
#
|
|
34
|
+
# @return [void]
|
|
35
|
+
def channels(channels_value)
|
|
36
|
+
@template.channels = channels_value
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module AudioGlue
|
|
2
|
+
# Loads +.glue+ templates and caches them.
|
|
3
|
+
#
|
|
4
|
+
# @example
|
|
5
|
+
# loader = AudioGlue::TemplateLoader.new('/project/audio_templates/')
|
|
6
|
+
#
|
|
7
|
+
# # load and cache "/project/audio_templates/john/hi.glue"
|
|
8
|
+
# loader.get('john/hi') # => subclass of AudioGlue::Template
|
|
9
|
+
class TemplateLoader
|
|
10
|
+
# Extension of template files.
|
|
11
|
+
TEMPLATE_EXT = 'glue'
|
|
12
|
+
|
|
13
|
+
# @attr_reader base_path [String] path to a directory with templates
|
|
14
|
+
attr_reader :base_path
|
|
15
|
+
|
|
16
|
+
# @attr_reader cache [Hash<String, Class>] cached templates, key is a path
|
|
17
|
+
# to a template file, value is a subclass of {AudioGlue::Template}
|
|
18
|
+
attr_reader :cache
|
|
19
|
+
|
|
20
|
+
# @param base_path [String] path to a directory with templates
|
|
21
|
+
# @param opts [Hash] options
|
|
22
|
+
# @option opts :helper [Module] module which provides custom methods
|
|
23
|
+
# for templates.
|
|
24
|
+
def initialize(base_path, opts = {})
|
|
25
|
+
@base_path = base_path
|
|
26
|
+
@helper = opts.delete(:helper)
|
|
27
|
+
@cache = {}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Load and cache the template from a +.glue+ template file.
|
|
31
|
+
#
|
|
32
|
+
# @param template_name [String] name of template in +base_path+ directory
|
|
33
|
+
#
|
|
34
|
+
# @return [Class] a subclass of {AudioGlue::Template}
|
|
35
|
+
def get(template_name)
|
|
36
|
+
path = absolute_path(template_name)
|
|
37
|
+
@cache[path] ||= load_template_from_file(path)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Reset the cache.
|
|
41
|
+
#
|
|
42
|
+
# @return [Hash] empty cache
|
|
43
|
+
def reset_cache!
|
|
44
|
+
@cache.clear
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# Calculate the absolute path to a file from a template name.
|
|
50
|
+
#
|
|
51
|
+
# @param template_name [String] name of template in +base_path+ directory
|
|
52
|
+
#
|
|
53
|
+
# @return [String] absolute path to a template file
|
|
54
|
+
def absolute_path(template_name)
|
|
55
|
+
File.join(@base_path, "#{template_name}.#{TEMPLATE_EXT}")
|
|
56
|
+
end
|
|
57
|
+
private :absolute_path
|
|
58
|
+
|
|
59
|
+
# Read a +.glue+ template file and create a template class from it.
|
|
60
|
+
#
|
|
61
|
+
# @param path [String] absolute path to .glue template file
|
|
62
|
+
#
|
|
63
|
+
# @return [Class] a subclass of {AudioGlue::Template}
|
|
64
|
+
def load_template_from_file(path)
|
|
65
|
+
Class.new(AudioGlue::Template).tap do |template|
|
|
66
|
+
content = File.read(path)
|
|
67
|
+
template.path = path
|
|
68
|
+
template.send(:include, @helper) if @helper
|
|
69
|
+
template.instance_eval(content, path)
|
|
70
|
+
end
|
|
71
|
+
rescue Errno::ENOENT => err
|
|
72
|
+
raise AudioGlue::LoadTemplateError, err.message
|
|
73
|
+
rescue SyntaxError, NameError => err
|
|
74
|
+
raise AudioGlue::LoadTemplateError, err.message, err.backtrace
|
|
75
|
+
end
|
|
76
|
+
private :load_template_from_file
|
|
77
|
+
end
|
|
78
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: audio_glue
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- TMX Credit
|
|
8
|
+
- Potapov Sergey
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-10-24 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: bundler
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
requirements:
|
|
18
|
+
- - ~>
|
|
19
|
+
- !ruby/object:Gem::Version
|
|
20
|
+
version: '1.0'
|
|
21
|
+
type: :development
|
|
22
|
+
prerelease: false
|
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
24
|
+
requirements:
|
|
25
|
+
- - ~>
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
version: '1.0'
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: jeweler
|
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ~>
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: 1.8.7
|
|
35
|
+
type: :development
|
|
36
|
+
prerelease: false
|
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
38
|
+
requirements:
|
|
39
|
+
- - ~>
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: 1.8.7
|
|
42
|
+
- !ruby/object:Gem::Dependency
|
|
43
|
+
name: yard
|
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - '>='
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0'
|
|
49
|
+
type: :development
|
|
50
|
+
prerelease: false
|
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - '>='
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '0'
|
|
56
|
+
- !ruby/object:Gem::Dependency
|
|
57
|
+
name: pry
|
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - '>='
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '0'
|
|
63
|
+
type: :development
|
|
64
|
+
prerelease: false
|
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - '>='
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '0'
|
|
70
|
+
- !ruby/object:Gem::Dependency
|
|
71
|
+
name: metric_fu
|
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
|
73
|
+
requirements:
|
|
74
|
+
- - '>='
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '0'
|
|
77
|
+
type: :development
|
|
78
|
+
prerelease: false
|
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
80
|
+
requirements:
|
|
81
|
+
- - '>='
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: '0'
|
|
84
|
+
description: Tool to assemble audio files from templates
|
|
85
|
+
email:
|
|
86
|
+
- rubygems@tmxcredit.com
|
|
87
|
+
- blake131313@gmail.com
|
|
88
|
+
executables: []
|
|
89
|
+
extensions: []
|
|
90
|
+
extra_rdoc_files:
|
|
91
|
+
- LICENSE.txt
|
|
92
|
+
- README.markdown
|
|
93
|
+
files:
|
|
94
|
+
- LICENSE.txt
|
|
95
|
+
- README.markdown
|
|
96
|
+
- lib/audio_glue.rb
|
|
97
|
+
- lib/audio_glue/base_adapter.rb
|
|
98
|
+
- lib/audio_glue/builder.rb
|
|
99
|
+
- lib/audio_glue/snippet.rb
|
|
100
|
+
- lib/audio_glue/snippet_packet.rb
|
|
101
|
+
- lib/audio_glue/template.rb
|
|
102
|
+
- lib/audio_glue/template/head_context.rb
|
|
103
|
+
- lib/audio_glue/template_loader.rb
|
|
104
|
+
homepage: http://github.com/TMXCredit/audio_glue
|
|
105
|
+
licenses:
|
|
106
|
+
- MIT
|
|
107
|
+
metadata: {}
|
|
108
|
+
post_install_message:
|
|
109
|
+
rdoc_options: []
|
|
110
|
+
require_paths:
|
|
111
|
+
- lib
|
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - '>='
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0'
|
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
|
+
requirements:
|
|
119
|
+
- - '>='
|
|
120
|
+
- !ruby/object:Gem::Version
|
|
121
|
+
version: '0'
|
|
122
|
+
requirements: []
|
|
123
|
+
rubyforge_project:
|
|
124
|
+
rubygems_version: 2.0.3
|
|
125
|
+
signing_key:
|
|
126
|
+
specification_version: 4
|
|
127
|
+
summary: aka ERB for audio files
|
|
128
|
+
test_files: []
|
|
129
|
+
has_rdoc:
|