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.
- data/.yardopts +3 -0
- data/LICENSE.txt +27 -0
- data/README.md +96 -0
- data/Rakefile +19 -0
- data/examples/harmonizer.rb +25 -0
- data/examples/launchpad/launchpad.rb +65 -0
- data/examples/launchpad/launchpad_generator.rb +111 -0
- data/examples/list_devices.rb +6 -0
- data/examples/monitor.rb +15 -0
- data/examples/notes.rb +90 -0
- data/examples/transposer.rb +20 -0
- data/lib/jsound.rb +4 -0
- data/lib/jsound/convert.rb +30 -0
- data/lib/jsound/midi.rb +77 -0
- data/lib/jsound/midi/device.rb +72 -0
- data/lib/jsound/midi/device_list.rb +157 -0
- data/lib/jsound/midi/devices/generator.rb +22 -0
- data/lib/jsound/midi/devices/input_device.rb +51 -0
- data/lib/jsound/midi/devices/jdevice.rb +100 -0
- data/lib/jsound/midi/devices/monitor.rb +18 -0
- data/lib/jsound/midi/devices/output_device.rb +36 -0
- data/lib/jsound/midi/devices/recorder.rb +56 -0
- data/lib/jsound/midi/devices/repeater.rb +28 -0
- data/lib/jsound/midi/devices/transformer.rb +30 -0
- data/lib/jsound/midi/message.rb +165 -0
- data/lib/jsound/midi/message_builder.rb +52 -0
- data/lib/jsound/midi/messages/channel_pressure.rb +26 -0
- data/lib/jsound/midi/messages/control_change.rb +29 -0
- data/lib/jsound/midi/messages/note_off.rb +10 -0
- data/lib/jsound/midi/messages/note_on.rb +29 -0
- data/lib/jsound/midi/messages/pitch_bend.rb +43 -0
- data/lib/jsound/midi/messages/poly_pressure.rb +29 -0
- data/lib/jsound/midi/messages/program_change.rb +27 -0
- data/lib/jsound/type_from_class_name.rb +23 -0
- data/spec/jsound/convert_spec.rb +68 -0
- data/spec/jsound/midi/device_spec.rb +75 -0
- data/spec/jsound/midi/devices/generator_spec.rb +21 -0
- data/spec/jsound/midi/devices/output_device_spec.rb +22 -0
- data/spec/jsound/midi/devices/recorder_spec.rb +88 -0
- data/spec/jsound/midi/devices/repeater_device_spec.rb +19 -0
- data/spec/jsound/midi/devices/transformer_spec.rb +20 -0
- data/spec/jsound/midi/devlice_list_spec.rb +60 -0
- data/spec/jsound/midi/message_builder_spec.rb +22 -0
- data/spec/jsound/midi/message_spec.rb +30 -0
- data/spec/jsound/midi/messages/note_off_spec.rb +62 -0
- data/spec/jsound/midi/messages/note_on_spec.rb +109 -0
- data/spec/jsound/midi/messages/pitch_bend_spec.rb +88 -0
- data/spec/jsound/midi_spec.rb +33 -0
- data/spec/jsound/type_from_class_name_spec.rb +26 -0
- data/spec/spec_helper.rb +23 -0
- metadata +103 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module JSound::Midi::Devices
|
4
|
+
describe Repeater do
|
5
|
+
|
6
|
+
let(:repeater) { Repeater.new }
|
7
|
+
let(:output1) { mock 'device1' }
|
8
|
+
let(:output2) { mock 'device1' }
|
9
|
+
|
10
|
+
before { repeater >> [output1, output2] }
|
11
|
+
|
12
|
+
it "should pass all messages to its outputs" do
|
13
|
+
output1.should_receive(:message).once.with :the_message
|
14
|
+
output2.should_receive(:message).once.with :the_message
|
15
|
+
repeater.message :the_message
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module JSound::Midi
|
3
|
+
module Devices
|
4
|
+
|
5
|
+
describe Transformer do
|
6
|
+
|
7
|
+
describe "#message" do
|
8
|
+
it "transform the messages using the block passed to .new" do
|
9
|
+
transformer = Transformer.new{|message| message.pitch += 12; message }
|
10
|
+
output = mock 'device'
|
11
|
+
transformer >> output
|
12
|
+
output.should_receive(:message).once.with MessageBuilder.note_on(72,100)
|
13
|
+
transformer.message MessageBuilder.note_on(60,100)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module JSound::Midi
|
4
|
+
|
5
|
+
describe DeviceList do
|
6
|
+
|
7
|
+
let(:device1) { mock('device1', :description => 'Mock Device #1') }
|
8
|
+
let(:device2) { mock('device2', :description => 'Mock Device #2') }
|
9
|
+
let(:device3) { mock('device3', :description => 'Mock Device #3') }
|
10
|
+
let(:devices) { [device1,device2,device3] }
|
11
|
+
let(:device_list) { DeviceList.new devices }
|
12
|
+
|
13
|
+
describe '.new' do
|
14
|
+
it "constructs an empty device list with no arguments" do
|
15
|
+
DeviceList.new.should be_empty
|
16
|
+
end
|
17
|
+
|
18
|
+
it "constructs a list with the given arguments" do
|
19
|
+
DeviceList.new(devices).devices.should == devices
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#open" do
|
24
|
+
it "acts like #find and also opens the device" do
|
25
|
+
device2.should_receive :open
|
26
|
+
device_list.open(/Mock.*2/).should == device2
|
27
|
+
end
|
28
|
+
|
29
|
+
it "raises an error when no device is not found" do
|
30
|
+
lambda{ device_list.open(:nothing) }.should raise_error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#/" do
|
35
|
+
it "finds and opens the first device matching a regexp constructed from the argument" do
|
36
|
+
device1.should_receive(:open)
|
37
|
+
(device_list/'Mock').should == device1
|
38
|
+
end
|
39
|
+
|
40
|
+
it "is case insensitive" do
|
41
|
+
device1.should_receive(:open)
|
42
|
+
(device_list/'mock').should == device1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#method_missing" do
|
47
|
+
it "acts like #/ for unimplemented methods" do
|
48
|
+
device1.should_receive(:open)
|
49
|
+
device_list.mock.should == device1
|
50
|
+
end
|
51
|
+
|
52
|
+
it "treats '_' like a wildard" do
|
53
|
+
device2.should_receive(:open)
|
54
|
+
device_list.mock_2.should == device2
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module JSound::Midi
|
4
|
+
describe MessageBuilder do
|
5
|
+
|
6
|
+
it 'should expose its methods as module functions' do
|
7
|
+
msg = MessageBuilder.note_on(60)
|
8
|
+
msg.type.should == :note_on
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with MessageBuilder included' do
|
12
|
+
include MessageBuilder
|
13
|
+
|
14
|
+
it 'should provide a set of methods for building midi messages' do
|
15
|
+
msg = note_on(60)
|
16
|
+
msg.type.should == :note_on
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module JSound::Midi
|
4
|
+
|
5
|
+
describe Message do
|
6
|
+
|
7
|
+
let(:data) { [50,100]}
|
8
|
+
let(:channel) { 5 }
|
9
|
+
let(:message) { Message.new(data, channel) }
|
10
|
+
|
11
|
+
describe "#clone" do
|
12
|
+
it "constructs a new Message" do
|
13
|
+
message.clone.should_not be_equal message
|
14
|
+
end
|
15
|
+
|
16
|
+
it "constructs an equivalent Message" do
|
17
|
+
message.clone.should == message
|
18
|
+
end
|
19
|
+
|
20
|
+
it "constructs a new Message with the same data" do
|
21
|
+
message.clone.data.should == data
|
22
|
+
end
|
23
|
+
|
24
|
+
it "constructs a new Message with the same channel" do
|
25
|
+
message.clone.channel.should == channel
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module JSound::Midi::Messages
|
3
|
+
|
4
|
+
describe NoteOff do
|
5
|
+
|
6
|
+
let(:pitch) { 60 }
|
7
|
+
let(:velocity) { 100 }
|
8
|
+
let(:channel) { 3 }
|
9
|
+
let(:note_off) { NoteOff.new(pitch,velocity,channel) }
|
10
|
+
|
11
|
+
describe ".from_java" do
|
12
|
+
before do
|
13
|
+
@java_message = javax.sound.midi.ShortMessage.new
|
14
|
+
@java_message.setMessage(javax.sound.midi.ShortMessage::NOTE_OFF, channel, pitch, velocity)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "constructs a new instance from a javax.sound.midi.ShortMessage" do
|
18
|
+
NoteOff.from_java(@java_message).should be_a NoteOff
|
19
|
+
end
|
20
|
+
|
21
|
+
it "extracts the pitch from the data1 byte" do
|
22
|
+
NoteOff.from_java(@java_message).pitch.should == pitch
|
23
|
+
end
|
24
|
+
|
25
|
+
it "extracts the velocity from the data2 byte" do
|
26
|
+
NoteOff.from_java(@java_message).velocity.should == velocity
|
27
|
+
end
|
28
|
+
|
29
|
+
it "extracts the channel" do
|
30
|
+
NoteOff.from_java(@java_message).channel.should == channel
|
31
|
+
end
|
32
|
+
|
33
|
+
it "creates an equal object when called with itself's #to_java" do
|
34
|
+
NoteOff.from_java(note_off.to_java).should == note_off
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#to_java" do
|
39
|
+
it "creates a javax.sound.midi.ShortMessage" do
|
40
|
+
note_off.to_java.should be_a javax.sound.midi.ShortMessage
|
41
|
+
end
|
42
|
+
|
43
|
+
it "creates a message with a note_off command" do
|
44
|
+
note_off.to_java.command.should == javax.sound.midi.ShortMessage::NOTE_OFF
|
45
|
+
end
|
46
|
+
|
47
|
+
it "creates a message with pitch in the data1 byte" do
|
48
|
+
note_off.to_java.data1.should == pitch
|
49
|
+
end
|
50
|
+
|
51
|
+
it "creates a message with velocity in the data2 byte" do
|
52
|
+
note_off.to_java.data2.should == velocity
|
53
|
+
end
|
54
|
+
|
55
|
+
it "creates a message with the given channel" do
|
56
|
+
note_off.to_java.channel.should == channel
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module JSound::Midi::Messages
|
3
|
+
|
4
|
+
describe NoteOn do
|
5
|
+
|
6
|
+
let(:pitch) { 60 }
|
7
|
+
let(:velocity) { 100 }
|
8
|
+
let(:channel) { 3 }
|
9
|
+
let(:note_on) { NoteOn.new(pitch,velocity,channel) }
|
10
|
+
|
11
|
+
describe ".from_java" do
|
12
|
+
before do
|
13
|
+
@java_message = javax.sound.midi.ShortMessage.new
|
14
|
+
@java_message.setMessage(javax.sound.midi.ShortMessage::NOTE_ON, channel, pitch, velocity)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "constructs a new instance from a javax.sound.midi.ShortMessage" do
|
18
|
+
NoteOn.from_java(@java_message).should be_a NoteOn
|
19
|
+
end
|
20
|
+
|
21
|
+
it "extracts the pitch from the data1 byte" do
|
22
|
+
NoteOn.from_java(@java_message).pitch.should == pitch
|
23
|
+
end
|
24
|
+
|
25
|
+
it "extracts the velocity from the data2 byte" do
|
26
|
+
NoteOn.from_java(@java_message).velocity.should == velocity
|
27
|
+
end
|
28
|
+
|
29
|
+
it "extracts the channel" do
|
30
|
+
NoteOn.from_java(@java_message).channel.should == channel
|
31
|
+
end
|
32
|
+
|
33
|
+
it "creates an equal object when called with itself's #to_java" do
|
34
|
+
NoteOn.from_java(note_on.to_java).should == note_on
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#to_java" do
|
39
|
+
it "creates a javax.sound.midi.ShortMessage" do
|
40
|
+
note_on.to_java.should be_a javax.sound.midi.ShortMessage
|
41
|
+
end
|
42
|
+
|
43
|
+
it "creates a message with a NOTE_ON command" do
|
44
|
+
note_on.to_java.command.should == javax.sound.midi.ShortMessage::NOTE_ON
|
45
|
+
end
|
46
|
+
|
47
|
+
it "creates a message with pitch in the data1 byte" do
|
48
|
+
note_on.to_java.data1.should == pitch
|
49
|
+
end
|
50
|
+
|
51
|
+
it "creates a message with velocity in the data2 byte" do
|
52
|
+
note_on.to_java.data2.should == velocity
|
53
|
+
end
|
54
|
+
|
55
|
+
it "creates a message with the given channel" do
|
56
|
+
note_on.to_java.channel.should == channel
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#pitch" do
|
61
|
+
it "is the pitch of the message" do
|
62
|
+
note_on.pitch.should == pitch
|
63
|
+
end
|
64
|
+
|
65
|
+
it "is the first data byte" do
|
66
|
+
note_on.pitch.should == note_on.data[0]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#pitch=" do
|
71
|
+
it "sets the pitch of the message" do
|
72
|
+
pitch2 = pitch+1
|
73
|
+
note_on.pitch = pitch2
|
74
|
+
note_on.pitch.should == pitch2
|
75
|
+
end
|
76
|
+
|
77
|
+
it "causes the java_message (returned from #to_java) to be regenereated" do
|
78
|
+
pitch2 = pitch+1
|
79
|
+
note_on.pitch = pitch2
|
80
|
+
note_on.to_java.data1.should == pitch2
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#velocity" do
|
85
|
+
it "is the velocity of the message" do
|
86
|
+
note_on.velocity.should == velocity
|
87
|
+
end
|
88
|
+
|
89
|
+
it "is the second data byte" do
|
90
|
+
note_on.velocity.should == note_on.data[1]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#velocity=" do
|
95
|
+
it "sets the velocity of the message" do
|
96
|
+
velocity2 = velocity+1
|
97
|
+
note_on.velocity = velocity2
|
98
|
+
note_on.velocity.should == velocity2
|
99
|
+
end
|
100
|
+
|
101
|
+
it "causes the java_message (returned from #to_java) to be regenereated" do
|
102
|
+
velocity2 = velocity+1
|
103
|
+
note_on.velocity = velocity2
|
104
|
+
note_on.to_java.data2.should == velocity2
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module JSound::Midi::Messages
|
3
|
+
|
4
|
+
describe PitchBend do
|
5
|
+
|
6
|
+
let(:value) { 1000 }
|
7
|
+
let(:lsb) { value & 127 }
|
8
|
+
let(:msb) { (value >> 7) & 127 }
|
9
|
+
let(:channel) { 4 }
|
10
|
+
let(:pitch_bend) { PitchBend.new(value,channel) }
|
11
|
+
|
12
|
+
describe ".from_java" do
|
13
|
+
before do
|
14
|
+
@java_message = javax.sound.midi.ShortMessage.new
|
15
|
+
@java_message.setMessage(javax.sound.midi.ShortMessage::PITCH_BEND, channel, lsb, msb)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "constructs a new instance from a javax.sound.midi.ShortMessage" do
|
19
|
+
PitchBend.from_java(@java_message).should be_a PitchBend
|
20
|
+
end
|
21
|
+
|
22
|
+
it "extracts the 14-bit value from the 2 7-bit data bytes" do
|
23
|
+
pitch_bend = PitchBend.from_java(@java_message)
|
24
|
+
pitch_bend.value.should == value
|
25
|
+
end
|
26
|
+
|
27
|
+
it "extracts the channel" do
|
28
|
+
PitchBend.from_java(@java_message).channel.should == channel
|
29
|
+
end
|
30
|
+
|
31
|
+
it "creates an equal object when called with itself's #to_java" do
|
32
|
+
PitchBend.from_java(pitch_bend.to_java).should == pitch_bend
|
33
|
+
end
|
34
|
+
|
35
|
+
it "creates an object that returns the java message in response to #to_java" do
|
36
|
+
PitchBend.from_java(@java_message).to_java.should be_equal @java_message
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#to_java" do
|
41
|
+
it "creates a javax.sound.midi.ShortMessage" do
|
42
|
+
pitch_bend.to_java.should be_a javax.sound.midi.ShortMessage
|
43
|
+
end
|
44
|
+
|
45
|
+
it "creates a message with a PITCH_BEND command" do
|
46
|
+
pitch_bend.to_java.command.should == javax.sound.midi.ShortMessage::PITCH_BEND
|
47
|
+
end
|
48
|
+
|
49
|
+
it "creates a message with the least significant 7-bits in the data1 byte" do
|
50
|
+
pitch_bend.to_java.data1.should == lsb
|
51
|
+
end
|
52
|
+
|
53
|
+
it "creates a message with the most significant 7-bits in the data2 byte" do
|
54
|
+
pitch_bend.to_java.data2.should == msb
|
55
|
+
end
|
56
|
+
|
57
|
+
it "creates a message with the given channel" do
|
58
|
+
pitch_bend.to_java.channel.should == channel
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#value" do
|
63
|
+
it "is the value of the message" do
|
64
|
+
pitch_bend.value.should == value
|
65
|
+
end
|
66
|
+
|
67
|
+
it "is the 14-bit value of the message" do
|
68
|
+
pitch_bend.value.should == lsb + (msb << 7)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#value=" do
|
73
|
+
it "sets the value" do
|
74
|
+
pitch_bend.value = 2000
|
75
|
+
pitch_bend.value.should == 2000
|
76
|
+
end
|
77
|
+
|
78
|
+
it "affects the java message" do
|
79
|
+
pitch_bend.value = 2000
|
80
|
+
java_message = pitch_bend.to_java
|
81
|
+
java_message.data1.should == 2000 & 127
|
82
|
+
java_message.data2.should == (2000 >> 7) & 127
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module JSound
|
4
|
+
describe Midi do
|
5
|
+
|
6
|
+
# The spec doesn't care what MIDI devices are found,
|
7
|
+
# but it better find something or this library is not useful.
|
8
|
+
|
9
|
+
it 'should have DEVICES' do
|
10
|
+
Midi::DEVICES.should_not be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should have some INPUTS or OUTPUTS' do
|
14
|
+
(Midi::INPUTS.length + Midi::OUTPUTS.length).should > 1
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with Midi included' do
|
18
|
+
include Midi
|
19
|
+
describe '#refresh_devices' do
|
20
|
+
it 'should refresh the list of midi devices' do
|
21
|
+
Midi::DEVICES.clear
|
22
|
+
refresh_devices
|
23
|
+
Midi::DEVICES.should_not be_empty
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should expose #refresh_devices as a module function' do
|
29
|
+
Midi.refresh_devices
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|