ffi-coremidi 0.2.0 → 0.2.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/LICENSE +1 -1
- data/README.md +3 -3
- data/lib/coremidi.rb +11 -10
- data/lib/coremidi/destination.rb +1 -0
- data/lib/coremidi/source.rb +33 -16
- data/test/helper.rb +6 -6
- data/test/{test_input_buffer.rb → input_buffer_test.rb} +2 -4
- data/test/io_test.rb +90 -0
- metadata +17 -20
- data/test/test_io.rb +0 -83
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f0cd3edc0360a57ce8923b96a96f88e61b050ffd
|
4
|
+
data.tar.gz: 38f95b91e6ef5a5e34628dd56d024101062e7ed4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 46c3ff9c2e946688b0b5f92cb10a0b5062fe90afedcfde912e1fc89b955774ea924da28b3bb01db123615ed93b4218938ddcb149ae55608373e810e451847ef5
|
7
|
+
data.tar.gz: 3e4ccf3a0c4362908c5273f71a11ec989d2abce5fc7f9eb5d3204ebf4f5405561aa331d74a7545d44f2a5555017c906cf1ce48da240b3ee5fda13d656d163fcc
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
#### Realtime MIDI IO with Ruby for OSX
|
4
4
|
|
5
|
-
This is a Ruby implementation of the Apple Core MIDI framework API.
|
5
|
+
This is a Ruby implementation of the [Apple Core MIDI framework API](https://developer.apple.com/library/mac/#documentation/MusicAudio/Reference/CACoreMIDIRef/MIDIServices/).
|
6
6
|
|
7
7
|
Note that in the interest of allowing people on other platforms to utilize your code, please consider using [UniMIDI](http://github.com/arirusso/unimidi). UniMIDI is a platform independent wrapper which implements this library with a similar API.
|
8
8
|
|
@@ -18,7 +18,7 @@ Note that in the interest of allowing people on other platforms to utilize your
|
|
18
18
|
|
19
19
|
* [ffi](http://github.com/ffi/ffi)
|
20
20
|
|
21
|
-
###
|
21
|
+
### Installation
|
22
22
|
|
23
23
|
If you're using Bundler, add this line to your application's Gemfile:
|
24
24
|
|
@@ -48,4 +48,4 @@ Also thank you to [Jeremy Voorhis](http://github.com/jvoorhis) for some useful d
|
|
48
48
|
|
49
49
|
Apache 2.0, See the file LICENSE
|
50
50
|
|
51
|
-
Copyright (c) 2011-
|
51
|
+
Copyright (c) 2011-2014 [Ari Russo](http://github.com/arirusso)
|
data/lib/coremidi.rb
CHANGED
@@ -1,21 +1,22 @@
|
|
1
1
|
# ffi-coremidi
|
2
|
+
#
|
2
3
|
# Realtime MIDI IO with Ruby for OSX
|
3
|
-
# (c)2011-
|
4
|
+
# (c)2011-2014 Ari Russo
|
4
5
|
|
5
6
|
# libs
|
6
|
-
require
|
7
|
-
require
|
7
|
+
require "ffi"
|
8
|
+
require "forwardable"
|
8
9
|
|
9
10
|
# modules
|
10
|
-
require
|
11
|
-
require
|
11
|
+
require "coremidi/endpoint"
|
12
|
+
require "coremidi/map"
|
12
13
|
|
13
14
|
# classes
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
15
|
+
require "coremidi/entity"
|
16
|
+
require "coremidi/device"
|
17
|
+
require "coremidi/source"
|
18
|
+
require "coremidi/destination"
|
18
19
|
|
19
20
|
module CoreMIDI
|
20
|
-
VERSION = "0.2.
|
21
|
+
VERSION = "0.2.1"
|
21
22
|
end
|
data/lib/coremidi/destination.rb
CHANGED
data/lib/coremidi/source.rb
CHANGED
@@ -8,45 +8,51 @@ module CoreMIDI
|
|
8
8
|
attr_reader :buffer
|
9
9
|
|
10
10
|
#
|
11
|
-
#
|
11
|
+
# An array of MIDI event hashes as such:
|
12
12
|
# [
|
13
13
|
# { :data => [144, 60, 100], :timestamp => 1024 },
|
14
14
|
# { :data => [128, 60, 100], :timestamp => 1100 },
|
15
15
|
# { :data => [144, 40, 120], :timestamp => 1200 }
|
16
16
|
# ]
|
17
17
|
#
|
18
|
-
#
|
19
|
-
#
|
18
|
+
# The data is an array of Numeric bytes
|
19
|
+
# The timestamp is the number of millis since this input was enabled
|
20
20
|
#
|
21
|
+
# @return [Array<Hash>]
|
21
22
|
def gets
|
22
23
|
until queued_messages?
|
24
|
+
# per https://github.com/arirusso/unimidi/issues/20#issuecomment-44761318
|
25
|
+
sleep(0.0001) # patch to prevent 100% CPU issue with some midi controllers
|
23
26
|
end
|
24
|
-
|
27
|
+
messages = queued_messages
|
25
28
|
@pointer = @buffer.length
|
26
|
-
|
29
|
+
messages
|
27
30
|
end
|
28
31
|
alias_method :read, :gets
|
29
32
|
|
30
|
-
#
|
33
|
+
# Same as Source#gets except that it returns message data as string of hex
|
34
|
+
# digits as such:
|
31
35
|
# [
|
32
36
|
# { :data => "904060", :timestamp => 904 },
|
33
37
|
# { :data => "804060", :timestamp => 1150 },
|
34
38
|
# { :data => "90447F", :timestamp => 1300 }
|
35
39
|
# ]
|
36
40
|
#
|
37
|
-
#
|
41
|
+
# @return [Array<Hash>]
|
38
42
|
def gets_s
|
39
|
-
|
40
|
-
|
41
|
-
|
43
|
+
messages = gets
|
44
|
+
messages.each do |message|
|
45
|
+
message[:data] = numeric_bytes_to_hex_string(message[:data])
|
46
|
+
end
|
47
|
+
messages
|
42
48
|
end
|
43
49
|
alias_method :gets_bytestr, :gets_s
|
44
50
|
|
45
|
-
#
|
51
|
+
# Enable this the input for use; can be passed a block
|
46
52
|
def enable(options = {}, &block)
|
47
53
|
@enabled = true
|
48
54
|
|
49
|
-
|
55
|
+
if block_given?
|
50
56
|
begin
|
51
57
|
yield(self)
|
52
58
|
ensure
|
@@ -70,6 +76,7 @@ module CoreMIDI
|
|
70
76
|
#error = Map.MIDIEndpointDispose(@resource)
|
71
77
|
#raise "MIDIEndpointDispose returned error code #{error}" unless error.zero?
|
72
78
|
@enabled = false
|
79
|
+
true
|
73
80
|
end
|
74
81
|
|
75
82
|
# Shortcut to the first available input endpoint
|
@@ -140,12 +147,15 @@ module CoreMIDI
|
|
140
147
|
|
141
148
|
# Timestamp for a received MIDI message
|
142
149
|
def timestamp(now)
|
143
|
-
(
|
150
|
+
(now - @start_time) * 1000
|
144
151
|
end
|
145
152
|
|
146
153
|
# Give a message its timestamp and package it in a Hash
|
147
154
|
def get_message_formatted(raw, time)
|
148
|
-
{
|
155
|
+
{
|
156
|
+
:data => raw,
|
157
|
+
:timestamp => timestamp(time)
|
158
|
+
}
|
149
159
|
end
|
150
160
|
|
151
161
|
# Initialize a coremidi port for this endpoint
|
@@ -156,6 +166,7 @@ module CoreMIDI
|
|
156
166
|
error = Map.MIDIInputPortCreate(@client, port_name, @callback, nil, handle_ptr)
|
157
167
|
@handle = handle_ptr.read_pointer
|
158
168
|
raise "MIDIInputPortCreate returned error code #{error}" unless error.zero?
|
169
|
+
true
|
159
170
|
end
|
160
171
|
|
161
172
|
# Initialize the MIDI message buffer
|
@@ -165,12 +176,18 @@ module CoreMIDI
|
|
165
176
|
def @buffer.clear
|
166
177
|
super
|
167
178
|
@pointer = 0
|
168
|
-
end
|
179
|
+
end
|
180
|
+
true
|
169
181
|
end
|
170
182
|
|
171
183
|
# Convert an array of numeric byes to a hex string (e.g. [0x90, 0x40, 0x40] becomes "904040")
|
172
184
|
def numeric_bytes_to_hex_string(bytes)
|
173
|
-
bytes.map
|
185
|
+
string_bytes = bytes.map do |byte|
|
186
|
+
str = byte.to_s(16).upcase
|
187
|
+
str = "0" + str if byte < 16
|
188
|
+
str
|
189
|
+
end
|
190
|
+
string_bytes.join
|
174
191
|
end
|
175
192
|
|
176
193
|
end
|
data/test/helper.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
1
|
dir = File.dirname(File.expand_path(__FILE__))
|
4
|
-
$LOAD_PATH.unshift dir +
|
2
|
+
$LOAD_PATH.unshift dir + "/../lib"
|
5
3
|
|
6
|
-
require
|
7
|
-
require
|
4
|
+
require "test/unit"
|
5
|
+
require "mocha/test_unit"
|
6
|
+
require "shoulda-context"
|
7
|
+
require "coremidi"
|
8
8
|
|
9
9
|
module TestHelper
|
10
10
|
|
@@ -55,4 +55,4 @@ module TestHelper
|
|
55
55
|
|
56
56
|
end
|
57
57
|
|
58
|
-
TestHelper.select_devices
|
58
|
+
TestHelper.select_devices
|
data/test/io_test.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class CoreMIDI::IOTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
# ** these tests assume that TestOutput is connected to TestInput
|
6
|
+
context "CoreMIDI" do
|
7
|
+
|
8
|
+
setup do
|
9
|
+
sleep(1)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "full IO" do
|
13
|
+
|
14
|
+
context "using Arrays" do
|
15
|
+
|
16
|
+
setup do
|
17
|
+
@messages = TestHelper::VariousMIDIMessages
|
18
|
+
@messages_arr = @messages.inject { |a,b| a+b }.flatten
|
19
|
+
@received_arr = []
|
20
|
+
@pointer = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
should "do IO" do
|
24
|
+
$test_device[:output].open do |output|
|
25
|
+
$test_device[:input].open do |input|
|
26
|
+
|
27
|
+
input.buffer.clear
|
28
|
+
|
29
|
+
@messages.each do |msg|
|
30
|
+
|
31
|
+
$>.puts "sending: " + msg.inspect
|
32
|
+
|
33
|
+
output.puts(msg)
|
34
|
+
sleep(1)
|
35
|
+
received = input.gets.map { |m| m[:data] }.flatten
|
36
|
+
|
37
|
+
$>.puts "received: " + received.inspect
|
38
|
+
|
39
|
+
assert_equal(@messages_arr.slice(@pointer, received.length), received)
|
40
|
+
@pointer += received.length
|
41
|
+
@received_arr += received
|
42
|
+
end
|
43
|
+
assert_equal(@messages_arr.length, @received_arr.length)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "using byte Strings" do
|
51
|
+
|
52
|
+
setup do
|
53
|
+
@messages = TestHelper::VariousMIDIByteStrMessages
|
54
|
+
@messages_str = @messages.join
|
55
|
+
@received_str = ""
|
56
|
+
@pointer = 0
|
57
|
+
end
|
58
|
+
|
59
|
+
should "do IO" do
|
60
|
+
$test_device[:output].open do |output|
|
61
|
+
$test_device[:input].open do |input|
|
62
|
+
|
63
|
+
@messages.each do |msg|
|
64
|
+
|
65
|
+
$>.puts "sending: " + msg.inspect
|
66
|
+
|
67
|
+
output.puts(msg)
|
68
|
+
sleep(1)
|
69
|
+
received = input.gets_bytestr.map { |m| m[:data] }.flatten.join
|
70
|
+
$>.puts "received: " + received.inspect
|
71
|
+
|
72
|
+
assert_equal(@messages_str.slice(@pointer, received.length), received)
|
73
|
+
@pointer += received.length
|
74
|
+
@received_str += received
|
75
|
+
end
|
76
|
+
assert_equal(@messages_str, @received_str)
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
metadata
CHANGED
@@ -1,73 +1,70 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffi-coremidi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Ari Russo
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-08-31 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: ffi
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '1.0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '1.0'
|
30
|
-
description:
|
27
|
+
description: Perform realtime MIDI IO with Ruby for OSX
|
31
28
|
email:
|
32
29
|
- ari.russo@gmail.com
|
33
30
|
executables: []
|
34
31
|
extensions: []
|
35
32
|
extra_rdoc_files: []
|
36
33
|
files:
|
34
|
+
- LICENSE
|
35
|
+
- README.md
|
36
|
+
- lib/coremidi.rb
|
37
37
|
- lib/coremidi/destination.rb
|
38
38
|
- lib/coremidi/device.rb
|
39
39
|
- lib/coremidi/endpoint.rb
|
40
40
|
- lib/coremidi/entity.rb
|
41
41
|
- lib/coremidi/map.rb
|
42
42
|
- lib/coremidi/source.rb
|
43
|
-
- lib/coremidi.rb
|
44
43
|
- test/helper.rb
|
45
|
-
- test/
|
46
|
-
- test/
|
47
|
-
- LICENSE
|
48
|
-
- README.md
|
44
|
+
- test/input_buffer_test.rb
|
45
|
+
- test/io_test.rb
|
49
46
|
homepage: http://github.com/arirusso/ffi-coremidi
|
50
|
-
licenses:
|
47
|
+
licenses:
|
48
|
+
- Apache 2.0
|
49
|
+
metadata: {}
|
51
50
|
post_install_message:
|
52
51
|
rdoc_options: []
|
53
52
|
require_paths:
|
54
53
|
- lib
|
55
54
|
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
-
none: false
|
57
55
|
requirements:
|
58
|
-
- -
|
56
|
+
- - ">="
|
59
57
|
- !ruby/object:Gem::Version
|
60
58
|
version: '0'
|
61
59
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
-
none: false
|
63
60
|
requirements:
|
64
|
-
- -
|
61
|
+
- - ">="
|
65
62
|
- !ruby/object:Gem::Version
|
66
63
|
version: 1.3.6
|
67
64
|
requirements: []
|
68
65
|
rubyforge_project: ffi-coremidi
|
69
|
-
rubygems_version:
|
66
|
+
rubygems_version: 2.2.2
|
70
67
|
signing_key:
|
71
|
-
specification_version:
|
68
|
+
specification_version: 4
|
72
69
|
summary: Realtime MIDI IO with Ruby for OSX
|
73
70
|
test_files: []
|
data/test/test_io.rb
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'helper'
|
4
|
-
|
5
|
-
class IoTest < Test::Unit::TestCase
|
6
|
-
|
7
|
-
include CoreMIDI
|
8
|
-
include TestHelper
|
9
|
-
|
10
|
-
def test_full_io
|
11
|
-
sleep(2)
|
12
|
-
messages = VariousMIDIMessages
|
13
|
-
messages_arr = messages.inject { |a,b| a+b }.flatten
|
14
|
-
received_arr = []
|
15
|
-
pointer = 0
|
16
|
-
$test_device[:output].open do |output|
|
17
|
-
$test_device[:input].open do |input|
|
18
|
-
|
19
|
-
input.buffer.clear
|
20
|
-
|
21
|
-
messages.each do |msg|
|
22
|
-
|
23
|
-
$>.puts "sending: " + msg.inspect
|
24
|
-
|
25
|
-
output.puts(msg)
|
26
|
-
sleep(1)
|
27
|
-
received = input.gets.map { |m| m[:data] }.flatten
|
28
|
-
|
29
|
-
$>.puts "received: " + received.inspect
|
30
|
-
|
31
|
-
assert_equal(messages_arr.slice(pointer, received.length), received)
|
32
|
-
|
33
|
-
pointer += received.length
|
34
|
-
|
35
|
-
received_arr += received
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
assert_equal(messages_arr.length, received_arr.length)
|
40
|
-
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# ** this test assumes that TestOutput is connected to TestInput
|
46
|
-
def test_full_io_bytestr
|
47
|
-
sleep(2) # pause between tests
|
48
|
-
|
49
|
-
messages = VariousMIDIByteStrMessages
|
50
|
-
messages_str = messages.join
|
51
|
-
received_str = ""
|
52
|
-
pointer = 0
|
53
|
-
|
54
|
-
$test_device[:output].open do |output|
|
55
|
-
$test_device[:input].open do |input|
|
56
|
-
|
57
|
-
input.buffer.clear
|
58
|
-
|
59
|
-
messages.each do |msg|
|
60
|
-
|
61
|
-
$>.puts "sending: " + msg.inspect
|
62
|
-
|
63
|
-
output.puts_s(msg)
|
64
|
-
sleep(1)
|
65
|
-
received = input.gets_bytestr.map { |m| m[:data] }.flatten.join
|
66
|
-
$>.puts "received: " + received.inspect
|
67
|
-
|
68
|
-
assert_equal(messages_str.slice(pointer, received.length), received)
|
69
|
-
|
70
|
-
pointer += received.length
|
71
|
-
|
72
|
-
received_str += received
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
assert_equal(messages_str, received_str)
|
77
|
-
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
|
-
end
|