patchmaster 0.0.0 → 0.0.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.
@@ -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