AudioKit / Cookbook

Canonical Examples for Using the AudioKit Framework
MIT License
639 stars 103 forks source link

ADD MIDI CONTROL OUT EXAMPLE #120

Closed freekatet closed 1 year ago

freekatet commented 1 year ago

Description

Hello, I saw it was mentioned somewhere in the TODO list :) I am very new to swift and tried to mix the midi monitor example with some Controls example but I didn't figure out how to connect the ui value to the sendcontrol command .

if anyone has any lead or example, I take it ! ::)

thank you!

here is my code so far: // // File.swift //
// // Created by Frexka Tet on 12/27/22. //

import AudioKit import AudioKitUI import CoreMIDI import Foundation import SwiftUI import Controls

struct MIDIPortTestViewFreeka: View { @StateObject var conductor: MIDIPortTestConductor = .init() @State private var selectedPort1Uid: MIDIUniqueID? @State private var selectedPort2Uid: MIDIUniqueID? @State var x: Float = 0.5 @State var y: Float = 0.5

var body: some View {

    ZStack {
        Image("background")

// .resizable() .scaledToFit() .edgesIgnoringSafeArea(.all)

        Text("$scammer$")

// ScrollView { GeometryReader { proxy in

        VStack(alignment: .center) {
            HStack(spacing: 10) {
                XYPad(x: $x, y: $y)
                    .backgroundColor(.white.opacity(0.25))
                    .cornerRadius(0)
                    .foregroundColor(.white)
                    .indicatorSize(CGSize(width: 30, height: 30))
                    .squareFrame(proxy.size.height / 5)

            }

// print( x ) // print( y )

// Spacer() // Divider() HStack { Picker(selection: $selectedPort1Uid, label: Text("Destination Ports:")) { Text("All") .tag(nil as MIDIUniqueID?) ForEach(0 ..< conductor.destinationNames.count, id: .self) { index in

                            Text("\(conductor.destinationNames[index])")
                                .tag(conductor.destinationUIDs[index] as MIDIUniqueID?)
                        }
                    }
            }
            HStack {
                Button("Send NoteOn 60") {
                    let eventToSend = StMIDIEvent(statusType: MIDIStatusType.noteOn.rawValue,
                                                  channel: 0,
                                                  data1: 60,
                                                  data2: 90)
                    if selectedPort1Uid != nil {
                        conductor.sendEvent(eventToSend: eventToSend, portIDs: [selectedPort1Uid!])
                    } else {
                        conductor.sendEvent(eventToSend: eventToSend, portIDs: nil)
                    }
                }
                Button("Send NoteOff 60") {
                    let eventToSend = StMIDIEvent(statusType: MIDIStatusType.noteOff.rawValue,
                                                  channel: 0,
                                                  data1: 60,
                                                  data2: 90)
                    if selectedPort1Uid != nil {
                        conductor.sendEvent(eventToSend: eventToSend, portIDs: [selectedPort1Uid!])
                    } else {
                        conductor.sendEvent(eventToSend: eventToSend, portIDs: nil)
                    }
                }
                Button("Send Controller 5 - 127") {
                    let eventToSend = StMIDIEvent(statusType: MIDIStatusType.controllerChange.rawValue,
                                                  channel: 0,
                                                  data1: 5,
                                                  data2: 127)
                    if selectedPort1Uid != nil {
                        conductor.sendEvent(eventToSend: eventToSend, portIDs: [selectedPort1Uid!])
                    } else {
                        conductor.sendEvent(eventToSend: eventToSend, portIDs: nil)
                    }
                }
                Button("Send Controller 5 - 0") {
                    let eventToSend = StMIDIEvent(statusType: MIDIStatusType.controllerChange.rawValue,
                                                  channel: 0,
                                                  data1: 5,
                                                  data2: 0)

                    if selectedPort1Uid != nil {
                        conductor.sendEvent(eventToSend: eventToSend, portIDs: [selectedPort1Uid!])
                    } else {
                        conductor.sendEvent(eventToSend: eventToSend, portIDs: nil)
                    }
                }
            }

// // Divider() // HStack { // Toggle(isOn: $conductor.outputIsOpen) {} //// Toggle(isOn: $conductor.inputPortIsSwapped) {} //// Toggle(isOn: $conductor.outputPortIsSwapped) {} // } // HStack { // Text("use midi.openOutputs()") //// Text("Swap UID for the virtual Input Port") //// Text("Swap UID for the virtual Output Port") // } } .padding()

    }
    }
    .onAppear {
        conductor.start()
    }
    .onDisappear {
        conductor.stop()
    }

}

}

struct Previews_Midi_Freeka_Previews: PreviewProvider { static var previews: some View { /@START_MENU_TOKEN@/Text("Hello, World!")/@END_MENU_TOKEN@/ } }

Proposed Solution

/

Describe Alternatives You've Considered

/

Additional Context

No response

NickCulbertson commented 1 year ago

Which value are you wanting to send? If it is x or y you would place that as your data1 or data2 variable.

Evan made a midi out tutorial that might be helpful: https://youtu.be/gb1kcqpELeE

freekatet commented 1 year ago

Hey Nick thanks for the quick reply! watching your video I understand but I am slightly confused by how the XYslider from my code works and don't understand how to connect the x y value as data1 data2 (like you mentioned) also this function is working on button click but I am trying to send it when I use the XYslider ( would also have to convert those values as they are floats atm)

thank you for your help!

Button("Send Controller 5 - 127") { let eventToSend = StMIDIEvent(statusType: MIDIStatusType.controllerChange.rawValue, channel: 0, data1: 5, data2: 127) if selectedPort1Uid != nil { conductor.sendEvent(eventToSend: eventToSend, portIDs: [selectedPort1Uid!]) } else { conductor.sendEvent(eventToSend: eventToSend, portIDs: nil) } }

NickCulbertson commented 1 year ago
// add the variables to your conductor class and access their didSet method. You’ll probably need to resolve some issues with the red stop sign that shows up in Xcode.
extension MIDIPortTestConductor: ObservableObject {
    @Published var x : Float = 0.5  {
            didSet {
                        //Call MIDI method here
                    let eventToSend = StMIDIEvent(statusType: MIDIStatusType.controllerChange.rawValue,
                channel: 0,
 data1: Int(x*127),
 data2: 127)
                        conductor.sendEvent(eventToSend: eventToSend, portIDs: nil)
            }
        }
        @Published var y : Float = 0.5  {
            didSet {
                        //Call MIDI method here
                    let eventToSend = StMIDIEvent(statusType: MIDIStatusType.controllerChange.rawValue,
                channel: 0,
 data1: Int(y*127), data2: 127)

                        conductor.sendEvent(eventToSend: eventToSend, portIDs: nil)
            }
        }
}

// Update the pad to read the variables from the conductor.
XYPad(x: $conductor.x, y: $conductor.y)
                    .backgroundColor(.white.opacity(0.25))
                    .cornerRadius(0)
                    .foregroundColor(.white)
                    .indicatorSize(CGSize(width: 30, height: 30))
                    .squareFrame(proxy.size.height / 5)
freekatet commented 1 year ago

Thanks Nick! Great example. had to move things around a little bit but it works now <3