Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: CI
on: [push, pull_request]
jobs:
lint:
strategy:
matrix:
ruby-version:
- "2.4"
name: ${{ format('Lint (Ruby {0})', matrix.ruby-version) }}
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v1

- name: Install Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true

- name: Run Linter
run: |
bundle exec rubocop
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Gemfile.lock
.idea/**/*
*.gemspec
4 changes: 4 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Metrics/BlockLength:
IgnoredMethods: ['describe', 'context']
Naming/FileName:
Enabled: false
19 changes: 9 additions & 10 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
source "https://rubygems.org"
# frozen_string_literal: true

group :test do
gem "minitest", "~> 5.5", ">= 5.5.0"
gem "mocha", "~> 1.1", ">= 1.1.0"
gem "rake", "~> 10.4", ">= 10.4.2"
gem "shoulda-context", "~> 1.2", ">= 1.2.1"
end
source 'https://rubygems.org'

gem "midi-message", "~> 0.4", ">= 0.4.9"
gem "midi-nibbler", "~> 0.2", ">= 0.2.4"
gem "unimidi", "~> 0.4", ">= 0.4.8"
gem 'rake', '~> 13.0', '>= 13.0.6', groups: %i[development test]
gem 'rspec', '~> 3.11', '>= 3.11.0', groups: %i[test]
gem 'rubocop', '~> 1.10', '>= 1.10.0', groups: %i[development test], require: false

gem 'midi-message', '~> 0.4', '>= 0.4.9'
gem 'midi-nibbler', '~> 0.2', '>= 0.2.4'
gem 'unimidi', '~> 0.5', '>= 0.5.1'
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ The listener will try to positively match the parameters you pass in to the prop
In this example, we specify that the listener listens for note on/off messages, which are identifiable by their class.

```ruby
transpose.listen_for(:class => [MIDIMessage::NoteOn, MIDIMessage::NoteOff]) do |event|
transpose.listen_for(class: [MIDIMessage::NoteOn, MIDIMessage::NoteOff]) do |event|

# raise the note value by an octave
event[:message].note += 12
Expand All @@ -59,10 +59,10 @@ Once all the events are bound, start the listener
transpose.run
```

A listener can also be run in a background thread by passing in `:background => true`.
A listener can also be run in a background thread by passing in `background: true`.

```ruby
transpose.run(:background => true)
transpose.run(background: true)

transpose.join # join the background thread later
```
Expand Down
17 changes: 9 additions & 8 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
require "rake"
require "rake/testtask"
# frozen_string_literal: true

Rake::TestTask.new(:test) do |t|
t.libs << "test"
t.test_files = FileList["test/**/*_test.rb"]
t.verbose = true
end
begin
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:spec)

task :default => [:test]
task default: :spec
rescue LoadError
# no rspec available
end
10 changes: 5 additions & 5 deletions examples/monitor.rb
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#!/usr/bin/env ruby
$:.unshift(File.join("..", "lib"))
# frozen_string_literal: true

require "midi-eye"
$LOAD_PATH.unshift(File.join('..', 'lib'))

require 'midi-eye'

# This example takes any note messages received from a UniMIDI input,
# and prints them to the console
Expand All @@ -15,15 +17,13 @@
# Bind an event to the listener using Listener#listen_for
#
transpose.listen_for do |event|

message = event[:message]
p message

end

# Start the listener

p "Control-C to quit..."
p 'Control-C to quit...'

transpose.run

Expand Down
14 changes: 7 additions & 7 deletions examples/synched_arpeggios.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#!/usr/bin/env ruby
$:.unshift(File.join("..", "lib"))
# frozen_string_literal: true

require "midi-eye"
$LOAD_PATH.unshift(File.join('..', 'lib'))

require 'midi-eye'

#
# This example plays arpeggios in sync with MIDI clock ticks that are received on an input
Expand All @@ -25,8 +27,7 @@
is_note_on = true

# Listen for clock messages
@clock.listen_for(:name => "Clock") do |event|

@clock.listen_for(name: 'Clock') do |_event|
# Should it output a note on this click?
if message_counter.eql?(@ticks_per_note)

Expand All @@ -46,15 +47,14 @@

# Once its finished with both note on and off for this particular note,
# increment the note counter
note_counter = (note_counter < (@notes.length-1) ? note_counter + 1 : 0) if is_note_on
note_counter = (note_counter < (@notes.length - 1) ? note_counter + 1 : 0) if is_note_on
message_counter = 0
else
message_counter += 1
end

end

p "Control-C to quit..."
p 'Control-C to quit...'

# Start the listener
@clock.run
46 changes: 46 additions & 0 deletions examples/thru.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

$LOAD_PATH.unshift(File.join('..', 'lib'))

require 'midi-eye'

# This example takes any note messages received from a UniMIDI input,
# transposes them up one octave and sends them to an output

# First, initialize the MIDI io ports
@input = UniMIDI::Input.gets
@output = UniMIDI::Output.gets

# Create a listener for the input port
transpose = MIDIEye::Listener.new(@input)

# Bind an event to the listener using Listener#listen_for
#
# The listener will try to positively match the parameters you pass in to the properties of
# the messages it receives
#
# This example looks for note on/off messages
#
# You also have the option of leaving out the parameters altogether and including a conditional
# in your callback (eg if event[:message].class.eql?(NoteOn) do... etc)
#
# There's no limit to how many events can be binded to a listener
#
transpose.on_message do |event|
# Send the altered note message to the output
@output.puts(event[:message])
end

# Start the listener

p 'Control-C to quit...'

transpose.run

# You can also have the listener run only in a background thread by using
#
# Transpose.run(:background => true)
#
# This will allow you to run multiple listeners at the same time for example, if you
# want to listen on multiple input ports
14 changes: 7 additions & 7 deletions examples/transpose.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#!/usr/bin/env ruby
$:.unshift(File.join("..", "lib"))
# frozen_string_literal: true

require "midi-eye"
$LOAD_PATH.unshift(File.join('..', 'lib'))

require 'midi-eye'

# This example takes any note messages received from a UniMIDI input,
# transposes them up one octave and sends them to an output
Expand All @@ -25,21 +27,19 @@
#
# There's no limit to how many events can be binded to a listener
#
transpose.listen_for(:class => [MIDIMessage::NoteOn, MIDIMessage::NoteOff]) do |event|

transpose.listen_for(class: [MIDIMessage::NoteOn, MIDIMessage::NoteOff]) do |event|
# Raise the note value by an octave
new_note = event[:message].note + 12
puts "Transposing from note #{event[:message].note} to note #{(new_note)}"
puts "Transposing from note #{event[:message].note} to note #{new_note}"
event[:message].note = new_note

# Send the altered note message to the output
@output.puts(event[:message])

end

# Start the listener

p "Control-C to quit..."
p 'Control-C to quit...'

transpose.run

Expand Down
20 changes: 10 additions & 10 deletions lib/midi-eye.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

#
# midi-eye
# MIDI input event listener for Ruby
Expand All @@ -8,18 +10,16 @@
#

# libs
require "forwardable"
require "midi-message"
require "nibbler"
require "unimidi"
require 'forwardable'
require 'midi-message'
require 'nibbler'
require 'unimidi'

# classes
require "midi-eye/event"
require "midi-eye/listener"
require "midi-eye/source"
require 'midi-eye/event'
require 'midi-eye/listener'
require 'midi-eye/source'

module MIDIEye

VERSION = "0.3.10"

VERSION = '0.3.10'
end
57 changes: 28 additions & 29 deletions lib/midi-eye/event.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module MIDIEye
# frozen_string_literal: true

module MIDIEye
# User defined callbacks for input events
class Event

extend Forwardable

def_delegators :@event, :count
Expand Down Expand Up @@ -34,9 +34,9 @@ def add(options = {}, &callback)
name = options[:listener_name]
options.delete(:listener_name)
event = {
:conditions => options,
:proc => callback,
:listener_name => name
conditions: options,
proc: callback,
listener_name: name
}
@event << event
event
Expand All @@ -46,9 +46,9 @@ def add(options = {}, &callback)
# @return [Fixnum] The number of triggered events
def trigger_enqueued
counter = 0
while !@queue.empty? do
until @queue.empty?
counter += 1
trigger(@queue.shift)
trigger_event(@queue.shift)
end
counter
end
Expand All @@ -63,8 +63,8 @@ def enqueue_all(message)
# @return [Hash]
def enqueue(action, message)
event = {
:action => action,
:message => message
action: action,
message: message
}
@queue << event
event
Expand All @@ -74,33 +74,32 @@ def enqueue(action, message)

# Does the given message meet the given conditions?
def meets_conditions?(conditions, message)
results = conditions.map do |key, value|
if message.respond_to?(key)
if value.kind_of?(Array)
value.include?(message.send(key))
else
value.eql?(message.send(key))
end
else
false
end
end
results.all?
conditions.map { |key, value| condition_met?(message, key, value) }.all?
end

# Trigger an event
def trigger(event)
def trigger_event(event)
action = event[:action]
conditions = action[:conditions]
if conditions.nil? || meets_conditions?(conditions, event[:message][:message])
begin
action[:proc].call(event[:message])
rescue Exception => exception
Thread.main.raise(exception)
end
return unless conditions.nil? || meets_conditions?(conditions, event[:message][:message])

begin
action[:proc].call(event[:message])
rescue StandardError => e
Thread.main.raise(e)
end
end

def condition_met?(message, key, value)
if message.respond_to?(key)
if value.is_a?(Enumerable)
value.include?(message.send(key))
else
value.eql?(message.send(key))
end
else
false
end
end
end

end
Loading