prime4
This is an old revision of the document!
I own a working force and a force where the internal soundcard doesn't work anymore. On my “not well working force” i use a presonus USB soundcard. With this external soundcard, i have sound output only by using prime4.
To use prime 4, you have to change your productcode to JC11 when binding. (mount -o bind productcode “/sys/firmware/devicetree/base/inmusic,product-code”)
When running prime you'll see which file you can create for your assignments. Below is an example when i run prime 4 :
air.assignments.deviceadapter: Could not find file: "Akai_Pro_Force_Public_Assignments.qml" air.assignments.deviceadapter: Could not find file: "Akai_Pro_Force_Public_Device.qml" air.assignments.deviceadapter: Could not find file: "Akai_Pro_Force_Private_Assignments.qml" air.assignments.deviceadapter: Could not find file: "Akai_Pro_Force_Private_Device.qml" air.assignments.deviceadapter: Could not find file: "Akai_Pro_Force_MIDI_Port_Assignments.qml" air.assignments.deviceadapter: Could not find file: "Akai_Pro_Force_MIDI_Port_Assignments.qml" air.assignments.deviceadapter: Could not find file: "Akai_Pro_Force_MIDI_Port_Device.qml" air.assignments.deviceadapter: Could not find file: "Akai_Pro_Force_MIDI_Port_Device.qml" air.assignments.deviceadapter: Could not find file: "AudioBox_USB_96_MIDI_1_Assignments.qml" air.assignments.deviceadapter: Could not find file: "AudioBox_USB_96_MIDI_1_Assignments.qml" air.assignments.deviceadapter: Could not find file: "AudioBox_USB_96_MIDI_1_Device.qml" air.assignments.deviceadapter: Could not find file: "AudioBox_USB_96_MIDI_1_Device.qml"
So all these qml files can be created.
Then you can use the following qml to use it on your force. (qml syntax has been taken from Prime Firmware)
Akai_Pro_Force_Private_Device.qml : import airAssignments 1.0 import InputAssignment 0.1 import OutputAssignment 0.1 import Device 0.1 import QtQuick 2.9 // QT_LOGGING_RULES=air.planck.firmware.upgrade=true LD_LIBRARY_PATH=/usr/qt/lib /usr/Engine/JC11 -d0 Device { id: device property real gamma: 3.5 property real padGamma: 3.5 controls: [] useGlobalShift: false numberOfLayers: 0 property string deviceInfo: "" property string currentMixerFirmwareVersion /////////////////////////////////////////////////////////////////////////// // Setup function queryAbsoluteControls() { console.log("Query absolute position controls") Midi.sendSysEx("F0 00 02 0B 7F 0C 04 00 00 F7") } property Timer initPhaseEndTimer: Timer { interval: 1000 repeat: false onTriggered: { console.log("Initialization phase ended") device.isInitializing = false queryAbsoluteControls() } } property bool isInitializing: false Component.onCompleted: { currentColors = {} currentSimpleColors = {} console.log("Sending Initilization Message Akai Pro AMX") Midi.sendSysEx("47 7F 2C 60 00 04 04 01 00 00"); isInitializing = true requestPowerOnButtonState() console.log("Sending initialization message for PRIME GO ...") Midi.sendSysEx("F0 00 02 0B 7F 0C 60 00 04 04 01 01 04 F7") initPhaseEndTimer.start() } Component.onDestruction: { Midi.sendNoteOff(0, 118) } property var currentColors property var currentSimpleColors // Dec to Hex Conversion function d2h(d){ return (+d).toString(16).toUpperCase() } function midiColorChannel(c, gamma){ return d2h(Math.min(127, Math.max(0, Math.floor(Math.pow(c, gamma) * 127)))) } function mapColor(color) { return Qt.rgba(color.r, color.g, color.b , color.a) } function midiColor(color, gamma) { var c = mapColor(color) return midiColorChannel(c.r, gamma) + " " + midiColorChannel(c.g, gamma) + " " + midiColorChannel(c.b, gamma) } function sendNoteOn(channel, index, value) { Midi.sendNoteOn(channel, index, value) } function sendSimpleColor(channel, index, value) { currentSimpleColors[index] = value if (value === 0) { Midi.sendNoteOff(channel, index) } else { Midi.sendNoteOn(channel, index, value) } } //Color Send Function function sendColor(channel, index, color) { currentColors[index] = color var g = device.gamma if(index >= 15 && index <= 23) { g = device.padGamma } var sysEx = "F0 00 02 0B 7F 0C 03 00 05 " + d2h(channel) + " " + d2h(index) + " " + midiColor(color, g)+" F7" Midi.sendSysEx(sysEx) } function requestPowerOnButtonState() { Midi.sendSysEx("F0 00 02 0B 7f 0C 42 00 00 F7") } function sysExToIntList(sysExString) { var valueList = sysExString.split(" ") var result = [] for(var i = 0; i < valueList.length; ++i) { result.push(parseInt(valueList[i], 16)) } return result } function sysEx(sysExString) { console.info("Received SysEx:", sysExString) var valueList = sysExToIntList(sysExString) var result = "" // 0xf0 0x00 0x02 0x0b 0x00 0x06 0x42 0x00 0x01 0x01 0xf7 if(valueList[1] === 0x00 && valueList[2] === 0x02 && valueList[3] === 0x0B && valueList[4] === 0x00 && valueList[6] === 0x42) { if(valueList[9] === 0x0) { console.log("No special power on request") } else if(valueList[9] === 0x1) { console.log("Request test-mode entry") quitToTestApp() } } else if(valueList[1] === 0x7E && valueList[2] === 0x00 && valueList[3] === 0x06 && valueList[4] === 0x02) { var i for(i = 0; i < 4; ++i) { result += valueList[i + 11] if(i === 1) { result += "." } } deviceInfo = result var mixerVersion = "" if(valueList.length === 43) { //mixerVersion = "00." + valueList[40].toString(16) for(i = 0; i < 4; ++i) { mixerVersion += valueList[i + 37] if(i === 1) { mixerVersion += "." } } } currentMixerFirmwareVersion = mixerVersion console.log("Mixer version:", mixerVersion, "(", valueList, ")") var currentSerialNumber = Planck.readFromFile("/sys/firmware/devicetree/base/serial-number") var serial = "" for(i = 20; i < 35; ++i) { if(valueList[i] === 0) { break } serial += String.fromCharCode(valueList[i]) } if(serial !== currentSerialNumber && serial.length > 0) { Planck.setDeviceSerialNumber(serial) } } } }
import airAssignments 1.0 import ControlSurfaceModules 0.1 import Planck 1.0 import QtQuick 2.12 import InputAssignment 0.1 import OutputAssignment 0.1 MidiAssignment { objectName: "PRIME 4 Controller Assignment" Utility { id: util } GlobalAssignmentConfig { id: globalConfig midiChannel: 0 } GlobalAction { id: globalAction } Back { note: 67 ledType: LedType.Simple } Forward { //note: 115 shiftAction: Action.Quantize ledType: LedType.Simple } BrowseEncoder { //pushNote: 111 turnCC: 100 ledType: LedType.Simple } View { note: 0 holdAction: Action.ToggleControlCenter shiftAction: Action.SwitchMainViewLayout ledType: LedType.Simple } Shift { note: 49 ledType: LedType.Simple } Media { mediaButtonsModel: ListModel { ListElement { name: 'Eject' shiftName: 'Source' note: 20 hasLed: true } } } Mixer { cueMixCC: 12 cueGainCC: 13 crossfaderCC: 32 } MicSettings {} Mics { mic1Note: 36 mic2Note: 37 mic1ShiftAction: Action.ToggleMicTalkover } Repeater { model: ListModel { ListElement { deckName: 'Left' deckMidiChannel: 9 loadNote: 123 } } Item { DeckAssignmentConfig { id: deckConfig name: model.deckName midiChannel: model.deckMidiChannel } DeckAction { id: deckAction } Bank {} Load { note: model.loadNote ledType: LedType.Simple } PerformanceModes { ledType: LedType.RGB modesModel: ListModel { ListElement { note: 110 view: "CUES" } ListElement { note: 111 view: "LOOPS" altView: "AUTO" } ListElement { note: 112 view: "ROLL" } ListElement { note: 113 view: "SLICER" altView: "FIXED" } } } ActionPads { firstPadNote: 102 ledType: LedType.RGB } Sync { syncNote: 115 syncHoldAction: Action.KeySync } PlayCue { cueNote: 37 cueShiftAction: Action.SetCuePoint playNote: 114 } PitchBend { minusNote: 29 plusNote: 30 } JogWheel { touchNote: 33 ccUpper: 0x37 ccLower: 0x4D jogSensitivity: 1638.7 * 10.08 hasTrackSearch: true } Vinyl { note: 35 holdAction: Action.GridCueEdit } AutoLoop { pushNote: 116 turnCC: 160 loopInactiveShiftTurnAction: Action.BeatJump ledType: LedType.Simple } SpeedSlider { ccUpper: 0x1F ccLower: 0x4B invert: true } } } Repeater { model: ListModel { ListElement { deckName: 'Right' deckMidiChannel: 9 loadNote: 124 } } Item { DeckAssignmentConfig { id: deckConfig name: model.deckName midiChannel: model.deckMidiChannel } DeckAction { id: deckAction } Bank {} Load { note: model.loadNote ledType: LedType.Simple } PerformanceModes { ledType: LedType.RGB modesModel: ListModel { ListElement { note: 78 view: "CUES" } ListElement { note: 79 view: "LOOPS" altView: "AUTO" } ListElement { note: 80 view: "ROLL" } ListElement { note: 81 view: "SLICER" altView: "FIXED" } } } ActionPads { firstPadNote: 70 ledType: LedType.RGB } Sync { syncNote: 83 syncHoldAction: Action.KeySync } PlayCue { cueNote: 9 cueShiftAction: Action.SetCuePoint playNote: 82 } PitchBend { minusNote: 29 plusNote: 30 } JogWheel { touchNote: 33 ccUpper: 0x37 ccLower: 0x4D jogSensitivity: 1638.7 * 10.08 hasTrackSearch: true } Vinyl { note: 35 holdAction: Action.GridCueEdit } AutoLoop { pushNote: 56 turnCC: 230 loopInactiveShiftTurnAction: Action.BeatJump ledType: LedType.Simple } SpeedSlider { ccUpper: 0x1F ccLower: 0x4B invert: true } } } Repeater { model: ListModel { ListElement { mixerChannelName: '1' mixerChannelMidiChannel: 0 } } Item { objectName: 'Mixer Channel %1'.arg(model.mixerChannelName) MixerChannelAssignmentConfig { id: mixerChannelConfig name: model.mixerChannelName midiChannel: model.mixerChannelMidiChannel } MixerChannelCore { pflNote: 13 trimCC: 3 trebleCC: 21 midCC: 6 bassCC: 200 faderCC: 14 } SweepFxKnob { cc: 24 } SweepFxSelect { channelNames: [model.mixerChannelName] buttonsModel: ListModel { ListElement { note: 60 fxIndex: SweepEffect.DualFilter } ListElement { note: 61 fxIndex: SweepEffect.Wash } } } } } Repeater { model: ListModel { ListElement { mixerChannelName: '2' mixerChannelMidiChannel: 0 } } Item { objectName: 'Mixer Channel %1'.arg(model.mixerChannelName) MixerChannelAssignmentConfig { id: mixerChannelConfig name: model.mixerChannelName midiChannel: model.mixerChannelMidiChannel } MixerChannelCore { pflNote: 13 trimCC: 3 trebleCC: 4 midCC: 6 bassCC: 22 faderCC: 14 } SweepFxKnob { cc: 24 } SweepFxSelect { channelNames: [model.mixerChannelName] buttonsModel: ListModel { ListElement { note: 62 fxIndex: SweepEffect.DualFilter } ListElement { note: 63 fxIndex: SweepEffect.Wash } } } } } /////////////////////////////////////////////////////////////////////////// // Effect Controls Repeater { model: ListModel { ListElement { deckName: "Left" deckMidiChannel: 0 } ListElement { deckName: "Right" deckMidiChannel: 1 } } Item { id: deckFx ValueNoteAssignment { objectName: "FX%1 Active Button".arg(1) note: 93 channel: deckMidiChannel enabled: !device.shift output: ActionOutput { target: PropertyTarget { path: "/Engine/Mixer/Channel%1/DJFx/Active".arg(1) } } } ValueNoteAssignment { objectName: "FX%1 Active Button".arg(2) note: 05 channel: deckMidiChannel enabled: !device.shift output: ActionOutput { target: PropertyTarget { path: "/Engine/Mixer/Channel%1/DJFx/Active".arg(2) } } } ValueCCAssignment { objectName: "FX%1 Selection".arg(1) cc: 17 channel: deckMidiChannel enabled: Planck.getProperty("/Engine/Mixer/Channel%1/DJFx/Selecting".arg(1)).translator.state output: QtObject { readonly property QObjProperty pSelectionIndex: Planck.getProperty("/Engine/Mixer/Channel%1/DJFx/PreselectIndex".arg(1)) function setValue(channel, value, assignmentEnabled) { if(assignmentEnabled) { if(value > 0.5) { // turn counter clockwise, value normalized pSelectionIndex.translator.unnormalized = pSelectionIndex.translator.unnormalized - 1 } else { pSelectionIndex.translator.unnormalized = pSelectionIndex.translator.unnormalized + 1 } } } } } ValueCCAssignment { objectName: "FX%1 Selecting".arg(1) cc: 17 channel: deckMidiChannel enabled: !Planck.getProperty("/Engine/Mixer/Channel%1/DJFx/Selecting".arg(1)).translator.state output: ActionOutput { behaviour: force.action target: PropertyTarget { path: "/Engine/Mixer/Channel%1/DJFx/Selecting".arg(1) } } } ValueCCAssignment { objectName: "FX%1 Selection".arg(2) cc: 20 channel: deckMidiChannel enabled: Planck.getProperty("/Engine/Mixer/Channel%1/DJFx/Selecting".arg(2)).translator.state output: QtObject { readonly property QObjProperty pSelectionIndex: Planck.getProperty("/Engine/Mixer/Channel%1/DJFx/PreselectIndex".arg(2)) function setValue(channel, value, assignmentEnabled) { if(assignmentEnabled) { if(value > 0.5) { // turn counter clockwise, value normalized pSelectionIndex.translator.unnormalized = pSelectionIndex.translator.unnormalized - 1 } else { pSelectionIndex.translator.unnormalized = pSelectionIndex.translator.unnormalized + 1 } } } } } ValueCCAssignment { objectName: "FX%1 Selecting".arg(2) cc: 20 channel: deckMidiChannel enabled: !Planck.getProperty("/Engine/Mixer/Channel%1/DJFx/Selecting".arg(2)).translator.state output: ActionOutput { behaviour: force.action target: PropertyTarget { path: "/Engine/Mixer/Channel%1/DJFx/Selecting".arg(2) } } } // ValueCCAssignment { // objectName: "FX%1 Rate".arg(1) // cc: 100 // channel: deckMidiChannel // enabled: Planck.getProperty("/Engine/Mixer/Channel%1/DJFx/Knob2Target".arg(1)).translator.string === "Rate" // output: QtObject { // readonly property QObjProperty pTarget: Planck.getProperty("/Engine/Mixer/Channel%1/DJFx/Rate".arg(1)) // function setValue(channel, value, assignmentEnabled) { // if(assignmentEnabled) { // var counterClock = value > 0.5 // var changeIndex = counterClock ? -1 : 1 // pTarget.translator.index = pTarget.translator.index + changeIndex // } // } // } // } ValueCCAssignment { objectName: "FX%1 Amount".arg(1) cc: 18 channel: deckMidiChannel enabled: Planck.getProperty("/Engine/Mixer/Channel%1/DJFx/Knob2Target".arg(1)).translator.string === "Amount" output: EndlessKnobOutput { smallestIncrement: 0.01 biggestIncrement: 0.1 target: PropertyTarget { path: "/Engine/Mixer/Channel%1/DJFx/Amount".arg(1) } } } ValueCCAssignment { objectName: "FX%1 Amount".arg(2) cc: 21 channel: deckMidiChannel enabled: Planck.getProperty("/Engine/Mixer/Channel%1/DJFx/Knob2Target".arg(2)).translator.string === "Amount" output: EndlessKnobOutput { smallestIncrement: 0.01 biggestIncrement: 0.1 target: PropertyTarget { path: "/Engine/Mixer/Channel%1/DJFx/Amount".arg(2) } } } ValueCCAssignment { objectName: "FX%1 Mix".arg(1) cc: 19 channel: deckMidiChannel output: ValueOutput { target: PropertyTarget { path: "/Engine/Mixer/Channel%1/DJFx/Mix".arg(1) } } } ValueCCAssignment { objectName: "FX%1 Mix".arg(2) cc: 22 channel: deckMidiChannel output: ValueOutput { target: PropertyTarget { path: "/Engine/Mixer/Channel%1/DJFx/Mix".arg(2) } } } } } /* FxAssignmentConfig { id: fxConfig midiChannel: 0 channelNames: ['1', '2'] } DJFxSelect { pushNote: 53 touchNote: 91 turnCC: 100 } DJFxTime { pushNote: 8 turnCC: 18 } DJFxWetDry { cc: 19 } DJFxActivate { fxActivateType: FxActivateType.Button activateControlsModel: ListModel { ListElement { midiChannel: 0 note: 93 } ListElement { midiChannel: 0 note: 92 } } } DJFxAssign { notes: [94, 95] } */ }
prime4.1694375118.txt.gz · Last modified: 2023/09/10 21:45 by ounsatn