Skip to content

Instantly share code, notes, and snippets.

@willwade
Last active November 25, 2024 16:50
Show Gist options
  • Save willwade/fb772a9e39f218af0e4035552a29a557 to your computer and use it in GitHub Desktop.
Save willwade/fb772a9e39f218af0e4035552a29a557 to your computer and use it in GitHub Desktop.
Midi-Switch controller
import UIKit
class ViewController: UIViewController {
var midiController: MIDIController?
override func viewDidLoad() {
super.viewDidLoad()
// Initialize the MIDI controller
midiController = MIDIController()
// Example: Send a MIDI Note On and Note Off
sendMIDINotes()
}
func sendMIDINotes() {
// Send Note On for MIDI note 60 (Middle C), velocity 127, channel 1
midiController?.sendNoteOn(note: 60, velocity: 127, channel: 0)
// Hold the note for 1 second, then send Note Off
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.midiController?.sendNoteOff(note: 60, velocity: 127, channel: 0)
}
}
}
import UIKit
import CoreMIDI
class MIDIController {
private var midiClient: MIDIClientRef = 0
private var midiOutPort: MIDIPortRef = 0
private var destination: MIDIEndpointRef?
init() {
setupMIDI()
}
private func setupMIDI() {
// Create a MIDI client
MIDIClientCreate("MIDIClient" as CFString, nil, nil, &midiClient)
// Create an output port
MIDIOutputPortCreate(midiClient, "MIDIOutPort" as CFString, &midiOutPort)
// Find the first available MIDI destination
let destinationCount = MIDIGetNumberOfDestinations()
if destinationCount > 0 {
destination = MIDIGetDestination(0)
} else {
print("No MIDI destinations found")
}
}
func sendNoteOn(note: UInt8, velocity: UInt8, channel: UInt8) {
guard let destination = destination else { return }
// Create a MIDI Note On message
var packet = MIDIPacket()
packet.timeStamp = 0
packet.length = 3
packet.data.0 = 0x90 | (channel & 0x0F) // Note On message, channel 1
packet.data.1 = note // MIDI note number
packet.data.2 = velocity // Velocity
var packetList = MIDIPacketList(numPackets: 1, packet: packet)
// Send the packet list to the destination
MIDIReceived(destination, &packetList)
}
func sendNoteOff(note: UInt8, velocity: UInt8, channel: UInt8) {
guard let destination = destination else { return }
// Create a MIDI Note Off message
var packet = MIDIPacket()
packet.timeStamp = 0
packet.length = 3
packet.data.0 = 0x80 | (channel & 0x0F) // Note Off message, channel 1
packet.data.1 = note // MIDI note number
packet.data.2 = velocity // Velocity
var packetList = MIDIPacketList(numPackets: 1, packet: packet)
// Send the packet list to the destination
MIDIReceived(destination, &packetList)
}
}
import time
import board
import digitalio
import usb_midi
import adafruit_midi
from adafruit_midi.note_on import NoteOn
from adafruit_midi.note_off import NoteOff
# Initialize USB MIDI
midi = adafruit_midi.MIDI(midi_in=usb_midi.ports[0], in_channel=0)
# Configure GPIO pins for the 3.5mm switch jacks
switch_jacks = {
"switch_1": digitalio.DigitalInOut(board.D2),
"switch_2": digitalio.DigitalInOut(board.D3),
"switch_3": digitalio.DigitalInOut(board.D4),
"switch_4": digitalio.DigitalInOut(board.D5),
}
# Set all switch jacks as outputs and default to LOW
for switch in switch_jacks.values():
switch.direction = digitalio.Direction.OUTPUT
switch.value = False
# Define a mapping between MIDI notes and switch jacks
midi_to_switch = {
60: "switch_1", # MIDI Note 60 -> Switch 1
61: "switch_2", # MIDI Note 61 -> Switch 2
62: "switch_3", # MIDI Note 62 -> Switch 3
63: "switch_4", # MIDI Note 63 -> Switch 4
}
# Dictionary to track the current state of each switch (for holding)
active_switches = {}
def activate_switch(switch_name):
"""Activate the specified switch."""
if switch_name in switch_jacks:
switch_jacks[switch_name].value = True
def deactivate_switch(switch_name):
"""Deactivate the specified switch."""
if switch_name in switch_jacks:
switch_jacks[switch_name].value = False
# Main loop to listen for MIDI signals and control switches
while True:
# Check for incoming MIDI messages
midi_msg = midi.receive()
if isinstance(midi_msg, NoteOn):
# NoteOn message: activate the corresponding switch
note = midi_msg.note
if note in midi_to_switch:
switch_name = midi_to_switch[note]
activate_switch(switch_name)
# Record the start time for holding the switch
active_switches[switch_name] = time.monotonic()
elif isinstance(midi_msg, NoteOff):
# NoteOff message: deactivate the corresponding switch
note = midi_msg.note
if note in midi_to_switch:
switch_name = midi_to_switch[note]
deactivate_switch(switch_name)
# Remove the switch from the active list
if switch_name in active_switches:
del active_switches[switch_name]
# Manage holding logic for active switches
for switch_name, start_time in list(active_switches.items()):
# Check how long the switch has been held (in seconds)
duration = time.monotonic() - start_time
if duration > 0: # Optional: Limit max hold duration if needed
# For now, we're simply holding the switch as long as NoteOn is held
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment