lygre 0.0.2 → 0.0.3

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,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c100850289adec3dc56f49db675050c9363706e0
4
- data.tar.gz: a47121a23251de440329e1866dbacb532dd07152
3
+ metadata.gz: b246c70e332e42827f7747ab0439d890b368b720
4
+ data.tar.gz: 6029592482f7d71440f9a5dd402715ad4f504f12
5
5
  SHA512:
6
- metadata.gz: 38b9473ca607f631bd91e10138d5492bb5b72e4ecaceab71d70c13ee7bc8caa521e494f2b1f30889c81412e495dfdf1eae144539982b1e56af80315453fb9d10
7
- data.tar.gz: f697b60699d01c32a0eeb2150351e4765357fbba409917a940b7c1c421a37bf90c4061c1b38a83661412ccf3b336054ca7f269f5fc2c6727cbd1da666b3ffeb9
6
+ metadata.gz: b6bb4e396985f00612b94be4e3b53bbdc4adfdaebd2f7a950e66824aa7d979d966008fb08eb69678e2850e3680352dc562052e7646d8d841f783a77242b53c81
7
+ data.tar.gz: 2fca20a9e491d4b5d33f87d95cdd1a6239a65b49ca797f0cb236dd435595da19112b813a8dc5adc84debebad70bbb8c49ce046a789cb7b6e84bb38dd99616020
@@ -4,10 +4,7 @@
4
4
  gabcscore
5
5
  gabcsemantics
6
6
  gabcpitchreader
7
+ gabcparser
7
8
  lilypondconvertor
9
+ musictheory
8
10
  }.each {|f| require_relative File.join('lygre', f)}
9
-
10
- # gabc parser
11
- require 'polyglot'
12
- require 'treetop'
13
- Treetop.load File.expand_path('../lib/lygre/gabcgrammar', File.dirname(__FILE__))
@@ -0,0 +1,4 @@
1
+ # load treetop grammar, emit class GabcParser
2
+ require 'polyglot'
3
+ require 'treetop'
4
+ Treetop.load File.expand_path('gabcgrammar', File.dirname(__FILE__))
@@ -1,7 +1,5 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'rb-music-theory'
4
-
5
3
  # responsible for converting the 'visual pitch' information
6
4
  # contained in gabc to absolute musical pitch
7
5
  class GabcPitchReader
@@ -55,18 +53,13 @@ class NoteFactory
55
53
  note = notesym[0]
56
54
  octaves = notesym[1..-1]
57
55
 
58
- n = RBMusicTheory::Note.new note.upcase
59
56
  sign = 0
60
- base_octave_shift = -1 # Note.new('C') returns c'=60, not c=48
57
+ octave = 0
61
58
  if octaves then
62
59
  sign = (octaves[0] == ',' ? -1 : 1)
63
- octave_shift = (octaves.size * sign) + base_octave_shift
64
- else
65
- octave_shift = base_octave_shift
60
+ octave += (octaves.size * sign)
66
61
  end
67
- n += octave_shift * RBMusicTheory::NoteInterval.octave.value # strangely, NoteInterval cannot be multiplied
68
-
69
- return n
62
+ return MusicTheory::Note.new note.to_sym, octave
70
63
  end
71
64
 
72
65
  alias :create_note :create
@@ -78,57 +71,8 @@ class NoteFactory
78
71
  # #create translates lilypond pitch to Note and #lily_abs_pitch
79
72
  # does the reverse translation, so maybe just the class should be renamed
80
73
  def lily_abs_pitch(note)
81
- octave_shifts = ''
82
- octave_diff = note.value - create('c').value
83
-
84
- octave_value = RBMusicTheory::NoteInterval.octave.value
85
- octave_shift = octave_diff.abs / octave_value
86
- if octave_diff < 0 and (octave_diff.abs % octave_value) > 0 then
87
- octave_shift += 1
88
- end
89
-
90
- octave_signs = (octave_diff >= 0 ? "'" : ",") * octave_shift
91
- note.name.downcase + octave_signs
92
- end
93
- end
94
- end
95
-
96
- # monkey-patch Note to add step arithmetics
97
- module RBMusicTheory
98
-
99
- class Note
100
-
101
- def diatonic_steps(steps, scale=nil)
102
- if scale.nil? then
103
- scale = self.class.new('C').major_scale
104
- end
105
-
106
- deg = self.degree_in(scale)
107
-
108
- return scale.degree(deg + steps)
109
- end
110
-
111
- # note's degree in a scale
112
- def degree_in(scale)
113
- degree = scale.note_names.index(self.name)
114
- if degree.nil? then
115
- raise ArgumentError.new("#{name} is not a member of #{scale.note_names} scale")
116
- end
117
- degree += 1 # degrees start with 1
118
-
119
- in_base_octave = scale.degree(degree)
120
- octave_steps = scale.note_names.size
121
- octave_value = RBMusicTheory::NoteInterval.octave.value
122
-
123
- value_difference = self.value - in_base_octave.value
124
- octave_difference = value_difference.abs / octave_value
125
- if value_difference < 0 then
126
- octave_difference *= -1
127
- end
128
-
129
- degree += octave_difference * octave_steps
130
-
131
- return degree
74
+ octave_signs = (note.octave >= 0 ? "'" : ",") * note.octave.abs
75
+ note.pitch.to_s + octave_signs
132
76
  end
133
77
  end
134
78
  end
@@ -15,6 +15,8 @@ class Immutable
15
15
 
16
16
  freeze
17
17
  end
18
+
19
+ attr_accessor :text_value
18
20
  end
19
21
 
20
22
  # clean and easy to use music data produced by
@@ -100,16 +100,19 @@ module Gabc
100
100
  if ele.is_a? NoteNode then
101
101
  arr << GabcNote.new do |n|
102
102
  n.pitch = ele.note_pitch.text_value.downcase.to_sym
103
+ n.text_value = ele.text_value
103
104
  end
104
105
  elsif ele.is_a? DivisioNode then
105
106
  arr << GabcDivisio.new do |d|
106
107
  d.type = ele.text_value
108
+ d.text_value = ele.text_value
107
109
  end
108
110
  elsif ele.is_a? ClefNode then
109
111
  arr << GabcClef.new do |c|
110
112
  c.pitch = ele.clef_symbol.text_value.to_sym
111
113
  c.bemol = ele.bemol.text_value == 'b'
112
114
  c.line = ele.line_number.text_value.to_i
115
+ c.text_value = ele.text_value
113
116
  end
114
117
  else
115
118
  collect_notes ele, arr
@@ -0,0 +1,44 @@
1
+ # Simple diatonic music theory necessary for parsing of Gregorian chant scores
2
+ module MusicTheory
3
+ PITCHES = [:c, :d, :e, :f, :g, :a, :b]
4
+ VALUES = [0, 2, 4, 5, 7, 9, 11]
5
+
6
+ class Note
7
+ def initialize(pitch=:c, octave=1)
8
+ @pitch = pitch
9
+ @pitch_numeric = PITCHES.index @pitch
10
+ @octave = octave
11
+
12
+ if @pitch_numeric.nil?
13
+ raise ArgumentError.new("Invalid pitch #{pitch.inspect}")
14
+ end
15
+ end
16
+
17
+ attr_reader :pitch, :octave
18
+
19
+ def diatonic_steps(steps)
20
+ base_steps = steps % PITCHES.size
21
+ octaves = steps / PITCHES.size
22
+ new_step = @pitch_numeric + base_steps
23
+ if new_step >= PITCHES.size
24
+ new_step -= PITCHES.size
25
+ octaves += 1
26
+ end
27
+ new_pitch = PITCHES[new_step]
28
+ self.class.new(new_pitch, @octave + octaves)
29
+ end
30
+
31
+ def value
32
+ (@octave + 4) * 12 + VALUES[@pitch_numeric]
33
+ end
34
+
35
+ def ==(other)
36
+ other.pitch == @pitch &&
37
+ other.octave == @octave
38
+ end
39
+
40
+ def hash
41
+ [@pitch, @octave].hash
42
+ end
43
+ end
44
+ end
@@ -1,4 +1,5 @@
1
1
  # encoding: UTF-8
2
+ require 'spec_helper'
2
3
 
3
4
  describe GabcPitchReader do
4
5
 
@@ -70,9 +71,9 @@ describe NoteFactory do
70
71
  end
71
72
 
72
73
  describe '.lily_abs_pitch' do
73
- it 'operates exactly reverse to .create' do
74
+ describe 'operates exactly reverse to .create' do
74
75
  %w{ c d g c' f' a' b' g'' d''' c, c,, c,,, d, e, e,, b, }.each do |lypitch|
75
- @f.lily_abs_pitch(@f[lypitch]).should eq lypitch
76
+ it { @f.lily_abs_pitch(@f[lypitch]).should eq lypitch }
76
77
  end
77
78
  end
78
79
  end
@@ -82,55 +83,3 @@ describe NoteFactory do
82
83
  it { @f["c''"].value.should eq 72 }
83
84
  end
84
85
  end
85
-
86
- describe 'monkey-patched RBMusicTheory' do
87
-
88
- before :each do
89
- @f = NoteFactory
90
- @s = @f["c''"].major_scale
91
- end
92
-
93
- describe 'Note#diatonic_steps' do
94
- it { @f["c'"].diatonic_steps(1).should eq @f["d'"] }
95
- it { @f["c'"].diatonic_steps(0).should eq @f["c'"] }
96
- it { @f["c'"].diatonic_steps(7).should eq @f["c''"] }
97
- it { @f["c'"].diatonic_steps(8).should eq @f["d''"] }
98
- it { @f["c'"].diatonic_steps(-2).should eq @f["a"] }
99
- it { @f["c''"].diatonic_steps(-9).should eq @f["a"] }
100
- it { @f["c'''"].diatonic_steps(-9).should eq @f["a'"] }
101
- it { @f["c,"].diatonic_steps(-9).should eq @f["a,,,"] }
102
- it { @f["c,"].diatonic_steps(-10).should eq @f["g,,,"] }
103
- end
104
-
105
- describe 'Note#degree_in' do
106
- it { @f["c''"].degree_in(@s).should eq 1 }
107
- it { @f["d''"].degree_in(@s).should eq 2 }
108
-
109
- it { @f["c'''"].degree_in(@s).should eq 8 }
110
- it { @f["e'''"].degree_in(@s).should eq 10 }
111
- it { @f["b'"].degree_in(@s).should eq 0 }
112
- it { @f["a'"].degree_in(@s).should eq -1 }
113
- it { @f["a"].degree_in(@s).should eq -8 }
114
-
115
- it 'behaves consistently with Scale#degree' do
116
- [2, 8, -1, -12].each do |deg|
117
- @s.degree(deg).degree_in(@s).should eq deg
118
- end
119
- end
120
- end
121
-
122
- describe 'Scale#degree' do
123
- describe 'for positive degrees it behaves as expected' do
124
- it { @s.degree(1).should eq @f["c''"] }
125
- it { @s.degree(2).should eq @f["d''"] }
126
- it { @s.degree(8).should eq @f["c'''"] }
127
- end
128
-
129
- describe 'and then there is zero and negative numbers' do
130
- it { @s.degree(0).should eq @f["b'"] }
131
- it { @s.degree(-1).should eq @f["a'"] }
132
- it { @s.degree(-8).should eq @f["a"] }
133
- it { @s.degree(-15).should eq @f["a,"] }
134
- end
135
- end
136
- end
@@ -0,0 +1,44 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+
4
+ describe MusicTheory do
5
+ describe MusicTheory::Note do
6
+ let(:c1) { described_class.new(:c) }
7
+ let(:c2) { described_class.new(:c, 2) }
8
+
9
+ describe '#diatonic_steps' do
10
+ it 'step in the base octave' do
11
+ c1.diatonic_steps(1).should eq described_class.new(:d)
12
+ end
13
+
14
+ it 'octave step' do
15
+ c1.diatonic_steps(7).should eq c2
16
+ end
17
+
18
+ it 'single step to the next octave' do
19
+ b = described_class.new(:b)
20
+ b.diatonic_steps(1).should eq c2
21
+ end
22
+
23
+ it 'single step to the previous octave' do
24
+ c1.diatonic_steps(-1).should eq described_class.new(:b, 0)
25
+ end
26
+
27
+ it 'preserve octave' do
28
+ c = described_class.new(:c, -1)
29
+ c.diatonic_steps(1).should eq described_class.new(:d, -1)
30
+ end
31
+ end
32
+
33
+ describe '#value' do
34
+ it { c1.value.should eq 60 }
35
+ it { described_class.new(:d).value.should eq 62 }
36
+ it { described_class.new(:e).value.should eq 64 }
37
+ it { described_class.new(:f).value.should eq 65 }
38
+ it { described_class.new(:g).value.should eq 67 }
39
+ it { described_class.new(:a).value.should eq 69 }
40
+ it { described_class.new(:b).value.should eq 71 }
41
+ it { described_class.new(:c, 2).value.should eq 72 }
42
+ end
43
+ end
44
+ end
@@ -15,17 +15,8 @@ RSpec.configure do |config|
15
15
  config.order = 'random'
16
16
  end
17
17
 
18
- require 'polyglot'
19
- require 'treetop'
20
-
21
18
  require_relative 'matchers'
22
19
 
23
-
24
- $: << '../lib'
25
- require 'grely'
26
-
27
- Treetop.load File.expand_path('../lib/lygre/gabcgrammar', File.dirname(__FILE__))
28
-
29
20
  def load_example(fname)
30
21
  File.read(
31
22
  File.expand_path(
@@ -34,3 +25,6 @@ def load_example(fname)
34
25
  )
35
26
  )
36
27
  end
28
+
29
+ # load the tested code
30
+ require_relative '../lib/grely'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lygre
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub Pavlík
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-02 00:00:00.000000000 Z
11
+ date: 2016-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: treetop
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.3'
41
- - !ruby/object:Gem::Dependency
42
- name: rb-music-theory
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.1'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '0.1'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: rspec
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -74,10 +60,6 @@ description: |
74
60
  input format (gabc) to simple LilyPond input.
75
61
 
76
62
  In future another tool for the other direction of conversion may be added.
77
-
78
- As rb-music-theory is not at RubyGems, either install it before
79
- attempting to 'gem install lygre', or get lygre's source from github
80
- and install the dependencies by 'bundle install'.
81
63
  email: jkb.pavlik@gmail.com
82
64
  executables:
83
65
  - grely.rb
@@ -87,16 +69,19 @@ files:
87
69
  - bin/grely.rb
88
70
  - lib/grely.rb
89
71
  - lib/lygre/gabcgrammar.treetop
72
+ - lib/lygre/gabcparser.rb
90
73
  - lib/lygre/gabcpitchreader.rb
91
74
  - lib/lygre/gabcscore.rb
92
75
  - lib/lygre/gabcsemantics.rb
93
76
  - lib/lygre/lilypondconvertor.rb
77
+ - lib/lygre/musictheory.rb
94
78
  - spec/gabcgrammar_spec.rb
95
79
  - spec/gabcparser_spec.rb
96
80
  - spec/gabcpitchreader_spec.rb
97
81
  - spec/gabcscore_spec.rb
98
82
  - spec/lilypondconvertor_spec.rb
99
83
  - spec/matchers.rb
84
+ - spec/musictheory_spec.rb
100
85
  - spec/spec_helper.rb
101
86
  homepage: http://github.com/igneus/lygre
102
87
  licenses:
@@ -119,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
104
  version: '0'
120
105
  requirements: []
121
106
  rubyforge_project:
122
- rubygems_version: 2.4.8
107
+ rubygems_version: 2.2.0
123
108
  signing_key:
124
109
  specification_version: 4
125
110
  summary: converts music formats gabc -> lilypond