shmidi 0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/HISTORY.md ADDED
@@ -0,0 +1,2 @@
1
+ # 3.0.RC-1 Complete rebuild
2
+
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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env rake
2
+ require 'rake/testtask'
3
+
4
+ task :build do
5
+ system('gem build shmidi.gemspec')
6
+ end
7
+
8
+ task :default => :build
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
@@ -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
@@ -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,10 @@
1
+ # coding: utf-8
2
+ module Shmidi
3
+ class Encoder < Knob
4
+ CTYPE = :ENC
5
+
6
+ def increasing?
7
+ @value == 1
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ # coding: utf-8
2
+ module Shmidi
3
+ class Fader < Knob
4
+ CTYPE = :FAD
5
+ end
6
+ 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
@@ -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