serinette 0.0.0.pre
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/.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
|
+
[](https://codeclimate.com/github/jclif/serinette)
|
|
6
|
+
[](https://travis-ci.org/jclif/serinette)
|
|
7
|
+
[](https://codeclimate.com/github/jclif/serinette)
|
|
8
|
+
[](https://gemnasium.com/jclif/serinette)
|
|
9
|
+
[](https://inch-ci.org/github/jclif/serinette)
|
|
10
|
+
[](https://gitter.im/jclif/serinette?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
|
11
|
+
[](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
|
+
[](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:
|