mass 0.0.1 → 0.0.2

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 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