serinette 0.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.bundle/config +2 -0
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/.travis.yml +23 -0
- data/CHANGELOG.md +10 -0
- data/CONTRIBUTING.md +3 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +22 -0
- data/README.md +107 -0
- data/Rakefile +16 -0
- data/data/sounds/haunting_voices.wav +0 -0
- data/data/sounds/hypnotic_loop.wav +0 -0
- data/dependencies.rb +4 -0
- data/lib/mixins/descendents.rb +15 -0
- data/lib/mixins/sox_options.rb +59 -0
- data/lib/serinette/effect.rb +22 -0
- data/lib/serinette/noise.rb +19 -0
- data/lib/serinette/reverb_effect.rb +63 -0
- data/lib/serinette/song.rb +70 -0
- data/lib/serinette/source_noise.rb +23 -0
- data/lib/serinette/synth_noise.rb +74 -0
- data/lib/serinette/track.rb +24 -0
- data/lib/serinette/version.rb +3 -0
- data/lib/serinette.rb +57 -0
- data/lib/utils/file_name.rb +7 -0
- data/lib/utils/sox_wrapper.rb +41 -0
- data/serinette.gemspec +25 -0
- data/spec/serinette/effect_spec.rb +16 -0
- data/spec/serinette/mixins/descendents_spec.rb +17 -0
- data/spec/serinette/mixins/sox_options_spec.rb +69 -0
- data/spec/serinette/noise_spec.rb +7 -0
- data/spec/serinette/reverb_effect_spec.rb +9 -0
- data/spec/serinette/song_spec.rb +77 -0
- data/spec/serinette/source_noise_spec.rb +16 -0
- data/spec/serinette/synth_noise_spec.rb +11 -0
- data/spec/serinette/track_spec.rb +16 -0
- data/spec/serinette/utils/file_name_spec.rb +16 -0
- data/spec/serinette/utils/sox_wrapper_spec.rb +15 -0
- data/spec/serinette_spec.rb +52 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/matchers/have_constant.rb +5 -0
- data/tmp/.gitkeep +0 -0
- metadata +158 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a03120ebbc77c513989a69ab9fa002778e2a8f7a
|
4
|
+
data.tar.gz: a5da094dd669c14f50cfa9d633bae4b9f9b0d7af
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8b26b0a300b81bae7e6bd926c851ba3347d99a4c65283aafb8d3de4fd342e463e70012b0a7e9c4c972373eba2cb144aca9dcd3b28f413225d7379327641d64d7
|
7
|
+
data.tar.gz: 3bd31184c2062eae9d1fbe3f34f9b47b2a1adb22e6db3d37877a1cf0298b6b37e69bbe4b942914c8b33d4d3ce61e8f312f8735bcd5fca12c75d1ff70db2bbefe
|
data/.bundle/config
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# still in beta
|
2
|
+
# os:
|
3
|
+
# - linux
|
4
|
+
# - osx
|
5
|
+
language: ruby
|
6
|
+
rvm:
|
7
|
+
- 1.9.3
|
8
|
+
- 2.0.0
|
9
|
+
- 2.1.0
|
10
|
+
- 2.2.0
|
11
|
+
- ruby-head
|
12
|
+
- jruby-head
|
13
|
+
notifications:
|
14
|
+
slack:
|
15
|
+
secure: KCr8I8N78I0wOX5Cx8nJwPMM7jEDEPHI9z2RCIaANLy+sdFkV3Jz1RAx/6F4hctVzHHDWirZ7lWjRwljuBtV31rTSga1YRInxXvreWyLorN6stZAC4ZGZG4SMqUZCeAmgKp2WdweYeRAHLOy2fW9jLeoBOFtyl8PkooHmob7isA=
|
16
|
+
addons:
|
17
|
+
code_climate:
|
18
|
+
repo_token: e470e0610710700b03b559ceb7cbe2972d02735cc687a4dd6c2dac6f86fc4950
|
19
|
+
virtualenv:
|
20
|
+
system_site_packages: true
|
21
|
+
before_install:
|
22
|
+
- sudo apt-get install sox
|
23
|
+
script: bundle exec rake travis_spec
|
data/CHANGELOG.md
ADDED
data/CONTRIBUTING.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Jared Clifton
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
# [serinette](http://jclif.github.io/serinette/)
|
2
|
+
|
3
|
+
Generates music from the command line.
|
4
|
+
|
5
|
+
[![Code Climate](https://codeclimate.com/github/jclif/serinette/badges/gpa.svg)](https://codeclimate.com/github/jclif/serinette)
|
6
|
+
[![Build Status](https://travis-ci.org/jclif/serinette.svg?branch=master)](https://travis-ci.org/jclif/serinette)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/jclif/serinette/badges/gpa.svg)](https://codeclimate.com/github/jclif/serinette)
|
8
|
+
[![Dependency Status](https://gemnasium.com/jclif/serinette.svg)](https://gemnasium.com/jclif/serinette)
|
9
|
+
[![Documentation](https://inch-ci.org/github/jclif/serinette.svg?branch=master)](https://inch-ci.org/github/jclif/serinette)
|
10
|
+
[![Chatroom](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jclif/serinette?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
11
|
+
[![Stories in Ready](https://badge.waffle.io/jclif/serinette.png?label=ready&title=Ready)](https://waffle.io/jclif/serinette)
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Wow, what helpful installation instructions.
|
16
|
+
|
17
|
+
```
|
18
|
+
gem install yada-yada-dont-actually-run-this-please
|
19
|
+
```
|
20
|
+
|
21
|
+
## Basic Usage
|
22
|
+
|
23
|
+
We're not quite there yet. Get off my back, brah. It'll work something like this though:
|
24
|
+
|
25
|
+
```
|
26
|
+
serinette orchestrate
|
27
|
+
```
|
28
|
+
|
29
|
+
Alternatively you can pass serinette a list of amazing flags and arguments and stuff (you can't)
|
30
|
+
|
31
|
+
```
|
32
|
+
serinette orchestrate --wow -f me
|
33
|
+
```
|
34
|
+
|
35
|
+
For more details check the available command-line options (none of these work at all, please just go away):
|
36
|
+
|
37
|
+
```
|
38
|
+
serinette -h
|
39
|
+
```
|
40
|
+
|
41
|
+
Command flag | Description
|
42
|
+
--------------------------|------------------------------------------------------------
|
43
|
+
`-v/--version` | Displays the current version and exits.
|
44
|
+
`-V/--verbose-version` | Displays the current version plus the version of Parser and Ruby.
|
45
|
+
`-d/--debug` | Displays some extra debug output.
|
46
|
+
`-f/--format` | Choose a formatter.
|
47
|
+
|
48
|
+
##Configuration
|
49
|
+
|
50
|
+
The behavior of Serinette can be controlled via the why_are_you_still_readying_this.yml
|
51
|
+
|
52
|
+
```
|
53
|
+
Cool: A value or something
|
54
|
+
|
55
|
+
Style:
|
56
|
+
Enabled: OhYes
|
57
|
+
```
|
58
|
+
|
59
|
+
## Team
|
60
|
+
|
61
|
+
Here's a list of Serinette's core developers:
|
62
|
+
|
63
|
+
* [Yours Truly](https://github.com/jclif)
|
64
|
+
* [Austin Gatlin](https://github.com/aegnog)
|
65
|
+
|
66
|
+
## Logo
|
67
|
+
|
68
|
+
We don't have one. Thanks for asking.
|
69
|
+
|
70
|
+
If we did, it would be licensed under a
|
71
|
+
[Creative Commons Attribution-NonCommercial 4.0 International License](http://creativecommons.org/licenses/by-nc/4.0/deed.en_GB).
|
72
|
+
|
73
|
+
## Contributors
|
74
|
+
|
75
|
+
Here's a [list](https://github.com/jclif/serinette/contributors) of
|
76
|
+
all the people who have contributed to the development of Serinette.
|
77
|
+
|
78
|
+
Thank you SOOOO much (me)!
|
79
|
+
|
80
|
+
If you'd like to contribute to Serintte, please take the time to go
|
81
|
+
through our short
|
82
|
+
[contribution guidelines](CONTRIBUTING.md).
|
83
|
+
|
84
|
+
You can also support my work on Serinette and
|
85
|
+
[all my other projects](https://github.com/jclif) via
|
86
|
+
[gratipay](https://www.gratipay.com/jclif), but why would you ever want to.
|
87
|
+
|
88
|
+
[![Support via Gratipay](http://img.shields.io/gratipay/jclif.svg)](https://gratipay.com/jclif/)
|
89
|
+
|
90
|
+
## Mailing List
|
91
|
+
|
92
|
+
If you're interested in everything regarding Serinette development,
|
93
|
+
I'm sorry there is nothing I can do for you. Do people use google groups for this
|
94
|
+
[Google Group](https://groups.google.com/).
|
95
|
+
|
96
|
+
## Freenode
|
97
|
+
|
98
|
+
What's that.
|
99
|
+
|
100
|
+
## Changelog
|
101
|
+
|
102
|
+
Serinette's changelog is available [here](CHANGELOG.md).
|
103
|
+
|
104
|
+
## Copyright
|
105
|
+
|
106
|
+
Copyright (c) 2015 Jared Clifton. See [LICENSE.txt](LICENSE.txt) for
|
107
|
+
further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require './dependencies.rb'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
6
|
+
t.fail_on_error = false
|
7
|
+
t.rspec_opts = ['--format documentation', '--color', '--order=default']
|
8
|
+
t.pattern = ARGV[1] || 'spec/**/*_spec.rb'
|
9
|
+
end
|
10
|
+
|
11
|
+
RSpec::Core::RakeTask.new(:travis_spec) do |t|
|
12
|
+
t.fail_on_error = true
|
13
|
+
t.pattern = ARGV[1] || 'spec/**/*_spec.rb'
|
14
|
+
end
|
15
|
+
|
16
|
+
task default: :spec
|
Binary file
|
Binary file
|
data/dependencies.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Serinette
|
2
|
+
# Gives mixed in classes a method for returning an array of their descendents
|
3
|
+
module Descendents
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
# required for inheritance
|
9
|
+
module ClassMethods
|
10
|
+
def descendents
|
11
|
+
ObjectSpace.each_object(Class).select { |klass| klass < self }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Serinette
|
2
|
+
# Gives mixed in classes a method for randomizing effect options
|
3
|
+
module SoxOptions
|
4
|
+
# Takes a sox effect config and returns randomized Hash.
|
5
|
+
#
|
6
|
+
# @param config [Array] Sox effect options config
|
7
|
+
#
|
8
|
+
# @return [string] Randomized effect hash to be used with Sox::Cmd.set_effects
|
9
|
+
def self.randomize_options_as_string(configs)
|
10
|
+
configs.map do |o|
|
11
|
+
stringify_option(o)
|
12
|
+
end.compact.join(' ')
|
13
|
+
end
|
14
|
+
|
15
|
+
# Takes an individual option and checks for type, (if flag, its either on of
|
16
|
+
# off; if traig, randomize within the range given
|
17
|
+
#
|
18
|
+
# @param option [Option] Sox effect option
|
19
|
+
# Looks like this:
|
20
|
+
# {
|
21
|
+
# type: :flag,
|
22
|
+
# name: 'wet-only',
|
23
|
+
# value: '-w'
|
24
|
+
# }
|
25
|
+
# or this:
|
26
|
+
# {
|
27
|
+
# type: :trait,
|
28
|
+
# name: 'reverberance',
|
29
|
+
# range: (0..100), <== this can be an array or range, and it should sample
|
30
|
+
# default: 50
|
31
|
+
# {
|
32
|
+
#
|
33
|
+
# @return [string] Randomized effect hash to be used with Sox::Cmd.set_effects
|
34
|
+
def self.stringify_option(option)
|
35
|
+
case option[:type]
|
36
|
+
when :flag
|
37
|
+
return [true, false].sample ? option[:value] : nil
|
38
|
+
when :trait # TODO add check for proc here
|
39
|
+
return process_trait(option[:value])
|
40
|
+
else
|
41
|
+
fail Serinette::Error, '#stringify_option requires type of flag or trait'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.process_trait(trait)
|
46
|
+
case trait
|
47
|
+
when Range
|
48
|
+
return trait.to_a.sample
|
49
|
+
when Array
|
50
|
+
return trait.sample
|
51
|
+
when Proc
|
52
|
+
return trait.call
|
53
|
+
else
|
54
|
+
msg = '#process_trait requires trait of type Array, Range, or Proc'
|
55
|
+
fail Serinette::Error, msg
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Serinette
|
2
|
+
# Used to get subclasses and generate sox commands
|
3
|
+
class Effect
|
4
|
+
include Descendents
|
5
|
+
include SoxOptions
|
6
|
+
|
7
|
+
# Gets a specified number of Effect subclasses.
|
8
|
+
#
|
9
|
+
# @param num [Fixnum] Number of effects
|
10
|
+
# @return [Array] An array of Effect subclasses
|
11
|
+
def self.sample_effects_classes(num)
|
12
|
+
Array.new(num).map do
|
13
|
+
Effect.descendents.sample.new
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Gets a key pair for a given sox effect and its args
|
18
|
+
def to_sox_key_pair
|
19
|
+
{ return_root_command => generate_options }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Serinette
|
2
|
+
# Most basic unit of sound; will eventually provide base class for many
|
3
|
+
# different kinds of noises (SynthNoise, SourceNoise, etc)
|
4
|
+
class Noise
|
5
|
+
include Descendents
|
6
|
+
|
7
|
+
attr_accessor :wavefile
|
8
|
+
|
9
|
+
# Gets a specified number of Noise subclasses.
|
10
|
+
#
|
11
|
+
# @param num [Fixnum] Number of noises
|
12
|
+
# @return [Array] An array of Noise subclasses
|
13
|
+
def self.sample_noise_classes(num = 1)
|
14
|
+
Array.new(num).map do
|
15
|
+
Noise.descendents.sample
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Serinette
|
2
|
+
# Reverb type of effect
|
3
|
+
class ReverbEffect < Effect
|
4
|
+
ROOT_COMMAND = 'reverb'.freeze
|
5
|
+
|
6
|
+
# Sox options:
|
7
|
+
# -w|--wet-only [on - off]
|
8
|
+
# reverberance (50%) [0 - 100]
|
9
|
+
# HF-damping (50%) [0 - 100]
|
10
|
+
# room-scale (100%) [0 - 100]
|
11
|
+
# stereo-depth (100%) [0 - 100]
|
12
|
+
# pre-delay (0ms) [0] TODO dtermine max pre-delay
|
13
|
+
# wet-gain (0dB) [-10 - 10] TODO dB range
|
14
|
+
SOX_OPTIONS_CONFIG = [
|
15
|
+
{
|
16
|
+
type: :flag,
|
17
|
+
name: 'wet-only',
|
18
|
+
value: '-w'
|
19
|
+
}, {
|
20
|
+
type: :trait,
|
21
|
+
name: 'reverberance',
|
22
|
+
value: (0..100),
|
23
|
+
default: 50
|
24
|
+
}, {
|
25
|
+
type: :trait,
|
26
|
+
name: 'HF-damping',
|
27
|
+
value: (0..100),
|
28
|
+
default: 50
|
29
|
+
}, {
|
30
|
+
type: :trait,
|
31
|
+
name: 'room-scale',
|
32
|
+
value: (0..100),
|
33
|
+
default: 100
|
34
|
+
}, {
|
35
|
+
type: :trait,
|
36
|
+
name: 'stereo-depth',
|
37
|
+
value: (0..100),
|
38
|
+
default: 100
|
39
|
+
}, {
|
40
|
+
type: :trait,
|
41
|
+
name: 'pre-delay',
|
42
|
+
value: (0..5),
|
43
|
+
default: 0
|
44
|
+
}, {
|
45
|
+
type: :trait,
|
46
|
+
name: 'wet-gain',
|
47
|
+
value: (-10..10),
|
48
|
+
default: 0
|
49
|
+
}
|
50
|
+
]
|
51
|
+
|
52
|
+
# Passes in the Effect Subclasses config to generate sox option hash
|
53
|
+
#
|
54
|
+
# @return [String] Result of randomized string representation of options
|
55
|
+
def generate_options
|
56
|
+
SoxOptions.randomize_options_as_string(SOX_OPTIONS_CONFIG)
|
57
|
+
end
|
58
|
+
# Sox command
|
59
|
+
def return_root_command
|
60
|
+
ROOT_COMMAND
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Serinette
|
2
|
+
# Has functions for kicking off initializer chain, rendering final song, and
|
3
|
+
# constants necessary for determining song-level characteristcs
|
4
|
+
class Song
|
5
|
+
LOWEST_DURATION = 60
|
6
|
+
HIGHEST_DURATION = 180
|
7
|
+
TRACK_NUMBER = 2
|
8
|
+
EFFECT_NUMBER = 1
|
9
|
+
|
10
|
+
CHANNELS = 2
|
11
|
+
RATE = 99_600
|
12
|
+
|
13
|
+
attr_accessor :duration, :tracks, :effects
|
14
|
+
|
15
|
+
def self.default_effects
|
16
|
+
{ rate: RATE, channels: CHANNELS }
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
init_duration
|
21
|
+
init_tracks
|
22
|
+
init_effects
|
23
|
+
end
|
24
|
+
|
25
|
+
# Recurses render tree via render
|
26
|
+
def render
|
27
|
+
@tracks.map(&:render)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Taks a sox instance and adds input, sets effects, and sets output
|
31
|
+
#
|
32
|
+
# @param sox [Sox::Cmd] Sox command instance
|
33
|
+
def configure_command(sox)
|
34
|
+
render.each do |file|
|
35
|
+
sox.add_input(file)
|
36
|
+
end
|
37
|
+
sox.set_effects(generate_effects_options)
|
38
|
+
sox.set_output(Serinette.output_path)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Uses effects instance variable to generate hash of all effects as sox
|
44
|
+
# key/pairs
|
45
|
+
def generate_effects_options
|
46
|
+
effects_hash = Song.default_effects
|
47
|
+
|
48
|
+
@effects.each do |effect|
|
49
|
+
effects_hash.merge! effect.to_sox_key_pair
|
50
|
+
end
|
51
|
+
|
52
|
+
effects_hash
|
53
|
+
end
|
54
|
+
|
55
|
+
# Initializes duration
|
56
|
+
def init_duration
|
57
|
+
@duration = (LOWEST_DURATION..HIGHEST_DURATION).to_a.sample
|
58
|
+
end
|
59
|
+
|
60
|
+
# Initializes tracks
|
61
|
+
def init_tracks
|
62
|
+
@tracks = Array.new(TRACK_NUMBER) { Track.new }
|
63
|
+
end
|
64
|
+
|
65
|
+
# Initializes effects
|
66
|
+
def init_effects
|
67
|
+
@effects = Effect.sample_effects_classes(1)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Serinette
|
2
|
+
# Sourced Noises; will provide noises sourced from wav files found in a
|
3
|
+
# particular directory
|
4
|
+
class SourceNoise < Noise
|
5
|
+
SOUND_DIRECTORY = './data/sounds/*'
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
init_wavefile
|
9
|
+
end
|
10
|
+
|
11
|
+
def init_wavefile
|
12
|
+
sox = SoxWrapper.generate_and_run input: SourceNoise.pick_random_file
|
13
|
+
@wavefile = sox.output.path
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.pick_random_file
|
17
|
+
sound_files = Dir.glob(SOUND_DIRECTORY).sort
|
18
|
+
num = (0..sound_files.length - 1).to_a.sample
|
19
|
+
|
20
|
+
sound_files[num]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Serinette
|
2
|
+
# Synthesized Noises; using arguments such as type (sin, square, saw) and will
|
3
|
+
# describe a subclass of Noises which corresponds to the use of the synth
|
4
|
+
# sox command
|
5
|
+
class SynthNoise < Noise
|
6
|
+
ROOT_COMMAND = 'synth'.freeze
|
7
|
+
|
8
|
+
# Sox options:
|
9
|
+
# len (0) [0 - 10] length in seconds TODO determine resonable range
|
10
|
+
# type (sine) [sine, square, triangle, sawtooth, trapezium, exp,
|
11
|
+
# [white]noise, tpdfnoise pinknoise, brownnoise, pluck]
|
12
|
+
# combine (create) [create, mix, amod (amplitude modulation), fmod
|
13
|
+
# (frequency modulation)]
|
14
|
+
# freq/freq2 (A4) [A0-G9:A0-G9] TODO expand stringify_options to allow for
|
15
|
+
# swept or fixed frequencies; perhaps a lambda to generate both
|
16
|
+
# thoughts: the freq can be given as a single note (fixed), or two (swept);
|
17
|
+
# if swept notes are chosen, one of the following separators must be used:
|
18
|
+
# ':' (linear) the tone will change by a fixed number of hertz per second
|
19
|
+
# '+' (square) a second-order function is used to change the tone
|
20
|
+
# '/' (exp) the tone will change by a fixed number of semitones per second
|
21
|
+
# '-' (exp) link '/', but initial phase always zero, and stepped (rougher)
|
22
|
+
# frequency changes
|
23
|
+
SOX_OPTIONS_CONFIG = [
|
24
|
+
{
|
25
|
+
type: :trait,
|
26
|
+
name: 'length',
|
27
|
+
value: (1..5), # cannot be zero, or will run indefinitely
|
28
|
+
default: 1
|
29
|
+
}, {
|
30
|
+
type: :trait,
|
31
|
+
name: 'type',
|
32
|
+
value: %w(sine square triangle sawtooth trapezium exp),
|
33
|
+
default: 'sine'
|
34
|
+
}, {
|
35
|
+
type: :trait,
|
36
|
+
name: 'combine',
|
37
|
+
value: %w(create mix amod fmod),
|
38
|
+
default: 'create'
|
39
|
+
}, {
|
40
|
+
type: :trait,
|
41
|
+
name: 'freq',
|
42
|
+
value: Proc.new do
|
43
|
+
freq = ('A'..'G').to_a.product((0..9).to_a).map { |el| el.join('') }.sample
|
44
|
+
if [true, false].sample
|
45
|
+
freq << [':','+','/','-'].sample
|
46
|
+
freq << ('A'..'G').to_a.product((0..9).to_a).map { |el| el.join('') }.sample
|
47
|
+
end
|
48
|
+
freq
|
49
|
+
end,
|
50
|
+
default: 'A4'
|
51
|
+
}
|
52
|
+
]
|
53
|
+
|
54
|
+
def initialize
|
55
|
+
init_noise
|
56
|
+
apply_effects
|
57
|
+
end
|
58
|
+
|
59
|
+
def init_noise
|
60
|
+
sox_options = {
|
61
|
+
output: FileName::generate,
|
62
|
+
effects: {ROOT_COMMAND => SoxOptions::randomize_options_as_string(SOX_OPTIONS_CONFIG)}
|
63
|
+
}
|
64
|
+
|
65
|
+
SoxWrapper.generate_and_run(sox_options)
|
66
|
+
|
67
|
+
@wavefile = sox_options[:output]
|
68
|
+
end
|
69
|
+
|
70
|
+
def apply_effects
|
71
|
+
# TODO
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Serinette
|
2
|
+
# Contains noise, efects on noise, and when (timestamps) and
|
3
|
+
# how (volume) noise is played
|
4
|
+
class Track
|
5
|
+
attr_accessor :noise
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@noise = init_noise
|
9
|
+
end
|
10
|
+
|
11
|
+
# For now, just returns the result of noises render; this will be where
|
12
|
+
# the noise is brought in and out of the song
|
13
|
+
def render
|
14
|
+
@noise.wavefile
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# Initializes noise
|
20
|
+
def init_noise
|
21
|
+
Noise.sample_noise_classes.first.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/serinette.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'sox'
|
5
|
+
|
6
|
+
require 'mixins/descendents'
|
7
|
+
require 'mixins/sox_options'
|
8
|
+
|
9
|
+
require 'utils/file_name'
|
10
|
+
require 'utils/sox_wrapper'
|
11
|
+
|
12
|
+
require 'serinette/effect'
|
13
|
+
require 'serinette/reverb_effect'
|
14
|
+
|
15
|
+
require 'serinette/noise'
|
16
|
+
require 'serinette/synth_noise'
|
17
|
+
require 'serinette/source_noise'
|
18
|
+
|
19
|
+
require 'serinette/song'
|
20
|
+
require 'serinette/track'
|
21
|
+
|
22
|
+
# Contains functions for running essential commands and
|
23
|
+
# defining app level constants
|
24
|
+
module Serinette
|
25
|
+
OUTPUT_FILE_NAME = 'output'
|
26
|
+
TMP_DIR = './tmp/'
|
27
|
+
SOUND_FILE_TYPE = '.wav'
|
28
|
+
|
29
|
+
# Returns pull path of output file from project root
|
30
|
+
def self.output_path
|
31
|
+
Serinette::TMP_DIR +
|
32
|
+
Serinette::OUTPUT_FILE_NAME +
|
33
|
+
Serinette::SOUND_FILE_TYPE
|
34
|
+
end
|
35
|
+
|
36
|
+
# Removes all files in TMP_DIR of type SOUND_FILE_TYPE
|
37
|
+
def self.clean
|
38
|
+
FileUtils.rm_rf(Dir.glob("#{TMP_DIR}*#{SOUND_FILE_TYPE}"))
|
39
|
+
end
|
40
|
+
|
41
|
+
# Primary function for creating and outputing new songs
|
42
|
+
def self.orchestrate
|
43
|
+
clean
|
44
|
+
|
45
|
+
sox = Sox::Cmd.new(combine: :mix)
|
46
|
+
|
47
|
+
song = Song.new
|
48
|
+
song.configure_command(sox)
|
49
|
+
puts "Running sox with: #{sox.to_s}"
|
50
|
+
|
51
|
+
sox.run
|
52
|
+
end
|
53
|
+
|
54
|
+
# Basic Serinette error:
|
55
|
+
class Error < StandardError
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Serinette
|
2
|
+
# Provides Sox helper functions
|
3
|
+
module SoxWrapper
|
4
|
+
# Takes options, generates a configured Sox::Cmd, and runs
|
5
|
+
#
|
6
|
+
# @params [Hash] options hash
|
7
|
+
# @returns [Sox::Cmd] Sox command with all configurations
|
8
|
+
def self.generate_and_run(options = {})
|
9
|
+
setup(options, true)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Takes options and generates a configured Sox::Cmd
|
13
|
+
#
|
14
|
+
# @params [Hash] options hash
|
15
|
+
# @returns [Sox::Cmd] Sox commands with all configurations
|
16
|
+
def self.generate(options = {})
|
17
|
+
setup(options, false)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# Internal function for setting up and running (if should_run) sox command
|
23
|
+
def self.setup(options, should_run)
|
24
|
+
options[:global_options] ||= {}
|
25
|
+
options[:input] ||= '-n'
|
26
|
+
options[:output] ||= FileName.generate
|
27
|
+
options[:effects] ||= {}
|
28
|
+
|
29
|
+
options[:effects].merge! Song::default_effects
|
30
|
+
|
31
|
+
sox = Sox::Cmd.new options[:global_options]
|
32
|
+
|
33
|
+
sox.add_input(options[:input])
|
34
|
+
sox.set_effects(options[:effects])
|
35
|
+
sox.set_output(options[:output])
|
36
|
+
|
37
|
+
sox.run if should_run
|
38
|
+
sox
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/serinette.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "serinette/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = 'serinette'
|
6
|
+
gem.version = Serinette::VERSION
|
7
|
+
gem.summary = "Random music from the command line."
|
8
|
+
gem.description = "Serinette is a library with a strongly opionated approach to generating random music from the command line."
|
9
|
+
gem.authors = ['Jared Clifton', 'Austin Gatlin']
|
10
|
+
gem.email = 'jaredcraigclifton@gmail.com'
|
11
|
+
gem.files = `git ls-files`.split("\n")
|
12
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
13
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
|
+
gem.require_paths = ['lib']
|
15
|
+
gem.homepage = 'http://jclif.github.io/serinette/'
|
16
|
+
gem.license = 'MIT'
|
17
|
+
|
18
|
+
gem.required_ruby_version = '>= 1.9.3'
|
19
|
+
|
20
|
+
gem.add_dependency 'cliver', '0.3.2'
|
21
|
+
gem.add_dependency 'ruby-sox', '0.0.3'
|
22
|
+
|
23
|
+
gem.add_development_dependency 'rake', '10.4.2'
|
24
|
+
gem.add_development_dependency 'rspec', '3.2.0'
|
25
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Serinette::Effect do
|
4
|
+
describe '.sample_effects_classes' do
|
5
|
+
it 'should exist' do
|
6
|
+
expect(Serinette::Effect).to respond_to(:sample_effects_classes)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'given an effect' do
|
11
|
+
subject(:effect) { Serinette::Effect.new }
|
12
|
+
it 'should have a method #to_sox_key_pair' do
|
13
|
+
expect(effect).to respond_to(:to_sox_key_pair)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Serinette::Descendents do
|
4
|
+
let(:klass) { Class.new { include Serinette::Descendents } }
|
5
|
+
|
6
|
+
context 'a class method #descendents' do
|
7
|
+
it 'should exist in classes which include the module' do
|
8
|
+
expect(klass).to respond_to(:descendents)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should return a classes descendents' do
|
12
|
+
class Subklass1 < klass; end
|
13
|
+
class Subklass2 < klass; end
|
14
|
+
expect(klass.descendents - [Subklass1, Subklass2]).to eq []
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Serinette::SoxOptions do
|
4
|
+
context 'a method #randomize_options_as_string' do
|
5
|
+
it 'should exist' do
|
6
|
+
expect(Serinette::SoxOptions).to respond_to(:randomize_options_as_string)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'a method #stringify_option' do
|
11
|
+
it 'should exist' do
|
12
|
+
expect(Serinette::SoxOptions).to respond_to(:stringify_option)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should return correct string when given type: :flag' do
|
16
|
+
good_option1 = {
|
17
|
+
type: :flag,
|
18
|
+
name: 'wet-only',
|
19
|
+
value: '-w'
|
20
|
+
}
|
21
|
+
|
22
|
+
allow_any_instance_of(Array).to receive(:sample).and_return(true)
|
23
|
+
expect(Serinette::SoxOptions.stringify_option(good_option1)).to eq('-w')
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should return correct string when given type: :trait as range' do
|
27
|
+
good_option2 = {
|
28
|
+
type: :trait,
|
29
|
+
name: 'reverberance',
|
30
|
+
value: (0..100),
|
31
|
+
default: 50
|
32
|
+
}
|
33
|
+
|
34
|
+
result = Serinette::SoxOptions.stringify_option(good_option2)
|
35
|
+
|
36
|
+
expect(result).not_to be_nil
|
37
|
+
expect(result.to_i).to be_between(0, 100)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should return correct string when given type: :trait as array' do
|
41
|
+
good_option2 = {
|
42
|
+
type: :trait,
|
43
|
+
name: 'reverberance',
|
44
|
+
value: [0, 50, 100],
|
45
|
+
default: 50
|
46
|
+
}
|
47
|
+
|
48
|
+
allow_any_instance_of(Array).to receive(:sample).and_return(50)
|
49
|
+
|
50
|
+
result = Serinette::SoxOptions.stringify_option(good_option2)
|
51
|
+
|
52
|
+
expect(result).not_to be_nil
|
53
|
+
expect(result.to_i).to eq(50)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should return correct string when given type: :trait as proc'
|
57
|
+
|
58
|
+
it 'should fail when type is bad' do
|
59
|
+
bad_option = {
|
60
|
+
type: :bad,
|
61
|
+
name: 'wet-only',
|
62
|
+
value: '-w'
|
63
|
+
}
|
64
|
+
|
65
|
+
error = Serinette::Error
|
66
|
+
expect { Serinette::SoxOptions.stringify_option(bad_option) }.to raise_error(error)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Serinette::Song do
|
4
|
+
it 'should have a constant TRACK_NUMBER' do
|
5
|
+
expect(Serinette::Song).to have_constant(:TRACK_NUMBER)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should have a constant EFFECT_NUMBER' do
|
9
|
+
expect(Serinette::Song).to have_constant(:EFFECT_NUMBER)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should have a constant CHANNELS' do
|
13
|
+
expect(Serinette::Song).to have_constant(:CHANNELS)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should have a constant RATE' do
|
17
|
+
expect(Serinette::Song).to have_constant(:RATE)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '.default_effects' do
|
21
|
+
it 'should exist' do
|
22
|
+
expect(Serinette::Song).to respond_to(:default_effects)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should get output path' do
|
26
|
+
default_effects = { rate: Serinette::Song::RATE, channels: Serinette::Song::CHANNELS }
|
27
|
+
expect(Serinette::Song.default_effects).to eq default_effects
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'given a song' do
|
32
|
+
subject(:song) { Serinette::Song.new }
|
33
|
+
|
34
|
+
it 'should have correct number of effects' do
|
35
|
+
expect(song.effects.length).to be Serinette::Song::EFFECT_NUMBER
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should have correct number of tracks' do
|
39
|
+
expect(song.tracks.length).to be Serinette::Song::TRACK_NUMBER
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should have a variable duration' do
|
43
|
+
expect(song.duration).to be_a Fixnum
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should have a duration less than three minutes' do
|
47
|
+
expect(song.duration).to be <= 180
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should have a duration more than one minute' do
|
51
|
+
expect(song.duration).to be >= 60
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should have tracks' do
|
55
|
+
expect(song.tracks).to be_a Array
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should have effects' do
|
59
|
+
expect(song.effects).to be_a Array
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should have correct number of tracks' do
|
63
|
+
expect(song.tracks.length).to be Serinette::Song::TRACK_NUMBER
|
64
|
+
song.tracks.each do |track|
|
65
|
+
expect(track).to be_a Serinette::Track
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should call render on all tracks' do
|
70
|
+
song.tracks.each do |track|
|
71
|
+
expect(track).to receive(:render)
|
72
|
+
end
|
73
|
+
|
74
|
+
song.render
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Serinette::SourceNoise do
|
4
|
+
|
5
|
+
it 'should inherit from Noise' do
|
6
|
+
expect(Serinette::SourceNoise.ancestors.include?(Serinette::Noise)).to eq(true)
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'given a source noise' do
|
10
|
+
subject(:source_noise) { Serinette::SourceNoise.new }
|
11
|
+
|
12
|
+
it 'should have a wavefile' do
|
13
|
+
expect(source_noise.wavefile).to be_a String
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Serinette::SynthNoise do
|
4
|
+
it 'should have a constant SOX_OPTIONS_CONFIG' do
|
5
|
+
expect(Serinette::SynthNoise).to have_constant(:SOX_OPTIONS_CONFIG)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should inherit from Noise' do
|
9
|
+
expect(Serinette::SynthNoise.ancestors.include?(Serinette::Noise)).to eq(true)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Serinette::Track do
|
4
|
+
context 'given a track' do
|
5
|
+
subject(:track) { Serinette::Track.new }
|
6
|
+
|
7
|
+
it 'should have a noise' do
|
8
|
+
expect(track.noise).to be_a Serinette::Noise
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should have method render that creates a tem file and returns the path' do
|
12
|
+
file_name = track.render
|
13
|
+
expect(File.exist?(file_name)).to be true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Serinette::FileName do
|
4
|
+
context 'a class method #generate' do
|
5
|
+
it 'should exist' do
|
6
|
+
expect(Serinette::FileName).to respond_to(:generate)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should return a string' do
|
10
|
+
expect(Serinette::FileName.generate).to be_a String
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should be random'
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Serinette::SoxWrapper do
|
4
|
+
context 'a class method #generate' do
|
5
|
+
it 'should exist' do
|
6
|
+
expect(Serinette::SoxWrapper).to respond_to(:generate)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should return a Sox::Cmd' do
|
10
|
+
expect(Serinette::SoxWrapper.generate).to be_a Sox::Cmd
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should configure the Sox::Cmd correctly'
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Serinette do
|
4
|
+
it 'should have a variable called OUTPUT_FILE_NAME' do
|
5
|
+
expect(Serinette::OUTPUT_FILE_NAME).not_to be_nil
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should have a variable called TMP_DIR' do
|
9
|
+
expect(Serinette::TMP_DIR).not_to be_nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should have a variable called SOUND_FILE_TYPE' do
|
13
|
+
expect(Serinette::SOUND_FILE_TYPE).not_to be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.clean' do
|
17
|
+
it 'should exist' do
|
18
|
+
expect(Serinette).to respond_to(:clean)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should remove all wav files from the tmp directory' do
|
22
|
+
file_name = "#{Serinette::TMP_DIR}test.#{Serinette::SOUND_FILE_TYPE}"
|
23
|
+
FileUtils.touch(file_name)
|
24
|
+
Serinette.clean
|
25
|
+
expect(File.exist?(file_name)).to be false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '.output_path' do
|
30
|
+
it 'should exist' do
|
31
|
+
expect(Serinette).to respond_to(:output_path)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should get output path' do
|
35
|
+
path = Serinette::TMP_DIR +
|
36
|
+
Serinette::OUTPUT_FILE_NAME +
|
37
|
+
Serinette::SOUND_FILE_TYPE
|
38
|
+
expect(Serinette.output_path).to eq path
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '.orchestrate' do
|
43
|
+
it 'should exist' do
|
44
|
+
expect(Serinette).to respond_to(:orchestrate)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should output a file' do
|
48
|
+
Serinette.orchestrate
|
49
|
+
expect(File.exist?(Serinette.output_path)).to be true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# require 'coveralls'
|
2
|
+
require 'codeclimate-test-reporter'
|
3
|
+
|
4
|
+
# Coveralls.wear!
|
5
|
+
CodeClimate::TestReporter.start
|
6
|
+
|
7
|
+
require 'serinette'
|
8
|
+
|
9
|
+
# Custom Matchers
|
10
|
+
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
|
data/tmp/.gitkeep
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: serinette
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0.pre
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jared Clifton
|
8
|
+
- Austin Gatlin
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-02-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: cliver
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - '='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 0.3.2
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - '='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.3.2
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: ruby-sox
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - '='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.0.3
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - '='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 0.0.3
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rake
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - '='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 10.4.2
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - '='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 10.4.2
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rspec
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - '='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 3.2.0
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 3.2.0
|
70
|
+
description: Serinette is a library with a strongly opionated approach to generating
|
71
|
+
random music from the command line.
|
72
|
+
email: jaredcraigclifton@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".bundle/config"
|
78
|
+
- ".gitignore"
|
79
|
+
- ".rspec"
|
80
|
+
- ".travis.yml"
|
81
|
+
- CHANGELOG.md
|
82
|
+
- CONTRIBUTING.md
|
83
|
+
- Gemfile
|
84
|
+
- LICENSE.txt
|
85
|
+
- README.md
|
86
|
+
- Rakefile
|
87
|
+
- data/sounds/haunting_voices.wav
|
88
|
+
- data/sounds/hypnotic_loop.wav
|
89
|
+
- dependencies.rb
|
90
|
+
- lib/mixins/descendents.rb
|
91
|
+
- lib/mixins/sox_options.rb
|
92
|
+
- lib/serinette.rb
|
93
|
+
- lib/serinette/effect.rb
|
94
|
+
- lib/serinette/noise.rb
|
95
|
+
- lib/serinette/reverb_effect.rb
|
96
|
+
- lib/serinette/song.rb
|
97
|
+
- lib/serinette/source_noise.rb
|
98
|
+
- lib/serinette/synth_noise.rb
|
99
|
+
- lib/serinette/track.rb
|
100
|
+
- lib/serinette/version.rb
|
101
|
+
- lib/utils/file_name.rb
|
102
|
+
- lib/utils/sox_wrapper.rb
|
103
|
+
- serinette.gemspec
|
104
|
+
- spec/serinette/effect_spec.rb
|
105
|
+
- spec/serinette/mixins/descendents_spec.rb
|
106
|
+
- spec/serinette/mixins/sox_options_spec.rb
|
107
|
+
- spec/serinette/noise_spec.rb
|
108
|
+
- spec/serinette/reverb_effect_spec.rb
|
109
|
+
- spec/serinette/song_spec.rb
|
110
|
+
- spec/serinette/source_noise_spec.rb
|
111
|
+
- spec/serinette/synth_noise_spec.rb
|
112
|
+
- spec/serinette/track_spec.rb
|
113
|
+
- spec/serinette/utils/file_name_spec.rb
|
114
|
+
- spec/serinette/utils/sox_wrapper_spec.rb
|
115
|
+
- spec/serinette_spec.rb
|
116
|
+
- spec/spec_helper.rb
|
117
|
+
- spec/support/matchers/have_constant.rb
|
118
|
+
- tmp/.gitkeep
|
119
|
+
homepage: http://jclif.github.io/serinette/
|
120
|
+
licenses:
|
121
|
+
- MIT
|
122
|
+
metadata: {}
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 1.9.3
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - ">"
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: 1.3.1
|
137
|
+
requirements: []
|
138
|
+
rubyforge_project:
|
139
|
+
rubygems_version: 2.4.5
|
140
|
+
signing_key:
|
141
|
+
specification_version: 4
|
142
|
+
summary: Random music from the command line.
|
143
|
+
test_files:
|
144
|
+
- spec/serinette/effect_spec.rb
|
145
|
+
- spec/serinette/mixins/descendents_spec.rb
|
146
|
+
- spec/serinette/mixins/sox_options_spec.rb
|
147
|
+
- spec/serinette/noise_spec.rb
|
148
|
+
- spec/serinette/reverb_effect_spec.rb
|
149
|
+
- spec/serinette/song_spec.rb
|
150
|
+
- spec/serinette/source_noise_spec.rb
|
151
|
+
- spec/serinette/synth_noise_spec.rb
|
152
|
+
- spec/serinette/track_spec.rb
|
153
|
+
- spec/serinette/utils/file_name_spec.rb
|
154
|
+
- spec/serinette/utils/sox_wrapper_spec.rb
|
155
|
+
- spec/serinette_spec.rb
|
156
|
+
- spec/spec_helper.rb
|
157
|
+
- spec/support/matchers/have_constant.rb
|
158
|
+
has_rdoc:
|