Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions Modality/Classes/MIDI/MIDIControl14bit.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
MIDIControl14BitHelperLobyte{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need two separate classes for this? it seems to me an unnecessary clutter of the ClassTable...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... I guess it could be combined, if we make lobyte or hibyte an instance variable that is set on creation.
(of course, then I will need to figure out a testing scenario again as I am no longer close to the device).

var <cc14helper;

*new{ |cc14|
^super.new.init( cc14 );
}

init{ |cc14|
cc14helper = cc14;
}

value{ |val|
^cc14helper.value( val, \lobyte );
}

}

MIDIControl14BitHelper {
var loCCnum, hiCCnum;
var loByte, hiByte;
var waitingForLoByte = false;

*new{arg hiCCnum;
^super.new.init(hiCCnum);
}

init{ |hiCC|
hiCCnum = hiCC;
loCCnum = hiCC + 32;
}

calculate{ arg lo, hi;
var result;
result = lo + (hi << 7);
^result;
}

value{ arg val, byte=\hibyte;
var outval;
if ( byte == \hibyte ){
hiByte = val;
waitingForLoByte = true;
};
if ( byte == \lobyte ){
loByte = val;
if( waitingForLoByte, {
outval = this.calculate( loByte, hiByte );
waitingForLoByte = false;
});
};
^outval;
}

}

// sending out 14 bit midi control
+ MIDIOut{
control14 { arg chan, ctlNum=7, val=64;
this.control( chan, ctlNum, val >> 7 );
this.control( chan, ctlNum+32, val % 128 );
}
}
96 changes: 89 additions & 7 deletions Modality/Classes/MIDI/MIDIMKtlDevice.sc
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,23 @@ MIDIMKtlDevice : MKtlDevice {
var <responders; // the MIDIFuncs responding to each protocol
var <msgTypes; // the msgTypes for which this MKtl needs MIDIfuncs

var <cc14helpers;
var <cc14nums;

*initClass {
allMsgTypes = #[
\noteOn, \noteOff, /* \noteOnOff, */ \cc, \control, \polyTouch, \polytouch,
\noteOn, \noteOff, /* \noteOnOff, */
\cc, \control,
\cc14, \control14,
\polyTouch, \polytouch,
\touch, \bend, \program,
\midiClock, \start, \stop, \continue, \reset,
\allNotesOff
];

msgTypeKeys = (
\cc14: "c14_%_%",
\control14: "c14_%_%",
\cc: "c_%_%",
\control: "c_%_%",
\noteOn: "non_%_%",
Expand Down Expand Up @@ -274,6 +282,11 @@ MIDIMKtlDevice : MKtlDevice {
hashKeys = msgType.asArray.collect { |type|
MIDIMKtlDevice.makeMsgKey(type, elemDesc[\midiChan], elemDesc[\midiNum]);
};
if ( [ \control14, \cc14].includes( msgType ) ){
hashKeys = [ 0, 32 ].collect { |offset|
MIDIMKtlDevice.makeMsgKey(msgType, elemDesc[\midiChan], elemDesc[\midiNum] + offset );
};
};
^hashKeys
}

Expand All @@ -298,6 +311,9 @@ MIDIMKtlDevice : MKtlDevice {
var elementsDict = mktl.elementsDict;
midiKeyToElemDict = ();

cc14helpers = ();
cc14nums = Set.new;

if (elementsDict.isNil) {
warn("% has no elementsDict?".format(mktl));
^this
Expand All @@ -306,13 +322,24 @@ MIDIMKtlDevice : MKtlDevice {
elementsDict.do { |elem|
var elemDesc = elem.elemDesc;
var midiKeys = this.makeHashKey( elemDesc, elem );
// midiKeys.postln;
// elemDesc[\midiNum].postln;

// set the inputs only; outputs can use elemDesc directly
if ( [nil, \in, \inout].includes(elemDesc[\ioType])) {
// element has specific description for the input
midiKeys.do { |key|
midiKeyToElemDict.put(*[key, elem]);
};
if ( [\control14,\cc14].includes( elemDesc[\midiMsgType] ) ){
// create a cc14 helper
var cc14 = MIDIControl14BitHelper.new( elemDesc[\midiNum] );
var cc14lo = MIDIControl14BitHelperLobyte.new( cc14 );
cc14nums.add( elemDesc[ \midiNum] );
cc14nums.add( elemDesc[ \midiNum] + 32 );
cc14helpers.put( midiKeys[0], cc14 );
cc14helpers.put( midiKeys[1], cc14lo );
};
};
};
}
Expand Down Expand Up @@ -365,27 +392,68 @@ MIDIMKtlDevice : MKtlDevice {
var hash = MIDIMKtlDevice.makeMsgKey(typeKey, chan, num);
var el = midiKeyToElemDict[hash];

// do global actions first
// do global actions first
midiRawAction.value(typeKey, src, chan, num, value);
global[typeKey].value(chan, num, value);
global[typeKey].value(chan, num, value);

if (el.notNil) {
el.deviceValueAction_(value);
if(traceRunning) {
MIDIMKtlDevice.postMsgTrace(mktl, el,
typeKey, value, num, chan, src);
typeKey, value, num, chan, src);
};
} { // element is nil
if (traceRunning) {
MIDIMKtlDevice.postMsgNotFound(mktl, typeKey,
value, num, chan, src);
if ( cc14nums.includes( num ).not ){
MIDIMKtlDevice.postMsgNotFound(mktl, typeKey,
value, num, chan, src);
};
};
}

}, msgType: typeKey, srcID: srcUid).permanent_(true);
);
}

// 14bit cc
makeChanNumCC14MsgMIDIFunc { |typeKey, srcUid|
if (typeKey == \cc14) { typeKey = \control14 };

responders.put(typeKey,
MIDIFunc({ |value, num, chan, src|
var elhash, el;
var hash = MIDIMKtlDevice.makeMsgKey(typeKey, chan, num);
var cc14 = cc14helpers[hash];
var value14;

// do global actions first
midiRawAction.value(typeKey, src, chan, num, value);
global[typeKey].value(chan, num, value);

if ( cc14.notNil ){
value14 = cc14.value( value );
if ( value14.notNil ){
elhash = MIDIMKtlDevice.makeMsgKey(typeKey, chan, num - 32); // lo byte comes second
el = midiKeyToElemDict[hash];
if ( el.notNil) {
el.deviceValueAction_(value14);
if(traceRunning) {
MIDIMKtlDevice.postMsgTrace(mktl, el,
typeKey, value14, num, chan, src);
};
}{ // element is nil
if (traceRunning) {
MIDIMKtlDevice.postMsgNotFound(mktl, typeKey,
value, num, chan, src);
};
};
};
};
}, msgType: \control, srcID: srcUid).permanent_(true); // explicit control
);
}


*postMsgNotFound { |mktl, msgType, value, num, chan, src|
var numStr = if (num.notNil) { "midiNum: %, ".format(num) } { "" };

Expand All @@ -402,12 +470,16 @@ MIDIMKtlDevice : MKtlDevice {
numStr = msgType.switch(
\cc, "ccNum: %, ",
\control, "ccNum: %, ",

\cc14, "ccNum14: %, %",
\control14, "ccNum14: %, %",

\noteOn, "noteNum: %, ",
\noteOff, "noteNum: %, ",
\polyTouch, "touch: %, ",
\polytouch, "touch: %, "
)
.format(num)
.format(num, num+32)
} { "" };

"% midi, % > %, raw: %, \n"
Expand Down Expand Up @@ -450,6 +522,10 @@ MIDIMKtlDevice : MKtlDevice {
switch(msgType,
\cc, { this.makeChanNumMsgMIDIFunc(msgType, srcID) },
\control, { this.makeChanNumMsgMIDIFunc(msgType, srcID) },

\cc14, { this.makeChanNumCC14MsgMIDIFunc(msgType, srcID) },
\control14, { this.makeChanNumCC14MsgMIDIFunc(msgType, srcID) },

\noteOn, { this.makeChanNumMsgMIDIFunc(msgType, srcID) },
\noteOff, { this.makeChanNumMsgMIDIFunc(msgType, srcID) },
\noteOnOff, {
Expand All @@ -476,6 +552,8 @@ MIDIMKtlDevice : MKtlDevice {
send { |key, val|
var elem, elemDesc, msgType, chan, num;

val = val.asInteger; // integer is needed for MIDI output

// check that midiout needed for sending exists,
// complain and exit if it is missing

Expand Down Expand Up @@ -515,6 +593,10 @@ MIDIMKtlDevice : MKtlDevice {
switch(msgType,
\cc, { midiOut.control(chan, num, val ) },
\control, { midiOut.control(chan, num, val ) },

\cc14, { midiOut.control14(chan, num, val ) },
\control14, { midiOut.control14(chan, num, val ) },

\noteOn, { midiOut.noteOn(chan, num, val ) },
\noteOff, { midiOut.noteOff(chan, num, val ) },
\touch, { midiOut.touch(chan, val ) },
Expand Down
Loading