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 CHANGED
@@ -1,2 +1,20 @@
1
- *.ly
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
2
18
  *.pdf
19
+ *.ly
20
+ *.txt
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
- gem "spec"
4
- gem "yard"
3
+ # Specify your gem's dependencies in webern.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^lib/(.+)\.rb$}) { "spec" }
6
+ watch(%r{^spec/(.+)\.rb$}) { "spec" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
data/README.md CHANGED
@@ -1,50 +1,51 @@
1
- # webern
1
+ # Webern
2
2
 
3
- ### current version: 0.2.0
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
- [http://github.com/mikowitz/webern][webern]
5
+ Possible outputs:
6
6
 
7
- ## Description
8
-
9
- Taking a 12-tone row generated from user input Webern will create the full matrix based upon this
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
- Install the gemcutter gem
16
-
17
- ~$ gem install gemcutter
13
+ Add this line to your application's Gemfile:
18
14
 
19
- Add gemcutter.org to your gem remote sources
15
+ gem 'webern'
20
16
 
21
- ~$ gem tumble
17
+ And then execute:
22
18
 
23
- Download and install this gem
19
+ $ bundle
24
20
 
25
- ~$ gem install crayon
21
+ Or install it yourself as:
26
22
 
27
- ## Requirements
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
- `Webern` can accept a full 12-tone row, a partial 12-tone row, or a list of strings which will be parsed into a numeric row:
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
- ~$ webern 9 1 4 7 8 2 0 10 5 6 11 3
36
- ~$ webern 0 6 10 9 4 7
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
- In the instance where a partial row is given, or the strings given do not provide 12 distinct letters, `Webern` will complete the row with the missing numbers in ascending order. In the example above, `Webern` would complete the row like this:
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
- [0 6 10 9 4 7] #=> [0 6 10 9 4 7 1 2 3 5 8 11]
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
- `Webern` will take the completed row and create the full 12-tone matrix, then generate a LilyPond file containing all 48 possible rows contained in the matrix, and output them to a .pdf file.
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
- ## Copyright
43
+ The `lilypond` executable is required in order to convert the resulting `filename.ly` file to PDF.
46
44
 
47
- Copyright (c) 2010 Michael Berkowitz. See LICENSE for details.
45
+ ## Contributing
48
46
 
49
- [webern]: http://github.com/mikowitz/webern "Webern repository"
50
- [lilypond]: http://lilypond.org "LilyPond"
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 'rubygems'
2
- require 'rake'
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
3
 
4
- begin
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
- require 'spec/rake/spectask'
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
- $:.unshift File.dirname(__FILE__)
2
- $:.unshift File.dirname(__FILE__) + "/webern"
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(*_row)
4
- @row = _row
5
- check_for_valid_row(@row)
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 retrograde; Row.new *reverse; end
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 retrograde_inversion
18
- Row.new *inversion.retrograde
12
+ def prime
13
+ Row.new *self
19
14
  end
20
15
 
21
- def transpose(interval)
22
- Row.new *map{|note| (note + interval) % 12 }
16
+ def inversion
17
+ Row.new *self.map{|i| (12 - i) % 12}
23
18
  end
24
19
 
25
- def complete_row
26
- return @row if @row.size == 12
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 process_strings
32
- full_string = @row.join("").split("")
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 check_for_valid_row(elements)
38
- raise InvalidRow unless row_is_valid_numbers? or row_is_strings?
28
+ def transpose(distance)
29
+ Row.new *self.map{|i| (i + distance) % 12 }
39
30
  end
40
31
 
41
- def row_is_valid_numbers?
42
- @row.all?{|element| element.is_a?(Fixnum) } and (@row - Array(0..11)).empty?
32
+ def zero
33
+ Row.new *self.map{|i| (i + 12 - self[0]) % 12}
43
34
  end
44
35
 
45
- def row_is_strings?
46
- @row.all?{|element| element.is_a?(String) }
47
- end
36
+ private
48
37
 
49
- def zero_row
50
- transpose(12-self[0])
38
+ def complete_row
39
+ missing = Array(0..11) - @row
40
+ @row + missing
51
41
  end
52
42
  end
53
43
  end
@@ -0,0 +1,3 @@
1
+ module Webern
2
+ VERSION = "0.3.0"
3
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'webern'
@@ -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 'helper'
2
-
3
- def test_with_full_row(row, expected_result)
4
- it "should return #{expected_result.inspect} for #{row.inspect}" do
5
- Webern.new(*row).prime_row.should == expected_result
6
- end
7
- end
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
- prerelease: false
5
- segments:
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
- date: 2010-04-22 00:00:00 -04:00
18
- default_executable: webern
19
- dependencies: []
20
-
21
- description: 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.
22
- email: michael.berkowitz@gmail.com
23
- executables:
24
- - webern
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
- extra_rdoc_files:
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
- - LICENSE
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/lilypond_builder.rb
43
- - lib/webern/matrix.rb
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
- - spec/array_spec.rb
46
- - spec/helper.rb
47
- - spec/lilypond_builder_spec.rb
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
- has_rdoc: true
52
- homepage: http://github.com/mikowitz/webern
53
- licenses: []
54
-
166
+ - webern.gemspec
167
+ homepage: ''
168
+ licenses:
169
+ - MIT
55
170
  post_install_message:
56
- rdoc_options:
57
- - --charset=UTF-8
58
- require_paths:
171
+ rdoc_options: []
172
+ require_paths:
59
173
  - lib
60
- required_ruby_version: !ruby/object:Gem::Requirement
61
- requirements:
62
- - - ">="
63
- - !ruby/object:Gem::Version
64
- segments:
65
- - 0
66
- version: "0"
67
- required_rubygems_version: !ruby/object:Gem::Requirement
68
- requirements:
69
- - - ">="
70
- - !ruby/object:Gem::Version
71
- segments:
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.3.6
188
+ rubygems_version: 1.8.23
78
189
  signing_key:
79
190
  specification_version: 3
80
- summary: Creates a .pdf reference sheet for all 12-tone rows generated from a given prime row's matrix.
81
- test_files:
82
- - spec/array_spec.rb
83
- - spec/helper.rb
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
@@ -1,4 +0,0 @@
1
- lib/**/*.rb
2
- -
3
- CHANGELOG.md
4
- LICENSE
data/CHANGELOG.md DELETED
@@ -1,3 +0,0 @@
1
- ### 0.2.0 : 04/22/10
2
-
3
- * Reimplementation of code.
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
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require File.dirname(__FILE__) + '/../lib/webern'
4
- require 'optparse'
5
-
6
- if ARGV.is_all_integers?
7
- Webern.new(*ARGV.map(&:to_i))
8
- else
9
- Webern.new(*ARGV)
10
- end
data/lib/core_ext.rb DELETED
@@ -1,11 +0,0 @@
1
- class Array
2
- def is_all_integers?
3
- self.all?{|element| element.to_i.to_s == element }
4
- rescue Exception
5
- false
6
- end
7
-
8
- def generate_row_from_letters
9
- self.map{|element| self.sort.index(element) }
10
- end
11
- end
@@ -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,5 +0,0 @@
1
- require 'spec'
2
-
3
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
- $LOAD_PATH.unshift(File.dirname(__FILE__))
5
- require 'webern'
@@ -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