Usb host midi output ringbuffer overflow?


#1

Hello :=)

I am trying to make Axoloti talk to a Launchpad mini MkII and I am experiencing an error with blue text, which as far as I know is related to the connected USB device.

The error:
usb host midi output ringbuffer overflow

..... Which just keeps repeating the message in the log until I disconnect and reconnect the Launchpad. then it works for a few minuts and I get the same error again.

The data I am sending from Axoloti to Launch and back is data for the LED's. I do send quite a lot of data, since there are 64 pads that needs to be updated on the Launchpad.

My solution has been for now to use a counter which counts at k-rate, updates the LED's 3000 times a second. I am not that technical, so I am not sure if my expectations are to high here? Could it be because the LED update at krate is too fast, that I get the error?

I did a bit of research on the topic in the forum, and the only place I found it mentioned was
in @thetechnobear's comment here:

Technobear mention decimation in that thread, as a mean to prevent the ringbuffer overflowing. Are there any examples of this in the community library?

@johannes, do you have a suggestion to what I can do to work around this issue?

The patch is pretty complicated, so if someone wants an example, I can probably wrap up a simple version for testing. Let me know if you need it.

Oh, btw, the LaunchPad Mini MkII is connecte over to the USB host port of Axoloti. I have also tried sending the data over the device port, but this results in Axoloti disconneting randomly, which is worse than the Launchpad disconneting, imo.

Thanks and have a great day :slight_smile:


#2

Ahh found this too:

Argh....... I really hope this can be fixed somehow. I have been putting all my time into this project over the last week and I am really happy about it, but its basically not worth much if I cant fix this issue.

@beat
I have been looking a bit into your launch mini sequencer too and it seems like I am not getting the error when using your sequencer. What did you do to fix this cause I can se you also had the same issue at some point?

Edit: ohh.. it just happened with @beats version too, now. After the sequencers have been running for 5 minuts it suddenly froze. No ringbuffer error, just a freeze.... argh...

Thanks!


#3

its a simple fix, you have to throttle the data
i.e. send some of the data, wait a while , send some more

also, the api, has a call which tells you how much space is left on the queue, you should not be sending data when it says its full .. actually id back off a bit, before that to give some headroom.

the reason is simple... midi data is not sent in the audio thread (for obvious reasons), therefore it has to be stored/queued - this takes memory (aka ring buffer), which has to be 'finite' , we could allow more , but then you'd have less space for your patch :wink:

(the amount i chose was a compromise, for large messages and midi 'bursts', and the fact that in 'normal' operation there usually is only one or two messages 'in flight')

in my experience (when i did this for the Push1) the issue is, when you want to initialise a grids leds, you send a load of messages in one go... way more than you would in normal midi use.

as i say, the easy solution is send at a rate where the queue does not build up too fast,
don't worry, this is fast enough, that in practice, as a user of the grid, you won't even see this.

for the push 1 , i had to not only initialise all pads, but buttons and the LCD, and even though i throttled the data, it still 'appeared' to be instantaneously initialised.


#4

if your saying, your sending a whole bunch of midi messages every k-rate cycle, then yes thats unrealistic.
probably (unfortunately) a too simplistic solution.
im sure i do something rather similar in my push code, and in that i only have to send messages out when the user does something, and then i try to minimise them.

(generally, even if this did work... to get best performance, you really want to keep IO to a minimum , this is even true on desktops!)


#5

Cool, I will look into this :slight_smile:

Yeah I had a feeling that might be the issue. I based my solution on what @Blindsmyth did here, using a square lfo to update the Launchpad. But that didnt update it fast enough, so I tried with a krate counter, which was probably a bit over the top :slight_smile: But it looked damn good, all LED's looks steady :slight_smile:

Blindsmyth solution with the square lfo:

So ill first try and slow the update rate down a bit, maybe simply just try with a square lfo again.

Thanks :slight_smile:


#6

Yay, I think slowing it down helped here. It froze one time, then I lowered the speed a little bit more and it has gone several minuts now without freezing now :slight_smile:


#7

this statement confuses me ...
surely the LP does not need constant midi messages to keep the pad on... thats seems extremely unlikely.
i.e. you should just set the pad colour (with a cc/note ?) and then its stays like that till, you tell it otherwise (or turn it off :wink:)
so there should be no flicker at any update rate.


#8

btw, just had a quick look at the manual
https://github.com/Granjow/launchpad-mini/blob/master/doc/launchpad-programmers-reference.pdf

last paragraph of first page is important, and probably the source of the issues you've seen

so these features should be used to help keep the message count down, due to its low usb speeds.
(note: I dont have a LP , so this is just from a quick look at the manual)


#9

I tried several approaches. The first one I tried I had to use a midi out object for each pad and that worked as you say, I just send a single note to the midi out and it turn on the pad...

But problem was with this I could not get it to work with just a single midi/note/out object, I had to use one for each pad and there are 64 of them.

So instead of of using 64 midi/note/out objects, I use ONE single midi/note/out object and then I use the counter we talked about to scan through the pads 0-64 at a reasonable high rate.... and update them all with only one midi/out/note. That seemed the most efficient.

But yeah, this is based on my humble programming skills. I am sure someone else could come up with a much smater solution, like the one you suggest form the manual

But I see the notes from the manual. I dont fully understand how to do that, but Ill look into it. Seems like there might be an even simpler way there ,that have even less chance of overloading.

But for now lowering the speed have helped :slight_smile:

Thanks again!


#10

Hi jaffasplaffa,
it took me a long time to finally find a good solution working with the pixel matrix of the Launchpad.

I wrote a simple class representing the pixel-information of the launchpad and provides simple methods to set single pixels.

Here is the code:

class LP {
private:
int8_t pixel [80];
int8_t buffer [80];
bool change [80];

int8_t ptr = 0;
int counter = 0;

void next () {ptr = (ptr+1)%80;}
bool hasChanged (int8_t p) {
	if (change[ptr]){
		change[ptr] = false;
		return true;
	}
	return false;
}

public:
LP () {
	for (int i=0; i<80; i++) {
		pixel[i] = Off;
	}
}

void kRate () {
	if (MidiGetOutputBufferPending(MIDI_DEVICE_USB_HOST)>0) return;

	swap();

	for (int8_t c=0; c<80; c++) {
		next();
		if (hasChanged(ptr)) {
			if (ptr<64) MidiSend3(MIDI_DEVICE_USB_HOST,0,MIDI_NOTE_ON, posToLp[ptr],pixel[ptr]);
			else if (ptr<72) MidiSend3(MIDI_DEVICE_USB_HOST,0,MIDI_CONTROL_CHANGE, posToLp[ptr],pixel[ptr]);
			else if (ptr<80) MidiSend3(MIDI_DEVICE_USB_HOST,0,MIDI_NOTE_ON, posToLp[ptr],pixel[ptr]);
			return;
		}
	}
}

void set (int8_t pos, int8_t color) {
	if (pos<0 || pos>79) return;
	buffer[pos] = color;
}

void swap () {
	for (int p=0; p<80; p++) {
		if (buffer[p]!=pixel[p]) {
			pixel[p] = buffer[p];
			change[p] = true;
		}
	}
}

void clear (int8_t start, int8_t area) {
	for (int8_t p = start; p<start+area; p++) set(p,Off);
}

void clear (int8_t start, int8_t area, bool c) {
	for (int8_t p = start; p<start+area; p++) {
		set(p,Off);
		change[p] = c;
	}
}

static bool isSide (int8_t p) {return (p>=72 && p<80);}
static bool isTop (int8_t p) {return (p>=64 && p<72);}
static bool isMatrix (int8_t p) {return (p>=0 && p<64);}
static bool isTopHalf (int8_t p) {return (p>=0 && p<32);}
static bool isBottomHalf (int8_t p) {return (p>=32 && p<64);}
};

Just use copy the code to "Local Data" of your object, create an instance of it and call the "kRate()" method in kRate.

The class just updates changed pixels. To set a pixel just use "set()", where the first argument is the position (matrix: 0-63, top: 64-71, side: 72-79) and the second is the MIDI-color value used by the launchpad.


#11

Hey @beat :slight_smile:

Thank you, I'll read it over a few times and give it a go :slight_smile:


Launchcontrol XL Led Feedback
#12

He there for LED feedback I have made really good experience storing the state of the leds into tables and sending to the conroller via @rbrt's objects. "vel send" I think. He has a bunch of objects that do this quite nicely.
I did this for the launchcontrols, so in case of the XL that is 24buttons / messages though.

Good luck with finding a solution!


#13

I just came across this issue and I found that you can also use chThdSleepMilliseconds.
Probably not a great solution, changing only the needed LEDs is certainly a good idea. But if you need to change all at once, this is probably the easiest. However I guess it might cause audio dropouts.