shmidi 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/Gemfile +2 -0
- data/HISTORY.md +2 -0
- data/LICENSE.txt +20 -0
- data/README.md +17 -0
- data/Rakefile +8 -0
- data/bin/shmidi +51 -0
- data/lib/shmidi/base.rb +90 -0
- data/lib/shmidi/clock.rb +46 -0
- data/lib/shmidi/composite/rgy_led.rb +34 -0
- data/lib/shmidi/control.rb +21 -0
- data/lib/shmidi/controller.rb +24 -0
- data/lib/shmidi/controls/button.rb +52 -0
- data/lib/shmidi/controls/encoder.rb +10 -0
- data/lib/shmidi/controls/fader.rb +6 -0
- data/lib/shmidi/controls/knob.rb +32 -0
- data/lib/shmidi/controls/led.rb +37 -0
- data/lib/shmidi/event.rb +102 -0
- data/lib/shmidi/ffi-coremidi-patch.rb +259 -0
- data/lib/shmidi/led_button.rb +25 -0
- data/lib/shmidi/on_off_clock.rb +27 -0
- data/lib/shmidi/socket.rb +78 -0
- data/lib/shmidi/switch.rb +28 -0
- data/lib/shmidi/version.rb +5 -0
- data/lib/shmidi.rb +100 -0
- data/shmidi.gemspec +28 -0
- data/shmidi.sublime-project +30 -0
- data/test/xonek1-ledtest.json +42 -0
- metadata +184 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a3597c4286b7e19268aa340d94bc77346a045a75
|
4
|
+
data.tar.gz: be66d51d451f14247d77b2f2e792b39d23a3c860
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 758e82429e48ac2659b5021e89344ee2f1d3e7d0f6ea0e8c59e2dde76450316efbe95f54b1695344f92f2458dd7f29c6b47097c57ee43fade65d7649e2f60802
|
7
|
+
data.tar.gz: bdf94aad7c06e4c9d825292a8ba9b3dd15e68d022d9d08d7c7f8d7c1f9b6df74c4b5ab3b3debbcb56f9d0df9c53c24e9e6e3bd2f931a62fa6115d3eed7bcf2a2
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
*~
|
2
|
+
~*
|
3
|
+
.DS_Store
|
4
|
+
._.DS_Store
|
5
|
+
thumbs.db
|
6
|
+
*.log
|
7
|
+
*.pid
|
8
|
+
*.dump
|
9
|
+
*.profile
|
10
|
+
*.profile.gif
|
11
|
+
*.profile.dot
|
12
|
+
*.profile.symbols
|
13
|
+
.svn/
|
14
|
+
.hg/
|
15
|
+
*.sublime-workspace
|
16
|
+
.env
|
17
|
+
.rbenv-version
|
18
|
+
.ruby-version
|
19
|
+
Gemfile.lock
|
20
|
+
core
|
21
|
+
*.gem
|
22
|
+
/doc/
|
23
|
+
/var/
|
data/Gemfile
ADDED
data/HISTORY.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
MIT License, http://opensource.org/licenses/MIT
|
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/README.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# shmidi
|
2
|
+
Midi experiments
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
`gem install shmidi` as usual.
|
6
|
+
|
7
|
+
## Usage by example
|
8
|
+
TODO
|
9
|
+
|
10
|
+
## Documentation
|
11
|
+
This README is all i could say in a rush. No other documentation provided at this moment, see the sources.
|
12
|
+
|
13
|
+
## If you've found a bug or drawback
|
14
|
+
Don't hesistate to leave a report.
|
15
|
+
|
16
|
+
## License
|
17
|
+
MIT for now.
|
data/Rakefile
ADDED
data/bin/shmidi
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'shmidi'
|
3
|
+
require 'io/console'
|
4
|
+
|
5
|
+
if Shmidi::PROFILE
|
6
|
+
begin
|
7
|
+
require 'perftools'
|
8
|
+
PerfTools::CpuProfiler.start 'test.profile'
|
9
|
+
at_exit { PerfTools::CpuProfiler.stop }
|
10
|
+
rescue LoadError
|
11
|
+
Shmidi.ON_EXCEPTION
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
@ctl = Shmidi::Controller.new('xonek1-ledtest')
|
16
|
+
trap('INT') do
|
17
|
+
@ctl.reset
|
18
|
+
puts(@ctl.inspect)
|
19
|
+
exit(0)
|
20
|
+
end
|
21
|
+
|
22
|
+
case ARGV.shift
|
23
|
+
when 'list'
|
24
|
+
Shmidi::Socket.print_device_list
|
25
|
+
when 'ledtest'
|
26
|
+
if ARGV.size == 1
|
27
|
+
@ctl = Shmidi.JSON_PARSE(File.read(ARGV.shift))
|
28
|
+
else
|
29
|
+
@sock = 'xone'
|
30
|
+
@ctl.sockets << Shmidi::Socket.new(@sock, ARGV.shift, ARGV.shift)
|
31
|
+
@chan = 15
|
32
|
+
@ctl.controls['led'] = Shmidi::RGYLed.new(
|
33
|
+
Shmidi::Led.new(@sock, @chan, 'C0'),
|
34
|
+
Shmidi::Led.new(@sock, @chan, 'G#0'),
|
35
|
+
Shmidi::Led.new(@sock, @chan, 'E0', true)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
sleep(0.15)
|
39
|
+
loop do
|
40
|
+
@ctl.controls['led'].turn_on('red')
|
41
|
+
sleep(0.15)
|
42
|
+
@ctl.controls['led'].turn_on('green')
|
43
|
+
sleep(0.15)
|
44
|
+
@ctl.controls['led'].turn_on('yellow')
|
45
|
+
sleep(0.15)
|
46
|
+
@ctl.controls['led'].turn_off
|
47
|
+
sleep(0.15)
|
48
|
+
end
|
49
|
+
else
|
50
|
+
puts('NOOP')
|
51
|
+
end
|
data/lib/shmidi/base.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
module Shmidi
|
2
|
+
module Base
|
3
|
+
CTYPE = :ABS
|
4
|
+
attr_accessor :_id
|
5
|
+
attr_accessor :_rev
|
6
|
+
attr_accessor :_deleted
|
7
|
+
attr_accessor :_attachments
|
8
|
+
attr_accessor :version
|
9
|
+
|
10
|
+
def to_hash
|
11
|
+
hash = {JSON_CREATE_ID => self.class.name}
|
12
|
+
instance_variables.each do |var|
|
13
|
+
hvar = var[1..-1]
|
14
|
+
next if hvar =~ /^__/
|
15
|
+
hash[hvar] = instance_variable_get(var)
|
16
|
+
end
|
17
|
+
hash
|
18
|
+
end
|
19
|
+
|
20
|
+
def init
|
21
|
+
# ABSTRACT
|
22
|
+
end
|
23
|
+
|
24
|
+
def reset
|
25
|
+
# ABSTRACT
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
dump
|
30
|
+
end
|
31
|
+
|
32
|
+
def dump
|
33
|
+
Shmidi::DUMP(to_hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect
|
37
|
+
Shmidi::PRETTY(self)
|
38
|
+
end
|
39
|
+
|
40
|
+
def [](arg)
|
41
|
+
send arg.to_sym
|
42
|
+
end
|
43
|
+
def []=(arg, value)
|
44
|
+
send "#{arg}=".to_sym, value
|
45
|
+
end
|
46
|
+
|
47
|
+
def clone
|
48
|
+
self.class.ensure(dump)
|
49
|
+
end
|
50
|
+
|
51
|
+
def etag
|
52
|
+
"\"#{_rev}\""
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.included(base)
|
56
|
+
base.extend(ClassMethods)
|
57
|
+
end
|
58
|
+
|
59
|
+
module ClassMethods
|
60
|
+
def ensure(obj)
|
61
|
+
# ------
|
62
|
+
m = if obj.kind_of?(self)
|
63
|
+
obj
|
64
|
+
elsif obj.kind_of?(Hash)
|
65
|
+
self.json_create(obj)
|
66
|
+
elsif obj.kind_of?(String)
|
67
|
+
self.ensure(Shmidi::JSON_PARSE(obj))
|
68
|
+
else
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
(block_given? && m) ? yield(m) : m
|
72
|
+
end
|
73
|
+
|
74
|
+
def json_create(hash = {})
|
75
|
+
obj = allocate
|
76
|
+
hash.each do |key, value|
|
77
|
+
begin
|
78
|
+
obj.instance_variable_set("@#{key}", value)
|
79
|
+
rescue Exception
|
80
|
+
Shmidi::ON_EXCEPTION
|
81
|
+
end
|
82
|
+
end
|
83
|
+
obj.version ||= 0
|
84
|
+
obj.init
|
85
|
+
obj.reset
|
86
|
+
return obj
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/shmidi/clock.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Shmidi
|
3
|
+
class Event
|
4
|
+
attr_accessor :destination
|
5
|
+
end
|
6
|
+
|
7
|
+
class Clock
|
8
|
+
def initialize(socket, delay = 0.25)
|
9
|
+
@socket = socket
|
10
|
+
@delay = delay
|
11
|
+
@buffer = []
|
12
|
+
@thread = Thread.new do
|
13
|
+
loop do
|
14
|
+
begin
|
15
|
+
buf = filter
|
16
|
+
Socket[@socket].push(buf)
|
17
|
+
buf.each do |event|
|
18
|
+
event.destination.push(true)
|
19
|
+
end
|
20
|
+
wait
|
21
|
+
rescue
|
22
|
+
Shmidi.ON_EXCEPTION
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def sync(event)
|
29
|
+
event.destination = Queue.new
|
30
|
+
@buffer << event
|
31
|
+
event.destination.pop
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def filter
|
37
|
+
b = @buffer
|
38
|
+
@buffer = []
|
39
|
+
b
|
40
|
+
end
|
41
|
+
|
42
|
+
def wait
|
43
|
+
sleep(@delay)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Shmidi
|
3
|
+
class RGYLed
|
4
|
+
include Base
|
5
|
+
CTYPE = :RGY
|
6
|
+
attr_reader :leds
|
7
|
+
|
8
|
+
def initialize(red, green, yellow)
|
9
|
+
@leds = {'red' => red, 'green' => green, 'yellow' => yellow}
|
10
|
+
end
|
11
|
+
|
12
|
+
def reset
|
13
|
+
@leds.values.each {|led| led.reset}
|
14
|
+
end
|
15
|
+
|
16
|
+
def on?
|
17
|
+
@leds.each {|color, led| return color if led.turned_on?}
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def turn_on(color = 'yellow', clock = nil)
|
22
|
+
@leds.each do |c, led|
|
23
|
+
next if c == color
|
24
|
+
led.turn_off
|
25
|
+
end
|
26
|
+
@leds[color].turn_on(clock)
|
27
|
+
end
|
28
|
+
|
29
|
+
def turn_off(clock = nil)
|
30
|
+
@leds.values.each {|led| led.turn_off(clock)}
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Shmidi
|
3
|
+
class Control
|
4
|
+
include Base
|
5
|
+
attr_accessor :channel, :note
|
6
|
+
|
7
|
+
def socket
|
8
|
+
Socket[@socket]
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(socket, channel, note)
|
12
|
+
@socket = socket
|
13
|
+
@channel = channel
|
14
|
+
@note = note
|
15
|
+
end
|
16
|
+
|
17
|
+
def id
|
18
|
+
"#{@channel}:#{@note}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Shmidi
|
3
|
+
class Controller
|
4
|
+
include Base
|
5
|
+
attr_accessor :internals
|
6
|
+
attr_reader :name
|
7
|
+
def initialize(name)
|
8
|
+
@name = name
|
9
|
+
@internals = [[], {}]
|
10
|
+
end
|
11
|
+
|
12
|
+
def reset
|
13
|
+
controls.values.each {|control| control.reset}
|
14
|
+
end
|
15
|
+
|
16
|
+
def sockets
|
17
|
+
@internals.first
|
18
|
+
end
|
19
|
+
|
20
|
+
def controls
|
21
|
+
@internals.last
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Shmidi
|
3
|
+
class Button < Control
|
4
|
+
CTYPE = :BUT
|
5
|
+
|
6
|
+
attr_reader :counter
|
7
|
+
|
8
|
+
def initialize(socket, channel, note, pressed = false)
|
9
|
+
super(socket, channel, note)
|
10
|
+
@pressed = pressed
|
11
|
+
init
|
12
|
+
end
|
13
|
+
|
14
|
+
def init
|
15
|
+
@counter = 0
|
16
|
+
@__on_press = []
|
17
|
+
socket.on_event(channel, :on, note) do |event|
|
18
|
+
@pressed = true
|
19
|
+
@counter += 1 # intentionaly before handlers
|
20
|
+
Shmidi.TRACE("#{CTYPE}\t#{id}\tPRESSED\t#{event.value}")
|
21
|
+
@__on_press.each { |b| b.call(self) }
|
22
|
+
end
|
23
|
+
|
24
|
+
@on_release = []
|
25
|
+
socket.on_event(channel, :off, note) do |event|
|
26
|
+
@pressed = false
|
27
|
+
Shmidi.TRACE("#{CTYPE}\t#{id}\tRELEASE\t#{event.value}")
|
28
|
+
@on_release.each { |b| b.call(self) }
|
29
|
+
@counter += 1 # intentionaly after handlers
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def reset
|
34
|
+
@pressed = false
|
35
|
+
end
|
36
|
+
|
37
|
+
def pressed?
|
38
|
+
!!@pressed
|
39
|
+
end
|
40
|
+
def on_press(&block)
|
41
|
+
@__on_press << block
|
42
|
+
end
|
43
|
+
|
44
|
+
def released?
|
45
|
+
!@pressed
|
46
|
+
end
|
47
|
+
def on_release(&block)
|
48
|
+
@on_release << block
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Shmidi
|
3
|
+
class Knob < Control
|
4
|
+
CTYPE = :KNO
|
5
|
+
attr_reader :value
|
6
|
+
|
7
|
+
def initialize(socket, channel, note, value = 0)
|
8
|
+
super(socket, channel, note)
|
9
|
+
init(value)
|
10
|
+
end
|
11
|
+
|
12
|
+
def init(value = 0)
|
13
|
+
@prev_value = value
|
14
|
+
@value = value
|
15
|
+
@__on_value = []
|
16
|
+
socket.on_event(channel, :cc, note) do |event|
|
17
|
+
reset(event.value)
|
18
|
+
Shmidi.TRACE("#{CTYPE}\t#{id}\t#{@value}")
|
19
|
+
@__on_value.each { |b| b.call(self) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def reset(new_value=0)
|
24
|
+
@prev_value = @value
|
25
|
+
@value = 0
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_value(&block)
|
29
|
+
@__on_value << block
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Shmidi
|
3
|
+
class Led < Control
|
4
|
+
CTYPE = :LED
|
5
|
+
|
6
|
+
def initialize(socket, channel, note, turned_on = false)
|
7
|
+
super(socket, channel, note)
|
8
|
+
init(turned_on)
|
9
|
+
end
|
10
|
+
|
11
|
+
def init(turned_on = false)
|
12
|
+
@turned_on = false
|
13
|
+
@__turn_on_event = Event.new_on(@channel, @note)
|
14
|
+
@__turn_off_event = Event.new_off(@channel, @note)
|
15
|
+
turn_on if turned_on
|
16
|
+
end
|
17
|
+
|
18
|
+
def reset
|
19
|
+
turn_off
|
20
|
+
end
|
21
|
+
|
22
|
+
def on?
|
23
|
+
!!@turned_on
|
24
|
+
end
|
25
|
+
|
26
|
+
def turn_on(clock = nil)
|
27
|
+
(clock && clock.sync(@__turn_on_event)) || socket.push(@__turn_on_event)
|
28
|
+
@turned_on = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def turn_off(clock = nil)
|
32
|
+
(clock && clock.sync(@__turn_off_event)) || socket.push(@__turn_off_event)
|
33
|
+
@turned_on = false
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/lib/shmidi/event.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Shmidi
|
3
|
+
class Event
|
4
|
+
#TODO: eat symbols and strings as needed for shmidi piping
|
5
|
+
attr_reader :source
|
6
|
+
attr_reader :data, :timestamp
|
7
|
+
attr_reader :channel, :message_int, :note_int, :value
|
8
|
+
attr_reader :message, :note
|
9
|
+
|
10
|
+
MESSAGES ||= begin
|
11
|
+
h = { 8 => :off,
|
12
|
+
9 => :on,
|
13
|
+
11 => :cc,
|
14
|
+
14 => :pitch}
|
15
|
+
h.keys.each {|k| h[h[k]] = k}
|
16
|
+
h
|
17
|
+
end
|
18
|
+
|
19
|
+
def octave
|
20
|
+
return nil unless @note.kind_of?(String)
|
21
|
+
(@note_int / 12) - 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(h)
|
25
|
+
@source = h[:source]
|
26
|
+
@timestamp = (h[:timestamp] || 0).floor
|
27
|
+
@data = h[:data].clone if h[:data]
|
28
|
+
if @data
|
29
|
+
@channel = (@data[0] & 0x0f) + 1
|
30
|
+
@message_int= @data[0] >> 4
|
31
|
+
@message = @message_int
|
32
|
+
@message = MESSAGES[@message_int] || @message_int
|
33
|
+
@note_int = @data[1]
|
34
|
+
@note = @note_int
|
35
|
+
parse_note_int if [:on, :off].include?(@message)
|
36
|
+
@value = @data[2]
|
37
|
+
else # no numeric data array
|
38
|
+
@message_int = h[:message_int] || MESSAGES[h[:message]] || h[:message]
|
39
|
+
@message = MESSAGES[@message_int]
|
40
|
+
@value = h[:value] || 0
|
41
|
+
@channel = h[:channel] || 1
|
42
|
+
@note = h[:note]
|
43
|
+
@note_int = h[:note]
|
44
|
+
if h[:note].kind_of?(Numeric) && [:on, :off].include?(@message)
|
45
|
+
parse_note_int
|
46
|
+
elsif h[:note].kind_of?(String)
|
47
|
+
@note = h[:note]
|
48
|
+
#@note += h[:note][1] if h[:note][1] == '#'
|
49
|
+
h[:note] =~ /^(.#?)(-?\d+)$/
|
50
|
+
@note_int = ($2.to_i + 1) * 12 + 'C C#D D#E F F#G G#A A#B '.index($1) / 2
|
51
|
+
end
|
52
|
+
@data = [0,0,0]
|
53
|
+
@data[1] = @note_int
|
54
|
+
@data[2] = @value
|
55
|
+
@data[0] = (@message_int << 4) + (@channel - 1)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.new_on(channel, note, value = 127)
|
60
|
+
Event.new(
|
61
|
+
:channel => channel,
|
62
|
+
:message => :on,
|
63
|
+
:note => note,
|
64
|
+
:value => value)
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.new_off(channel, note, value = 0)
|
68
|
+
Event.new(
|
69
|
+
:channel => channel,
|
70
|
+
:message => :off,
|
71
|
+
:note => note,
|
72
|
+
:value => value)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.new_cc(channel, cc, value)
|
76
|
+
Event.new(
|
77
|
+
:channel => channel,
|
78
|
+
:message => :cc,
|
79
|
+
:note => cc,
|
80
|
+
:value => value)
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_s
|
84
|
+
"CH:#{@channel}\t#{@message}\t#{@note}\t=#{@value}"
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_hash
|
88
|
+
hash = {}
|
89
|
+
instance_variables.each do |var|
|
90
|
+
hash[var[1..-1].to_sym] = instance_variable_get(var)
|
91
|
+
end
|
92
|
+
hash
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def parse_note_int
|
98
|
+
@note = 'C C#D D#E F F#G G#A A#B '[((@note_int % 12) * 2), 2].strip
|
99
|
+
@note += "#{octave}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|