it wasn’t easy!
learned a ton about bits/bytes and computer memory during the process…
at some point even wrote my own little hex analyser thing just for this, to compare diffs between different kits/patterns/etc…:
it can read data straight from the machine, unwrap it from the sysex container and has a few modes for highlighting structures, comparing diffs etc…
basically: press space, tweak a knob, press space, look at data, rinse repeat… made things much easier.
then for every data type, there’s an OOP wrapper class and a bunch of helper functions so that working with the data is straightforward.
e.g. copying a track between two patterns, including p-locks & proper handling of track lengths etc.:
- (void)copyPattern:(ARPattern *)patternA track:(uint8_t)trackA
toPattern:(ARPattern *)patternB track:(uint8_t)trackB
{
[patternB clearTrack:trackB];
ARPatternTimeMode sourceTimeMode = patternA.timeMode;
ARPatternTimeMode targetTimeMode = patternB.timeMode;
int sourceLen = sourceTimeMode == ARPatternTimeModeNormal ? patternA.masterLength : [patternA track:trackA].settings->trackLength;
int targetLen = targetTimeMode == ARPatternTimeModeNormal ? patternB.masterLength : sourceLen;
*[patternB track:trackB].settings = *[patternA track:trackA].settings;
[patternB track:trackB].settings->trackLength = targetLen;
int sourceStep = 0, targetStep = 0;
for(; targetStep < targetLen; targetStep++)
{
ARTrig sourceTrig = [patternA trigAtStep:sourceStep inTrack:trackA];
[patternB setTrig:sourceTrig atStep:targetStep inTrack:trackB];
ARPVal locks[72];
uint8_t numLocks = 0;
if(ARLocksForTrackAndStep(patternA, sourceStep, trackA, locks, &numLocks))
{
for(int i = 0; i < numLocks; i++)
{
[patternB setLock:locks[i] atStep:targetStep inTrack:trackB];
}
}
sourceStep++;
if(sourceStep == sourceLen)
sourceStep = 0;
}
}
the entire MIDI communication is similarly abstracted away…
e.g. in the Kitten app, to load any kit into the current kit buffer, it’s just:
- (void) switchKit:(int)offset
{
// keys is an array of string descriptors of the stuff you want to read from the machine.
NSString *key = [NSString stringWithFormat:@"kit.%d", offset];
NSLog(@"switching to %@", key);
[ARRequest requestWithKeys:@[key]
completionHandler:^(NSDictionary *dict) {
ARKit *kit = dict[key];
[kit sendTemp]; // sendTemp sends kit to the current buffer
} errorHandler:^(NSError *err) {
}];
}
pretty much like a http request
so yeah this stuff was so a ton of work but it’s very reliable now and allows new features to be developed quickly…