rtmidi 0.2.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 951dc43b29adbc7d76f79f191f1e4a9ad6c034fd
4
- data.tar.gz: 4733255fee9f6e321cc690594afafa8fa9e520af
3
+ metadata.gz: 3c430949e32e04bb62083aae6879c0b20dad223e
4
+ data.tar.gz: 81ab70ee2a3fe78349ed6de2542fea7e42ca3bfc
5
5
  SHA512:
6
- metadata.gz: 9777c38f05c57c90f63c731279cb0c3d4ca3064049758d4c28c21bcd8a458900a0d51c33fff557d449bd4d7fdbfadcd6d1ecd7b4aa324f98ece78af57dc3849b
7
- data.tar.gz: 897d148e298d4b9d76ebf953234bfe35bc5e3c76457f4395e8728cf519dacc77400a8d56375b68afbb30499b07e3c0b5587ddb45a525e1c699d74e4a9059e17d
6
+ metadata.gz: 55647eec74cde698b047ad3abea4b3b2c88d8b3f42ca318e05106bd4ceaab9191da0194873b8c16675bc78e6bc0a4f77dd6a19207204261d39f1259e1bb9b690
7
+ data.tar.gz: 7953645285988a046841e8bf4a75e403d1919b3c95640bbdfaa59db64b7934fc21cacba08bff03e24380569a54e367c5daab7ce346df0d870462c406574f6c4f
data/README.md CHANGED
@@ -1,24 +1,25 @@
1
1
  Ruby-RtMidi
2
2
  ===========
3
3
 
4
+ [![Build Status](https://travis-ci.org/adamjmurray/ruby-rtmidi.png)](http://travis-ci.org/adamjmurray/ruby-rtmidi)
5
+
4
6
  [Ruby](http://www.ruby-lang.org/) wrapper for [RtMidi](http://www.music.mcgill.ca/~gary/rtmidi/index.html),
5
7
  a cross-platform C++ library for realtime MIDI input and output.
6
8
 
7
9
  Features:
8
10
 
9
11
  * List MIDI I/O ports
10
- * Send 3-byte MIDI messages to output ports
11
- * Listen for 3-byte messages on input ports
12
+ * Send MIDI messages to output ports
13
+ * Receive messages on input ports
12
14
 
13
- In other words, it can handle [channel messages](http://www.cs.cf.ac.uk/Dave/Multimedia/node158.html)
14
- (notes, control change, pitch bend, pressure, program),
15
- but there is no support for [SySex](https://en.wikipedia.org/wiki/SysEx#System_Exclusive_messages) messages yet.
15
+ In other words, everything you'd want from a low-level MIDI library.
16
+ It's still your responsibility to interpret the MIDI message byte streams!
16
17
 
17
18
  Supported Platforms:
18
19
 
19
20
  * OS X
20
21
  * Windows
21
- * Linux with [JACK](http://jackaudio.org/) or [ALSA](http://www.alsa-project.org)
22
+ * Linux
22
23
 
23
24
 
24
25
  Requirements
@@ -54,8 +55,14 @@ Windows Setup
54
55
  * MinGW Developer ToolKit
55
56
  * Use the the MinGW Shell (MSYS) to install
56
57
 
57
- Linux Setup (Ubuntu)
58
- --------------------
58
+ Note: when installing under MinGW, this library may not work outside of MinGW. If that is a problem for you, use Visual Studio to install.
59
+
60
+ Linux Setup
61
+ -----------
62
+
63
+ Install [JACK](http://jackaudio.org/) or [ALSA](http://www.alsa-project.org).
64
+
65
+ This should work on Ubuntu:
59
66
 
60
67
  sudo apt-get install g++
61
68
  sudo apt-get install jackd
@@ -75,19 +82,39 @@ Usage
75
82
 
76
83
  See the following examples:
77
84
 
78
- * [List MIDI devices](http://rdoc.info/github/adamjmurray/ruby-rtmidi/file/examples/list_ports.rb)
79
- * [MIDI output](http://rdoc.info/github/adamjmurray/ruby-rtmidi/file/examples/play_notes.rb)
80
- * [MIDI input](http://rdoc.info/github/adamjmurray/ruby-rtmidi/file/examples/monitor_input.rb)
85
+ * [list MIDI devices](http://rdoc.info/github/adamjmurray/ruby-rtmidi/file/examples/list_ports.rb)
86
+ * [MIDI channel output](http://rdoc.info/github/adamjmurray/ruby-rtmidi/file/examples/send_channel_message.rb)
87
+ * [MIDI channel input](http://rdoc.info/github/adamjmurray/ruby-rtmidi/file/examples/receive_channel_input.rb)
88
+ * [arbitrary MIDI output](http://rdoc.info/github/adamjmurray/ruby-rtmidi/file/examples/send_any_message.rb)
89
+ * [arbitrary MIDI input](http://rdoc.info/github/adamjmurray/ruby-rtmidi/file/examples/receive_any_input.rb)
90
+
91
+ Use the arbitrary MIDI IO to handle channel messages, SysEx, timing, and/or active sensing messages.
92
+ If you only need channel messages (notes, modulation/CC, pitch bend, aftertouch), it's recommended you
93
+ follow the channel IO examples.
81
94
 
82
95
 
83
96
  Documentation
84
97
  =============
98
+
85
99
  [http://rdoc.info/github/adamjmurray/ruby-rtmidi/frames](http://rdoc.info/github/adamjmurray/ruby-rtmidi/frames)
86
100
 
87
101
 
102
+ Contributing
103
+ ============
104
+
105
+ Pull requests are welcome. The following must work:
106
+
107
+ * `rake test` shows all unit tests are passing
108
+ * Build and test the gem manually:
109
+ * `gem build rtmidi.gemspec`
110
+ * `gem install rtmidi-#{version}.gem`
111
+ * the examples can be run successfully against this version of the gem (`ruby examples/**`)
112
+
113
+
88
114
  Changelog
89
115
  =========
90
116
 
117
+ * 0.3 - Support for arbitrary MIDI messages including SysEx
91
118
  * 0.2.2 - Compilable with Visual Studio on Windows
92
119
  * 0.2.1 - Linux support (thanks to [@quark-zju](https://github.com/quark-zju))
93
120
  * 0.2 - First stable release
data/Rakefile CHANGED
@@ -1,10 +1,27 @@
1
- load File.expand_path('ext/Rakefile', File.dirname(__FILE__))
1
+ require 'rake/clean'
2
+
3
+ CLEAN.include %w[ **/*.o **/*.lib **/*.obj **/*.log ]
4
+ CLOBBER.include %w[ **/*.so **/*.dll ]
5
+
2
6
 
3
- desc 'remove artifacts produced by make task'
4
- task :clean do
5
- for file in Dir["#{RTMIDI_DIR}/*.o", "#{EXT_DIR}/*.o","#{EXT_DIR}/*.so"]
6
- puts "Deleting #{file}"
7
- File.unlink(file)
7
+ require 'rspec/core/rake_task'
8
+
9
+ desc "Run tests"
10
+ RSpec::Core::RakeTask.new('test') do |spec|
11
+ spec.rspec_opts = ["--color", "--format", "nested"]
12
+ if ARGV[1]
13
+ # only run specs with filenames starting with the command line argument
14
+ spec.pattern = "spec/**/#{ARGV[1]}*"
8
15
  end
9
- puts
10
16
  end
17
+
18
+ task :spec => :test # alias test task as spec task
19
+
20
+
21
+ load File.expand_path('ext/Rakefile', File.dirname(__FILE__))
22
+
23
+
24
+ desc 'Build the gem'
25
+ task :gem do
26
+ system 'gem build rtmidi.gemspec'
27
+ end
@@ -4,12 +4,12 @@ puts
4
4
 
5
5
  midiin = RtMidi::In.new
6
6
  puts "Available MIDI input ports"
7
- midiin.port_names.each_with_index{|name,index| puts " ##{index+1}: #{name}" }
7
+ midiin.port_names.each_with_index{|name,index| puts " #{index+1}: #{name}" }
8
8
 
9
9
  puts
10
10
 
11
11
  midiout = RtMidi::Out.new
12
12
  puts "Available MIDI output ports"
13
- midiout.port_names.each_with_index{|name,index| puts " ##{index+1}: #{name}" }
13
+ midiout.port_names.each_with_index{|name,index| puts " #{index+1}: #{name}" }
14
14
 
15
15
  puts
@@ -0,0 +1,35 @@
1
+ require "rtmidi"
2
+
3
+ midiin = RtMidi::In.new
4
+
5
+
6
+ ##############################################################################
7
+ # Boilerplate code for selecting a MIDI port
8
+
9
+ puts "Available MIDI input ports"
10
+ midiin.port_names.each_with_index{|name,index| printf "%3i: %s\n", index, name }
11
+
12
+ def select_port(midiio)
13
+ print "Select a port number: "
14
+ if (port = gets) =~ /^\d+$/
15
+ return port.to_i if (0...midiio.port_count).include? port.to_i
16
+ end
17
+ puts "Invalid port number"
18
+ end
19
+
20
+ port_index = select_port(midiin) until port_index
21
+
22
+ ##############################################################################
23
+ # Use this approach when you need to receive any message including:
24
+ # System Exclusive (SysEx), timing, active sensing
25
+
26
+ midiin.receive_message do |*bytes|
27
+ puts bytes.inspect
28
+ end
29
+
30
+ puts "Receiving MIDI messages including SysEx..."
31
+ puts "Ctrl+C to exit"
32
+
33
+ midiin.open_port(port_index)
34
+
35
+ sleep # prevent Ruby from exiting immediately
@@ -0,0 +1,35 @@
1
+ require "rtmidi"
2
+
3
+ midiin = RtMidi::In.new
4
+
5
+
6
+ ##############################################################################
7
+ # Boilerplate code for selecting a MIDI port
8
+
9
+ puts "Available MIDI input ports"
10
+ midiin.port_names.each_with_index{|name,index| printf "%3i: %s\n", index, name }
11
+
12
+ def select_port(midiio)
13
+ print "Select a port number: "
14
+ if (port = gets) =~ /^\d+$/
15
+ return port.to_i if (0...midiio.port_count).include? port.to_i
16
+ end
17
+ puts "Invalid port number"
18
+ end
19
+
20
+ port_index = select_port(midiin) until port_index
21
+
22
+ ##############################################################################
23
+ # Use this approach when you only need to receive channel message like:
24
+ # MIDI notes, modulation/CC, pitch bend, aftertouch
25
+
26
+ midiin.receive_channel_message do |byte1, byte2, byte3|
27
+ puts "#{byte1} #{byte2} #{byte3}"
28
+ end
29
+
30
+ puts "Receiving MIDI channel messages..."
31
+ puts "Ctrl+C to exit"
32
+
33
+ midiin.open_port(port_index)
34
+
35
+ sleep # prevent Ruby from exiting immediately
@@ -0,0 +1,31 @@
1
+ require "rtmidi"
2
+
3
+ midiout = RtMidi::Out.new
4
+
5
+
6
+ ##############################################################################
7
+ # Boilerplate code for selecting a MIDI port
8
+
9
+ puts "Available MIDI output ports"
10
+ midiout.port_names.each_with_index{|name,index| printf "%3i: %s\n", index, name }
11
+
12
+ def select_port(midiio)
13
+ print "Select a port number: "
14
+ if (port = gets) =~ /^\d+$/
15
+ return port.to_i if (0...midiio.port_count).include? port.to_i
16
+ end
17
+ puts "Invalid port number"
18
+ end
19
+
20
+ port_index = select_port(midiout) until port_index
21
+
22
+ ##############################################################################
23
+ # Use this approach when you need to send any message including:
24
+ # System Exclusive (SysEx), timing, active sensing
25
+
26
+ midiout.open_port(port_index)
27
+
28
+ # Now send some SysEx messages
29
+ midiout.send_message(240, 67, 16, 0, 16, 34, 247)
30
+ # or if you prefer a single array argument:
31
+ midiout.send_message( [240, 67, 16, 0, 16, 35, 247] )
@@ -0,0 +1,34 @@
1
+ require "rtmidi"
2
+
3
+ midiout = RtMidi::Out.new
4
+
5
+
6
+ ##############################################################################
7
+ # Boilerplate code for selecting a MIDI port
8
+
9
+ puts "Available MIDI output ports"
10
+ midiout.port_names.each_with_index{|name,index| printf "%3i: %s\n", index, name }
11
+
12
+ def select_port(midiio)
13
+ print "Select a port number: "
14
+ if (port = gets) =~ /^\d+$/
15
+ return port.to_i if (0...midiio.port_count).include? port.to_i
16
+ end
17
+ puts "Invalid port number"
18
+ end
19
+
20
+ port_index = select_port(midiout) until port_index
21
+
22
+ ##############################################################################
23
+ # Use this approach when you only need to send channel message like:
24
+ # MIDI notes, modulation/CC, pitch bend, aftertouch
25
+
26
+ midiout.open_port(port_index)
27
+
28
+ for pitch in [60, 62, 64, 65, 67]
29
+ midiout.send_channel_message(0x90, pitch, 127) # note on
30
+ sleep 0.5
31
+ midiout.send_channel_message(0x90, pitch, 0) # note off
32
+ end
33
+
34
+ sleep 0.5 # give the final note off time to release
@@ -1,97 +1,11 @@
1
- require 'rake/clean'
2
-
3
- EXT_DIR = File.expand_path(File.dirname __FILE__)
4
- RTMIDI_DIR = "#{EXT_DIR}/rtmidi-2.0.1"
5
-
6
- HOST_OS = RbConfig::CONFIG['host_os'].downcase
7
- OS_X = (HOST_OS =~ /darwin/)
8
- WINDOWS = ((HOST_OS =~ /win/ and HOST_OS !~ /darwin/) or HOST_OS =~ /mingw/)
9
- LINUX = (HOST_OS =~ /linux/)
10
-
11
- CLEAN.include('**/*.o', '*.log')
12
- CLOBBER.include('*.so')
13
-
14
- def cd(dir)
15
- puts "cd #{dir}"
16
- Dir.chdir(dir)
17
- end
18
-
19
- def run(cmd)
20
- puts cmd
21
- unless system(cmd)
22
- puts "Error: command exited with return value #{$?.exitstatus}"
23
- exit $?.exitstatus
24
- end
25
- end
26
-
27
-
28
- require "mkmf"
29
- COMPILER = if WINDOWS and find_executable "cl.exe"
30
- :cl
31
- else
32
- if find_executable "gcc" and find_executable "g++"
33
- :gcc
34
- else
35
- abort "Cannot find gcc/g++ #{'or cl.exe ' if WINDOWS}compiler"
36
- end
37
- end
38
-
39
- PREDEFINE, SYSTEM_LIBS = *case
40
- when OS_X then ["__MACOSX_CORE__", "-framework CoreMIDI -framework CoreAudio -framework CoreFoundation"]
41
- when WINDOWS then ["__WINDOWS_MM__", "-lwinmm"]
42
- when LINUX then
43
- defines, libs = '', ''
44
- {:alsa => '__LINUX_ALSA__', :jack => '__UNIX_JACK__'}.select do |pkg, _|
45
- system "pkg-config --exists #{pkg}"
46
- end.each do |pkg, macro|
47
- defines << "#{macro} "
48
- libs << `pkg-config --libs #{pkg}`.chomp
49
- end
50
- if defines.empty?
51
- raise 'Neither JACK or ALSA detected using pkg-config. Please install one of them first.'
52
- end
53
- [defines, libs]
54
- else
55
- end
56
-
57
-
58
- def compile_rtmidi
59
- cd RTMIDI_DIR
60
- if COMPILER == :gcc
61
- run "g++ -O3 -Wall -Iinclude -fPIC -D#{PREDEFINE} -o RtMidi.o -c RtMidi.cpp"
62
- else
63
- run "cl /O2 /Iinclude /D#{PREDEFINE} /EHsc /FoRtMidi.obj /c RtMidi.cpp"
64
- end
65
- end
66
-
67
- def compile_ruby_rtmidi_wrapper
68
- cd EXT_DIR
69
- if COMPILER == :gcc
70
- run "g++ -g -Wall -I#{RTMIDI_DIR} -fPIC -o ruby-rtmidi.o -c ruby-rtmidi.cpp"
71
- else
72
- run "cl /I#{RTMIDI_DIR} /D__RUBY_RTMIDI_DLL__ /EHsc /Foruby-rtmidi.obj /c ruby-rtmidi.cpp"
73
- end
74
- end
75
-
76
- def create_shared_library
77
- cd EXT_DIR
78
- if COMPILER == :gcc
79
- run "g++ -g -Wall -I#{RTMIDI_DIR} -I#{RTMIDI_DIR}/include -D#{PREDEFINE} -fPIC -shared -o ruby-rtmidi.so " +
80
- "ruby-rtmidi.o #{RTMIDI_DIR}/RtMidi.o #{SYSTEM_LIBS}"
81
- else
82
- run "cl /I#{RTMIDI_DIR} /I#{RTMIDI_DIR}/include /D#{PREDEFINE} /LD ruby-rtmidi.obj #{RTMIDI_DIR}/RtMidi.obj winmm.lib"
83
- end
84
- end
85
-
86
-
87
- desc 'run the make task'
1
+ desc 'Run the make task'
88
2
  task :default => :make
89
3
 
90
- desc 'build the RtMidi C++ library with Ruby FFI wrapper'
4
+ desc 'Compile the RtMidi C++ library with Ruby FFI wrapper'
91
5
  task :make do
92
- compile_rtmidi
93
- puts
94
- compile_ruby_rtmidi_wrapper
95
- puts
96
- create_shared_library
6
+ require_relative '../lib/rtmidi/build/compiler'
7
+ ext_dir = File.expand_path(File.dirname __FILE__)
8
+ rtmidi_dir = "#{ext_dir}/rtmidi-2.0.1"
9
+ compiler = RtMidi::Build::Compiler.new(ext_dir, rtmidi_dir, verbose: true)
10
+ compiler.compile
97
11
  end
@@ -67,6 +67,21 @@ void midiin_set_callback(rtmidi_ptr p, rtmidi_callback callback) {
67
67
  midiin->setCallback(midiin_callback_proxy, (void *)callback);
68
68
  }
69
69
 
70
+ void midiin_varargs_callback_proxy( double deltatime, std::vector< unsigned char > *message, void *userData )
71
+ {
72
+ unsigned int byte_count = message->size();
73
+ // for ( unsigned int i=0; i<byte_count; i++ )
74
+ // std::cout << "Byte " << i << " = " << (int)message->at(i) << ", ";
75
+ // if ( byte_count > 0 )
76
+ // std::cout << "stamp = " << deltatime << std::endl; # TODO: do we care about the deltatime?
77
+ ((rtmidi_varargs_callback)userData)(&(*message)[0], byte_count);
78
+ }
79
+
80
+ void midiin_set_varargs_callback(rtmidi_ptr p, rtmidi_varargs_callback callback) {
81
+ RtMidiIn *midiin = static_cast<RtMidiIn *>(p);
82
+ midiin->setCallback(midiin_varargs_callback_proxy, (void *)callback);
83
+ }
84
+
70
85
  void midiin_cancel_callback(rtmidi_ptr p) {
71
86
  RtMidiIn *midiin = static_cast<RtMidiIn *>(p);
72
87
  midiin->cancelCallback();
@@ -117,3 +132,12 @@ void midiout_send_message(rtmidi_ptr p, int byte1, int byte2, int byte3) {
117
132
  message[2] = byte3;
118
133
  midiout->sendMessage(&message);
119
134
  }
135
+
136
+ void midiout_send_bytes(rtmidi_ptr p, int* bytes, int byte_count) {
137
+ RtMidiOut *midiout = static_cast<RtMidiOut *>(p);
138
+ std::vector<unsigned char> message;
139
+ for(int i=0; i<byte_count; i++) {
140
+ message.push_back(bytes[i]);
141
+ }
142
+ midiout->sendMessage(&message);
143
+ }
@@ -8,6 +8,7 @@ extern "C"
8
8
  {
9
9
  typedef void* rtmidi_ptr;
10
10
  typedef void (*rtmidi_callback)(int byte1, int byte2, int byte3);
11
+ typedef void (*rtmidi_varargs_callback)(unsigned char* bytes, int byte_count);
11
12
 
12
13
  //================================================
13
14
  // INPUT
@@ -28,6 +29,8 @@ extern "C"
28
29
 
29
30
  DLL_EXPORT void midiin_set_callback(rtmidi_ptr p, rtmidi_callback callback);
30
31
 
32
+ DLL_EXPORT void midiin_set_varargs_callback(rtmidi_ptr p, rtmidi_varargs_callback callback);
33
+
31
34
  DLL_EXPORT void midiin_cancel_callback(rtmidi_ptr p);
32
35
 
33
36
 
@@ -47,4 +50,6 @@ extern "C"
47
50
  DLL_EXPORT void midiout_close_port(rtmidi_ptr p);
48
51
 
49
52
  DLL_EXPORT void midiout_send_message(rtmidi_ptr p, int byte1, int byte2, int byte3);
53
+
54
+ DLL_EXPORT void midiout_send_bytes(rtmidi_ptr p, int* bytes, int byte_count);
50
55
  };