Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: ump: Transmit RPN/NRPN message at each MSB/LSB data reception

The UMP 1.1 spec says that an RPN/NRPN should be sent when one of the
following occurs:
* a CC 38 is received
* a subsequent CC 6 is received
* a CC 98, 99, 100, and 101 is received, indicating the last RPN/NRPN
message has ended and a new one has started

That said, we should send a partial data even if it's not fully
filled. Let's change the UMP conversion helper code to follow that
rule.

Link: https://patch.msgid.link/20240731130528.12600-2-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>

+33 -17
+1
include/sound/ump_convert.h
··· 13 13 unsigned char cc_nrpn_msb, cc_nrpn_lsb; 14 14 unsigned char cc_data_msb, cc_data_lsb; 15 15 unsigned char cc_bank_msb, cc_bank_lsb; 16 + bool cc_data_msb_set, cc_data_lsb_set; 16 17 }; 17 18 18 19 /* context for converting from MIDI1 byte stream to UMP packet */
+32 -17
sound/core/ump_convert.c
··· 287 287 return 4; 288 288 } 289 289 290 - static void fill_rpn(struct ump_cvt_to_ump_bank *cc, 291 - union snd_ump_midi2_msg *midi2) 290 + static int fill_rpn(struct ump_cvt_to_ump_bank *cc, 291 + union snd_ump_midi2_msg *midi2, 292 + bool flush) 292 293 { 294 + if (!(cc->cc_data_lsb_set || cc->cc_data_msb_set)) 295 + return 0; // skip 296 + /* when not flushing, wait for complete data set */ 297 + if (!flush && (!cc->cc_data_lsb_set || !cc->cc_data_msb_set)) 298 + return 0; // skip 299 + 293 300 if (cc->rpn_set) { 294 301 midi2->rpn.status = UMP_MSG_STATUS_RPN; 295 302 midi2->rpn.bank = cc->cc_rpn_msb; 296 303 midi2->rpn.index = cc->cc_rpn_lsb; 297 - cc->rpn_set = 0; 298 - cc->cc_rpn_msb = cc->cc_rpn_lsb = 0; 299 - } else { 304 + } else if (cc->nrpn_set) { 300 305 midi2->rpn.status = UMP_MSG_STATUS_NRPN; 301 306 midi2->rpn.bank = cc->cc_nrpn_msb; 302 307 midi2->rpn.index = cc->cc_nrpn_lsb; 303 - cc->nrpn_set = 0; 304 - cc->cc_nrpn_msb = cc->cc_nrpn_lsb = 0; 308 + } else { 309 + return 0; // skip 305 310 } 311 + 306 312 midi2->rpn.data = upscale_14_to_32bit((cc->cc_data_msb << 7) | 307 313 cc->cc_data_lsb); 314 + 315 + cc->rpn_set = 0; 316 + cc->nrpn_set = 0; 317 + cc->cc_rpn_msb = cc->cc_rpn_lsb = 0; 308 318 cc->cc_data_msb = cc->cc_data_lsb = 0; 319 + cc->cc_data_msb_set = cc->cc_data_lsb_set = 0; 320 + return 1; 309 321 } 310 322 311 323 /* convert to a MIDI 1.0 Channel Voice message */ ··· 330 318 struct ump_cvt_to_ump_bank *cc; 331 319 union snd_ump_midi2_msg *midi2 = (union snd_ump_midi2_msg *)data; 332 320 unsigned char status, channel; 321 + int ret; 333 322 334 323 BUILD_BUG_ON(sizeof(union snd_ump_midi1_msg) != 4); 335 324 BUILD_BUG_ON(sizeof(union snd_ump_midi2_msg) != 8); ··· 371 358 case UMP_MSG_STATUS_CC: 372 359 switch (buf[1]) { 373 360 case UMP_CC_RPN_MSB: 361 + ret = fill_rpn(cc, midi2, true); 374 362 cc->rpn_set = 1; 375 363 cc->cc_rpn_msb = buf[2]; 376 - return 0; // skip 364 + return ret; 377 365 case UMP_CC_RPN_LSB: 366 + ret = fill_rpn(cc, midi2, true); 378 367 cc->rpn_set = 1; 379 368 cc->cc_rpn_lsb = buf[2]; 380 - return 0; // skip 369 + return ret; 381 370 case UMP_CC_NRPN_MSB: 371 + ret = fill_rpn(cc, midi2, true); 382 372 cc->nrpn_set = 1; 383 373 cc->cc_nrpn_msb = buf[2]; 384 - return 0; // skip 374 + return ret; 385 375 case UMP_CC_NRPN_LSB: 376 + ret = fill_rpn(cc, midi2, true); 386 377 cc->nrpn_set = 1; 387 378 cc->cc_nrpn_lsb = buf[2]; 388 - return 0; // skip 379 + return ret; 389 380 case UMP_CC_DATA: 381 + cc->cc_data_msb_set = 1; 390 382 cc->cc_data_msb = buf[2]; 391 - return 0; // skip 383 + return fill_rpn(cc, midi2, false); 392 384 case UMP_CC_BANK_SELECT: 393 385 cc->bank_set = 1; 394 386 cc->cc_bank_msb = buf[2]; ··· 403 385 cc->cc_bank_lsb = buf[2]; 404 386 return 0; // skip 405 387 case UMP_CC_DATA_LSB: 388 + cc->cc_data_lsb_set = 1; 406 389 cc->cc_data_lsb = buf[2]; 407 - if (cc->rpn_set || cc->nrpn_set) 408 - fill_rpn(cc, midi2); 409 - else 410 - return 0; // skip 411 - break; 390 + return fill_rpn(cc, midi2, false); 412 391 default: 413 392 midi2->cc.index = buf[1]; 414 393 midi2->cc.data = upscale_7_to_32bit(buf[2]);