hammelin 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.rvmrc.example +2 -0
- data/Gemfile +4 -0
- data/README.md +66 -0
- data/Rakefile +1 -0
- data/bin/jfugue-4.0.3.jar +0 -0
- data/demos/nested_play.rb +20 -0
- data/hammelin.gemspec +24 -0
- data/lib/hammelin.rb +3 -0
- data/lib/hammelin/hammelin.rb +70 -0
- data/lib/hammelin/note.rb +84 -0
- data/lib/hammelin/notes_range.rb +55 -0
- data/lib/hammelin/version.rb +3 -0
- data/reference/Main.class +0 -0
- data/reference/Main.java +13 -0
- metadata +70 -0
data/.rvmrc.example
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Integration Exercise: Java Library Wrapper
|
2
|
+
|
3
|
+
# Hammelin
|
4
|
+
|
5
|
+
JFugue (http://www.jfugue.org/index.html) is a Java library that let's developers program a melody through using the basic notes, chords, etc. The music can be saved to a MIDI file, or played just then.
|
6
|
+
|
7
|
+
Hammelin wraps around JFugue functionality to let JRuby users create, play and save MIDIs file using Ruby syntax and some sugar with that.
|
8
|
+
|
9
|
+
# Using Hammelin
|
10
|
+
|
11
|
+
Hammelin gaves you easiness of play. Right now, you can use a MusicString
|
12
|
+
to play your own music:
|
13
|
+
|
14
|
+
Hammelin.play("E5s A5s C6s B5s E5s B5s D6s C6i E6i G#5i E6i | A5s E5s A5s C6s B5s E5s B5s D6s C6i A5i Ri")
|
15
|
+
|
16
|
+
You could also work with notes:
|
17
|
+
|
18
|
+
note = Hammelin::Note.new("E5s")
|
19
|
+
|
20
|
+
And then just play it
|
21
|
+
|
22
|
+
note.play
|
23
|
+
|
24
|
+
Hammelin also allows you to play with ranges:
|
25
|
+
|
26
|
+
note = Hammelin::Note.new("C")
|
27
|
+
note.upto("E5s").play
|
28
|
+
|
29
|
+
If wanted, you also have access to each note of the range:
|
30
|
+
|
31
|
+
note.upto("E5s").each do {|note| note.play }
|
32
|
+
note.upto("E5s").each do {|note| note.increase_octave }
|
33
|
+
|
34
|
+
|
35
|
+
Now go and make some interesting tunes :)
|
36
|
+
|
37
|
+
Hammelin.compose do
|
38
|
+
|
39
|
+
note = Hammelin::Note.new("C")
|
40
|
+
tune = note.upto("D#")
|
41
|
+
|
42
|
+
2.times do
|
43
|
+
play tune
|
44
|
+
play tune.reverse
|
45
|
+
|
46
|
+
2.times do
|
47
|
+
play tune
|
48
|
+
play tune.increase_octave
|
49
|
+
play tune.increase_octave(2)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
## Saving your work
|
57
|
+
|
58
|
+
Just send a filename to the compose method:
|
59
|
+
|
60
|
+
Hammelin.compose("file.mid") do
|
61
|
+
|
62
|
+
### Running on GNU/Linux?
|
63
|
+
|
64
|
+
There was a reported bug when a missing library wasn't found by the Java VM. The file (libpuse-java.so) should be on
|
65
|
+
|
66
|
+
/usr/lib/jvm/java-6-openjdk/jre/lib/i386
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative '../lib/hammelin'
|
2
|
+
|
3
|
+
Hammelin.compose("file.mid") do
|
4
|
+
|
5
|
+
note = Hammelin::Note.new("C")
|
6
|
+
tune = note.upto("D#")
|
7
|
+
|
8
|
+
2.times do
|
9
|
+
play tune
|
10
|
+
play tune.reverse
|
11
|
+
|
12
|
+
2.times do
|
13
|
+
play tune
|
14
|
+
play tune.increase_octave
|
15
|
+
play tune.increase_octave(2)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/hammelin.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "hammelin/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "hammelin"
|
7
|
+
s.version = Hammelin::VERSION
|
8
|
+
s.authors = ["Alvaro Pereyra"]
|
9
|
+
s.email = "alvaro@xendacentral.com"
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Hammelin allows you to play around with JFugue MIDI capabilities}
|
12
|
+
s.description = %q{Hammelin wraps around JFugue and lets your play with notes, making Ruby sing}
|
13
|
+
|
14
|
+
s.rubyforge_project = "hammelin"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
# s.executables = []
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
end
|
data/lib/hammelin.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'java'
|
2
|
+
|
3
|
+
require_relative '../../bin/jfugue-4.0.3.jar'
|
4
|
+
|
5
|
+
java_import org.jfugue.Player
|
6
|
+
java_import org.jfugue.Pattern
|
7
|
+
java_import org.jfugue.Rhythm
|
8
|
+
java_import org.jfugue.MusicStringParser
|
9
|
+
|
10
|
+
module Hammelin
|
11
|
+
|
12
|
+
extend self
|
13
|
+
|
14
|
+
PADDING = " "
|
15
|
+
@logged_music_string = ""
|
16
|
+
|
17
|
+
def play(tune)
|
18
|
+
if playable_tune?(tune)
|
19
|
+
play_tune(tune)
|
20
|
+
else
|
21
|
+
play_string(tune)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def play_string(tune)
|
26
|
+
player.play(tune)
|
27
|
+
add_to_log(tune)
|
28
|
+
player.close
|
29
|
+
end
|
30
|
+
|
31
|
+
def playable_tune?(tune)
|
32
|
+
return true if tune.respond_to? :play
|
33
|
+
return true if tune.is_a?(Array) ? playable_tune?(tune.first) : false
|
34
|
+
end
|
35
|
+
|
36
|
+
def play_tune(tune)
|
37
|
+
if tune.respond_to? :play
|
38
|
+
tune.play
|
39
|
+
else
|
40
|
+
tune.each(&:play) if playable_tune?(tune.first)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def compose(filename=nil,&block)
|
45
|
+
instance_eval &block
|
46
|
+
save_to_file(filename) if filename
|
47
|
+
ensure
|
48
|
+
player.close
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def add_to_log(tune)
|
54
|
+
logged_music_string << tune + PADDING
|
55
|
+
end
|
56
|
+
|
57
|
+
def logged_music_string
|
58
|
+
@logged_music_string
|
59
|
+
end
|
60
|
+
|
61
|
+
def save_to_file(filename)
|
62
|
+
file = java.io.File.new(filename)
|
63
|
+
player.save_midi(logged_music_string,file)
|
64
|
+
end
|
65
|
+
|
66
|
+
def player
|
67
|
+
@player ||= Player.new
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Hammelin
|
2
|
+
|
3
|
+
class Note
|
4
|
+
|
5
|
+
include Comparable
|
6
|
+
attr_accessor :token
|
7
|
+
|
8
|
+
OCTAVE_JUMP = 12
|
9
|
+
MAX_VALUE = 127
|
10
|
+
CAPPED_VALUE = MAX_VALUE - OCTAVE_JUMP
|
11
|
+
|
12
|
+
def initialize(note)
|
13
|
+
self.token = note
|
14
|
+
end
|
15
|
+
|
16
|
+
def play
|
17
|
+
Hammelin.play(music_string)
|
18
|
+
end
|
19
|
+
|
20
|
+
def upto(note)
|
21
|
+
NotesRange.new(self,Note.new(note))
|
22
|
+
end
|
23
|
+
|
24
|
+
def downto(note)
|
25
|
+
NotesRange.new(Note.new(note),self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.from_value(value)
|
29
|
+
Note.new("[#{value}]")
|
30
|
+
end
|
31
|
+
|
32
|
+
def music_string
|
33
|
+
"[#{parse_value}]"
|
34
|
+
end
|
35
|
+
|
36
|
+
def increase_octave(times)
|
37
|
+
Note.from_value(higher_octave(times))
|
38
|
+
end
|
39
|
+
|
40
|
+
def decrease_octave(times)
|
41
|
+
Note.from_value(lower_octave(times))
|
42
|
+
end
|
43
|
+
|
44
|
+
def increase_octave!(times)
|
45
|
+
self.token = increase_octaves(times).value
|
46
|
+
end
|
47
|
+
|
48
|
+
def decrease_octave!(times)
|
49
|
+
self.token = decrease_octaves(times).value
|
50
|
+
end
|
51
|
+
|
52
|
+
def value
|
53
|
+
parse_value
|
54
|
+
end
|
55
|
+
|
56
|
+
def <=>(other)
|
57
|
+
self.value <=> other.value
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def parse_value
|
63
|
+
MusicStringParser.get_note(self.token).get_value
|
64
|
+
end
|
65
|
+
|
66
|
+
def higher_octave(times=1)
|
67
|
+
OCTAVE_JUMP*times + self.value unless highest_octave?
|
68
|
+
end
|
69
|
+
|
70
|
+
def lower_octave(times=1)
|
71
|
+
OCTAVE_JUMP*times + self.value unless lowest_octave?
|
72
|
+
end
|
73
|
+
|
74
|
+
def highest_octave?
|
75
|
+
self.value >= CAPPED_VALUE
|
76
|
+
end
|
77
|
+
|
78
|
+
def lowest_octave?
|
79
|
+
self.value <= OCTAVE_JUMP
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Hammelin
|
4
|
+
|
5
|
+
class NotesRange < DelegateClass(Array)
|
6
|
+
|
7
|
+
def initialize(from,to)
|
8
|
+
@from, @to = from,to
|
9
|
+
super(transverse_notes)
|
10
|
+
end
|
11
|
+
|
12
|
+
def play
|
13
|
+
Hammelin.play music_string
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def reverse
|
18
|
+
NotesRange.new(@to,@from)
|
19
|
+
end
|
20
|
+
|
21
|
+
# downto and upto are just some sintactic sugar for expanding the range to
|
22
|
+
# a new value. It will create a new NotesRange object with the last Note
|
23
|
+
# and then will figure out how to get to the newest one.
|
24
|
+
def downto(value)
|
25
|
+
NotesRange.new(@to,value)
|
26
|
+
end
|
27
|
+
|
28
|
+
alias :upto :downto
|
29
|
+
|
30
|
+
def increase_octave(times=1)
|
31
|
+
NotesRange.new(@from.increase_octave(times), @to.increase_octave(times))
|
32
|
+
end
|
33
|
+
|
34
|
+
def decrease_octave(times=1)
|
35
|
+
NotesRange.new(@from.decrease_octave(times), @to.decrease_octave(times))
|
36
|
+
end
|
37
|
+
|
38
|
+
def music_string
|
39
|
+
map{|i| i.music_string }.join(" ")
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def transverse_notes
|
45
|
+
enum = if @from > @to
|
46
|
+
@from.value.downto(@to.value)
|
47
|
+
else
|
48
|
+
@from.value.upto(@to.value)
|
49
|
+
end
|
50
|
+
enum.map{|value| Note.from_value(value) }
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
Binary file
|
data/reference/Main.java
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
import org.jfugue.*;
|
2
|
+
public class Main
|
3
|
+
{
|
4
|
+
public static void main(String[] args)
|
5
|
+
{
|
6
|
+
Player player = new Player();
|
7
|
+
// Pattern pattern = new Pattern("C D E F G A B");
|
8
|
+
Pattern pattern = new Pattern("G B C D E A B");
|
9
|
+
|
10
|
+
player.play(pattern);
|
11
|
+
System.exit(0); // If using Java 1.4 or lower
|
12
|
+
}
|
13
|
+
}
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hammelin
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.2
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alvaro Pereyra
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-09-16 00:00:00 -05:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: Hammelin wraps around JFugue and lets your play with notes, making Ruby sing
|
18
|
+
email: alvaro@xendacentral.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files: []
|
24
|
+
|
25
|
+
files:
|
26
|
+
- .gitignore
|
27
|
+
- .rvmrc.example
|
28
|
+
- Gemfile
|
29
|
+
- README.md
|
30
|
+
- Rakefile
|
31
|
+
- bin/jfugue-4.0.3.jar
|
32
|
+
- demos/nested_play.rb
|
33
|
+
- hammelin.gemspec
|
34
|
+
- lib/hammelin.rb
|
35
|
+
- lib/hammelin/hammelin.rb
|
36
|
+
- lib/hammelin/note.rb
|
37
|
+
- lib/hammelin/notes_range.rb
|
38
|
+
- lib/hammelin/version.rb
|
39
|
+
- reference/Main.class
|
40
|
+
- reference/Main.java
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: ""
|
43
|
+
licenses: []
|
44
|
+
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project: hammelin
|
65
|
+
rubygems_version: 1.5.1
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Hammelin allows you to play around with JFugue MIDI capabilities
|
69
|
+
test_files: []
|
70
|
+
|