jsound 0.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.yardopts +3 -0
  2. data/LICENSE.txt +27 -0
  3. data/README.md +96 -0
  4. data/Rakefile +19 -0
  5. data/examples/harmonizer.rb +25 -0
  6. data/examples/launchpad/launchpad.rb +65 -0
  7. data/examples/launchpad/launchpad_generator.rb +111 -0
  8. data/examples/list_devices.rb +6 -0
  9. data/examples/monitor.rb +15 -0
  10. data/examples/notes.rb +90 -0
  11. data/examples/transposer.rb +20 -0
  12. data/lib/jsound.rb +4 -0
  13. data/lib/jsound/convert.rb +30 -0
  14. data/lib/jsound/midi.rb +77 -0
  15. data/lib/jsound/midi/device.rb +72 -0
  16. data/lib/jsound/midi/device_list.rb +157 -0
  17. data/lib/jsound/midi/devices/generator.rb +22 -0
  18. data/lib/jsound/midi/devices/input_device.rb +51 -0
  19. data/lib/jsound/midi/devices/jdevice.rb +100 -0
  20. data/lib/jsound/midi/devices/monitor.rb +18 -0
  21. data/lib/jsound/midi/devices/output_device.rb +36 -0
  22. data/lib/jsound/midi/devices/recorder.rb +56 -0
  23. data/lib/jsound/midi/devices/repeater.rb +28 -0
  24. data/lib/jsound/midi/devices/transformer.rb +30 -0
  25. data/lib/jsound/midi/message.rb +165 -0
  26. data/lib/jsound/midi/message_builder.rb +52 -0
  27. data/lib/jsound/midi/messages/channel_pressure.rb +26 -0
  28. data/lib/jsound/midi/messages/control_change.rb +29 -0
  29. data/lib/jsound/midi/messages/note_off.rb +10 -0
  30. data/lib/jsound/midi/messages/note_on.rb +29 -0
  31. data/lib/jsound/midi/messages/pitch_bend.rb +43 -0
  32. data/lib/jsound/midi/messages/poly_pressure.rb +29 -0
  33. data/lib/jsound/midi/messages/program_change.rb +27 -0
  34. data/lib/jsound/type_from_class_name.rb +23 -0
  35. data/spec/jsound/convert_spec.rb +68 -0
  36. data/spec/jsound/midi/device_spec.rb +75 -0
  37. data/spec/jsound/midi/devices/generator_spec.rb +21 -0
  38. data/spec/jsound/midi/devices/output_device_spec.rb +22 -0
  39. data/spec/jsound/midi/devices/recorder_spec.rb +88 -0
  40. data/spec/jsound/midi/devices/repeater_device_spec.rb +19 -0
  41. data/spec/jsound/midi/devices/transformer_spec.rb +20 -0
  42. data/spec/jsound/midi/devlice_list_spec.rb +60 -0
  43. data/spec/jsound/midi/message_builder_spec.rb +22 -0
  44. data/spec/jsound/midi/message_spec.rb +30 -0
  45. data/spec/jsound/midi/messages/note_off_spec.rb +62 -0
  46. data/spec/jsound/midi/messages/note_on_spec.rb +109 -0
  47. data/spec/jsound/midi/messages/pitch_bend_spec.rb +88 -0
  48. data/spec/jsound/midi_spec.rb +33 -0
  49. data/spec/jsound/type_from_class_name_spec.rb +26 -0
  50. data/spec/spec_helper.rb +23 -0
  51. metadata +103 -0
@@ -0,0 +1,3 @@
1
+ --readme README.md
2
+ --title "JSound: a Ruby wrapper for Java's sound API"
3
+ lib/**/*.rb
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2010-2011, Adam Murray (adam@compusition.com).
2
+
3
+ All rights reserved.
4
+
5
+ Redistribution and use of the "JSound" Ruby library, in source and binary
6
+ forms, with or without modification, are permitted provided that the
7
+ following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright
13
+ notice, this list of conditions and the following disclaimer in
14
+ the documentation and/or other materials provided with the
15
+ distribution.
16
+
17
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,96 @@
1
+ JSound: a Ruby wrapper for the Java sound API
2
+ =============================================
3
+
4
+ This library requires [JRuby](http://jruby.org)
5
+ and currently only supports the [MIDI API](http://java.sun.com/j2se/1.5.0/docs/api/javax/sound/midi/package-summary.html)
6
+
7
+
8
+
9
+ Project Info
10
+ ------------
11
+
12
+ Home: http://github.com/adamjmurray/jsound
13
+
14
+ Author: Adam Murray (adam@compusition.com)
15
+
16
+ License: Distributed under a permissive BSD-style license, see LICENSE.txt
17
+
18
+
19
+
20
+ Getting started
21
+ ---------------
22
+
23
+ 0. Install JRuby 1.5 or 1.6, either:
24
+ - via manual installation
25
+ - Download and unpack the [current binary version of JRuby](http://jruby.org/download)
26
+ - Put the JRuby bin folder on your PATH
27
+ - or via [rvm](https://rvm.beginrescueend.com/) (adjust version number as desired):
28
+
29
+ rvm install jruby-1.6.2
30
+ rvm use jruby-1.6.2
31
+
32
+ 0. Install JSound
33
+
34
+ jgem install jsound
35
+
36
+ 0. Try the examples (monitor.rb prints any input it receives, try playing a MIDI keyboard):
37
+
38
+ jruby examples/list_devices.rb
39
+ jruby examples/monitor.rb
40
+
41
+ 0. Take a look at the comments in examples/notes.rb for info on:
42
+ - routing MIDI inputs to MIDI outputs
43
+ - generating MIDI events and sending them to an output
44
+
45
+
46
+
47
+ Documentation
48
+ -------------
49
+
50
+ Gem: http://rubydoc.info/gems/jsound/0.0.1/frames
51
+
52
+ Latest for source: http://rubydoc.info/github/adamjmurray/jsound/master/frames
53
+
54
+
55
+ Notes
56
+ -----
57
+
58
+ ### OS X ###
59
+
60
+ By enabling the IAC (inter-application communication) driver, you can easily interface with any MIDI-enabled application:
61
+
62
+ 0. Run to /Applications/Utilities/Audio MIDI Setup
63
+
64
+ 0. In the menu, select: Window → Show MIDI Window
65
+
66
+ 0. Double click IAC Driver
67
+
68
+ 0. Check the box where it says "Device is online"
69
+
70
+ Now JSound should be able to locate an "IAC Driver" input and output device.
71
+
72
+ You can also add additional MIDI ports here, to work with multiple applications simultaneously.
73
+
74
+
75
+
76
+ Development Notes
77
+ -----------------
78
+
79
+ ### Run Tests ###
80
+
81
+ rake spec
82
+
83
+ and to quickly check compatibility with multiple JRuby versions via rvm:
84
+
85
+ rvm jruby-1.5.6,jruby-1.6.2 rake spec:fast
86
+
87
+
88
+ ### Generate Docs ###
89
+
90
+ yard
91
+ open doc/frames.html
92
+
93
+
94
+ ### Project Roadmap ###
95
+
96
+ https://www.pivotaltracker.com/projects/85719
@@ -0,0 +1,19 @@
1
+ require 'rspec/core/rake_task'
2
+ require 'rake/clean'
3
+
4
+ task :default => :spec
5
+
6
+ CLEAN.include('doc') # clean and clobber do the same thing for now
7
+
8
+
9
+ desc "Run RSpec tests with full output"
10
+ RSpec::Core::RakeTask.new do |spec|
11
+ spec.rspec_opts = ["--color", "--format", "nested"]
12
+ end
13
+
14
+ namespace :spec do
15
+ desc "Run RSpecs tests with summary output and fast failure"
16
+ RSpec::Core::RakeTask.new(:fast) do |spec|
17
+ spec.rspec_opts = ["--color", "--fail-fast"]
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env jruby
2
+ require 'rubygems'
3
+ require 'jsound'
4
+ include JSound::Midi
5
+ include Devices
6
+
7
+ harmonizer = Transformer.new do |message|
8
+ if message.respond_to? :pitch
9
+ transposed = message.clone # messages are mutable, so we have to clone them to keep the original in tact
10
+ transposed.pitch += 3
11
+ [message, transposed]
12
+ else
13
+ message # pass through everything else
14
+ end
15
+ end
16
+
17
+ # Adjust the INPUTS and OUTPUTS as needed to use the devices you want:
18
+ INPUTS.open_first >> harmonizer >> OUTPUTS.open_first
19
+ # For example, to send my Akai keyboard through the harmonizer to the OS X IAC bus, I can do:
20
+ # INPUTS.Akai >> harmonizer >> OUTPUTS.IAC
21
+
22
+ # force the script to keep running (MIDI devices run in a background thread)
23
+ while(true)
24
+ sleep 5
25
+ end
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env jruby --debug
2
+ require 'rubygems'
3
+ require 'jsound'
4
+ include JSound::Midi
5
+
6
+ # A quick prototype of monitoring input from a Novation Launchpad,
7
+ # after translating it to something more meaningful than the raw MIDI messages.
8
+
9
+ # Note: I have to hit a button on the top row of my Launchpad before I can receive any input.
10
+
11
+
12
+ # A higher-level representation of the messages coming from the Launchpad
13
+ class LaunchpadMessage < Messages::Message
14
+ def initialize(button_group, position, pressed, channel=0, source=nil)
15
+ @type = :launchpad_button
16
+ @button_group = button_group
17
+ @position = position
18
+ @pressed = pressed
19
+ @data = {:button_group => button_group, :position => position, :pressed => pressed}
20
+ @channel = channel
21
+ @source = source
22
+ end
23
+ end
24
+
25
+ # A device that converts the lower-level MIDI messages into LaunchpadMessages
26
+ class LaunchadTranslator < Devices::Device
27
+ def <=(message)
28
+ case message.type
29
+
30
+ when :control_change
31
+ button_group = :top
32
+ pressed = (message.value > 0)
33
+ position = message.control - 104
34
+
35
+ when :note_on
36
+ # everything else
37
+ pressed = (message.velocity > 0)
38
+ value = message.pitch
39
+ row = value / 16
40
+ col = value % 16
41
+ if col > 7
42
+ button_group = :right
43
+ position = row
44
+ else
45
+ button_group = :grid
46
+ position = [col,row]
47
+ end
48
+ end
49
+
50
+ super LaunchpadMessage.new(button_group, position, pressed, message.channel, message.source)
51
+ rescue
52
+ puts $!
53
+ end
54
+ end
55
+
56
+
57
+ # And now that those classes are defined,
58
+ # just hook up the Launchpad to a monitor, with the translator in between:
59
+ INPUTS.Launchpad >> LaunchadTranslator.new >> Devices::Monitor.new
60
+
61
+
62
+ # force the script to keep running (MIDI devices run in a background thread)
63
+ while(true)
64
+ sleep 5
65
+ end
@@ -0,0 +1,111 @@
1
+ # A device for controlling a Novation Launchpad
2
+ # To try this example, do this from the top-level project source folder
3
+ =begin
4
+
5
+ jirb -I lib
6
+ require 'jsound'
7
+ require 'examples/launchpad/launchpad_generator.rb'
8
+ include JSound::Midi
9
+ lp = OUTPUTS.Launchpad
10
+ g = LaunchpadGenerator.new
11
+ g >> lp
12
+
13
+ g.all_off
14
+
15
+ # Make the top left grid button green:
16
+ g.grid(0,0,:green)
17
+
18
+ # Make the mixer button red:
19
+ g.mixer(:red)
20
+
21
+ # Make the second 'scene launch' (rightmost column of buttons) orange:
22
+ g.scene_launch(2,:orange)
23
+
24
+ # and we can also do yellow:
25
+ g.grid(1,1,:yellow)
26
+
27
+ # and arbitrary mixtures of green and red LEDs (brightness levels for each range from 0-3)
28
+ g.grid(2,2,[1,1])
29
+
30
+ at_exit { g.all_off } # this will turn everything off when you exit irb
31
+
32
+ =end
33
+
34
+ class LaunchpadGenerator < JSound::Midi::Devices::Generator
35
+
36
+ def grid(x,y,color=3)
37
+ x = clip(x,0,15)
38
+ y = clip(y,0,7)
39
+ c = color_value(color)
40
+ note_on(16*y + x, c)
41
+ end
42
+
43
+ def scene_launch(position,color=3)
44
+ grid(8,position,color)
45
+ end
46
+
47
+
48
+ def control_row(position,color=3)
49
+ c = color_value(color)
50
+ p = 104 + clip(position,0,7)
51
+ control_change(p,c)
52
+ end
53
+
54
+ def up( color=3); control_row(0,color) end
55
+ def down( color=3); control_row(1,color) end
56
+ def left( color=3); control_row(2,color) end
57
+ def right( color=3); control_row(3,color) end
58
+ def session(color=3); control_row(4,color) end
59
+ def user1( color=3); control_row(5,color) end
60
+ def user2( color=3); control_row(6,color) end
61
+ def mixer( color=3); control_row(7,color) end
62
+
63
+ def all_on(brightness=3)
64
+ # convert brightness values 0,1,2,3 to 0,125,126,127
65
+ # (0=off, 125=low, 126=med, 127=high)
66
+ b = clip(brightness,0,3)
67
+ b += 124 if b > 0
68
+ control_change(0,b)
69
+ end
70
+
71
+ def all_off
72
+ control_change(0,0)
73
+ end
74
+
75
+ def duty_cycle(numerator,denominator)
76
+ n = clip(numerator,1,16)
77
+ d = clip(denominator,3,18)
78
+ if n < 9
79
+ control_change(30, 16*(n-1) + (d-3))
80
+ else
81
+ control_change(31, 16*(n-9) + (d-3))
82
+ end
83
+ end
84
+
85
+ def clip(value,min,max)
86
+ value = min if value.nil? or value < min
87
+ value = max if value > max
88
+ return value
89
+ end
90
+
91
+ def color_value(color)
92
+ case color
93
+ when Array
94
+ g,r = color[0],color[1]
95
+ when Numeric
96
+ g,r = color,0
97
+ else case color.to_s
98
+ when 'green', 'g' then g,r = 3,0
99
+ when 'yellow', 'y' then g,r = 3,2
100
+ when 'amber', 'a' then g,r = 3,3
101
+ when 'orange', 'o' then g,r = 2,3
102
+ when 'red', 'r' then g,r = 0,3
103
+ else g,r = 0,0
104
+ end
105
+ end
106
+ g = clip(g.to_i,0,3)
107
+ r = clip(r.to_i,0,3)
108
+ return 16*g + r
109
+ end
110
+
111
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env jruby
2
+ require 'rubygems'
3
+ require 'jsound'
4
+ include JSound::Midi
5
+
6
+ puts DEVICES
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env jruby
2
+ require 'rubygems'
3
+ require 'jsound'
4
+ include JSound::Midi
5
+
6
+ INPUTS.each do |input|
7
+ input.open
8
+ input >> Devices::Monitor.new
9
+ end
10
+
11
+ # force the script to keep running (MIDI devices run in a background thread)
12
+ while(true)
13
+ sleep 5
14
+ end
15
+
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env jruby
2
+ require 'rubygems'
3
+ require 'jsound'
4
+ include JSound::Midi
5
+
6
+ puts "ALL DEVICES:"
7
+ puts DEVICES
8
+ puts
9
+ puts "DEVICE VENDORS"
10
+ puts DEVICES.list_all(:vendor).uniq # list_all will include "unknown" values
11
+ puts
12
+ puts "INPUT DESCRIPTIONS:"
13
+ puts INPUTS.list
14
+ puts
15
+ puts "OUTPUT DESCRIPTIONS:"
16
+ puts OUTPUTS.list
17
+ puts
18
+
19
+
20
+ # The following examples use SimpleSynth as an output.
21
+ # It's a free program for OS X available http://notahat.com/simplesynth
22
+ # I assume SimpleSynth's MIDI Source is set to "SimpleSynth virtual input"
23
+
24
+ # On Windows or Linux, I *think* you can just use a built-in MIDI output for your soundcard
25
+ # If you need to do anything special on Windows/Linux, let me know @ http://github.com/adamjmurray
26
+ # and I'll update this example.
27
+
28
+
29
+ #######################################################
30
+ ## FINDING INPUTS AND OUTPUTS
31
+ ##
32
+ ## Based on the input and output descriptions,
33
+ ## you can locate the first device matching a description:
34
+ #> OUTPUTS/'SimpleSynth'
35
+ #
36
+ ## or just:
37
+ #> OUTPUTS/:SimpleSynth
38
+ #
39
+ ## the / operator is a shortcut for
40
+ #> OUTPUTS.find /SimpleSynth/
41
+ #
42
+ ## which has some more advanced options:
43
+ #> OUTPUTS.find :vendor => 'M-Audio'
44
+ #
45
+ ## Use Strings for exact matches and Regexp for partial matches
46
+ ## The find method returns the first match, find_all will return all of them:
47
+ #> OUTPUTS.find_all :name => /(Novation|M-Audio)/
48
+ #
49
+ ## All of these lookup options work for the INPUTS collection too:
50
+ #> INPUTS/'M-Audio'
51
+
52
+
53
+ ######################################################
54
+ ## ROUTING INPUTS TO OUTPUTS
55
+ ##
56
+ ## Once you have an input and an output, just connect them like so:
57
+ #> input = INPUTS/:Akai
58
+ #> output = OUTPUTS/:SimpleSynth
59
+ #> input >> output
60
+ #
61
+ ## If you are sure the inputs and outputs exist, you can do it altogether:
62
+ #> INPUTS/:Akai >> OUTPUTS/:SimpleSynth
63
+
64
+
65
+ ######################################################
66
+ ## MONITORING INPUT
67
+ ##
68
+ ## Route to an instance of JSound::Midi::Devices::Monitor
69
+ #> input >> Devcies::Monitor.new
70
+
71
+
72
+ ######################################################
73
+ ## GENERATING NOTES
74
+ ##
75
+ ## See message_builder.rb for list of messages currently supported,
76
+ ## including pitch_bend, control_change, channel_pressure, and more
77
+ #
78
+ # include JSound::Midi::Messages::Builder
79
+ # output = OUTPUTS/:SimpleSynth
80
+ # output.open
81
+ # while(true)
82
+ # output <= note_on(60,70)
83
+ # sleep 1
84
+ # output <= note_off(60)
85
+ # sleep 1
86
+ # end
87
+ #
88
+ ## Note that connecting to an output with >> will open the output automatically,
89
+ ## but passing in Messages with << does not.
90
+ ## That's why I explicitly call output.open in the above example.