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 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