Class: JSound::Midi::Message

Inherits:
Object
  • Object
show all
Includes:
TypeFromClassName
Defined in:
lib/jsound/midi/message.rb

Overview

A generic MIDI message. The various subclasses in this module deal with specific message details. See www.midi.org/techspecs/midimessages.php for info on how the MIDI spec defines these messages.

Constant Summary collapse

CLASS_FOR_STATUS =

Map java message status values to ruby classes

{}
STATUS_FOR_CLASS =

Map ruby classes to java message status values

{}
TYPE_FOR_STATUS =
{
  javax.sound.midi.ShortMessage::ACTIVE_SENSING        => :active_sensing,
  javax.sound.midi.ShortMessage::CONTINUE              => :continue,
  javax.sound.midi.ShortMessage::END_OF_EXCLUSIVE      => :end_of_exclusive,
  javax.sound.midi.ShortMessage::MIDI_TIME_CODE        => :multi_time_code,
  javax.sound.midi.ShortMessage::SONG_POSITION_POINTER => :song_position_pointer,
  javax.sound.midi.ShortMessage::SONG_SELECT           => :song_select,
  javax.sound.midi.ShortMessage::START                 => :start,
  javax.sound.midi.ShortMessage::STOP                  => :stop,
  javax.sound.midi.ShortMessage::SYSTEM_RESET          => :system_reset,
  javax.sound.midi.ShortMessage::TIMING_CLOCK          => :timing_clock,
  javax.sound.midi.ShortMessage::TUNE_REQUEST          => :tune_request
}
STATUS_FOR_TYPE =
TYPE_FOR_STATUS.invert

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from TypeFromClassName

included

Constructor Details

#initialize(data, channel = 0, options = {}) ⇒ Message

Returns a new instance of Message.



25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/jsound/midi/message.rb', line 25

def initialize(data, channel=0, options={})
  @data = data
  @channel = channel

  # Generic Message objects specify a type explicitly (see initialize).
  # Subclasses will typically use the class type (see JSound::Mixins::TypeFromClassName).
  @type = options[:type] ||= self.class.type

  @java_message = options[:java_message]

  @source = options[:source]
end

Instance Attribute Details

#channelObject (readonly)

The channel number of the message



19
20
21
# File 'lib/jsound/midi/message.rb', line 19

def channel
  @channel
end

#dataObject

The variable data for this message type. Contents depend on the message type.

Examples:

a NoteOn’s #data is [pitch,velocity]



16
17
18
# File 'lib/jsound/midi/message.rb', line 16

def data
  @data
end

#sourceObject (readonly)

The MIDI input Device which received this message.



12
13
14
# File 'lib/jsound/midi/message.rb', line 12

def source
  @source
end

#typeSymbol (readonly)

The type of message, such as :note_on or :control_change

Returns:

  • (Symbol)


23
24
25
# File 'lib/jsound/midi/message.rb', line 23

def type
  @type
end

Class Method Details

.from_java(java_message, options = {}) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/jsound/midi/message.rb', line 79

def self.from_java(java_message, options={})
  case java_message
  when javax.sound.midi.SysexMessage
    type = :sysex
    data = java_message.data # this is a byte array in Java, might need conversion?

  when javax.sound.midi.MetaMessage
    type = :meta
    data = java_message.data # this is a byte array in Java, might need conversion?

  when javax.sound.midi.ShortMessage
    # For command-type messages, the least significant 4 bits of the status byte will be the channel number.
    # java_message.command will return the desired command's status code in this case, or
    # we can just use a bitmask to grab the most significant 4 bits of the status byte like so:
    status = (java_message.status & 0xF0)

    message_class = CLASS_FOR_STATUS[status]
    return message_class.from_java(java_message, options) if message_class

    type = TYPE_FOR_STATUS[status] || :unknown
    data = [java_message.data1, java_message.data2]

  else
    type  = :unknown
    data = []
  end

  new data, java_message.channel, options.merge({:type => type, :java_message => java_message})
end

.inherited(child_class) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
# File 'lib/jsound/midi/message.rb', line 44

def self.inherited(child_class)
  # I'm using the convention that the message class names
  # correspond to the java ShortMessage constants, like:
  # NoteOn => ShortMessage::NOTE_ON
  const_name = child_class.type.to_s.upcase
  if javax.sound.midi.ShortMessage.const_defined? const_name
    status = javax.sound.midi.ShortMessage.const_get(const_name)
    CLASS_FOR_STATUS[status] = child_class
    STATUS_FOR_CLASS[child_class] = status
  end
end

Instance Method Details

#==(other) ⇒ Object

true when the argument has the same #type, #channel, and #data



73
74
75
76
77
# File 'lib/jsound/midi/message.rb', line 73

def == other
  other.respond_to? :type and type == other.type and
  other.respond_to? :channel and channel == other.channel and
  other.respond_to? :data and data == other.data
end

#cloneObject



158
159
160
# File 'lib/jsound/midi/message.rb', line 158

def clone
  self.class.new(@data, @channel, {:type => @type})
end

#data1Object



128
129
130
# File 'lib/jsound/midi/message.rb', line 128

def data1
  @data[0] if @data
end

#data1=(data) ⇒ Object



132
133
134
135
# File 'lib/jsound/midi/message.rb', line 132

def data1= data
  @data[0] = data
  update_java_message
end

#data2Object



137
138
139
# File 'lib/jsound/midi/message.rb', line 137

def data2
  @data[1] if @data
end

#data2=(data) ⇒ Object



141
142
143
144
# File 'lib/jsound/midi/message.rb', line 141

def data2= data
  @data[1] = data
  update_java_message
end

#statusObject



146
147
148
# File 'lib/jsound/midi/message.rb', line 146

def status
  @status ||= (STATUS_FOR_CLASS[self.class] || STATUS_FOR_TYPE[@type])
end

#to_javaObject



109
110
111
112
113
114
115
116
117
# File 'lib/jsound/midi/message.rb', line 109

def to_java
  if not @java_message
    @java_message = javax.sound.midi.ShortMessage.new
    update_java_message
  end
  # else, since all ruby message classes are backed by "ShortMessage",
  # we should be able to rely on @java_message being set for everything else
  @java_message
end

#to_sObject



154
155
156
# File 'lib/jsound/midi/message.rb', line 154

def to_s
  "#{type}(#{channel}): #{value.inspect}"
end

#update_java_messageObject



119
120
121
# File 'lib/jsound/midi/message.rb', line 119

def update_java_message
  @java_message.setMessage(status, @channel, @data[0], @data[1]) if @java_message
end

#valueObject



150
151
152
# File 'lib/jsound/midi/message.rb', line 150

def value
  @data
end