webern 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -1
- data/Gemfile +3 -3
- data/Guardfile +8 -0
- data/README.md +30 -29
- data/Rakefile +4 -83
- data/lib/webern.rb +2 -16
- data/lib/webern/formatters/base.rb +15 -0
- data/lib/webern/formatters/lilypond.rb +43 -0
- data/lib/webern/formatters/pdf.rb +18 -0
- data/lib/webern/formatters/text.rb +34 -0
- data/lib/webern/row.rb +21 -31
- data/lib/webern/version.rb +3 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/webern/row_spec.rb +73 -0
- data/spec/webern_spec.rb +8 -53
- data/webern.gemspec +30 -0
- metadata +174 -66
- data/.document +0 -4
- data/CHANGELOG.md +0 -3
- data/LICENSE +0 -20
- data/VERSION +0 -1
- data/bin/webern +0 -10
- data/lib/core_ext.rb +0 -11
- data/lib/webern/lilypond_builder.rb +0 -62
- data/lib/webern/matrix.rb +0 -26
- data/spec/array_spec.rb +0 -22
- data/spec/helper.rb +0 -5
- data/spec/lilypond_builder_spec.rb +0 -40
- data/spec/matrix_spec.rb +0 -22
- data/spec/row_spec.rb +0 -29
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
gem
|
4
|
-
|
3
|
+
# Specify your gem's dependencies in webern.gemspec
|
4
|
+
gemspec
|
data/Guardfile
ADDED
data/README.md
CHANGED
@@ -1,50 +1,51 @@
|
|
1
|
-
#
|
1
|
+
# Webern
|
2
2
|
|
3
|
-
|
3
|
+
Transforms user input into a complete 12-tone row and computes all 48 (at most) possible rows that result from the matrix of that row.
|
4
4
|
|
5
|
-
|
5
|
+
Possible outputs:
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
row, and then output all 48 possible rows created by that matrix to a .pdf file using the LilyPond notational
|
11
|
-
language.
|
7
|
+
* text
|
8
|
+
* pdf
|
9
|
+
* lilypond
|
12
10
|
|
13
11
|
## Installation
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
~$ gem install gemcutter
|
13
|
+
Add this line to your application's Gemfile:
|
18
14
|
|
19
|
-
|
15
|
+
gem 'webern'
|
20
16
|
|
21
|
-
|
17
|
+
And then execute:
|
22
18
|
|
23
|
-
|
19
|
+
$ bundle
|
24
20
|
|
25
|
-
|
21
|
+
Or install it yourself as:
|
26
22
|
|
27
|
-
|
28
|
-
|
29
|
-
No other gems are required, but you do need [LilyPond][lilypond] to generate the .pdf file.
|
23
|
+
$ gem install webern
|
30
24
|
|
31
25
|
## Usage
|
32
26
|
|
33
|
-
|
27
|
+
Create a row of the numbers 0 - 11
|
28
|
+
|
29
|
+
row = Webern::Row.new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
|
34
30
|
|
35
|
-
|
36
|
-
|
37
|
-
~$ webern michael berkowitz
|
31
|
+
You do not need to provide a full row. `Webern` will fill out the missing
|
32
|
+
numbers by adding them in ascending order to the end of the provided row.
|
38
33
|
|
39
|
-
|
34
|
+
row = Webern::Row.new(5, 4, 8, 7, 10, 11, 3, 2) #=> [5, 4, 8, 7, 10, 11, 3, 2, 0, 1, 6, 9]
|
40
35
|
|
41
|
-
|
36
|
+
Then choose a format in which to output either the matrix (text or pdf) or all
|
37
|
+
possible rows resulting from that matrix (lilypond).
|
42
38
|
|
43
|
-
|
39
|
+
Webern::Formatters.Text.new(row).print_to_file('filename.txt)
|
40
|
+
Webern::Formatters.Pdf.new(row).print_to_file('filename.pdf)
|
41
|
+
Webern::Formatters.Lilypond.new(row).print_to_file('filename.ly')
|
44
42
|
|
45
|
-
|
43
|
+
The `lilypond` executable is required in order to convert the resulting `filename.ly` file to PDF.
|
46
44
|
|
47
|
-
|
45
|
+
## Contributing
|
48
46
|
|
49
|
-
|
50
|
-
|
47
|
+
1. Fork it
|
48
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
49
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
50
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
51
|
+
5. Create new Pull Request
|
data/Rakefile
CHANGED
@@ -1,85 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require '
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rspec/core/rake_task'
|
3
3
|
|
4
|
-
|
5
|
-
require 'jeweler'
|
6
|
-
Jeweler::Tasks.new do |gem|
|
7
|
-
gem.name = "webern"
|
8
|
-
gem.summary = %Q{Creates a .pdf reference sheet for all 12-tone rows generated from a given prime row's matrix.}
|
9
|
-
gem.description = %Q{Taking a 12-tone row generated from user input Webern will create the full matrix based upon this row, and then output all 48 possible rows created by that matrix to a .pdf file using the LilyPond notational language.}
|
10
|
-
gem.email = "michael.berkowitz@gmail.com"
|
11
|
-
gem.homepage = "http://github.com/mikowitz/webern"
|
12
|
-
gem.authors = ["Michael Berkowitz"]
|
13
|
-
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
-
end
|
15
|
-
Jeweler::GemcutterTasks.new
|
16
|
-
rescue LoadError
|
17
|
-
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
18
|
-
end
|
4
|
+
RSpec::Core::RakeTask.new('spec')
|
19
5
|
|
20
|
-
|
21
|
-
Spec::Rake::SpecTask.new(:spec) do |spec|
|
22
|
-
spec.libs << "lib" << "spec"
|
23
|
-
spec.spec_opts = ["-cfs"]
|
24
|
-
spec.spec_files = FileList["spec/**/*_spec.rb"]
|
25
|
-
end
|
26
|
-
|
27
|
-
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
28
|
-
spec.libs << "lib" << "spec"
|
29
|
-
spec.pattern = "spec/**/*_spec.rb"
|
30
|
-
spec.rcov = true
|
31
|
-
end
|
32
|
-
|
33
|
-
task :test => :check_dependencies
|
34
|
-
|
35
|
-
begin
|
36
|
-
require 'reek/adapters/rake_task'
|
37
|
-
Reek::RakeTask.new do |t|
|
38
|
-
t.fail_on_error = true
|
39
|
-
t.verbose = false
|
40
|
-
t.source_files = 'lib/**/*.rb'
|
41
|
-
end
|
42
|
-
rescue LoadError
|
43
|
-
task :reek do
|
44
|
-
abort "Reek is not available. In order to run reek, you must: sudo gem install reek"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
begin
|
49
|
-
require 'roodi'
|
50
|
-
require 'roodi_task'
|
51
|
-
RoodiTask.new do |t|
|
52
|
-
t.verbose = false
|
53
|
-
end
|
54
|
-
rescue LoadError
|
55
|
-
task :roodi do
|
56
|
-
abort "Roodi is not available. In order to run roodi, you must: sudo gem install roodi"
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
task :default => :spec
|
61
|
-
|
62
|
-
begin
|
63
|
-
require 'yard'
|
64
|
-
YARD::Rake::YardocTask.new do |t|
|
65
|
-
t.options = %w{--no-private -mmarkdown}
|
66
|
-
end
|
67
|
-
rescue LoadError
|
68
|
-
task :yardoc do
|
69
|
-
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
begin
|
74
|
-
require 'hanna/rdoctask'
|
75
|
-
desc "generate hanna documentation"
|
76
|
-
Rake::RDocTask.new(:hanna) do |t|
|
77
|
-
t.rdoc_files.include("README.md", "License", "lib/**/*.rb")
|
78
|
-
t.main = "README.md"
|
79
|
-
t.rdoc_dir = "hanna"
|
80
|
-
end
|
81
|
-
rescue LoadError
|
82
|
-
task :hanna do
|
83
|
-
abort "hanna is not available. In order to run this task, you must: sudo gem install hanna"
|
84
|
-
end
|
85
|
-
end
|
6
|
+
task default: :spec
|
data/lib/webern.rb
CHANGED
@@ -1,19 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
%w{ core_ext lilypond_builder matrix row }.each {|file| require file }
|
1
|
+
require "webern/version"
|
2
|
+
Dir[File.dirname(__FILE__) + '/**/*.rb'].each {|file| require file}
|
5
3
|
|
6
4
|
module Webern
|
7
|
-
class << self
|
8
|
-
attr_accessor :prime_row
|
9
|
-
end
|
10
|
-
|
11
|
-
def Webern.new(*row_elements)
|
12
|
-
@prime_row = Row.new(*row_elements).zero_row
|
13
|
-
@m = Matrix.new(@prime_row)
|
14
|
-
LilypondBuilder.generate_file(@m)
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
InvalidRow = Class.new(Exception)
|
19
5
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Webern
|
2
|
+
module Formatters
|
3
|
+
class Base
|
4
|
+
PITCH_CLASSES = %w{ C C# D Eb E F F# G Ab A Bb B }
|
5
|
+
def initialize(prime_row, show_pitch_classes=true)
|
6
|
+
@prime_row = prime_row
|
7
|
+
@show_pitch_classes = show_pitch_classes
|
8
|
+
end
|
9
|
+
|
10
|
+
def pitch_value(n)
|
11
|
+
@show_pitch_classes ? PITCH_CLASSES[n] : n.to_s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Webern
|
2
|
+
module Formatters
|
3
|
+
class Lilypond < Base
|
4
|
+
def write_to_file(filename)
|
5
|
+
File.open(filename, 'w') do |f|
|
6
|
+
f << LILYPOND_HEADER
|
7
|
+
f << "rows = {\n"
|
8
|
+
f << "\\time 12/4\n"
|
9
|
+
f << "\\override Staff.Stem #'transparent = ##t\n"
|
10
|
+
{p: :prime, i: :inversion, r: :retrograde, ri: :retrograde_inversion}.each do |key, transformation|
|
11
|
+
(0..11).each do |transposition|
|
12
|
+
f << "\\mark \"#{key}#{transposition}\" "
|
13
|
+
f << @prime_row.send(transformation).zero.transpose(transposition).map{|n| lilypond_pitch(n) }.join(' ') + "\n"
|
14
|
+
end
|
15
|
+
f << "\\bar \"||\"\n"
|
16
|
+
end
|
17
|
+
f << "}\n"
|
18
|
+
f << LILYPOND_SCORE_BLOCK
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def lilypond_pitch(n)
|
23
|
+
%w{ c'' cs'' d'' ef'' e'' f' fs' g' af' a' bf' b' }[n]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
LILYPOND_HEADER = <<-pond
|
30
|
+
\\version "2.16.2"
|
31
|
+
\\include "english.ly"
|
32
|
+
|
33
|
+
#(set-global-staff-size 13)
|
34
|
+
|
35
|
+
pond
|
36
|
+
|
37
|
+
LILYPOND_SCORE_BLOCK = <<-pond
|
38
|
+
\\score {
|
39
|
+
<<
|
40
|
+
\\new Staff \\rows
|
41
|
+
>>
|
42
|
+
}
|
43
|
+
pond
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'prawn'
|
2
|
+
|
3
|
+
module Webern
|
4
|
+
module Formatters
|
5
|
+
class Pdf < Base
|
6
|
+
def write_to_file(filename)
|
7
|
+
data = @prime_row.inversion.map do |i|
|
8
|
+
@prime_row.transpose(i).map do |n|
|
9
|
+
pitch_value(n)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
Prawn::Document.generate(filename) do |pdf|
|
13
|
+
pdf.table data, cell_style: { width: 42, height: 42, align: :center, padding: 10}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Webern
|
2
|
+
module Formatters
|
3
|
+
class Text < Base
|
4
|
+
def draw
|
5
|
+
output($stdout)
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
def write_to_file(filename)
|
10
|
+
File.open(filename, 'w') do |f|
|
11
|
+
output(f)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def output(target)
|
18
|
+
@prime_row.inversion.each do |i|
|
19
|
+
target << border_row
|
20
|
+
target << empty_row
|
21
|
+
target << @prime_row.transpose(i).map{|n| pitch_cell(n) }.join + "|\n"
|
22
|
+
target << empty_row
|
23
|
+
end
|
24
|
+
target << border_row
|
25
|
+
end
|
26
|
+
|
27
|
+
def border_row; ('|---------' * 12) + "|\n"; end
|
28
|
+
def empty_row; ('| ' * 12) + "|\n"; end
|
29
|
+
def pitch_cell(n)
|
30
|
+
'| %s ' % (pitch_value(n)).rjust(2)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/webern/row.rb
CHANGED
@@ -1,53 +1,43 @@
|
|
1
1
|
module Webern
|
2
2
|
class Row < Array
|
3
|
-
def initialize(*
|
4
|
-
@row =
|
5
|
-
|
6
|
-
@row = process_strings if @row.any?{|element| element.is_a?(String) }
|
7
|
-
@row = complete_row[0..11]
|
8
|
-
replace @row
|
3
|
+
def initialize(*row)
|
4
|
+
@row = row
|
5
|
+
replace complete_row
|
9
6
|
end
|
10
7
|
|
11
|
-
def
|
12
|
-
|
13
|
-
def inversion
|
14
|
-
Row.new *map{|note| (12 - note) % 12 }
|
8
|
+
def zero!
|
9
|
+
replace zero
|
15
10
|
end
|
16
11
|
|
17
|
-
def
|
18
|
-
Row.new *
|
12
|
+
def prime
|
13
|
+
Row.new *self
|
19
14
|
end
|
20
15
|
|
21
|
-
def
|
22
|
-
Row.new *map{|
|
16
|
+
def inversion
|
17
|
+
Row.new *self.map{|i| (12 - i) % 12}
|
23
18
|
end
|
24
19
|
|
25
|
-
def
|
26
|
-
|
27
|
-
_remainder = Array(0..11) - @row
|
28
|
-
[@row, _remainder].flatten
|
20
|
+
def retrograde
|
21
|
+
Row.new *self.reverse
|
29
22
|
end
|
30
23
|
|
31
|
-
def
|
32
|
-
|
33
|
-
_letters = full_string.uniq[0..11]
|
34
|
-
_letters.generate_row_from_letters
|
24
|
+
def retrograde_inversion
|
25
|
+
Row.new *self.retrograde.inversion
|
35
26
|
end
|
36
27
|
|
37
|
-
def
|
38
|
-
|
28
|
+
def transpose(distance)
|
29
|
+
Row.new *self.map{|i| (i + distance) % 12 }
|
39
30
|
end
|
40
31
|
|
41
|
-
def
|
42
|
-
|
32
|
+
def zero
|
33
|
+
Row.new *self.map{|i| (i + 12 - self[0]) % 12}
|
43
34
|
end
|
44
35
|
|
45
|
-
|
46
|
-
@row.all?{|element| element.is_a?(String) }
|
47
|
-
end
|
36
|
+
private
|
48
37
|
|
49
|
-
def
|
50
|
-
|
38
|
+
def complete_row
|
39
|
+
missing = Array(0..11) - @row
|
40
|
+
@row + missing
|
51
41
|
end
|
52
42
|
end
|
53
43
|
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Webern::Row do
|
4
|
+
describe 'complete integer row' do
|
5
|
+
# Concerto for Nine Instruments, Op. 24
|
6
|
+
let(:row) { create_row(11, 10, 2, 3, 7, 6, 8, 4, 5, 0, 1, 9) }
|
7
|
+
|
8
|
+
describe '#zero' do
|
9
|
+
it 'should return the row normalized to start on 0' do
|
10
|
+
expect(row.zero).to eq [0, 11, 3, 4, 8, 7, 9, 5, 6, 1, 2, 10]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'transformations' do
|
15
|
+
before { row.zero! }
|
16
|
+
it 'should invert correctly' do
|
17
|
+
expect(row.inversion).to eq [0, 1, 9, 8, 4, 5, 3, 7, 6, 11, 10, 2]
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should retrograde correctly' do
|
21
|
+
expect(row.retrograde).to eq [10, 2, 1, 6, 5, 9, 7, 8, 4, 3, 11, 0]
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should retrograde-inversion correctly' do
|
25
|
+
expect(row.retrograde_inversion).to eq [2, 10, 11, 6, 7, 3, 5, 4, 8, 9, 1, 0]
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should transpose correctly' do
|
29
|
+
expect(row.transpose(2)).to eq [2, 1, 5, 6, 10, 9, 11, 7, 8, 3, 4, 0]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'incomplete integer row' do
|
35
|
+
# String Quartet, Op. 28
|
36
|
+
let(:row) { create_row(10, 9, 0, 11, 3, 4, 1, 2) } # actual ending: 6, 5, 8, 7
|
37
|
+
|
38
|
+
describe 'row completion' do
|
39
|
+
it 'should complete the row in ascending order of remaining pitches' do
|
40
|
+
expect(row).to eq [10, 9, 0, 11, 3, 4, 1, 2, 5, 6, 7, 8]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#zero' do
|
45
|
+
it 'should return the row normalized to start on 0' do
|
46
|
+
expect(row.zero).to eq [0, 11, 2, 1, 5, 6, 3, 4, 7, 8, 9, 10]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'transformations' do
|
51
|
+
before { row.zero! }
|
52
|
+
it 'should invert correctly' do
|
53
|
+
expect(row.inversion).to eq [0, 1, 10, 11, 7, 6, 9, 8, 5, 4, 3, 2]
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should retrograde correctly' do
|
57
|
+
expect(row.retrograde).to eq [10, 9, 8, 7, 4, 3 ,6, 5, 1, 2, 11, 0]
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should retrograde-inversion correctly' do
|
61
|
+
expect(row.retrograde_inversion).to eq [2, 3, 4, 5, 8, 9, 6, 7, 11, 10, 1, 0]
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should transpose correctly' do
|
65
|
+
expect(row.transpose(2)).to eq [2, 1, 4, 3, 7, 8, 5, 6, 9, 10, 11, 0]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_row(*args)
|
71
|
+
Webern::Row.new(*args)
|
72
|
+
end
|
73
|
+
end
|
data/spec/webern_spec.rb
CHANGED
@@ -1,55 +1,10 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
it
|
5
|
-
Webern.new(
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
alias :test_with_incomplete_row :test_with_full_row
|
10
|
-
alias :test_with_complete_string :test_with_full_row
|
11
|
-
alias :test_with_incomplete_string :test_with_full_row
|
12
|
-
|
13
|
-
describe "Webern" do
|
14
|
-
describe "parsing complete rows" do
|
15
|
-
# beginning with 0
|
16
|
-
test_with_full_row(Array(0..11), Array(0..11))
|
17
|
-
test_with_full_row([0,11,10,9,8,7,6,5,4,3,2,1], [0,11,10,9,8,7,6,5,4,3,2,1])
|
18
|
-
|
19
|
-
# not beginning with 0
|
20
|
-
test_with_full_row([1,2,3,9,7,8,6,4,5,0,11,10], [0,1,2,8,6,7,5,3,4,11,10,9])
|
21
|
-
test_with_full_row(Array(0..11).reverse, [0,11,10,9,8,7,6,5,4,3,2,1])
|
22
|
-
end
|
23
|
-
|
24
|
-
describe "parsing incomplete rows" do
|
25
|
-
# beginning with 0
|
26
|
-
test_with_incomplete_row(Array(0..6), Array(0..11))
|
27
|
-
test_with_incomplete_row([0,11,10,9,8,7], [0,11,10,9,8,7,1,2,3,4,5,6])
|
28
|
-
|
29
|
-
# not beginning with 0
|
30
|
-
test_with_incomplete_row([1,2,3,9,7,8,6], [0,1,2,8,6,7,5,11,3,4,9,10])
|
31
|
-
test_with_incomplete_row([11,10,9,8,7,6], [0,11,10,9,8,7,1,2,3,4,5,6])
|
32
|
-
end
|
33
|
-
|
34
|
-
describe "parsing invalid rows" do
|
35
|
-
it "should raise an error for [1,2,3,4,5,6,7,8,9,10,11,12]" do
|
36
|
-
lambda { Webern.new(*Array(1..12)) }.should raise_error Webern::InvalidRow
|
37
|
-
end
|
38
|
-
it "should raise an error for [-1,0,1,2,3]" do
|
39
|
-
lambda { Webern.new(*Array(-1..3)) }.should raise_error Webern::InvalidRow
|
40
|
-
end
|
41
|
-
it "should raise an error for [0,1,2,3,4.5]" do
|
42
|
-
lambda { Webern.new(0,1,2,3,4.5) }.should raise_error Webern::InvalidRow
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
describe "parsing strings that provide a full row" do
|
47
|
-
test_with_complete_string(%w{a b c d e f g h i j k l}, Array(0..11))
|
48
|
-
test_with_complete_string(%w{michael rowe berkowitz}, [0,9,6,8,4,7,11,2,1,3,5,10])
|
49
|
-
end
|
50
|
-
|
51
|
-
describe "parsing strings that do not provide a full row" do
|
52
|
-
test_with_incomplete_string(%w{a b c d e f g}, Array(0..11))
|
53
|
-
test_with_incomplete_string(%w{michael rowe}, [0,10,7,9,6,8,11,2,1,3,4,5])
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Webern do
|
4
|
+
it 'should output correctly' do
|
5
|
+
row = Webern::Row.new(11, 10, 2, 3, 7, 6, 8, 4, 5, 0, 1, 9)
|
6
|
+
Webern::Formatters::Text.new(row, false).write_to_file('row.txt')
|
7
|
+
Webern::Formatters::Pdf.new(row).write_to_file('row.pdf')
|
8
|
+
Webern::Formatters::Lilypond.new(row).write_to_file('lilypond-row.ly')
|
54
9
|
end
|
55
10
|
end
|
data/webern.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'webern/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "webern"
|
8
|
+
spec.version = Webern::VERSION
|
9
|
+
spec.authors = ["Michael Berkowitz"]
|
10
|
+
spec.email = ["michael.berkowitz@gmail.com"]
|
11
|
+
spec.description = %q{Transforms user input into a complete 12-tone row and computes all 48 (at most) possible rows that result from the matrix of that row.}
|
12
|
+
spec.summary = %q{Calculates all 48 possible 12-tone rows from the given input}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'prawn'
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "rspec"
|
26
|
+
spec.add_development_dependency "guard"
|
27
|
+
spec.add_development_dependency "guard-rspec"
|
28
|
+
spec.add_development_dependency "terminal-notifier-guard"
|
29
|
+
spec.add_development_dependency "rb-fsevent"
|
30
|
+
end
|
metadata
CHANGED
@@ -1,87 +1,195 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: webern
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 2
|
8
|
-
- 0
|
9
|
-
version: 0.2.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Michael Berkowitz
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
-
|
12
|
+
date: 2013-04-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: prawn
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.3'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.3'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: guard
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: guard-rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: terminal-notifier-guard
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: rb-fsevent
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
description: Transforms user input into a complete 12-tone row and computes all 48
|
143
|
+
(at most) possible rows that result from the matrix of that row.
|
144
|
+
email:
|
145
|
+
- michael.berkowitz@gmail.com
|
146
|
+
executables: []
|
25
147
|
extensions: []
|
26
|
-
|
27
|
-
|
28
|
-
- LICENSE
|
29
|
-
- README.md
|
30
|
-
files:
|
31
|
-
- .document
|
148
|
+
extra_rdoc_files: []
|
149
|
+
files:
|
32
150
|
- .gitignore
|
33
|
-
- CHANGELOG.md
|
34
151
|
- Gemfile
|
35
|
-
-
|
152
|
+
- Guardfile
|
153
|
+
- LICENSE.txt
|
36
154
|
- README.md
|
37
155
|
- Rakefile
|
38
|
-
- VERSION
|
39
|
-
- bin/webern
|
40
|
-
- lib/core_ext.rb
|
41
156
|
- lib/webern.rb
|
42
|
-
- lib/webern/
|
43
|
-
- lib/webern/
|
157
|
+
- lib/webern/formatters/base.rb
|
158
|
+
- lib/webern/formatters/lilypond.rb
|
159
|
+
- lib/webern/formatters/pdf.rb
|
160
|
+
- lib/webern/formatters/text.rb
|
44
161
|
- lib/webern/row.rb
|
45
|
-
-
|
46
|
-
- spec/
|
47
|
-
- spec/
|
48
|
-
- spec/matrix_spec.rb
|
49
|
-
- spec/row_spec.rb
|
162
|
+
- lib/webern/version.rb
|
163
|
+
- spec/spec_helper.rb
|
164
|
+
- spec/webern/row_spec.rb
|
50
165
|
- spec/webern_spec.rb
|
51
|
-
|
52
|
-
homepage:
|
53
|
-
licenses:
|
54
|
-
|
166
|
+
- webern.gemspec
|
167
|
+
homepage: ''
|
168
|
+
licenses:
|
169
|
+
- MIT
|
55
170
|
post_install_message:
|
56
|
-
rdoc_options:
|
57
|
-
|
58
|
-
require_paths:
|
171
|
+
rdoc_options: []
|
172
|
+
require_paths:
|
59
173
|
- lib
|
60
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
requirements:
|
69
|
-
- -
|
70
|
-
- !ruby/object:Gem::Version
|
71
|
-
|
72
|
-
- 0
|
73
|
-
version: "0"
|
174
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
175
|
+
none: false
|
176
|
+
requirements:
|
177
|
+
- - ! '>='
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
181
|
+
none: false
|
182
|
+
requirements:
|
183
|
+
- - ! '>='
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
74
186
|
requirements: []
|
75
|
-
|
76
187
|
rubyforge_project:
|
77
|
-
rubygems_version: 1.
|
188
|
+
rubygems_version: 1.8.23
|
78
189
|
signing_key:
|
79
190
|
specification_version: 3
|
80
|
-
summary:
|
81
|
-
test_files:
|
82
|
-
- spec/
|
83
|
-
- spec/
|
84
|
-
- spec/lilypond_builder_spec.rb
|
85
|
-
- spec/matrix_spec.rb
|
86
|
-
- spec/row_spec.rb
|
191
|
+
summary: Calculates all 48 possible 12-tone rows from the given input
|
192
|
+
test_files:
|
193
|
+
- spec/spec_helper.rb
|
194
|
+
- spec/webern/row_spec.rb
|
87
195
|
- spec/webern_spec.rb
|
data/.document
DELETED
data/CHANGELOG.md
DELETED
data/LICENSE
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
Copyright (c) 2010 Michael Berkowitz
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.2.0
|
data/bin/webern
DELETED
data/lib/core_ext.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
module Webern
|
2
|
-
module LilypondBuilder
|
3
|
-
NOTES = %w{c cs d ef e f fs g af a bf b}
|
4
|
-
|
5
|
-
class << self
|
6
|
-
attr_writer :zero_note
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.current_lilypond_version
|
10
|
-
`lilypond --version`.match(/\d+\.\d+\.\d+/)[0]
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.zero_note
|
14
|
-
@zero_note ||= "c"
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.convert_row(row)
|
18
|
-
row.map{|note| NOTES[(note + NOTES.index(self.zero_note)) % 12] }.join(" ")
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.generate_file(matrix)
|
22
|
-
file = [PREAMBLE_BLOCK, "\n"]
|
23
|
-
file << STAFF_BLOCK
|
24
|
-
[:primes, :retrogrades, :inversions, :retrograde_inversions].each do |method|
|
25
|
-
abbrev = method.to_s.scan(/^\w|_\w/).join("").gsub(/_/, "").upcase
|
26
|
-
matrix.send(method).each do |row|
|
27
|
-
first = row[0]
|
28
|
-
row = self.convert_row(row)
|
29
|
-
row = row.sub(" ", "^\\markup{#{abbrev}#{first}} ")
|
30
|
-
file << " #{row}"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
file << "\}" << "\n" << SCORE_BLOCK
|
34
|
-
File.open("matrix.ly", "w") do |f|
|
35
|
-
f << file.join("\n")
|
36
|
-
end
|
37
|
-
# TODO: This unless seems a bit messy
|
38
|
-
system("lilypond matrix.ly") unless $0 =~ /spec|rcov/
|
39
|
-
end
|
40
|
-
|
41
|
-
PREAMBLE_BLOCK = <<-STR
|
42
|
-
\\version \"#{self.current_lilypond_version}\"
|
43
|
-
\\include \"english.ly\"
|
44
|
-
#(set-global-staff-size 13)
|
45
|
-
STR
|
46
|
-
|
47
|
-
STAFF_BLOCK = <<-STR
|
48
|
-
rows = {
|
49
|
-
\\override Score.TimeSignature #'stencil = ##f
|
50
|
-
\\clef bass
|
51
|
-
\\time 12/4
|
52
|
-
STR
|
53
|
-
|
54
|
-
SCORE_BLOCK = <<-STR
|
55
|
-
\\score {
|
56
|
-
<<
|
57
|
-
\\new Staff \\rows
|
58
|
-
>>
|
59
|
-
}
|
60
|
-
STR
|
61
|
-
end
|
62
|
-
end
|
data/lib/webern/matrix.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
module Webern
|
2
|
-
class Matrix
|
3
|
-
attr_accessor :prime_row
|
4
|
-
BASIC_ROW = Array(0..11)
|
5
|
-
|
6
|
-
def initialize(row)
|
7
|
-
@prime_row = row
|
8
|
-
end
|
9
|
-
|
10
|
-
def primes
|
11
|
-
BASIC_ROW.map{|note| @prime_row.transpose(note) }
|
12
|
-
end
|
13
|
-
|
14
|
-
def inversions
|
15
|
-
BASIC_ROW.map{|note| @prime_row.transpose(note).inversion }
|
16
|
-
end
|
17
|
-
|
18
|
-
def retrogrades
|
19
|
-
BASIC_ROW.map{|note| @prime_row.transpose(note).retrograde }
|
20
|
-
end
|
21
|
-
|
22
|
-
def retrograde_inversions
|
23
|
-
BASIC_ROW.map{|note| @prime_row.transpose(note).retrograde_inversion }
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
data/spec/array_spec.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
describe "Array" do
|
2
|
-
describe "is_all_integers?" do
|
3
|
-
before do
|
4
|
-
@all_ints = %w{0 1 2 3 4 5 6 7 8 9 10 11}
|
5
|
-
@no_ints = %w{a b c d e f g h i j k}
|
6
|
-
@mixed = %w{a 1 b 2 c 3 d 4 5 6 7}
|
7
|
-
@bad_input = [{1 => 2}, [1,2,3], :"45"]
|
8
|
-
end
|
9
|
-
it "should return true when all elements are strings of integers" do
|
10
|
-
@all_ints.is_all_integers?.should be_true
|
11
|
-
end
|
12
|
-
it "should return false when no elements are strings of integers" do
|
13
|
-
@no_ints.is_all_integers?.should_not be_true
|
14
|
-
end
|
15
|
-
it "should return false when only some elements are strings of integers" do
|
16
|
-
@mixed.is_all_integers?.should_not be_true
|
17
|
-
end
|
18
|
-
it "should return false when some elements do not have a :to_i method" do
|
19
|
-
@bad_input.is_all_integers?.should_not be_true
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
data/spec/helper.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
if system("lilypond --version")
|
2
|
-
describe "LilypondBuilder" do
|
3
|
-
it "should find the current lilypond version" do
|
4
|
-
Webern::LilypondBuilder.current_lilypond_version.should =~ /\d+\.\d+\.\d+/
|
5
|
-
end
|
6
|
-
it "should, by default, have 0 == c" do
|
7
|
-
Webern::LilypondBuilder.zero_note = "c"
|
8
|
-
end
|
9
|
-
describe "converting rows into lilypond" do
|
10
|
-
before { @row = Webern::Row.new(0,1,2,3,4,5,6,7,8,9,10,11) }
|
11
|
-
it "should be correctly converted by default to 'c cs d ef e f fs g af a bf b'" do
|
12
|
-
Webern::LilypondBuilder.convert_row(@row).should == "c cs d ef e f fs g af a bf b"
|
13
|
-
end
|
14
|
-
describe "when the zero_note is shifted" do
|
15
|
-
before { Webern::LilypondBuilder.zero_note = "d" }
|
16
|
-
it "should correct convert the chromatic scale to 'd ef e f fs g af a bf b c cs'" do
|
17
|
-
Webern::LilypondBuilder.convert_row(@row).should == "d ef e f fs g af a bf b c cs"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
describe "generating lilypond file" do
|
22
|
-
before do
|
23
|
-
@row = Webern::Row.new(*Array(0..11))
|
24
|
-
@matrix = Webern::Matrix.new(@row)
|
25
|
-
@file_path = File.join(File.dirname(__FILE__), "..", "matrix.ly")
|
26
|
-
puts Webern::LilypondBuilder.generate_file(@matrix)
|
27
|
-
end
|
28
|
-
after do
|
29
|
-
File.delete(@file_path) if File.exists?(@file_path)
|
30
|
-
end
|
31
|
-
it "should create the file" do
|
32
|
-
File.exists?(@file_path).should be_true
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
else
|
37
|
-
describe "LilypondBuilder" do
|
38
|
-
it "needs Lilypond to be installed. Check out http://www.lilypond.org"
|
39
|
-
end
|
40
|
-
end
|
data/spec/matrix_spec.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
describe "Matrix" do
|
2
|
-
before { @m = Webern::Matrix.new(Webern::Row.new(0,1,2,3,4,5,6,7,8,9,10,11)) }
|
3
|
-
it "should have the correct prime row" do
|
4
|
-
@m.prime_row.should == Webern::Row.new(*Array(0..11))
|
5
|
-
end
|
6
|
-
it "should have the correct primes" do
|
7
|
-
@m.primes[0].should == @m.prime_row
|
8
|
-
@m.primes[3].should == @m.prime_row.transpose(3)
|
9
|
-
end
|
10
|
-
it "should have the correct inversions" do
|
11
|
-
@m.inversions[0].should == @m.prime_row.inversion
|
12
|
-
@m.inversions[6].should == @m.prime_row.inversion.transpose(6)
|
13
|
-
end
|
14
|
-
it "should have the correct retrogrades" do
|
15
|
-
@m.retrogrades[0].should == @m.prime_row.retrograde
|
16
|
-
@m.retrogrades[8].should == @m.prime_row.retrograde.transpose(8)
|
17
|
-
end
|
18
|
-
it "should have the correct retrograde inversions" do
|
19
|
-
@m.retrograde_inversions[0].should == @m.prime_row.retrograde_inversion
|
20
|
-
@m.retrograde_inversions[1].should == @m.prime_row.retrograde_inversion.transpose(11)
|
21
|
-
end
|
22
|
-
end
|
data/spec/row_spec.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
describe "Row" do
|
2
|
-
describe "a basic row" do
|
3
|
-
before { @row = Webern::Row.new(*Array(0..11)) }
|
4
|
-
it "should create the correct retrograde: [11,10,9,8,7,6,5,4,3,2,1,0]" do
|
5
|
-
@row.retrograde.should == Array(0..11).reverse
|
6
|
-
end
|
7
|
-
it "should create the correct inversion: [0,11,10,9,8,7,6,5,4,3,2,1]" do
|
8
|
-
@row.inversion.should == [0,11,10,9,8,7,6,5,4,3,2,1]
|
9
|
-
end
|
10
|
-
it "should create the correct retrograde inversion: [1,2,3,4,5,6,7,8,9,10,11,0]" do
|
11
|
-
@row.retrograde_inversion.should == [1,2,3,4,5,6,7,8,9,10,11,0]
|
12
|
-
end
|
13
|
-
it "should transpose correctly" do
|
14
|
-
@row.transpose(2).should == [2,3,4,5,6,7,8,9,10,11,0,1]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
describe "a more complex row" do
|
18
|
-
before { @row = Webern::Row.new(0,11,8,2,4,1,3,10,7,5,9,6) }
|
19
|
-
it "should create the correct retrograde: [6,9,5,7,10,3,1,4,2,8,11,0]" do
|
20
|
-
@row.retrograde.should == [6,9,5,7,10,3,1,4,2,8,11,0]
|
21
|
-
end
|
22
|
-
it "should create the correct inversion: [0,1,4,10,8,11,9,2,5,7,3,6]" do
|
23
|
-
@row.inversion.should == [0,1,4,10,8,11,9,2,5,7,3,6]
|
24
|
-
end
|
25
|
-
it "should create the correct retrograde inversion: [7,3,7,5,2,9,11,8,10,4,1,0]" do
|
26
|
-
@row.retrograde_inversion.should == [6,3,7,5,2,9,11,8,10,4,1,0]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|