patchmaster 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,3 @@
1
- require 'patchmaster/list'
2
- require 'patchmaster/list_container'
3
-
4
1
  module PM
5
2
 
6
3
  # A Song is a named list of Patches with a cursor.
@@ -8,11 +5,9 @@ class Song
8
5
 
9
6
  attr_accessor :name, :patches
10
7
 
11
- include ListContainer
12
-
13
8
  def initialize(name)
14
9
  @name = name
15
- @patches = List.new
10
+ @patches = []
16
11
  PatchMaster.instance.all_songs << self
17
12
  end
18
13
 
@@ -1,6 +1,3 @@
1
- require 'patchmaster/list'
2
- require 'patchmaster/list_container'
3
-
4
1
  module PM
5
2
 
6
3
  # A SongList is a list of Songs with a cursor.
@@ -8,11 +5,9 @@ class SongList
8
5
 
9
6
  attr_accessor :name, :songs
10
7
 
11
- include ListContainer
12
-
13
8
  def initialize(name)
14
9
  @name = name
15
- @songs = List.new
10
+ @songs = []
16
11
  end
17
12
 
18
13
  def <<(song)
@@ -30,10 +25,5 @@ class SongList
30
25
  %w(first prev curr next last).each do |dir|
31
26
  instance_eval("def #{dir}_patch; @songs.curr.#{dir}_patch; end")
32
27
  end
33
-
34
- # Called when moving out of this song list to another
35
- def stop_current_song
36
- @songs.stop_current
37
- end
38
28
  end
39
29
  end
@@ -5,7 +5,7 @@ class SortedSongList < SongList
5
5
  def <<(song)
6
6
  next_song_after = @songs.detect { |s| s.name > song.name }
7
7
  if next_song_after
8
- @songs.insert_before(next_song_after, song)
8
+ @songs.insert(@songs.index(next_song_after), song)
9
9
  else
10
10
  super(song)
11
11
  end
@@ -0,0 +1,32 @@
1
+ module PM
2
+
3
+ # A Trigger performs an action when it sees a particular array of bytes.
4
+ # Instruments have zero or more triggers. The action is a symbol that gets
5
+ # sent to PM::PatchMaster.
6
+ #
7
+ # Since we want to save them to files, we store the text representation as
8
+ # well.
9
+ class Trigger
10
+
11
+ attr_accessor :bytes, :block, :text
12
+
13
+ def initialize(bytes, block)
14
+ @bytes, @block = bytes, block
15
+ end
16
+
17
+ def method_missing(sym, *args)
18
+ PM::PatchMaster.instance.send(sym, *args)
19
+ end
20
+
21
+ # If +bytes+ matches our +@bytes+ array then run +@block+.
22
+ def signal(bytes)
23
+ if bytes == @bytes
24
+ block.call
25
+ end
26
+ end
27
+
28
+ def to_s
29
+ "#{@bytes.inspect} => #{@text ? @text.gsub(/\n\s*/, '; ') : ''}"
30
+ end
31
+ end
32
+ end
data/test/test_helper.rb CHANGED
@@ -1,23 +1,40 @@
1
1
  require 'test/unit'
2
2
  require 'patchmaster'
3
+ require 'midi-eye'
3
4
 
4
5
  # For all tests, make sure mock I/O MIDI ports are used.
5
6
  PM::PatchMaster.instance.no_midi!
6
7
 
7
8
  module PM
8
9
 
9
- # To help with testing, we replace MockInputPort#gets_data and
10
+ # To help with testing, we replace MockInputPort#gets and
10
11
  # MockOutputPort#puts with versions that send what we want and save what is
11
12
  # received.
12
13
  class MockInputPort
13
14
 
14
15
  attr_accessor :data_to_send
16
+
17
+ # For MIDIEye::Listener
18
+ def self.is_compatible?(input)
19
+ true
20
+ end
21
+
22
+ def initialize(_=nil)
23
+ @t0 = (Time.now.to_f * 1000).to_i
24
+ end
15
25
 
16
- def gets_data
26
+ def gets
17
27
  retval = @data_to_send || []
18
28
  @data_to_send = []
19
- retval
29
+ [{:data => retval, :timestamp => (Time.now.to_f * 1000).to_i - @t0}]
20
30
  end
31
+
32
+ def poll
33
+ yield gets
34
+ end
35
+
36
+ # add this class to the Listener class' known input types
37
+ MIDIEye::Listener.input_types << self
21
38
  end
22
39
 
23
40
  class MockOutputPort
@@ -43,16 +60,7 @@ class TestConnection < PM::Connection
43
60
  def midi_in(bytes)
44
61
  @bytes_received ||= []
45
62
  @bytes_received += bytes
46
- midi_out(@output, bytes)
63
+ midi_out(bytes)
47
64
  end
48
65
 
49
66
  end
50
-
51
- class PMTest < Test::Unit::TestCase
52
-
53
- # Data comes out of UniMIDI::Input#gets_ata as an array of arrays of MIDI
54
- # bytes.
55
- def midi_data(*bytes)
56
- [bytes]
57
- end
58
- end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: patchmaster
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-04-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: unimidi
16
- requirement: &2151875240 !ruby/object:Gem::Requirement
16
+ requirement: &2156042580 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2151875240
24
+ version_requirements: *2156042580
25
25
  description: ! 'PatchMaster is realtime MIDI performance software that alloweds a
26
26
  musician
27
27
 
@@ -44,19 +44,20 @@ files:
44
44
  - lib/patchmaster/app/patch_window.rb
45
45
  - lib/patchmaster/app/pm_window.rb
46
46
  - lib/patchmaster/app/prompt_window.rb
47
+ - lib/patchmaster/app/trigger_window.rb
47
48
  - lib/patchmaster/connection.rb
48
49
  - lib/patchmaster/consts.rb
50
+ - lib/patchmaster/cursor.rb
49
51
  - lib/patchmaster/dsl.rb
50
52
  - lib/patchmaster/filter.rb
51
- - lib/patchmaster/io.rb
52
- - lib/patchmaster/list.rb
53
- - lib/patchmaster/list_container.rb
53
+ - lib/patchmaster/instrument.rb
54
54
  - lib/patchmaster/patch.rb
55
55
  - lib/patchmaster/patchmaster.rb
56
56
  - lib/patchmaster/predicates.rb
57
57
  - lib/patchmaster/song.rb
58
58
  - lib/patchmaster/song_list.rb
59
59
  - lib/patchmaster/sorted_song_list.rb
60
+ - lib/patchmaster/trigger.rb
60
61
  - lib/patchmaster.rb
61
62
  - test/test_helper.rb
62
63
  homepage: https://github.com/jimm/patchmaster
@@ -1,121 +0,0 @@
1
- module PM
2
-
3
- # A list (Array) of things with a cursor. +@curr+ is an integer index into
4
- # an array of data.
5
- class List
6
-
7
- include Enumerable
8
-
9
- # If +enter_sym+ or +exit_sym+ are defined, they will be sent to a data
10
- # element when it becomes the current element or stops being the current
11
- # element.
12
- def initialize
13
- @data = []
14
- @curr = nil
15
- end
16
-
17
- # Adding data does not modify the cursor.
18
- def <<(data)
19
- @data << data
20
- end
21
-
22
- # Inserts +data+ before +before_this+. If +before_this+ is not in our
23
- # list, +data+ is inserted at the beginning of the list.
24
- def insert_before(before_this, data)
25
- idx = @data.index(before_this) || 0
26
- @data[idx, 0] = data
27
- end
28
-
29
- # Inserts +data+ after +after_this+. If +after_this+ is not in our list,
30
- # +data+ is inserted at the end of the list.
31
- def insert_after(after_this, data)
32
- idx = @data.index(after_this) || @data.length-1
33
- @data[idx + 1, 0] = data
34
- end
35
-
36
- def size
37
- @data.size
38
- end
39
- alias_method :length, :size
40
-
41
- def first?
42
- @curr == 0
43
- end
44
-
45
- def first
46
- if !@data.empty? && @curr != 0
47
- @curr = 0
48
- end
49
- curr
50
- end
51
-
52
- def next
53
- if @curr == nil || @curr >= @data.length - 1
54
- @curr = nil
55
- else
56
- @curr += 1
57
- end
58
- curr
59
- end
60
-
61
- def curr
62
- @curr ? @data[@curr] : nil
63
- end
64
-
65
- # This does not change what is stored at the current location. Rather,
66
- # it moves this list's cursor to point to +data+ and returns +data+.
67
- def curr=(data)
68
- if curr != data
69
- @curr = @data.index(data)
70
- end
71
- data
72
- end
73
-
74
- # Returns the +n+th data element. This method is not normally used to
75
- # access data because it does not change the cursor. It is used to peek
76
- # into the list's data array, for example during testing.
77
- def [](n)
78
- @data[n]
79
- end
80
-
81
- def prev
82
- if @curr == nil || @curr == 0
83
- @curr = nil
84
- else
85
- @curr -= 1
86
- end
87
- curr
88
- end
89
-
90
- def last
91
- if !@data.empty? && !last?
92
- @curr = @data.length - 1
93
- end
94
- curr
95
- end
96
-
97
- def last?
98
- @curr == nil || @curr == @data.length - 1
99
- end
100
-
101
- def remove(data)
102
- return unless @data.include?(data)
103
- @data[@data.index(data), 1] = []
104
- if @data.empty?
105
- @curr = nil
106
- elsif @curr >= @data.length
107
- @curr = @data.length - 1
108
- end
109
- end
110
-
111
- def each
112
- @data.each { |data| yield data }
113
- end
114
-
115
- # For debugging
116
- def to_s
117
- "List(#{@data.empty? ? 'empty' : @data[0].class.name}), size #{size}, curr index #{@curr}"
118
- end
119
-
120
- end
121
- end
@@ -1,36 +0,0 @@
1
- module PM
2
-
3
- # A ListContainer responds to messages that manipulate the cursors for one
4
- # or more List objects.
5
- module ListContainer
6
-
7
- def method_missing(sym, *args)
8
- case sym.to_s
9
- when /^curr_(\w+)=$/
10
- name = $1
11
- ivar_sym = "@#{pluralize(name)}".to_sym
12
- raise "no such ivar #{ivar_sym} in #{self.class}" unless instance_variable_defined?(ivar_sym)
13
- instance_variable_get(ivar_sym).send(:curr=, args[0])
14
- when /^(first|next|prev|curr|last)_(\w+)(\?)?$/
15
- method, ivar, qmark = $1, $2, $3
16
- ivar_sym = "@#{pluralize(ivar)}".to_sym
17
- raise "no such ivar #{ivar_sym} in #{self.class}" unless instance_variable_defined?(ivar_sym)
18
- instance_variable_get(ivar_sym).send("#{method}#{qmark}".to_sym)
19
- else
20
- super
21
- end
22
- end
23
-
24
- def pluralize(str)
25
- case str
26
- when /s$/, /ch$/
27
- "#{str}es"
28
- when /y$/
29
- "#{str[0..-2]}ies}"
30
- else
31
- "#{str}s"
32
- end
33
- end
34
-
35
- end
36
- end