User Tools

Site Tools


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

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki