ruck-midi 0.2.0

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