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.1694375067.txt.gz · Last modified: 2023/09/10 21:44 by ounsatn