Hi list, Contrary to what I thought ChucK's midi out can be used to send messages of lengths other then 3 bytes. ------------------ MidiOut mout; MidiMsg msg; mout.open(0); //refers to a program change on the first channel //add to it for following channels 192 => msg.data1; //refers to the program to be loaded 4 => msg.data2; mout.send(msg); ---------------- This should load the 5th program of the current bank on channel 1. " msg.data3" can be left blank or set to 0. Strictly speaking it could probably be loads of things because program change only has a single status byte but I imagine there would be issues if it would be set to -say- 144 so let's not push our luck. This was previously unclear to me and the documentation doesn't cover it so it might be usefull to others as well. Loading programs manually isn't the most expressive of musical gestures, after all... Yours, Kas.
On Fri, Jan 05, 2007 at 01:36:03AM +0100, Kassen wrote:
Hi list,
Contrary to what I thought ChucK's midi out can be used to send messages of lengths other then 3 bytes. ------------------ MidiOut mout; MidiMsg msg; mout.open(0);
//refers to a program change on the first channel //add to it for following channels 192 => msg.data1; //refers to the program to be loaded 4 => msg.data2;
You or others might find the midi stuff at http://www.rattus.net/~packrat/audio/ChucK/ useful for MIDI examples and wrappers for the most common MIDI messages. I did, that's why I wrote it :) B> -- Packrat (Wombat Implementor;COSO;Badgerphonic;Biokino Artist) Nihil illegitemi carbovndvm
Bruce Murphy; You or others might find the midi stuff at
http://www.rattus.net/~packrat/audio/ChucK/
useful for MIDI examples and wrappers for the most common MIDI messages. I did, that's why I wrote it :)
Definately! I should have searched, I hadn't realised we can use hex either. Oh well, we'll call it a learning experience :-) I see you had/have the same question I had; "// not sure what dance is required to make this only send two bytes." One of the things that occured to me is that we could pad the message with some of those undefined system-realtime ones. Those are a single byte and will be ignored at the receiving end. That doesn't stop us from wasting bandwith but at least it will make us conform to the spec and prevent the receiving end from trying to extract meaning from the third byte. Doing clock messages might be pushing it because we'd be wasting bandwith by 300% Oh, well... Thanks! Kas.
On Fri, Jan 05, 2007 at 01:13:24PM +0100, Kassen wrote:
Bruce Murphy;
Definately! I should have searched, I hadn't realised we can use hex either. Oh well, we'll call it a learning experience :-)
I generally use it out of habit and then very occasionally get surprised when it doesn't work. Fortunately, practically all languages thes days are written by people with C backgrounds, so this is included by default. Octal parsing is more intermittent :)
I see you had/have the same question I had; "// not sure what dance is required to make this only send two bytes."
One of the things that occured to me is that we could pad the message with some of those undefined system-realtime ones. Those are a single byte and will be ignored at the receiving end. That doesn't stop us from wasting bandwith but at least it will make us conform to the spec and prevent the receiving end from trying to extract meaning from the third byte.
I can't remember what I found when I looked through the ChucK MIDI source code, but I'm sure I did. I'm not near the laptop with my development ChucK build on it right now, but when I am next I'll check to make sure it isn't something obvious. Ah yes, so the underlying functions send an arbitrary length vector, but the polymorphic functions actually exposed to ChucK take the midi message and stuff all three bytes directly into the message without checking. This is where it would be nice to have something that knew what message was what. Sysex should be whatever is passed in, I guess. The nice thing about doing something like this is that it would give you the capabilities we want without requiring any existing ChucK code to be modified. My favoured solution [1] would be to have the midi message sending function know exactly how long the different types of messages should be and automatically send just that number of bytes from the message thing, unless overridden by a specific parameter. More interestingly, perhaps, the midi functions have polymorphic versions which take a number of bytes (1,2 or 3) and just send those. That would provide an immediate solution to make my own midi library work properly. So, what do people think about that change to MidiOut::send() in midiio_rtmidi.c ? Unless I hear some loud screaming, I'll write and submit the patch tonight. Speaking of which, where is my stom patch? B> -- Packrat (Wombat Implementor;COSO;Badgerphonic;Biokino Artist) Nihil illegitemi carbovndvm
Bruce; I generally use it out of habit and then very occasionally get surprised
when it doesn't work. Fortunately, practically all languages thes days are written by people with C backgrounds, so this is included by default. Octal parsing is more intermittent :)
It's usefull to have but I don't think I saw it in ChucK before. Learned another thing.
Ah yes, so the underlying functions send an arbitrary length vector, but the polymorphic functions actually exposed to ChucK take the midi message and stuff all three bytes directly into the message without checking. This is where it would be nice to have something that knew what message was what.
Yes, I agree.
My favoured solution [1] would be to have the midi message sending function know exactly how long the different types of messages should be and automatically send just that number of bytes from the message thing, unless overridden by a specific parameter.
A while ago I proposed to Ge to turn the MIDI implementation in ChucK into something like was done with the HID and adress them like functions. On the HID side isButtonDown() and so on make everything much easier to deal with then the old way of refering to each type of incoming data by a number. The exact same could be done quite easily with MIDI and at the same time message-length could be dealt with. Dealing with the numbers is very educational and it works but it's no fun at all and I don't think anybody feels like remembering 192 means a program change. I think Ge put this proposal on the list. In the meantime; I noticed that your own code that solves most of the numbers game isn't linked to on the Wiki. I think it would be quite valuable. Should I link to it there? Would you like to do this yourself? More interestingly, perhaps, the midi functions have polymorphic
versions which take a number of bytes (1,2 or 3) and just send those. That would provide an immediate solution to make my own midi library work properly.
So, what do people think about that change to MidiOut::send() in midiio_rtmidi.c ? Unless I hear some loud screaming, I'll write and submit the patch tonight.
I think it would be great but it might be best to check with Ge to avoid paralel efforts, considdering something similar is on the todo list. Another question, if we are talking about this anyway, is the MidiIn. I think the MidiIn might have some sort of filter that only makes it react to three byte messages, at least I think I got some quite odd result when feeding it other stuff. This isn't bad as such; we probably want to be able to avoid having every clock tick trigger some potentially complicated parsing sequence but maybe those filter settings should be configurable as a property of the MidiIn object? Thinking out loud again... Kas.
Bruce Murphy wrote:
You or others might find the midi stuff at
As kind of a tangent, I also started writing a MIDI wrapper, though mine was more concerned with handling incoming events (and thusfar only does note-on and note-off). Mine's more OO style, though since ChucK only lets you export one class per file, I've been doing way too much copying and pasting it into stuff. A basic example of how to use it is something like: fun void noteOnHandler(MidiHandler handler) { while(true) { handler.noteOn => now; <<< "Note On - Pitch: ", handler.noteOn.pitch, " Velocity: ", handler.noteOn.velocity >>>; } } MidiHandler handler; spork ~ noteOnHandler(handler); // do other stuff Sending a note-on is then: NoteOnEvent on; 1 => on.pitch; handler.send(on); This would be a bit cleaner if ChucK had constructors -- something like handler.send(NoteOnEvent(1, 127)); -Scott class MidiEvent extends Event { int id; fun void setData(int data1, int data2) { // Don't do anything in the default. } fun int[] data() { return [ 0, 0 ]; } } class NoteEvent extends MidiEvent { int pitch; int velocity; fun void setData(int data1, int data2) { data1 => pitch; data2 => velocity; } fun int[] data() { return [ pitch, velocity ]; } } class NoteOnEvent extends NoteEvent { 144 => id; 100 => velocity; } class NoteOffEvent extends NoteEvent { 128 => id; 0 => velocity; } class MidiHandler { // Members MidiIn input; MidiOut output; NoteOnEvent noteOn; NoteOffEvent noteOff; false => int running; MidiEvent events[2]; 0 => int inputDevice; 0 => int outputDevice; // Constructor if(!input.open(inputDevice)) { <<< "Could not open MIDI input device." >>>; me.exit(); } if(!output.open(outputDevice)) { <<< "Could not open MIDI output device." >>>; me.exit(); } noteOn @=> events[0]; noteOff @=> events[1]; spork ~ start(); // Functions fun void start() { true => running; MidiMsg message; while(running) { input => now; while(input.recv(message)) { 0 => int i; while(i < events.cap() && events[i].id != message.data1) { 1 +=> i; } if(i < events.cap()) { events[i].setData(message.data2, message.data3); events[i].broadcast(); } else { <<< "Unhandled MIDI Message: ", message.data1, message.data2, message.data3 >>>; } } } } fun void stop() { running => false; } fun void send(MidiEvent event) { event.data() @=> int data[]; if(data.cap() == 2) { MidiMsg message; event.id => message.data1; data[0] => message.data2; data[1] => message.data3; output.send(message); } else { <<< "Invalid data() for MidiEvent." >>>; } } }
participants (3)
-
Bruce Murphy
-
Kassen
-
Scott Wheeler