Author |
Message |
udderbot
Joined: Jul 15, 2007 Posts: 6 Location: suburbia
Audio files: 1
|
Posted: Thu Jan 24, 2008 8:23 pm Post subject:
Microtonal MIDI with ChucK |
|
|
This is where I hope to put various results of my attempts to use ChucK as a microtuner for MIDI data to my hardware synth (an Alesis QS8). This is what I have so far:
Code: |
// roundrobin.ck
// splits midi note events from a single channel input into
// multiple channels, such that each note gets its own channel
// (for microtuning purposes yet unimplemented)
2 => int device; // change this to match your input channel
MidiIn min;
MidiOut mouse;
MidiMsg inmsg, outmsg;
0 => int ctr;
int rr[128][2];
int chans[15];
[0,1,2,3,4,5,6,7,8,10,11,12,13,14,15] @=> chans; //exclude channel 10
if( !min.open(device)) me.exit();
if( !mouse.open(device)) me.exit();
// print out device that was opened
<<< min.num(), " -> ", min.name() >>>;
<<< mouse.num(), " -> ", mouse.name() >>>;
while ( true)
{
min => now;
while( min.recv(inmsg))
{
<<< "r ", inmsg.data1 / 16, inmsg.data1 % 16, inmsg.data2, inmsg.data3>>>;
if( inmsg.data1 / 16 == 9)
{
NoteOn(inmsg.data2, inmsg.data3);
}
if( inmsg.data1 / 16 == 8)
{
NoteOff(inmsg.data2, inmsg.data3);
}
if( inmsg.data1 / 16 == 12)
{
//prog change apply to channels 1-16
//works!
inmsg.data1 - (inmsg.data1 % 16) => int base;
for(0=>int i; i<15; i++)
{
base + chans[i] => outmsg.data1;
inmsg.data2 => outmsg.data2;
i++;
if( i == 15) {
0 => outmsg.data3;
mouse.send(outmsg);
break; }
base + chans[i] => outmsg.data3;
mouse.send(outmsg);
inmsg.data2 => outmsg.data1;
i++;
if( i == 15) {
0 => outmsg.data2 => outmsg.data3;
mouse.send(outmsg);
break;
}
base + chans[i] => outmsg.data2;
inmsg.data2 => outmsg.data3;
mouse.send(outmsg);
}
}
if( inmsg.data1 / 16 == 11)
{
//apply any controller data to channels 1-16
inmsg.data1 - (inmsg.data1 % 16) => int base;
inmsg.data2 => outmsg.data2;
inmsg.data3 => outmsg.data3;
for(0=>int i; i<16; i++)
{
base + i => outmsg.data1;
mouse.send(outmsg);
}
}
}
}
fun void NoteOn(int nn, int velocity)
{
144 + chans[ctr] => outmsg.data1;
chans[ctr] => rr[nn][0];
nn => rr[nn][1] => outmsg.data2;
velocity => outmsg.data3;
mouse.send(outmsg);
<<< "s ", outmsg.data1 / 16, outmsg.data1 % 16, outmsg.data2, outmsg.data3>>>;
(ctr + 1) % 15 => ctr;
}
fun void NoteOff(int nn, int velocity)
{
128 + rr[nn][0] => outmsg.data1;
rr[nn][1] => outmsg.data2;
velocity => outmsg.data3;
mouse.send(outmsg);
<<< "s ", outmsg.data1 / 16, outmsg.data1 % 16, outmsg.data2, outmsg.data3>>>;
0 => rr[nn][0] => rr[nn][1];
}
|
Any clue as to why the program change part wouldn't work? I don't know much about MIDI specs. Last edited by udderbot on Thu Jan 24, 2008 9:37 pm; edited 1 time in total |
|
Back to top
|
|
|
Kassen
Janitor
Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Thu Jan 24, 2008 9:01 pm Post subject:
Re: Microtonal MIDI with ChucK |
|
|
udderbot wrote: | This is where I hope to put various results of my attempts to use ChucK as a microtuner for MIDI data to my hardware synth (an Alesis QS8). |
Yay! Cool plan!
Quote: | Any clue as to why the program change part wouldn't work? I don't know much about MIDI specs. |
Yeah.... Program change is a two byte message and ChucK filters all incoming messages and only lets three byte ones (regular notes, CC's, etc) through. This affects MIDI clock input as well.
Sending program changes is fine though, that side isn't filtered. What you could do, until the MIDI situation is cleaned up, is have a computer keyboard interface that sends program change messages?
I'd recommend you comment your code as well to make sure you'll know where all those numbers come from in half a year. I mean; it's your code but this would quickly drive me insane, MIDI is random enough as it is... Just a friendly warning.
Great initiative! _________________ Kassen |
|
Back to top
|
|
|
udderbot
Joined: Jul 15, 2007 Posts: 6 Location: suburbia
Audio files: 1
|
Posted: Thu Jan 24, 2008 9:41 pm Post subject:
|
|
|
Quote: | Yeah.... Program change is a two byte message and ChucK filters all incoming messages and only lets three byte ones (regular notes, CC's, etc) through. This affects MIDI clock input as well. |
Ahh! I see from this page, which I wasn't finding earlier, that midi messages are 1, 2, or 3 bytes. ChucK's MidiOut class seems limited to sending them in threes.
Sending a third byte of 00000000 doesn't make my QS8 happy, so here (actually, above) I changed the code to cycle a two-byte message through the three-byte sending constraint. Works! But really kludgy.
On to some actual microtuning ! |
|
Back to top
|
|
|
Kassen
Janitor
Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Thu Jan 24, 2008 10:02 pm Post subject:
|
|
|
Ah, that's a amusing solution. Clever.
What I do is have a message called "patchselect" and I only ever define bytes 1 and 2. I can send that just fine, no need for a dummy third byte. This works with a Clavia Nord Modular, not sure how your Alesis will deal with it and I'm not 100% sure there's no third byte being send anyway, it's been a while since I wrote that but I do remember a MIDI monitor came in quite handy. _________________ Kassen |
|
Back to top
|
|
|
udderbot
Joined: Jul 15, 2007 Posts: 6 Location: suburbia
Audio files: 1
|
Posted: Thu Mar 06, 2008 12:42 am Post subject:
key velocity gate Subject description: success! |
|
|
Woohoo! Basic micro-tuning success! Attachment is me playing around in this patch. It is a trick finding a good threshold value that lets you play loud notes without going sharp. As an under-practiced keyboardist, I find it really hard to play chords mixed above and below the threshold...
Code: | // roundrobin.ck
// splits midi note events from a single channel input into
// multiple channels, such that each note gets its own channel
// velocity gate quartertones
// when key velocity is over the threshold, note is raised a quartertone.
2 => int device; // change this to match your input channel
MidiIn min;
MidiOut mouse;
MidiMsg inmsg, outmsg;
0 => int ctr;
int rr[128][3];
// index = note number of key pressed
// column 0 = channel sent to
// column 1 = note number sent
int chans[15];
[0,1,2,3,4,5,6,7,8,10,11,12,13,14,15] @=> chans; //exclude channel 10
//microtuning stuff
110 => int gateThresh;
// sends pitchbend, assuming +/- wholestep pitchbend range
// returns note number required for correct frequency
fun int PitchBend(int nn, int velocity)
{
VeloGate24(nn, velocity) => float freq;
//send pitchbend
224 + chans[ctr] => outmsg.data1;
0 => outmsg.data2;
Math.round((freq % 1.0) * 32.0 + 32.0) $ int => outmsg.data3;
mouse.send(outmsg);
return Math.ceil(freq) $ int;
}
fun float VeloGate24(int nn, int velocity)
{
if(velocity >= gateThresh)
{
return nn + 0.5;
}
else { return nn + 0.001; }
}
if( !min.open(device)) me.exit();
if( !mouse.open(device)) me.exit();
// print out device that was opened
<<<min>>>;
<<<mouse>>>;
while ( true)
{
min => now;
while( min.recv(inmsg))
{
<<< "r ", inmsg.data1 / 16, inmsg.data1 % 16, inmsg.data2, inmsg.data3>>>;
if( inmsg.data1 / 16 == 9)
{
NoteOn(inmsg.data2, inmsg.data3);
}
if( inmsg.data1 / 16 == 8)
{
NoteOff(inmsg.data2, inmsg.data3);
}
if( inmsg.data1 / 16 == 12)
{
//prog change apply to channels 1-16
//works!
inmsg.data1 - (inmsg.data1 % 16) => int base;
for(0=>int i; i<15> outmsg.data1;
inmsg.data2 => outmsg.data2;
i++;
if( i == 15) {
0 => outmsg.data3;
mouse.send(outmsg);
break; }
base + chans[i] => outmsg.data3;
mouse.send(outmsg);
inmsg.data2 => outmsg.data1;
i++;
if( i == 15) {
0 => outmsg.data2 => outmsg.data3;
mouse.send(outmsg);
break;
}
base + chans[i] => outmsg.data2;
inmsg.data2 => outmsg.data3;
mouse.send(outmsg);
}
}
if( inmsg.data1 / 16 == 11)
{
//apply any controller data to channels 1-16
inmsg.data1 - (inmsg.data1 % 16) => int base;
inmsg.data2 => outmsg.data2;
inmsg.data3 => outmsg.data3;
for(0=>int i; i<16> outmsg.data1;
mouse.send(outmsg);
}
}
}
}
fun void NoteOn(int nn, int velocity)
{
PitchBend(nn, velocity) => rr[nn][1] => outmsg.data2;
// note on, right channel
144 + chans[ctr] => outmsg.data1;
chans[ctr] => rr[nn][0];
velocity => outmsg.data3;
mouse.send(outmsg);
//<<< "s ", outmsg.data1 / 16, outmsg.data1 % 16, outmsg.data2, outmsg.data3>>>;
(ctr + 1) % 15 => ctr;
}
fun void NoteOff(int nn, int velocity)
{
128 + rr[nn][0] => outmsg.data1;
rr[nn][1] => outmsg.data2;
velocity => outmsg.data3;
mouse.send(outmsg);
//<<< "s ", outmsg.data1 / 16, outmsg.data1 % 16, outmsg.data2, outmsg.data3>>>;
0 => rr[nn][0] => rr[nn][1];
} |
Description: |
example of quartertones by way of key velocity gate |
|
Download |
Filename: |
velo gate sketch (quarter tone 24).mp3 |
Filesize: |
3.28 MB |
Downloaded: |
409 Time(s) |
|
|
Back to top
|
|
|
|