electro-music.com   Dedicated to experimental electro-acoustic
and electronic music
 
    Front Page  |  Radio
 |  Media  |  Forum  |  Wiki  |  Links
Forum with support of Syndicator RSS
 FAQFAQ   CalendarCalendar   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   LinksLinks
 RegisterRegister   ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in  Chat RoomChat Room 
 Forum index » DIY Hardware and Software » ChucK programming language
Microtonal MIDI with ChucK
Post new topic   Reply to topic Moderators: Kassen
Page 1 of 1 [5 Posts]
View unread posts
View new posts in the last week
Mark the topic unread :: View previous topic :: View next topic
Author Message
udderbot



Joined: Jul 15, 2007
Posts: 6
Location: suburbia
Audio files: 1

PostPosted: Thu Jan 24, 2008 8:23 pm    Post subject: Microtonal MIDI with ChucK Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Thu Jan 24, 2008 9:01 pm    Post subject: Re: Microtonal MIDI with ChucK Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message Send e-mail Visit poster's website
udderbot



Joined: Jul 15, 2007
Posts: 6
Location: suburbia
Audio files: 1

PostPosted: Thu Jan 24, 2008 9:41 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Thu Jan 24, 2008 10:02 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message Send e-mail Visit poster's website
udderbot



Joined: Jul 15, 2007
Posts: 6
Location: suburbia
Audio files: 1

PostPosted: Thu Mar 06, 2008 12:42 am    Post subject: key velocity gate
Subject description: success!
Reply with quote  Mark this post and the followings unread

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];
   
}



velo gate sketch (quarter tone 24).mp3
 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
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic Moderators: Kassen
Page 1 of 1 [5 Posts]
View unread posts
View new posts in the last week
Mark the topic unread :: View previous topic :: View next topic
 Forum index » DIY Hardware and Software » ChucK programming language
Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Forum with support of Syndicator RSS
Powered by phpBB © 2001, 2005 phpBB Group
Copyright © 2003 through 2009 by electro-music.com - Conditions Of Use