jsound 0.1.0-java

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