View Issue Details

IDProjectCategoryView StatusLast Update
0008117ardourbugspublic2020-05-15 20:50
Reportergwyndaf Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
PlatformLinux Mint Debian Edition 4OSDebianOS Version10/Buster
Product Version5.12 
Summary0008117: Unexpected response to Midi Machine Control (MMC) from control surface: track arm/mute/solo
Description1. Pressing controller button for Arm (record ready) on each of tracks 1-9 activates Record control on corresponding Ardour track, as expected. Pressing button on track 10 arms track 11 in Ardour, skipping track 10. Same behaviour with tracks 18 and 26, i.e. skipping every 8th track.

2. Pressing Mute button for any track has no effect in Ardour

3. Pressing Solo buttons for any track has no effect in Ardour (possible feature request, as I think this isn't supported, and may be non-standard MMC)

4. No MMC output from Ardour in response to any of the above track controls being pressed.

For 1-3, MIDI Tracer (on MMC in) reports "MMC command 41" for all controls across all tracks; for 3 also "[WARNING]: MIDI::MachineControl: masked write to 66 not implemented" in error messages. 4 produces no MIDI Tracer output (on MMC out)
Steps To ReproduceI've tried 3 ways (all with JACK and ALSA-MIDI bridge running). Have at least 12 audio tracks in Ardour (I used 32 to suit my controller)

A. Hardware controller (Tascam US428 or US224)
Connect and make sure us428control is running (manually if not started automatically).
Connect us428control midi out to Ardour MMC in
Press Record, Mute, Solo for each track in turn, using bank shift to access higher tracks.

B. Virtual controller (QmidiCtl on Android device, connecting to QmidiNet on Linux)
Connect QmidiNet MIDI out to Ardour MMC in
Press Record, Mute, Solo for each track in turn, using bank shift to access higher tracks.

C. Translate keyboard notes into MMC codes
Run the attached mididings script: 'python midi_notes-mmc.py' to create MMC-Translate device (which translates)
Connect MMC-Translate input to keyboard and output to Ardour MMC in
Note 24-35 (octave up from C) send Record Ready on for tracks 1-12; notes 36-47 send Record Ready off for tracks 1-12 (masked write 4f)
Note 48-59 (octave up from C) send Mute on for tracks 1-12; notes 60-71 send Mute off for tracks 1-12 (masked write 62)
Note 72-83 (octave up from C) send Solo on for tracks 1-12; notes 84-95 send Record Ready off for tracks 1-12 (masked write 66)
Additional InformationI think the cause of 1. might lie in libs/midi++2/mmc.cc (lines 555-559). These seem to calculate track numbers for arming from a base track that's a multiple of 8 when translating the MIDI bitmap. I think MIDI uses only 7 data bits in each byte, so the 8th bit is ignored. The attached ods gives my calculations of converting the MMC code into visible bits, and it seems the 'track skip' is built into how the bits are used.

I'm not a great C++ coder, but wonder if a possible fix might be to replace all of lines 555-559 with: base_track = (msg[0] * 7) - 5 (so the 8th bit of each byte doesn't get taken to signify a track number).

I don't think I'm up to testing this out and compiling something on the scale of Ardour, but happy to help with testing.
Tagscontrol, Midi

Activities

gwyndaf

2020-05-15 20:22

reporter  

midi_notes-mmc.py (5,122 bytes)   
from mididings import *

config(
  client_name='MMC-Translate',
     in_ports=[('MIDI-note-CC-in')],
     out_ports=[('MMC-out')],
	)
run(
	#######  MPK Midi to MMC  ########
  (
	Filter(CTRL)
	>> CtrlSplit({
		# Play
		4: SysEx('\xf0\x7f\x7f\x06\x02\xf7'),
		# Stop
		3: SysEx('\xf0\x7f\x7f\x06\x01\xf7'),
		# Rew
		1: SysEx('\xf0\x7f\x7f\x06\x05\xf7'),
		# Fwd
		2: SysEx('\xf0\x7f\x7f\x06\x04\xf7') 
		})
	)
	//
	(
	Filter(NOTE)
	>> KeySplit ({
		# 24-35 octave sends MMC RecArm (0x4f) ON
		24: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x00\x20\x20\xf7'),
		25: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x00\x40\x40\xf7'),
		26: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x01\x01\xf7'),
		27: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x02\x02\xf7'),
		28: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x04\x04\xf7'),
		29: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x08\x08\xf7'),
		30: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x10\x10\xf7'),
		31: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x20\x20\xf7'),
		32: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x40\x40\xf7'),
		33: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x02\x01\x01\xf7'),
		34: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x02\x02\x02\xf7'),
		35: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x02\x04\x04\xf7'),
		# 24-35 octave sends MMC RecArm (0x4f) OFF
		36: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x00\x20\x00\xf7'),
		37: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x00\x40\x00\xf7'),
		38: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x01\x00\xf7'),
		39: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x02\x00\xf7'),
		40: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x04\x00\xf7'),
		41: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x08\x00\xf7'),
		42: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x10\x00\xf7'),
		43: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x20\x00\xf7'),
		44: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x01\x40\x00\xf7'),
		45: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x02\x01\x00\xf7'),
		46: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x02\x02\x00\xf7'),
		47: SysEx('\xf0\x7f\x7f\x06\x41\x04\x4f\x02\x04\x00\xf7'),
		# 48-59 keys send MMC Mute (0x62) ON
		48: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x00\x20\x20\xf7'),
		49: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x00\x40\x40\xf7'),
		50: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x01\x01\xf7'),
		51: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x02\x02\xf7'),
		52: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x04\x04\xf7'),
		53: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x08\x08\xf7'),
		54: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x10\x10\xf7'),
		55: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x20\x20\xf7'),
		56: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x40\x40\xf7'),
		57: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x02\x01\x01\xf7'),
		58: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x02\x02\x02\xf7'),
		59: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x02\x04\x04\xf7'),
		# 60-71 keys send MMC Mute (0x62) OFF
		60: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x00\x20\x00\xf7'),
		61: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x00\x40\x00\xf7'),
		62: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x01\x00\xf7'),
		63: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x02\x00\xf7'),
		64: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x04\x00\xf7'),
		65: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x08\x00\xf7'),
		66: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x10\x00\xf7'),
		67: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x20\x00\xf7'),
		68: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x01\x40\x00\xf7'),
		69: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x02\x01\x00\xf7'),
		70: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x02\x02\x00\xf7'),
		71: SysEx('\xf0\x7f\x7f\x06\x41\x04\x62\x02\x04\x00\xf7'),
		# 72-83 octave sends MMC Solo (0x66) ON
		72: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x00\x20\x20\xf7'),
		73: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x00\x40\x40\xf7'),
		74: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x01\x01\xf7'),
		75: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x02\x02\xf7'),
		76: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x04\x04\xf7'),
		77: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x08\x08\xf7'),
		78: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x10\x10\xf7'),
		79: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x20\x20\xf7'),
		80: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x40\x40\xf7'),
		81: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x02\x01\x01\xf7'),
		82: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x02\x02\x02\xf7'),
		83: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x02\x04\x04\xf7'),
		# 84-95 octave sends MMC Solo (0x66) ON
		84: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x00\x20\x00\xf7'),
		85: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x00\x40\x00\xf7'),
		86: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x01\x00\xf7'),
		87: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x02\x00\xf7'),
		88: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x04\x00\xf7'),
		89: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x08\x00\xf7'),
		90: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x10\x00\xf7'),
		91: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x20\x00\xf7'),
		92: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x01\x40\x00\xf7'),
		93: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x02\x01\x00\xf7'),
		94: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x02\x02\x00\xf7'),
		95: SysEx('\xf0\x7f\x7f\x06\x41\x04\x66\x02\x04\x00\xf7')
		})
	)
	>> Port('MMC-out') 
)
midi_notes-mmc.py (5,122 bytes)   

gwyndaf

2020-05-15 20:50

reporter   ~0024158

Note: my main reference as to 'correct' MMC functionality has been only Qtractor, as I don't have access to any other DAW that I know supports MMC track controls, as another point of reference. I found it's useful to have that connected in parallel with Ardour, to verify the relevant controller is working ok.

However, I'm also aware that Qtractor, along with us428control and QmidiCtl/Net are all developed by the same person, so may be that they're more geared to working well with each other. However, I've tried to check them (i.e. that MIDI message that go in/out of them) against the MMC spec and they seem sound, with the exception of the Solo function, which I know he's added as a non-standard MMC implementation, albeit consistently (and quite handy).

Issue History

Date Modified Username Field Change
2020-05-15 20:22 gwyndaf New Issue
2020-05-15 20:22 gwyndaf Tag Attached: control
2020-05-15 20:22 gwyndaf Tag Attached: Midi
2020-05-15 20:22 gwyndaf File Added: midi_notes-mmc.py
2020-05-15 20:22 gwyndaf File Added: MIDI MMC Masked Write calcs.ods
2020-05-15 20:50 gwyndaf Note Added: 0024158