mass 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YmUwMjYwZDZlOWNkOWZiNWJhMmI5YmEzNzcxZDhkNmQwYjI0ZjcwOQ==
4
+ YTIyODFiODNmNzVlMTMyNDg5ZDA4MTZkZTJjOTMxNGE2MmQwOWNmNw==
5
5
  data.tar.gz: !binary |-
6
- Mjk4YjIxZjM1Yjg5ZTAzNzNjZTE5NTI3MzJiNTY3NDgxOTJiZmUzMg==
6
+ NGMxY2JkYTcwZGVkYjEyZDBkMzExMTQ4MGVkYmFjY2U5YzU4MzU4YQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NjVlZmRmNzdjZTg1MWU0NTU3YmNmODUxNjQ5NGYyNDNjYTg5NDY3YmVlZmYz
10
- MmNmODk3NjFmM2NlZWJlZWI1NWY3NmIzNWNiMGRhNDVhNWIxNjQwNTJiN2Jl
11
- ZTg1MWNlOGVmZGQ5ZmJmMGVlZDU1MGFiNjAzMDg3M2M0MDY4NjU=
9
+ ZTY0ZjY4NmU5ODAyZmYyMjIyZTcxYjgyOGYwNjY0MGEyY2ViZjY4NWM0ZWRk
10
+ MTQ4OGEwNzhiN2FjNzBjNjliMDY2YzMzNmI5OWJiZDAyMzI2OWU0NjY5OGE1
11
+ MGQ5YzMxZDNkMmQ2NTk4YmY2Njc1MzE4Nzg5NzhiOWRlODg5NjQ=
12
12
  data.tar.gz: !binary |-
13
- ZWFmYjhjODI3ODVkMGIyM2MyOGNmOWM2ZjVmYzdlODExNTAxN2Q3N2VlZjI3
14
- MDMyYzk3ZjEwYzdiY2U0MDEwNmRmMWE1Y2Y4OTAxMDY0NmYzZGY1Mzg2Mjcy
15
- OTc5NDVjZDFmMDQ2OWI5MjFkZDAzODlkYWU2YzZlZGVhM2VmZDM=
13
+ MTk0ODQ4M2RjMmJhODU1NjIzYmYwMmE0Mzk1M2M2Mzk3MmM5MGJiMjhjYWZm
14
+ MDllN2I2NTg4YWVkZTc0MWI3ZTA4YWE3NzhmOGE2MTNiMzQ1ZDA4N2NiYWI3
15
+ NTg1ZjM0MDgwMDJjYTI1MzczZWNlNzhkMmM2YzM4YmYxYjFmMjA=
data/README.md CHANGED
@@ -41,10 +41,10 @@ include Mass
41
41
 
42
42
  bpm 128
43
43
  pattern bars: 4 do
44
- note 4, pitch: 'c2'
45
- note 4, pitch: 'c3'
46
- note 4, pitch: 'c4'
47
- note 4, pitch: 'c3'
44
+ note 4, pitch: 'C2'
45
+ note 4, pitch: 'C3'
46
+ note 4, pitch: 'C4'
47
+ note 4, pitch: 'C3'
48
48
  end
49
49
  ```
50
50
 
@@ -80,3 +80,8 @@ newly built `.gem` file to [RubyGems][gem]:
80
80
  ```bash
81
81
  $ bin/rake release
82
82
  ```
83
+
84
+ [tubbo]: https://github.com/tubbo
85
+ [rdoc]: http://www.rubydoc.info/github/tubbo/mass/master/frames
86
+ [gem]: https://rubygems.org
87
+ [mit]: https://github.com/tubbo/mass/blob/master/LICENSE.txt
@@ -4,48 +4,11 @@ require 'mass/version'
4
4
  require 'mass/pitch'
5
5
  require 'mass/note'
6
6
  require 'mass/pattern'
7
+ require 'mass/sequence'
7
8
 
8
9
  # A massive synth library.
9
10
  module Mass
10
- class << self
11
- # The current BPM of this track. Defaults to +100+.
12
- #
13
- # @return [Integer]
14
- def current_bpm
15
- @current_bpm ||= 100
16
- end
17
-
18
- # Change BPM of the track.
19
- #
20
- # @example
21
- # require 'mass'
22
- # include Mass
23
- #
24
- # bpm 128
25
- #
26
- def bpm(new_bpm)
27
- @current_bpm = new_bpm
28
- end
29
-
30
- # Create a pattern in Mass.
31
- #
32
- # @example
33
- # require 'mass'
34
- # include Mass
35
- #
36
- # pattern name: 'verse', bars: 1 do
37
- # note 8, pitch: 'C4'
38
- # note 8, pitch: 'C3'
39
- # note 8, pitch: 'A3'
40
- # note 8, pitch: 'B4'
41
- # note 8, pitch: 'C4'
42
- # note 8, pitch: 'Gb2'
43
- # note 8, pitch: 'C4'
44
- # rest 8
45
- # end
46
- #
47
- def pattern(**params, &block)
48
- Pattern.create(**params, &block)
49
- end
11
+ def self.sequence(*args)
12
+ Sequence.define(*args)
50
13
  end
51
14
  end
@@ -1,4 +1,5 @@
1
1
  require 'forwardable'
2
+ require 'mass/pitch'
2
3
 
3
4
  module Mass
4
5
  # Represents a single note in the pattern.
@@ -49,6 +50,16 @@ module Mass
49
50
  # @attr_reader [Mass::Pitch]
50
51
  attr_reader :pitch
51
52
 
53
+ # Rhythmic duration value for this note.
54
+ #
55
+ # @attr_reader [Integer]
56
+ attr_reader :value
57
+
58
+ # BPM passed in from the sequence.
59
+ #
60
+ # @attr_reader [Integer]
61
+ attr_reader :bpm
62
+
52
63
  # Hex value for sending to +UniMIDI+ that signals when
53
64
  # this note should begin playing.
54
65
  #
@@ -65,18 +76,15 @@ module Mass
65
76
  # @param [String] pitch
66
77
  # @param [Symbol | Integer] exp - Can be expressed as either
67
78
  # @param [UniMIDI::Output] midi
68
- def initialize(value: 1, pitch: nil, exp: :mp, midi: nil)
79
+ def initialize(value: 1, pitch: nil, exp: :mp, midi: nil, bpm: 100)
69
80
  @value = value
81
+ @name = pitch
70
82
  @pitch = Pitch.find pitch
71
83
  @expression = exp
72
84
  @midi = midi
85
+ @bpm = bpm
73
86
  end
74
87
 
75
- # The given note name.
76
- #
77
- # @return [String]
78
- def_delegator :pitch, :name, :id
79
-
80
88
  # This note as expressed in a MIDI pitch value.
81
89
  #
82
90
  # @return [Integer]
@@ -92,14 +100,20 @@ module Mass
92
100
  # The given duration value divided by the BPM of
93
101
  # the current song.
94
102
  def duration
95
- value / Mass.current_bpm
103
+ vpm * 0.01
96
104
  end
97
105
 
98
106
  # Play the current note through the +UniMIDI+ output.
99
107
  def play
100
- midi.puts ON, to_midi, to_velocity if pitch.present?
108
+ midi.puts ON, to_midi, to_velocity unless pitch.nil?
101
109
  sleep duration
102
- midi.puts OFF, to_midi, to_velocity if pitch.present?
110
+ midi.puts OFF, to_midi, to_velocity unless pitch.nil?
111
+ end
112
+
113
+ private
114
+
115
+ def vpm
116
+ bpm / value
103
117
  end
104
118
  end
105
119
  end
@@ -1,18 +1,22 @@
1
+ require 'unimidi'
2
+ require 'mass/note'
3
+
1
4
  module Mass
2
5
  # A single pattern written using the +Mass+ DSL. This is the
3
6
  # "collection"-style object which holds each +Note+ and plays
4
7
  # them in sequence, but has no control over their durations or
5
8
  # pitches.
6
9
  class Pattern
7
- attr_reader :name, :bars, :notes
10
+ attr_reader :name, :bars, :notes, :sequence
8
11
 
9
12
  # @param [String] name
10
13
  # @param [Integer] bars
11
14
  # @param block
12
- def initialize(name: '', bars: 4, &_block)
15
+ def initialize(name: '', bars: 4, sequence: nil)
13
16
  @name = name
14
17
  @bars = bars
15
18
  @notes = []
19
+ @sequence = sequence
16
20
  yield if block_given?
17
21
  end
18
22
 
@@ -21,9 +25,11 @@ module Mass
21
25
  # @param [String] name
22
26
  # @param [Integer] bars
23
27
  # @param block
24
- def self.create(name: '', bars: 4, repeat: false, &block)
25
- pattern = new(name: name, bars: bars, &block)
26
- pattern.play! in_loop: repeat
28
+ def self.create(
29
+ name: '', bars: 4, repeat: false, sequence: nil, &block
30
+ )
31
+ pattern = new(name: name, bars: bars, sequence: sequence, &block)
32
+ pattern.play in_loop: repeat if pattern.notes.any?
27
33
  pattern
28
34
  end
29
35
 
@@ -31,9 +37,16 @@ module Mass
31
37
  # into it.
32
38
  #
33
39
  # @param [Boolean] in_loop - defaults to +false+.
34
- def play!(in_loop: false)
35
- _play_once unless in_loop
36
- loop { _play_once }
40
+ def play(in_loop: false)
41
+ return _play_once unless in_loop
42
+ _play_in_loop
43
+ end
44
+
45
+ # Tests equivilance bases on name
46
+ #
47
+ # @return [Boolean] whether both patterns have the same name
48
+ def ==(other)
49
+ other.name == name
37
50
  end
38
51
 
39
52
  protected
@@ -53,7 +66,8 @@ module Mass
53
66
  value: value,
54
67
  pitch: pitch,
55
68
  exp: expression,
56
- midi: _midi
69
+ midi: sequence._midi,
70
+ bpm: sequence._bpm
57
71
  )
58
72
  end
59
73
 
@@ -63,12 +77,12 @@ module Mass
63
77
 
64
78
  private
65
79
 
66
- def _midi
67
- @midi ||= UniMIDI::Output.gets
80
+ def _play_once
81
+ notes.all?(&:play)
68
82
  end
69
83
 
70
- def _play_once
71
- notes.map(&:play)
84
+ def _play_in_loop
85
+ loop { _play_once }
72
86
  end
73
87
  end
74
88
  end
@@ -4,7 +4,10 @@ module Mass
4
4
  # calculating the proper duration and actually playing out
5
5
  # the note.
6
6
  class Pitch
7
- attr_reader :id, :name, :value
7
+ attr_reader :id
8
+ attr_reader :name
9
+ attr_reader :octave
10
+ attr_reader :value
8
11
 
9
12
  # A dictionary of MIDI note values that are substituted
10
13
  # for a given String note value.
@@ -37,10 +40,10 @@ module Mass
37
40
  REQUIRED = %i(name octave value)
38
41
 
39
42
  # @param [String] id - Identifier string of this pitch.
40
- def initialize(identifier)
41
- @id = identifier.to_s
42
- @name = id.gsub(/\d/, '').to_s
43
- @octave = id.gsub(/#{name}/, '').to_i
43
+ def initialize(id: '')
44
+ @id = id.to_s
45
+ @name = @id.gsub(/\d/, '').to_s
46
+ @octave = @id.gsub(/#{name}/, '').to_i
44
47
  @value = begin
45
48
  VALUES[name]
46
49
  rescue
@@ -50,12 +53,11 @@ module Mass
50
53
 
51
54
  # Find a +Pitch+ by its given +id+.
52
55
  #
56
+ # @param [String] by_id
53
57
  # @return [Pitch] when the id is valid
54
- # @throw [Pitch::NotFound] when id is not valid
55
- def self.find(id)
56
- pitch = new(id)
57
- fail NotFound, id unless pitch.valid?
58
- pitch
58
+ def self.find(by_id = nil)
59
+ return if by_id.nil?
60
+ new id: by_id
59
61
  end
60
62
 
61
63
  # Make sure the +name+ and +octave+ attributes have
@@ -75,6 +77,13 @@ module Mass
75
77
  value + octave_modifier
76
78
  end
77
79
 
80
+ # Use the +id+ parameter to define equivalence.
81
+ #
82
+ # @return [Boolean] whether both pitches have the same ID.
83
+ def ==(other)
84
+ other.id == id
85
+ end
86
+
78
87
  private
79
88
 
80
89
  def required_params
@@ -0,0 +1,70 @@
1
+ module Mass
2
+ # A sequence of patterns that is played in order immediately
3
+ # as it is defined.
4
+ class Sequence
5
+ # Name of this sequence
6
+ #
7
+ # @attr_reader [String]
8
+ attr_reader :name
9
+
10
+ # Beats per minute speed of the sequence
11
+ #
12
+ # @attr_reader [Integer]
13
+ attr_reader :_bpm
14
+
15
+ # MIDI driver used to power all notes in the sequence.
16
+ #
17
+ # @attr_reader [UniMIDI::Output]
18
+ attr_reader :_midi
19
+
20
+ # @param [String] name
21
+ # @option [Integer] bpm - defaults to 100
22
+ def initialize(name, bpm: 100)
23
+ @name = name
24
+ @_bpm = bpm
25
+ @_midi ||= UniMIDI::Output.gets
26
+ yield if block_given?
27
+ end
28
+
29
+ # Define a new sequence into the global namespace
30
+ #
31
+ # @param [String] name
32
+ # @options [KeywordArguments] params
33
+ # @param [Proc] block
34
+ # @return [Mass::Sequence]
35
+ def self.define(name, **params, &block)
36
+ new name, **params, &block
37
+ end
38
+
39
+ # Change BPM.
40
+ #
41
+ # @param [Integer] new_bpm
42
+ # @example
43
+ # bpm 128
44
+ #
45
+ def bpm(new_bpm)
46
+ @_bpm = new_bpm
47
+ end
48
+
49
+ # Create a pattern. See the docs on +Mass::Pattern+ for more
50
+ # information about its requirements.
51
+ #
52
+ # @options [KeywordArguments] params
53
+ # @options [Proc] block
54
+ # @example
55
+ # pattern name: 'verse', bars: 1 do
56
+ # note 8, pitch: 'C4'
57
+ # note 8, pitch: 'C3'
58
+ # note 8, pitch: 'A3'
59
+ # note 8, pitch: 'B4'
60
+ # note 8, pitch: 'C4'
61
+ # note 8, pitch: 'Gb2'
62
+ # note 8, pitch: 'C4'
63
+ # rest 8
64
+ # end
65
+ #
66
+ def pattern(**params, &block)
67
+ Pattern.create(**params.merge(sequence: self), &block)
68
+ end
69
+ end
70
+ end
@@ -3,5 +3,5 @@ module Mass
3
3
  # Version number
4
4
  #
5
5
  # @type [String]
6
- VERSION = '0.0.1'
6
+ VERSION = '0.0.2'
7
7
  end
@@ -28,5 +28,5 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency 'travis', '~> 1.8'
29
29
  spec.add_development_dependency 'codeclimate-test-reporter', '~> 0'
30
30
 
31
- spec.add_dependency 'unimidi'
31
+ spec.add_dependency 'unimidi', '~> 0'
32
32
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mass
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Scott
@@ -98,14 +98,14 @@ dependencies:
98
98
  name: unimidi
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ! '>='
101
+ - - ~>
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ! '>='
108
+ - - ~>
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  description: Synth framework for Ruby. Build a cool synth!
@@ -143,7 +143,7 @@ files:
143
143
  - lib/mass/note.rb
144
144
  - lib/mass/pattern.rb
145
145
  - lib/mass/pitch.rb
146
- - lib/mass/pitch/not_found.rb
146
+ - lib/mass/sequence.rb
147
147
  - lib/mass/version.rb
148
148
  - mass.gemspec
149
149
  homepage: https://github.com/tubbo/mass
@@ -1,10 +0,0 @@
1
- module Mass
2
- class Pitch
3
- # Thrown when a +Pitch+ cannot be found, e.g. it is not valid.
4
- class NotFound < RuntimeError
5
- def initialize(name)
6
- @message = "Invalid pitch '#{name}'"
7
- end
8
- end
9
- end
10
- end