Is there an easier way to do all of this?

My first thoughts are how much memory is it going to need, and can you please unindent your { and } lines one level? Oh, and you're going to stop using String, aren't you?

buffer[serialIn] = incomingByte;
serialIn++;

Here it would be prudent to do a bounds check before appending to the array, just in case.
Also, wouldn't it be best to reset serialIn to zero and re-terminate the buffer every time you get a StartOfPacket character?

I agree that you should be doing the input parsing using a common function. Is it conceivable that your tokenising will return less than 9 tokens? You assume the number found is 9 but it would be safer to confirm that.
If the number is (expected to be) constant, as implied by the code, I'd parse each message directly into an int array instead of building arrays of char * and cut out all that horribly repetitive chanxsort() stuff. If you parse and validate the channel field first, you can chuck the remaining fields directly into the relevant chanx array. I'd much prefer to see those stored in an array of arrays. In general, when you find yourself appending numbers to variable names, you should be looking for ways to put them in an array and consolidate the processing into common code.

map(rojo, 0, 4095, 4095, 0);

The result of map() is given in the return value, which you ignore. In any case, do you really need map() here? All you need is rojo = 4095 - rojo.

I haven't compared doChan1(), doChan2() etc but they look identical except for the array they operate in. Pass that in as a parameter and delete the redundant code. And, change that array into a struct holding the fields that you have named at the start of doChan0() and pass them in as a struct pointer, not an array pointer. You should be able to abstract the parsing logic into a function that takes a character pointer and returns a struct containing the result of parsing it, and just assign that to the relevent index of your chan[] array of structs.

I haven't noticed anything that controls how fast this loop() runs, but you seem to be driving the hardware and taking samples and so on. Do you actually want to do this as fast as possible, or should this be being done at a fixed frequency?

unsigned long endMillis = startMillis + 100;

This code above that seems to be defining fading implies some code to detect an end time which will not deal correctly with timer overflow. Maybe you don't expect this to be kept powered up for the month or so it will take for that to happen, and I don't even know whether tlc_addFade() is your code, but make a mental note that this is not a good way to specify a time for things that are intended to happen in the future.