hammelin 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|