ruck-midi 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/README ADDED
@@ -0,0 +1,8 @@
1
+
2
+ This ruck shreduler uses MIDIator and midilib to support
3
+ real-time and offline MIDI generation.
4
+
5
+ $ ruck_midi MIDI_FILENAME NUM_TRACKS LIVE SCRIPT_FILENAME[S]
6
+
7
+ where LIVE is "no" to only save the MIDI output, or "yes"
8
+ to also play in real-time.
@@ -0,0 +1,24 @@
1
+ require "rubygems"
2
+ require "rake"
3
+
4
+ begin
5
+ require "jeweler"
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "ruck-midi"
8
+ gem.email = "tom@alltom.com"
9
+ gem.homepage = "http://github.com/alltom/ruck-midi"
10
+ gem.authors = ["Tom Lieber"]
11
+ gem.summary = %Q{real-time and offline ruck shredulers for MIDI (thanks midiator and midilib)}
12
+ gem.description = <<-EOF
13
+ Real-time and offline ruck shredulers for MIDI using midiator and midilib.
14
+ EOF
15
+ gem.has_rdoc = false
16
+ gem.add_dependency "ruck", ">= 0"
17
+ gem.add_dependency "midiator", ">= 0"
18
+ gem.add_dependency "midilib", ">= 0"
19
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
20
+ end
21
+ Jeweler::GemcutterTasks.new
22
+ rescue LoadError
23
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
24
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+
5
+ # for testing inside gem dir
6
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
7
+
8
+ require "ruck"
9
+ require "ruck/midi"
10
+
11
+ if ARGV.length < 4
12
+ puts "ruby midilib_runner.rb MIDI_FILENAME NUM_TRACKS LIVE SCRIPT_FILENAME [...]"
13
+ exit 1
14
+ end
15
+
16
+ MIDI_FILENAME = ARGV[0]
17
+ NUM_TRACKS = ARGV[1].to_i
18
+ ALSO_LIVE = ["yes", "true", "1", "yeah"].include? ARGV[2].downcase
19
+ FILENAMES = ARGV[3..-1]
20
+
21
+ # state
22
+ $midi = Ruck::MIDI::MIDIOutput.new(ALSO_LIVE, MIDI_FILENAME, NUM_TRACKS)
23
+ SHREDULER = Ruck::MIDI::MIDIShreduler.new($midi, ALSO_LIVE)
24
+
25
+ at_exit { $midi.save }
26
+
27
+ FILENAMES.each do |filename|
28
+ unless File.readable?(filename)
29
+ LOG.fatal "Cannot read file #{filename}"
30
+ exit
31
+ end
32
+ end
33
+
34
+ FILENAMES.each do |filename|
35
+ SHREDULER.spork(filename) do
36
+ include Ruck::MIDI::ShredLocal
37
+ require filename
38
+ end
39
+ end
40
+
41
+ SHREDULER.run
42
+
43
+ $midi.save
@@ -0,0 +1,21 @@
1
+
2
+ def maybe
3
+ rand >= 0.5
4
+ end
5
+
6
+ control_change(32, 1, 10)
7
+ program_change(26, 10)
8
+
9
+ def play(note, dur = 1.quarter_note)
10
+ return if maybe
11
+ note_on note, 100, 10
12
+ wait dur
13
+ note_off note, 10
14
+ end
15
+
16
+ 30.times do
17
+ spork { play(rand(30) + 40, rand * 3.quarter_notes + 3.quarter_notes) }
18
+ wait 0.5.quarter_note
19
+ end
20
+
21
+ wait 2.quarter_notes; note_off 0 # end padding
@@ -0,0 +1,76 @@
1
+
2
+ def maybe
3
+ rand >= 0.5
4
+ end
5
+
6
+ @base = 43
7
+ @scale = 0
8
+ @chord = 0
9
+
10
+ major_scale = [0, 2, 4, 5, 7, 9, 11]
11
+ minor_scale = [0, 2, 3, 5, 7, 8, 11]
12
+ @scales = [major_scale, minor_scale]
13
+
14
+ def scale(note, scale)
15
+ len = scale.length
16
+ oct = note / len
17
+ off = note % len
18
+ while off < 0
19
+ off += len
20
+ oct -= 1
21
+ end
22
+ oct * 12 + scale[off]
23
+ end
24
+
25
+ def play(note, dur = 1.beat)
26
+ midi_note = @base + scale(note, @scales[@scale])
27
+ note_on midi_note, 100
28
+ wait dur
29
+ note_off midi_note
30
+ end
31
+
32
+ def change_chords
33
+ loop do
34
+ wait 4.beats
35
+ @chord = rand(7)
36
+ if rand <= 0.1
37
+ @scale = (@scale + 1) % @scales.length
38
+ end
39
+ end
40
+ end
41
+
42
+ def play_chord(dur)
43
+ spork { play(@chord, dur) }
44
+ spork { play(@chord + 2, dur) }
45
+ spork { play(@chord + 4, dur) }
46
+ end
47
+
48
+ def play_chords
49
+ loop do
50
+ if maybe && maybe
51
+ play_chord 2.beats
52
+ wait 2.beats
53
+ play_chord 2.beats
54
+ wait 2.beats
55
+ else
56
+ play_chord 4.beats
57
+ wait 4.beats
58
+ end
59
+ end
60
+ end
61
+
62
+ def play_melody
63
+ loop do
64
+ len = ((rand(2) + 1) / 2.0).beats
65
+ play(@chord + 7 + 2 * rand(4), len)
66
+ wait len
67
+ end
68
+ end
69
+
70
+ shreds = []
71
+ shreds << spork { change_chords }
72
+ shreds << spork { play_chords }
73
+ shreds << spork { play_melody }
74
+
75
+ wait 16.beats
76
+ shreds.each { |s| s.finish }
@@ -0,0 +1,2 @@
1
+
2
+ require File.join(File.dirname(__FILE__), "midi", "midi")
@@ -0,0 +1,192 @@
1
+
2
+ require "midilib"
3
+ require "midiator"
4
+
5
+ module Ruck
6
+ module MIDI
7
+
8
+ class MIDIShreduler < Ruck::Shreduler
9
+ attr_reader :midi
10
+
11
+ def initialize(midi, real_time)
12
+ super()
13
+ @midi = midi
14
+ @real_time = real_time
15
+ end
16
+
17
+ def run
18
+ @start_time = Time.now
19
+ super
20
+ end
21
+
22
+ def sim_to(new_now)
23
+ d = new_now - @now
24
+
25
+ @midi.tick(d)
26
+
27
+ # sync with wall clock
28
+ if @real_time
29
+ actual_now = Time.now
30
+ simulated_now = @start_time + (new_now.to_f / @midi.ppqn / @midi.bpm * 60.0)
31
+ if simulated_now > actual_now
32
+ sleep(simulated_now - actual_now)
33
+ end
34
+ end
35
+
36
+ @now = new_now
37
+ end
38
+ end
39
+
40
+ class MIDIOutput
41
+ def initialize(real_time, save_filename = nil, num_tracks = 1)
42
+ if save_filename
43
+ @filename = save_filename
44
+ @sequence = ::MIDI::Sequence.new
45
+ @tracks = (1..num_tracks).map { ::MIDI::Track.new(@sequence) }
46
+ @track_deltas = @tracks.map { 0 }
47
+
48
+ @tracks.each do |track|
49
+ @sequence.tracks << track
50
+ #track.events << ::MIDI::Tempo.new(::MIDI::Tempo.bpm_to_mpq(120))
51
+ end
52
+ end
53
+
54
+ if real_time
55
+ @player = MIDIator::Interface.new
56
+ @player.use :dls_synth
57
+ @player.instruct_user!
58
+ end
59
+ end
60
+
61
+ def ppqn
62
+ @sequence.ppqn
63
+ end
64
+
65
+ def bpm
66
+ @sequence.bpm
67
+ end
68
+
69
+ def tick(delta)
70
+ if @sequence
71
+ @track_deltas.each_with_index do |track_delta, i|
72
+ @track_deltas[i] = track_delta + delta
73
+ end
74
+ end
75
+ end
76
+
77
+ def note_on(note, velocity = 127, channel = 0, track = 0)
78
+ if @sequence
79
+ @tracks[track].events << ::MIDI::NoteOnEvent.new(channel, note, velocity, @track_deltas[track].to_i)
80
+ @track_deltas[track] = 0
81
+ end
82
+
83
+ if @player
84
+ @player.driver.note_on(note, channel, velocity)
85
+ end
86
+ end
87
+
88
+ def note_off(note, channel = 0, track = 0)
89
+ if @sequence
90
+ @tracks[track].events << ::MIDI::NoteOffEvent.new(channel, note, 0, @track_deltas[track].to_i)
91
+ @track_deltas[track] = 0
92
+ end
93
+
94
+ if @player
95
+ @player.driver.note_on(note, channel, 0)
96
+ end
97
+ end
98
+
99
+ def control_change(controller, value, channel = 0, track = 0)
100
+ if @sequence
101
+ @tracks[track].events << ::MIDI::Controller.new(channel, controller, value)
102
+ end
103
+
104
+ if @player
105
+ @player.driver.control_change(controller, channel, value)
106
+ end
107
+ end
108
+
109
+ def program_change(program, channel = 0, track = 0)
110
+ if @sequence
111
+ @tracks[track].events << ::MIDI::ProgramChange.new(channel, program)
112
+ end
113
+
114
+ if @player
115
+ @player.driver.program_change(channel, program)
116
+ end
117
+ end
118
+
119
+ def save
120
+ return if @saved
121
+ return unless @sequence
122
+
123
+ @saved = true
124
+
125
+ File.open(@filename, "wb") do |file|
126
+ @sequence.write(file)
127
+ end
128
+ end
129
+ end
130
+
131
+ # stuff accessible in a shred
132
+ module ShredLocal
133
+ def now
134
+ SHREDULER.now
135
+ end
136
+
137
+ def spork(name = "unnamed", &shred)
138
+ SHREDULER.spork(name, &shred)
139
+ end
140
+
141
+ def wait(pulses)
142
+ SHREDULER.current_shred.yield(pulses)
143
+ end
144
+
145
+ def finish
146
+ shred = SHREDULER.current_shred
147
+ SHREDULER.remove_shred shred
148
+ shred.finish
149
+ end
150
+
151
+ def note_on(note, velocity = 127, channel = 0, track = 0)
152
+ SHREDULER.midi.note_on(note, velocity, channel, track)
153
+ end
154
+
155
+ def note_off(note, channel = 0, track = 0)
156
+ SHREDULER.midi.note_off(note, channel, track)
157
+ end
158
+
159
+ def control_change(controller, value, channel = 0, track = 0)
160
+ SHREDULER.midi.control_change(controller, value, channel, track)
161
+ end
162
+
163
+ def program_change(program, channel = 0, track = 0)
164
+ SHREDULER.midi.program_change(program, channel, track)
165
+ end
166
+ end
167
+
168
+ end
169
+ end
170
+
171
+ # set up some useful time helpers
172
+ module MIDITime
173
+ def pulse
174
+ self
175
+ end
176
+ alias_method :pulses, :pulse
177
+
178
+ def quarter_note
179
+ self * SHREDULER.midi.ppqn
180
+ end
181
+ alias_method :quarter_notes, :quarter_note
182
+ alias_method :beat, :quarter_note
183
+ alias_method :beats, :quarter_note
184
+ end
185
+
186
+ class Fixnum
187
+ include MIDITime
188
+ end
189
+
190
+ class Float
191
+ include MIDITime
192
+ end
@@ -0,0 +1,63 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ruck-midi}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Tom Lieber"]
12
+ s.date = %q{2010-07-10}
13
+ s.default_executable = %q{ruck_midi}
14
+ s.description = %q{ Real-time and offline ruck shredulers for MIDI using midiator and midilib.
15
+ }
16
+ s.email = %q{tom@alltom.com}
17
+ s.executables = ["ruck_midi"]
18
+ s.extra_rdoc_files = [
19
+ "README"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".gitignore",
24
+ "README",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "bin/ruck_midi",
28
+ "examples/ex01.rb",
29
+ "examples/ex02.rb",
30
+ "lib/ruck/midi.rb",
31
+ "lib/ruck/midi/midi.rb",
32
+ "ruck-midi.gemspec"
33
+ ]
34
+ s.homepage = %q{http://github.com/alltom/ruck-midi}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.6}
38
+ s.summary = %q{real-time and offline ruck shredulers for MIDI (thanks midiator and midilib)}
39
+ s.test_files = [
40
+ "examples/ex01.rb",
41
+ "examples/ex02.rb"
42
+ ]
43
+
44
+ if s.respond_to? :specification_version then
45
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
49
+ s.add_runtime_dependency(%q<ruck>, [">= 0"])
50
+ s.add_runtime_dependency(%q<midiator>, [">= 0"])
51
+ s.add_runtime_dependency(%q<midilib>, [">= 0"])
52
+ else
53
+ s.add_dependency(%q<ruck>, [">= 0"])
54
+ s.add_dependency(%q<midiator>, [">= 0"])
55
+ s.add_dependency(%q<midilib>, [">= 0"])
56
+ end
57
+ else
58
+ s.add_dependency(%q<ruck>, [">= 0"])
59
+ s.add_dependency(%q<midiator>, [">= 0"])
60
+ s.add_dependency(%q<midilib>, [">= 0"])
61
+ end
62
+ end
63
+
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruck-midi
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
+ platform: ruby
11
+ authors:
12
+ - Tom Lieber
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-10 00:00:00 -07:00
18
+ default_executable: ruck_midi
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: ruck
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: midiator
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
42
+ type: :runtime
43
+ version_requirements: *id002
44
+ - !ruby/object:Gem::Dependency
45
+ name: midilib
46
+ prerelease: false
47
+ requirement: &id003 !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ type: :runtime
55
+ version_requirements: *id003
56
+ description: " Real-time and offline ruck shredulers for MIDI using midiator and midilib.\n"
57
+ email: tom@alltom.com
58
+ executables:
59
+ - ruck_midi
60
+ extensions: []
61
+
62
+ extra_rdoc_files:
63
+ - README
64
+ files:
65
+ - .document
66
+ - .gitignore
67
+ - README
68
+ - Rakefile
69
+ - VERSION
70
+ - bin/ruck_midi
71
+ - examples/ex01.rb
72
+ - examples/ex02.rb
73
+ - lib/ruck/midi.rb
74
+ - lib/ruck/midi/midi.rb
75
+ - ruck-midi.gemspec
76
+ has_rdoc: true
77
+ homepage: http://github.com/alltom/ruck-midi
78
+ licenses: []
79
+
80
+ post_install_message:
81
+ rdoc_options:
82
+ - --charset=UTF-8
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ segments:
97
+ - 0
98
+ version: "0"
99
+ requirements: []
100
+
101
+ rubyforge_project:
102
+ rubygems_version: 1.3.6
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: real-time and offline ruck shredulers for MIDI (thanks midiator and midilib)
106
+ test_files:
107
+ - examples/ex01.rb
108
+ - examples/ex02.rb