mikowitz-webern 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +3 -0
- data/Manifest.txt +12 -0
- data/README.txt +64 -0
- data/Rakefile +47 -0
- data/bin/webern +11 -0
- data/lib/webern.rb +4 -0
- data/lib/webern/lilypond_builder.rb +74 -0
- data/lib/webern/matrix.rb +37 -0
- data/lib/webern/version.rb +9 -0
- data/lib/webern/webern.rb +41 -0
- data/test/test_webern.rb +26 -0
- data/webern.gemspec +16 -0
- metadata +66 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
= Webern
|
2
|
+
|
3
|
+
http://github.com/mikowitz/webern
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Taking a 12-tone row generated from user input (see SYNOPSIS below), Webern will create the full matrix based upon this row, and then output all 48 possible rows created by that matrix out to a .pdf file using the LilyPond notational language.
|
8
|
+
|
9
|
+
|
10
|
+
Rake Tasks Provided:
|
11
|
+
|
12
|
+
* clear_ly_files - Removes rows.ly, rows.ps, and rows.pdf
|
13
|
+
* update_lib - Updates your lib/project_name.rb file to include all files in your lib/project_name/ folder
|
14
|
+
* update_manifest - Updates the gems Manifest.txt file to include any added files
|
15
|
+
|
16
|
+
== FEATURES/PROBLEMS:
|
17
|
+
|
18
|
+
* Not yet packaged as an installable gem. Coming soon, though. In the meantime, see the INSTALL section below.
|
19
|
+
|
20
|
+
== SYNOPSIS:
|
21
|
+
|
22
|
+
Webern can accept three different types of input.
|
23
|
+
|
24
|
+
* A full 12 tone row:
|
25
|
+
$ webern 9 1 4 7 8 2 0 10 5 6 11 3
|
26
|
+
|
27
|
+
* An incomplete row, in which case the missing numbers will be added sequentially following what you have provided. See Webern::Webern.finish_partial_row:
|
28
|
+
$ webern 0 6 10 9 4 7 (1 2 3 5 8 11 will be added by Webern)
|
29
|
+
|
30
|
+
* A string, which will be converted to a 12-tone row. See Webern::Webern.make_row_from_string:
|
31
|
+
$ webern michael berkowitz
|
32
|
+
|
33
|
+
== REQUIREMENTS:
|
34
|
+
|
35
|
+
* No other gems, but you do need lilypond (http://lilypond.org/web/) to generate the .pdf file.
|
36
|
+
|
37
|
+
== INSTALL:
|
38
|
+
|
39
|
+
* Not packaged as a gem yet. Run rake install_gem from project root to install as a gem on your computer.
|
40
|
+
|
41
|
+
== LICENSE:
|
42
|
+
|
43
|
+
(The MIT License)
|
44
|
+
|
45
|
+
Copyright (c) 2008 FIX
|
46
|
+
|
47
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
48
|
+
a copy of this software and associated documentation files (the
|
49
|
+
'Software'), to deal in the Software without restriction, including
|
50
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
51
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
52
|
+
permit persons to whom the Software is furnished to do so, subject to
|
53
|
+
the following conditions:
|
54
|
+
|
55
|
+
The above copyright notice and this permission notice shall be
|
56
|
+
included in all copies or substantial portions of the Software.
|
57
|
+
|
58
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
59
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
60
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
61
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
62
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
63
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
64
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hoe'
|
3
|
+
require 'fileutils'
|
4
|
+
require File.dirname(__FILE__) + '/lib/webern.rb'
|
5
|
+
|
6
|
+
PKG_NAME = 'webern'
|
7
|
+
PKG_VER = Webern::Version::STRING
|
8
|
+
|
9
|
+
Hoe.new('webern', Webern::Version::STRING) do |p|
|
10
|
+
p.name = PKG_NAME
|
11
|
+
p.version = PKG_VER
|
12
|
+
p.developer('Michael Berkowitz', 'michael.berkowitz@gmail.com')
|
13
|
+
p.email = 'michael.berkowitz@gmail.com'
|
14
|
+
p.author = 'Michael Berkowitz'
|
15
|
+
p.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 out to a .pdf file using the LilyPond notational language. }
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Updates Manifest.txt"
|
19
|
+
task :update_manifest do
|
20
|
+
files = Dir.glob('**/*') - ["bin", "lib", "lib/webern", "test"]
|
21
|
+
puts "Cleaning gem. Removing extraneous pkg and doc files that should not be included in your Manifest.txt file."
|
22
|
+
`rake clean`
|
23
|
+
File.open('Manifest.txt', 'w') do |f|
|
24
|
+
puts "Updating Manifest.txt. Re-run this task as you add files to your gem."
|
25
|
+
files.sort.each do |file|
|
26
|
+
puts "Adding #{file} to Manifest.txt"
|
27
|
+
f << file << "\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Updates lib/webern.rb to include all files contained in lib/webern/"
|
33
|
+
task :update_lib do
|
34
|
+
files = Dir.glob('lib/webern/*.rb')
|
35
|
+
File.open('lib/webern.rb', 'w') do |f|
|
36
|
+
files.each do |file|
|
37
|
+
f << "require File.dirname(__FILE__) + '#{file[3..-1]}'\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Removes rows.ly, rows.pdf, rows.ps"
|
43
|
+
task :clear_ly_files do
|
44
|
+
Dir.glob('rows.*').each do |file|
|
45
|
+
rm file
|
46
|
+
end
|
47
|
+
end
|
data/bin/webern
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# webern
|
3
|
+
# created by Michael Berkowitz
|
4
|
+
|
5
|
+
require File.dirname(__FILE__) + '/../lib/webern'
|
6
|
+
|
7
|
+
Webern::Webern.new(*ARGV)
|
8
|
+
puts "rows.ly generated" unless !File.exists?('rows.ly')
|
9
|
+
print "Path to lilypond binary: "
|
10
|
+
lilypond_path = STDIN.gets.chomp
|
11
|
+
`#{lilypond_path} rows.ly`
|
data/lib/webern.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Webern
|
4
|
+
class LilypondBuilder
|
5
|
+
include FileUtils
|
6
|
+
|
7
|
+
NOTES = {
|
8
|
+
0 => "c",
|
9
|
+
1 => "cs",
|
10
|
+
2 => "d",
|
11
|
+
3 => "ef",
|
12
|
+
4 => "e",
|
13
|
+
5 => "f",
|
14
|
+
6 => "fs",
|
15
|
+
7 => "g",
|
16
|
+
8 => "af",
|
17
|
+
9 => "a",
|
18
|
+
10 => "bf",
|
19
|
+
11 => "b"
|
20
|
+
}
|
21
|
+
|
22
|
+
LILYPOND_PREAMBLE = <<-LILYPOND
|
23
|
+
\\version "2.11.57"
|
24
|
+
\\include "english.ly"
|
25
|
+
#(set-global-staff-size 13)
|
26
|
+
|
27
|
+
rows = {
|
28
|
+
\\override Score.TimeSignature #'stencil = ##f
|
29
|
+
\\time 12/4
|
30
|
+
LILYPOND
|
31
|
+
|
32
|
+
LILYPOND_POSTAMBLE = <<-LILYPOND
|
33
|
+
}
|
34
|
+
|
35
|
+
\\book {
|
36
|
+
\\score {
|
37
|
+
<<
|
38
|
+
\\new Staff \\rows
|
39
|
+
>>
|
40
|
+
}
|
41
|
+
}
|
42
|
+
LILYPOND
|
43
|
+
|
44
|
+
attr_reader :matrix # An instance of Webern::Matrix
|
45
|
+
|
46
|
+
def initialize(matrix)
|
47
|
+
@matrix = matrix
|
48
|
+
build_lilypond_file
|
49
|
+
end
|
50
|
+
|
51
|
+
# Converts an array of rows into vaild LilyPond code.
|
52
|
+
def build_rows(row_type)
|
53
|
+
str = ''
|
54
|
+
abbrev = row_type.scan(/^[a-z]|_[a-z]/).join("")
|
55
|
+
@matrix.send(row_type).sort { |a, b| a[0] <=> b[0] }.each do |row|
|
56
|
+
str += "#{NOTES[row[0]]}'^\\markup{#{abbrev}#{row[0]}} "
|
57
|
+
str += row[1..-1].map { |n| NOTES[n] }.join("' ") + "'\n"
|
58
|
+
end
|
59
|
+
str += "\\break\n"
|
60
|
+
str
|
61
|
+
end
|
62
|
+
|
63
|
+
# Generates a valid LilyPond file from the Webern::Matrix object passed into the LilypondBuilder
|
64
|
+
def build_lilypond_file
|
65
|
+
File.open('rows.ly', 'w') do |f|
|
66
|
+
f << LILYPOND_PREAMBLE
|
67
|
+
['primes', 'retrogrades', 'inversions', 'retrograde_inversions'].each do |row_type|
|
68
|
+
f << build_rows(row_type)
|
69
|
+
end
|
70
|
+
f << LILYPOND_POSTAMBLE
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Webern
|
2
|
+
class Matrix
|
3
|
+
attr_reader :primes, :retrogrades, :inversions, :retrograde_inversions
|
4
|
+
def initialize p0
|
5
|
+
create_primes(p0)
|
6
|
+
create_retrogrades
|
7
|
+
create_inversions
|
8
|
+
create_retrograde_inversions
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_primes(p0)
|
12
|
+
@primes = []
|
13
|
+
p0.each do |offset|
|
14
|
+
@primes << p0.map { |c| (12 - offset + c) % 12 }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_retrogrades
|
19
|
+
@retrogrades = @primes.map { |row| row.reverse }
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_inversions
|
23
|
+
@inversions = []
|
24
|
+
(0...12).each do |i|
|
25
|
+
i_row = []
|
26
|
+
@primes.each do |row|
|
27
|
+
i_row << row[i]
|
28
|
+
end
|
29
|
+
@inversions << i_row
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_retrograde_inversions
|
34
|
+
@retrograde_inversions = @inversions.map { |row| row.reverse }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Webern
|
2
|
+
class Webern
|
3
|
+
attr_reader :row
|
4
|
+
|
5
|
+
# Takes either a full or partial row of integers 0-11 or a string that can be
|
6
|
+
# converted into a row of integers
|
7
|
+
def initialize(*args)
|
8
|
+
begin
|
9
|
+
if args.map { |c| c.to_i }.sort == (0...12).to_a
|
10
|
+
row = args.map { |c| c.to_i }
|
11
|
+
elsif args.map { |c| c.to_i }.uniq == [0]
|
12
|
+
row = make_row_from_string args.join("")
|
13
|
+
else
|
14
|
+
row = finish_partial_row args
|
15
|
+
end
|
16
|
+
offset = row.first
|
17
|
+
@row = row.map { |c| (c + 12 - offset) % 12 }
|
18
|
+
m = Matrix.new(@row)
|
19
|
+
LilypondBuilder.new(m)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Creates a 12-tone row from a string provided as an original argument.
|
24
|
+
def make_row_from_string(str)
|
25
|
+
working_row, row = str.downcase.gsub(/[^a-z]/, '').split('') + ('a'..'z').to_a, []
|
26
|
+
while row.size < 12
|
27
|
+
(row << working_row.shift).uniq!
|
28
|
+
end
|
29
|
+
alph_row = row.dup.sort
|
30
|
+
row.map { |c| alph_row.index(c) }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Completes a 12-tone row if only a partial row was provided
|
34
|
+
# as the original argument.
|
35
|
+
def finish_partial_row(row)
|
36
|
+
working_row = row.map { |c| c.to_i }
|
37
|
+
missing = (0...12).to_a - working_row
|
38
|
+
working_row + missing
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/test/test_webern.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/webern.rb'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class WebernTest < Test::Unit::TestCase
|
5
|
+
def test_create_row
|
6
|
+
# Test full row beginning with 0
|
7
|
+
w = Webern::Webern.new("0", "2", "8", "1", "3", "11", "10", "7", "4", "6", "9", "5")
|
8
|
+
assert_equal [0,2,8,1,3,11,10,7,4,6,9,5], w.row
|
9
|
+
|
10
|
+
# Test full row not starting with 0
|
11
|
+
w = Webern::Webern.new("1", "2", "4", "5", "8", "10", "11", "6", "0", "3", "7", "9")
|
12
|
+
assert_equal [0,1,3,4,7,9,10,5,11,2,6,8], w.row
|
13
|
+
|
14
|
+
# Test starting string that provides 12 unique characters
|
15
|
+
w = Webern::Webern.new("Michael", "Berkowitz")
|
16
|
+
assert_equal [0,9,6,8,4,7,11,5,2,10,1,3], w.row
|
17
|
+
|
18
|
+
# Test starting string that does not provide 12 unique characters
|
19
|
+
w = Webern::Webern.new('Erica', 'Smith')
|
20
|
+
assert_equal [0,5,3,10,8,6,4,7,2,9,11,1], w.row
|
21
|
+
|
22
|
+
# Test incomplete row beginning with 0
|
23
|
+
w = Webern::Webern.new("0", "2", "4", "6", "8", "10")
|
24
|
+
assert_equal [0,2,4,6,8,10,1,3,5,7,9,11], w.row
|
25
|
+
end
|
26
|
+
end
|
data/webern.gemspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "webern"
|
3
|
+
s.version = "0.1.0"
|
4
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
5
|
+
s.authors = ['Michael Berkowitz']
|
6
|
+
s.date = "2008-11-16"
|
7
|
+
s.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 out to a .pdf file using the LilyPond notational language. }
|
8
|
+
s.email = 'michael.berkowitz@gmail.com'
|
9
|
+
s.executables = ['webern']
|
10
|
+
s.extra_rdoc_files = ['History.txt', 'Manifest.txt', 'README.txt']
|
11
|
+
s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "bin/webern", "lib/webern.rb", "lib/webern/lilypond_builder.rb", "lib/webern/matrix.rb", "lib/webern/version.rb", "lib/webern/webern.rb", "test/test_webern.rb", "webern.gemspec"]
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.require_paths = ['lib']
|
14
|
+
s.summary = s.description
|
15
|
+
s.test_files = ["test/test_webern.rb"]
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mikowitz-webern
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Berkowitz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-11-16 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
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 out to a .pdf file using the LilyPond notational language.
|
17
|
+
email: michael.berkowitz@gmail.com
|
18
|
+
executables:
|
19
|
+
- webern
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- History.txt
|
24
|
+
- Manifest.txt
|
25
|
+
- README.txt
|
26
|
+
files:
|
27
|
+
- History.txt
|
28
|
+
- Manifest.txt
|
29
|
+
- README.txt
|
30
|
+
- Rakefile
|
31
|
+
- bin/webern
|
32
|
+
- lib/webern.rb
|
33
|
+
- lib/webern/lilypond_builder.rb
|
34
|
+
- lib/webern/matrix.rb
|
35
|
+
- lib/webern/version.rb
|
36
|
+
- lib/webern/webern.rb
|
37
|
+
- test/test_webern.rb
|
38
|
+
- webern.gemspec
|
39
|
+
has_rdoc: true
|
40
|
+
homepage:
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.2.0
|
62
|
+
signing_key:
|
63
|
+
specification_version: 2
|
64
|
+
summary: 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 out to a .pdf file using the LilyPond notational language.
|
65
|
+
test_files:
|
66
|
+
- test/test_webern.rb
|