midiator 0.3.0 → 0.3.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.
- data/examples/amen_break.rb +157 -0
- data/examples/chords.rb +34 -0
- data/examples/chromatic_scale.rb +2 -2
- data/examples/drum_chords.rb +49 -0
- data/examples/metronome.rb +12 -12
- data/examples/synth.rb +34 -0
- data/examples/twinkle.rb +2 -2
- data/lib/midiator.rb +4 -4
- data/lib/midiator/driver.rb +87 -87
- data/lib/midiator/driver_registry.rb +24 -24
- data/lib/midiator/drivers/alsa.rb +36 -36
- data/lib/midiator/drivers/core_midi.rb +46 -46
- data/lib/midiator/drivers/dls_synth.rb +97 -97
- data/lib/midiator/drivers/mmj.rb +35 -0
- data/lib/midiator/drivers/winmm.rb +18 -18
- data/lib/midiator/drums.rb +19 -19
- data/lib/midiator/interface.rb +90 -79
- data/lib/midiator/notes.rb +62 -62
- data/lib/midiator/timer.rb +33 -33
- data/lib/string_extensions.rb +39 -39
- data/misc/rake/packaging.rb +20 -20
- data/misc/rake/rdoc.rb +16 -21
- data/misc/rake/testing.rb +9 -9
- data/spec/driver_registry_spec.rb +96 -96
- data/spec/driver_spec.rb +8 -8
- data/spec/interface_spec.rb +114 -114
- data/spec/string_extensions_spec.rb +12 -12
- metadata +7 -2
@@ -0,0 +1,157 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Plays the amen break. Demonstrates playing on a different channel and use
|
4
|
+
# of the MIDIator::Drums and MIDIator::Durations mixins.
|
5
|
+
#
|
6
|
+
# == Authors
|
7
|
+
#
|
8
|
+
# * Ben Bleything <ben@bleything.net>
|
9
|
+
#
|
10
|
+
# == Copyright
|
11
|
+
#
|
12
|
+
# Copyright (c) 2009 Ben Bleything
|
13
|
+
#
|
14
|
+
# This code released under the terms of the MIT license.
|
15
|
+
#
|
16
|
+
|
17
|
+
require 'midiator'
|
18
|
+
|
19
|
+
@midi = MIDIator::Interface.new
|
20
|
+
# @midi.autodetect_driver
|
21
|
+
@midi.use :dls_synth
|
22
|
+
|
23
|
+
# let's get some drums!
|
24
|
+
include MIDIator::Drums
|
25
|
+
@midi.control_change 32, 10, 1 # TR-808 is Program 26 in LSB bank 1
|
26
|
+
@midi.program_change 10, 26
|
27
|
+
|
28
|
+
# set up some tempo constants
|
29
|
+
tempo = 120
|
30
|
+
QuarterNote = 60.0 / tempo
|
31
|
+
EighthNote = QuarterNote / 2
|
32
|
+
SixteenthNote = EighthNote / 2
|
33
|
+
|
34
|
+
# a helper method!
|
35
|
+
def beat( note, duration = EighthNote )
|
36
|
+
@midi.play note, duration, 10
|
37
|
+
end
|
38
|
+
|
39
|
+
# instrument shortcuts
|
40
|
+
bass = BassDrum1
|
41
|
+
snare = SnareDrum1
|
42
|
+
cymbal = RideCymbal1
|
43
|
+
|
44
|
+
# "chord" shortcuts
|
45
|
+
bass_cymbal = [ bass, cymbal ]
|
46
|
+
snare_cymbal = [ snare, cymbal ]
|
47
|
+
|
48
|
+
# as transcribed at http://www.onlinedrumlessons.com/main/2005/09/classic-break-beat.htm
|
49
|
+
loop do
|
50
|
+
|
51
|
+
# first measure is repeated
|
52
|
+
2.times do
|
53
|
+
# beat 1
|
54
|
+
beat bass_cymbal
|
55
|
+
beat bass_cymbal
|
56
|
+
|
57
|
+
# beat 2
|
58
|
+
beat snare_cymbal
|
59
|
+
@midi.rest SixteenthNote
|
60
|
+
beat snare, SixteenthNote
|
61
|
+
|
62
|
+
# beat 3
|
63
|
+
beat cymbal, SixteenthNote
|
64
|
+
beat snare, SixteenthNote
|
65
|
+
beat bass_cymbal, SixteenthNote
|
66
|
+
beat bass, SixteenthNote
|
67
|
+
|
68
|
+
# beat 4
|
69
|
+
beat snare_cymbal
|
70
|
+
beat cymbal, SixteenthNote
|
71
|
+
beat snare, SixteenthNote
|
72
|
+
end
|
73
|
+
|
74
|
+
# third measure starts out like the first...
|
75
|
+
# beat 1
|
76
|
+
beat bass_cymbal
|
77
|
+
beat bass_cymbal
|
78
|
+
|
79
|
+
# beat 2
|
80
|
+
beat snare_cymbal
|
81
|
+
@midi.rest SixteenthNote
|
82
|
+
beat snare, SixteenthNote
|
83
|
+
|
84
|
+
# beat 3
|
85
|
+
beat cymbal, SixteenthNote
|
86
|
+
beat snare, SixteenthNote
|
87
|
+
beat bass_cymbal
|
88
|
+
|
89
|
+
# beat 4
|
90
|
+
beat cymbal
|
91
|
+
beat snare_cymbal
|
92
|
+
|
93
|
+
# and then the fourth measure goes off the rails
|
94
|
+
# beat 1
|
95
|
+
beat cymbal, SixteenthNote
|
96
|
+
beat snare, SixteenthNote
|
97
|
+
beat bass_cymbal, SixteenthNote
|
98
|
+
beat bass, SixteenthNote
|
99
|
+
|
100
|
+
# beat 2
|
101
|
+
beat snare_cymbal
|
102
|
+
beat cymbal, SixteenthNote
|
103
|
+
beat snare, SixteenthNote
|
104
|
+
|
105
|
+
# beat 3
|
106
|
+
beat cymbal, SixteenthNote
|
107
|
+
beat snare, SixteenthNote
|
108
|
+
beat
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
exit
|
113
|
+
|
114
|
+
loop do
|
115
|
+
# first bar is repeated twice
|
116
|
+
2.times do
|
117
|
+
@midi.play BassDrum1, EighthNote, 9
|
118
|
+
@midi.play BassDrum1, EighthNote, 9
|
119
|
+
@midi.play SnareDrum1, EighthNote, 9
|
120
|
+
@midi.rest SixteenthNote
|
121
|
+
@midi.play SnareDrum1, SixteenthNote, 9
|
122
|
+
@midi.rest SixteenthNote
|
123
|
+
@midi.play SnareDrum1, SixteenthNote, 9
|
124
|
+
@midi.play BassDrum1, SixteenthNote, 9
|
125
|
+
@midi.play BassDrum1, SixteenthNote, 9
|
126
|
+
@midi.play SnareDrum1, EighthNote, 9
|
127
|
+
@midi.rest EighthNote
|
128
|
+
end
|
129
|
+
|
130
|
+
# bar 3
|
131
|
+
@midi.play BassDrum1, EighthNote, 9
|
132
|
+
@midi.play BassDrum1, EighthNote, 9
|
133
|
+
@midi.play SnareDrum1, EighthNote, 9
|
134
|
+
@midi.rest SixteenthNote
|
135
|
+
@midi.play SnareDrum1, SixteenthNote, 9
|
136
|
+
@midi.rest SixteenthNote
|
137
|
+
@midi.play SnareDrum1, SixteenthNote, 9
|
138
|
+
@midi.play BassDrum1, EighthNote, 9
|
139
|
+
@midi.rest EighthNote
|
140
|
+
@midi.play SnareDrum1, EighthNote, 9
|
141
|
+
|
142
|
+
# bar 4
|
143
|
+
@midi.rest EighthNote
|
144
|
+
@midi.play BassDrum1, SixteenthNote, 9
|
145
|
+
@midi.play BassDrum1, SixteenthNote, 9
|
146
|
+
@midi.play SnareDrum1, EighthNote, 9
|
147
|
+
@midi.rest SixteenthNote
|
148
|
+
@midi.play SnareDrum1, SixteenthNote, 9
|
149
|
+
@midi.rest SixteenthNote
|
150
|
+
@midi.play SnareDrum1, SixteenthNote, 9
|
151
|
+
@midi.play BassDrum1, EighthNote, 9
|
152
|
+
@midi.rest EighthNote
|
153
|
+
@midi.play BassDrum1, EighthNote, 9
|
154
|
+
|
155
|
+
# a little break
|
156
|
+
@midi.rest HalfNote
|
157
|
+
end
|
data/examples/chords.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# A simple example of playing chords with MIDIator
|
4
|
+
#
|
5
|
+
# == Authors
|
6
|
+
#
|
7
|
+
# * David Brady <dbrady@shinybit.com>
|
8
|
+
#
|
9
|
+
# == Copyright
|
10
|
+
#
|
11
|
+
# Copyright (c) 2008 David Brady
|
12
|
+
#
|
13
|
+
# This code released under the terms of the MIT license.
|
14
|
+
#
|
15
|
+
|
16
|
+
require 'rubygems'
|
17
|
+
require 'midiator'
|
18
|
+
|
19
|
+
midi = MIDIator::Interface.new
|
20
|
+
midi.autodetect_driver
|
21
|
+
|
22
|
+
include MIDIator::Notes
|
23
|
+
|
24
|
+
C4MAJ = [ C4, E4, G4 ]
|
25
|
+
F4MAJII = [ C4, F4, A4 ]
|
26
|
+
G4MAJ = [ D4, G4, B4 ]
|
27
|
+
|
28
|
+
song = [ C3, C4MAJ, C3, C4MAJ, F3, F4MAJII, F3, F4MAJII, G3, G4MAJ, G3, G4MAJ, C5, C4MAJ, C2, C4MAJ]
|
29
|
+
|
30
|
+
4.times do
|
31
|
+
song.each do |note|
|
32
|
+
midi.play note, 0.25
|
33
|
+
end
|
34
|
+
end
|
data/examples/chromatic_scale.rb
CHANGED
@@ -27,9 +27,9 @@ scale = [ C4, Cs4, D4, Eb4, E4, F4, Fs4, G4, Gs4, A4, Bb4, B4,
|
|
27
27
|
C5, Cs5, D5, Eb5, E5, F5, Fs5, G5, Gs5, A5, Bb5, B5 ]
|
28
28
|
|
29
29
|
scale.each do |note|
|
30
|
-
|
30
|
+
midi.play note
|
31
31
|
end
|
32
32
|
|
33
33
|
scale.reverse.each do |note|
|
34
|
-
|
34
|
+
midi.play note
|
35
35
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Plays a simple polyphonic drumbeat.
|
4
|
+
#
|
5
|
+
# == Authors
|
6
|
+
#
|
7
|
+
# * David Brady <dbrady@shinybit.com>
|
8
|
+
#
|
9
|
+
# == Copyright
|
10
|
+
#
|
11
|
+
# Copyright (c) 2008 David Brady
|
12
|
+
#
|
13
|
+
# This code released under the terms of the MIT license.
|
14
|
+
#
|
15
|
+
|
16
|
+
require 'rubygems'
|
17
|
+
require 'midiator'
|
18
|
+
|
19
|
+
midi = MIDIator::Interface.new
|
20
|
+
midi.autodetect_driver
|
21
|
+
|
22
|
+
midi.control_change 32, 10, 1 # TR-808 is Program 26 in LSB bank 1
|
23
|
+
midi.program_change 10, 26
|
24
|
+
|
25
|
+
include MIDIator::Drums
|
26
|
+
|
27
|
+
song = [ BassDrum1,
|
28
|
+
[BassDrum2, SnareDrum1],
|
29
|
+
BassDrum1,
|
30
|
+
[BassDrum1, SnareDrum1, SnareDrum2, CrashCymbal1]
|
31
|
+
]
|
32
|
+
riff = [ HighTom1, HighTom2, LowTom1, LowTom2 ]
|
33
|
+
|
34
|
+
# This starts to push the usability limit of play.
|
35
|
+
4.times do
|
36
|
+
song.each do |note|
|
37
|
+
midi.play note, 0.25, 10
|
38
|
+
end
|
39
|
+
end
|
40
|
+
riff.each do |note|
|
41
|
+
midi.play note, 0.067, 10
|
42
|
+
end
|
43
|
+
midi.play CrashCymbal2, 0.25, 10
|
44
|
+
|
45
|
+
4.times do
|
46
|
+
song.each do |note|
|
47
|
+
midi.play note, 0.25, 10
|
48
|
+
end
|
49
|
+
end
|
data/examples/metronome.rb
CHANGED
@@ -28,15 +28,15 @@
|
|
28
28
|
@tempo = 120.0
|
29
29
|
|
30
30
|
if input = ARGV[0]
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
begin
|
32
|
+
@tempo = Float( input )
|
33
|
+
rescue ArgumentError => e
|
34
|
+
$stderr.puts "'#{input}' is not a valid tempo.\n"
|
35
|
+
$stderr.puts "Please specify the tempo in beats per minute " +
|
36
|
+
"(bpm). Fractional values are allowed!"
|
37
37
|
|
38
|
-
|
39
|
-
|
38
|
+
exit 1
|
39
|
+
end
|
40
40
|
end
|
41
41
|
|
42
42
|
require 'rubygems'
|
@@ -66,10 +66,10 @@ Signal.trap( "INT" ) { @timer.thread.exit! }
|
|
66
66
|
@timer = MIDIator::Timer.new( @interval / 10 )
|
67
67
|
|
68
68
|
def register_next_bang( time )
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
69
|
+
@timer.at( time ) do |yielded_time|
|
70
|
+
register_next_bang yielded_time + @interval
|
71
|
+
@midi.play MiddleC
|
72
|
+
end
|
73
73
|
end
|
74
74
|
|
75
75
|
puts "Starting metronome running at #{@tempo} bpm."
|
data/examples/synth.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# A copy of the chromatic scale example which uses the OS X built-in synth.
|
4
|
+
#
|
5
|
+
# == Authors
|
6
|
+
#
|
7
|
+
# * Ben Bleything <ben@bleything.net>
|
8
|
+
#
|
9
|
+
# == Copyright
|
10
|
+
#
|
11
|
+
# Copyright (c) 2008 Ben Bleything
|
12
|
+
#
|
13
|
+
# This code released under the terms of the MIT license.
|
14
|
+
#
|
15
|
+
|
16
|
+
require 'rubygems'
|
17
|
+
require 'midiator'
|
18
|
+
|
19
|
+
midi = MIDIator::Interface.new
|
20
|
+
midi.use :dls_synth
|
21
|
+
midi.instruct_user!
|
22
|
+
|
23
|
+
include MIDIator::Notes
|
24
|
+
|
25
|
+
scale = [ C4, Cs4, D4, Eb4, E4, F4, Fs4, G4, Gs4, A4, Bb4, B4,
|
26
|
+
C5, Cs5, D5, Eb5, E5, F5, Fs5, G5, Gs5, A5, Bb5, B5 ]
|
27
|
+
|
28
|
+
scale.each do |note|
|
29
|
+
midi.play note
|
30
|
+
end
|
31
|
+
|
32
|
+
scale.reverse.each do |note|
|
33
|
+
midi.play note
|
34
|
+
end
|
data/examples/twinkle.rb
CHANGED
@@ -26,9 +26,9 @@ scale = [ C4, Cs4, D4, Eb4, E4, F4, Fs4, G4, Gs4, A4, Bb4, B4,
|
|
26
26
|
C5, Cs5, D5, Eb5, E5, F5, Fs5, G5, Gs5, A5, Bb5, B5 ]
|
27
27
|
|
28
28
|
scale.each do |note|
|
29
|
-
|
29
|
+
midi.play note
|
30
30
|
end
|
31
31
|
|
32
32
|
scale.reverse.each do |note|
|
33
|
-
|
33
|
+
midi.play note
|
34
34
|
end
|
data/lib/midiator.rb
CHANGED
@@ -14,22 +14,22 @@
|
|
14
14
|
#
|
15
15
|
|
16
16
|
module MIDIator
|
17
|
-
|
17
|
+
VERSION = "0.3.1"
|
18
18
|
end
|
19
19
|
|
20
20
|
#####################################################################
|
21
|
-
###
|
21
|
+
### E X T E R N A L D E P E N D E N C I E S
|
22
22
|
#####################################################################
|
23
23
|
require 'rubygems'
|
24
24
|
require 'platform'
|
25
25
|
|
26
26
|
#####################################################################
|
27
|
-
###
|
27
|
+
### C O R E L I B R A R Y E X T E N S I O N S
|
28
28
|
#####################################################################
|
29
29
|
require 'string_extensions'
|
30
30
|
|
31
31
|
#####################################################################
|
32
|
-
###
|
32
|
+
### M I D I A T O R C O R E
|
33
33
|
#####################################################################
|
34
34
|
require 'midiator/driver'
|
35
35
|
require 'midiator/driver_registry'
|
data/lib/midiator/driver.rb
CHANGED
@@ -22,127 +22,127 @@ require 'midiator/driver_registry'
|
|
22
22
|
|
23
23
|
class MIDIator::Driver
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
##########################################################################
|
26
|
+
### M I D I C O M M A N D C O N S T A N T S
|
27
|
+
##########################################################################
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
# Note on
|
30
|
+
ON = 0x90
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
# Note off
|
33
|
+
OFF = 0x80
|
34
34
|
|
35
|
-
|
36
|
-
|
35
|
+
# Polyphonic aftertouch
|
36
|
+
PA = 0xa0
|
37
37
|
|
38
|
-
|
39
|
-
|
38
|
+
# Control change
|
39
|
+
CC = 0xb0
|
40
40
|
|
41
|
-
|
42
|
-
|
41
|
+
# Program change
|
42
|
+
PC = 0xc0
|
43
43
|
|
44
|
-
|
45
|
-
|
44
|
+
# Channel aftertouch
|
45
|
+
CA = 0xd0
|
46
46
|
|
47
|
-
|
48
|
-
|
47
|
+
# Pitch bend
|
48
|
+
PB = 0xe0
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
##########################################################################
|
51
|
+
### M A G I C H O O K S
|
52
|
+
##########################################################################
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
54
|
+
### Auto-registers subclasses of MIDIator::Driver with the driver registry.
|
55
|
+
def self::inherited( driver_class )
|
56
|
+
driver_name = driver_class.to_s.underscore
|
57
|
+
MIDIator::DriverRegistry.instance.register( driver_name, driver_class )
|
58
|
+
end
|
59
59
|
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
61
|
+
##########################################################################
|
62
|
+
### I N T E R F A C E A P I
|
63
|
+
##########################################################################
|
64
|
+
# These methods are the same across all drivers and are the interface that
|
65
|
+
# MIDIator::Interface interacts with.
|
66
|
+
##########################################################################
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
68
|
+
### Do any pre-open setup necessary. Often will not be overridden.
|
69
|
+
def initialize
|
70
|
+
open
|
71
|
+
end
|
72
72
|
|
73
73
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
74
|
+
### Shortcut to send a note_on message.
|
75
|
+
def note_on( note, channel, velocity )
|
76
|
+
message( ON | channel, note, velocity )
|
77
|
+
end
|
78
78
|
|
79
79
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
80
|
+
### Shortcut to send a note_off message.
|
81
|
+
def note_off( note, channel, velocity = 0 )
|
82
|
+
message( OFF | channel, note, velocity )
|
83
|
+
end
|
84
84
|
|
85
85
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
### Shortcut to send a polyphonic aftertouch message for an individual note.
|
87
|
+
def aftertouch( note, channel, pressure )
|
88
|
+
message( PA | channel, note, pressure )
|
89
|
+
end
|
90
90
|
|
91
91
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
92
|
+
### Shortcut to send a control change.
|
93
|
+
def control_change( number, channel, value )
|
94
|
+
message( CC | channel, number, value )
|
95
|
+
end
|
96
96
|
|
97
97
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
98
|
+
### Shortcut to send a program_change message.
|
99
|
+
def program_change( channel, program )
|
100
|
+
message( PC | channel, program )
|
101
|
+
end
|
102
102
|
|
103
103
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
104
|
+
### Shortcut to send a channel aftertouch message.
|
105
|
+
def channel_aftertouch( channel, pressure )
|
106
|
+
message( CA | channel, pressure )
|
107
|
+
end
|
108
108
|
|
109
109
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
110
|
+
### Shortcut to send a pitch bend message.
|
111
|
+
def pitch_bend( channel, value )
|
112
|
+
message( PB | channel, value )
|
113
|
+
end
|
114
|
+
alias bend pitch_bend
|
115
115
|
|
116
116
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
117
|
+
##########################################################################
|
118
|
+
### D R I V E R A P I
|
119
|
+
##########################################################################
|
120
|
+
# subclasses must implement these methods.
|
121
|
+
##########################################################################
|
122
|
+
protected
|
123
|
+
##########################################################################
|
124
124
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
125
|
+
### Open the channel to the MIDI service.
|
126
|
+
def open
|
127
|
+
raise NotImplementedError, "You must implement #open in your driver."
|
128
|
+
end
|
129
129
|
|
130
130
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
131
|
+
### Close the channel to the MIDI service.
|
132
|
+
def close
|
133
|
+
raise NotImplementedError, "You must implement #close in your driver."
|
134
|
+
end
|
135
135
|
|
136
136
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
137
|
+
### Send MIDI message to the MIDI service.
|
138
|
+
def message( *args )
|
139
|
+
raise NotImplementedError, "You must implement #message in your driver."
|
140
|
+
end
|
141
141
|
|
142
142
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
143
|
+
### The only non-required method. Override this to give the user instructions
|
144
|
+
### if necessary.
|
145
|
+
def instruct_user!
|
146
|
+
end
|
147
147
|
|
148
148
|
end
|