shmidi 0.1
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.
- 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
|