electro-music.com   Dedicated to experimental electro-acoustic
and electronic music
 
    Front Page  |  Articles  |  Radio
 |  Media  |  Forum  |  Links  |  Store
Forum with support of Syndicator RSS
 FAQFAQ   CalendarCalendar   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   LinksLinks GalleryGallery 
 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
midi controller seq (basic)
Post new topic   Reply to topic Moderators: Kassen
Page 1 of 1 [13 Posts]
View unread posts
View new posts in the last week
Mark the topic unread :: View previous topic :: View next topic
Author Message
jimmysword



Joined: Jan 11, 2008
Posts: 12
Location: Leeds, W Yorks

PostPosted: Fri Jan 25, 2008 2:09 pm    Post subject: midi controller seq (basic)
Subject description: 16 knob step seq
Reply with quote  Mark this post and the followings unread

Firstly, thanks to kassen for putting the idea in my head to 'think of my midi controller as a sequencer'.

The idea is that each of the 16 knobs on my controller represents step 1 to 16 of the sequence. The value of each knob dictates the note value that should be played on that step.

I think I have made the part of the patch which will control the sequence itself but I'm not sure how to get it to play back (code follows):
Code:
//define empty sequencer array
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] @=> int seq[];
//int seq[16]; guess I can do it this way too but it seemed to behave strangely

//define variables
.5::second => dur time;
int mstep;
int mnote;
int note;
MidiIn min;
MidiMsg msg;
MidiOut mout;

//open midi reciever, exit on fail
if ( !min.open(0) ) me.exit();

while (true)
{
   //wait on midi event
   min => now;
   //recieve midimsg
   while( min.recv( msg ) )
   {
      msg.data2 => mstep;
      msg.data3 => mnote;
      mnote => seq[mstep];
      <<< mstep, mnote >>>;
      <<< seq[mstep] >>>;
   }
}


I'm thinking read through the array, send the relevant mnote from each seq[mstep] to say, midi channel 2 as a note out.
Back to top
View user's profile Send private message
jimmysword



Joined: Jan 11, 2008
Posts: 12
Location: Leeds, W Yorks

PostPosted: Sun Jan 27, 2008 1:06 pm    Post subject: Reply with quote  Mark this post and the followings unread

edit: double post - didn't have html turned off
Last edited by jimmysword on Sun Jan 27, 2008 1:08 pm; edited 1 time in total
Back to top
View user's profile Send private message
jimmysword



Joined: Jan 11, 2008
Posts: 12
Location: Leeds, W Yorks

PostPosted: Sun Jan 27, 2008 1:07 pm    Post subject: Reply with quote  Mark this post and the followings unread

Revised code reads through the array once a midi message is recieved then reads through the array once more but then stops. I want the sequence to be read on a loop so I tried a while inside the for but this stopped any data from being written to the sequence... (I think that's what happened anyway).

Code:

//define empty sequencer array
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] @=> int seq[];
//int seq[16];

//define variables
.5::second => dur time;
int mstep;
int mnote;
int note;
int bar;

//call midi classes to variable
MidiIn min;
MidiMsg msg;
MidiOut mout;

//open midi in/out, exit on fail
if ( !min.open(0) ) me.exit();
if ( !mout.open(0) ) me.exit();

while (true)
{
   //wait on midi event
   min => now;
   //recieve midimsg
   while( min.recv( msg ) )
   {
      msg.data2 => mstep;
      msg.data3 => mnote;
      mnote => seq[mstep];      
   }
   for (   0 => int step; step < seq.cap(); step++ )
      {    
         <<< seq[step] >>>;
         time => now;
      }
}


Probably something obviously wrong here but I have no idea what it is, any ideas?
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


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

PostPosted: Sun Jan 27, 2008 1:24 pm    Post subject: Reply with quote  Mark this post and the followings unread

Well, it all depends on what you want but...

Personally I would never advance time within a loop that waits for a event (MIDI, HID, etc) as that might mean missing some events.

It seems to me that what you are after here could be done more reliably using a second shred. Maybe it would be a good idea to read a bit about sporking shreds from functions and concurrency in the manual and examples.

I think a good core for a sequencer is to have a array that holds the data, then use one shred that listens for events (MIDI in your case) and where needed writes to this array, then have a second shred that deals with playback and reads from the same array to determine what to play when and how.

_________________
while(!machine.crash() ) <<<"all is well">>>;
Back to top
View user's profile Send private message Send e-mail Visit poster's website
jimmysword



Joined: Jan 11, 2008
Posts: 12
Location: Leeds, W Yorks

PostPosted: Mon Jan 28, 2008 1:16 pm    Post subject: Reply with quote  Mark this post and the followings unread

Thanks for the reply Kassen, I have a lot to learn!

I've done some reading up on shreds/functions/sporks but I'm having a very hard time getting my head round things. What is the difference between a spork and a function for example?

Also how can I run two shreds at the same time? I set up the shreds:
Code:

fun void mwrite()
{
   while (true)
   {
      //wait on midi event
      min => now;
      //recieve midimsg
      while( min.recv( msg ) )
      {
         msg.data2 => mstep;
         msg.data3 => mnote;
         mnote => seq[mstep];
      }
   }
}

fun void mread()
{
   for ( 0 => int step; step < seq.cap(); step++ )
   {    
      while (true)
      {
      <<< seq[step] >>>;
      time => now;
      }
   }
}


and tried some things like:
Code:

while (true)
{
spork ~ mwrite();
spork ~ mread();
}
this really breaks things (I couldn't even get chuck to stop after running this).

and
Code:

while (true)
{
spork ~ mwrite();
while (true)
{
spork ~ mread();
}
}

this didn't do anything either... I tried lots of other things too (I probably need to understand flow control better for this) but haven't managed to have both shreds running at the same time (or at least if I did then they don't work together as planned).
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


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

PostPosted: Mon Jan 28, 2008 1:53 pm    Post subject: Reply with quote  Mark this post and the followings unread

jimmysword wrote:

I've done some reading up on shreds/functions/sporks but I'm having a very hard time getting my head round things. What is the difference between a spork and a function for example?


Well, a function can be seen as a sort of shorthand for a certain amount of code. Basically a function is a amount of code that has a name (and sometimes parameters) so you call the function (by it's name :¬) ) and it runs.

In ChucK there are two main ways of calling functions; you can call them normally and if you do they will run as if the code they represent was written in their place and the program will go on as soon as it's done with running that function. The other way is "sporking" them which means the function will execute and at the same time the rest of the program will go on as well. In you case above, for example, you probably want the sequencer to run while also parsing MIDI data.

Quote:

Also how can I run two shreds at the same time? I set up the shreds:
Code:

fun void mwrite()
{
   while (true)
   {
      //wait on midi event
      min => now;
      //recieve midimsg
      while( min.recv( msg ) )
      {
         msg.data2 => mstep;
         msg.data3 => mnote;
         mnote => seq[mstep];
      }
   }
}

fun void mread()
{
   for ( 0 => int step; step < seq.cap(); step++ )
   {    
      while (true)
      {
      <<< seq[step] >>>;
      time => now;
      }
   }
}



Looks good to me, at least after a quick glance.

Quote:
and tried some things like:
Code:

while (true)
{
spork ~ mwrite();
spork ~ mread();
}
this really breaks things (I couldn't even get chuck to stop after running this).



Yeah! I imagine! What you are doing here is starting two new "shreds" (paralel ChucK processes) and after you did so you start them again, and again and again.... So the program will start more processes as quickly as it can and at some point you run out of CPU power.

Quote:

this didn't do anything either... I tried lots of other things too (I probably need to understand flow control better for this) but haven't managed to have both shreds running at the same time (or at least if I did then they don't work together as planned).


Try;
Code:

//spork the first
spork ~ mwrite();
//spork the second
spork ~ mread();
//keep the main shred allive
day => now;


You see, if the "mother" shred, the one that sporks the others, leaves the VM then all her "children" will go with her.

Another thing to notice is that ChucK will never get out of a "while(true)" loop unless there is a "break" instruction in it. Because of this I think you intend your second function to go something like;

Code:

fun void mread()
{
while(true)
   {
   for ( 0 => int step; step < seq.cap(); step++ )
   {    
        <<< seq[step] >>>;
   time => now;
   }
    }
}


We could do this yet nicer and yet a bit cleaner but let's make sure you get this stuff first. "while(true)" is extremely useful and great but it's also something that should be used with a little care, as I'm sure your crash showed.... :¬)

Hope that helps.

_________________
while(!machine.crash() ) <<<"all is well">>>;
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Frostburn



Joined: Dec 12, 2007
Posts: 166
Location: Finland
Audio files: 5

PostPosted: Mon Jan 28, 2008 2:03 pm    Post subject: Reply with quote  Mark this post and the followings unread

It seems that Kassen answered your question while I was writing my own post... :)

I'll leave it here just in case.

Quote:
What is the difference between a spork and a function for example?

Sporks are written as functions and you can as far as I know spork any function wheter it makes sense or not, but to make a new shred you need a function that advances time on it's own. Otherwise the shred will simply run and exit.
And when you've sporked a shred you need to advance time in the main shred too or things will go haywire like in your example:
Quote:
Code:
while (true)
{
spork ~ mwrite();
spork ~ mread();
}

This one will spork an infinite number of new shreds because it doesn't advance time.
What you need to do is:
Code:

spork ~ mwrite();
spork ~ mread();
while (true)
{
second => now;
}

Now you've created two new shreds that will do their thing on their own and you're also advancing time in the main shred so it doesn't die or get stuck in an infine loop.

_________________
In Serendipity We Trust
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


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

PostPosted: Mon Jan 28, 2008 2:26 pm    Post subject: Reply with quote  Mark this post and the followings unread

Frostburn wrote:

Sporks are written as functions and you can as far as I know spork any function wheter it makes sense or not,


To add to this; I do think the function needs to be of type "void" as the calling process can't/won't wait for it to return anything so I don't think it *can* return anything.

But yes, I can't think of any situation where sporking a function that doesn't advance time would be useful either.

I think that with that we covered most of the basics, sporking is closely linked to managing time&timing indeed.

_________________
while(!machine.crash() ) <<<"all is well">>>;
Back to top
View user's profile Send private message Send e-mail Visit poster's website
jimmysword



Joined: Jan 11, 2008
Posts: 12
Location: Leeds, W Yorks

PostPosted: Tue Jan 29, 2008 2:17 am    Post subject: Reply with quote  Mark this post and the followings unread

Excellent work guys, I have a much better grasp now thank you very much! I can now see that sporking shreds is the way to go (I always wondered wth everyone was on about)!

This is all very exciting stuff...
Back to top
View user's profile Send private message
jimmysword



Joined: Jan 11, 2008
Posts: 12
Location: Leeds, W Yorks

PostPosted: Tue Jan 29, 2008 3:22 am    Post subject: Reply with quote  Mark this post and the followings unread

Is there any documentation on MidiOut ? The Midi section of the chuck language specifation http://chuck.cs.princeton.edu/doc/language/event.html#midi goes into MidiIn and MidiMsg in the example but although I know MidiOut exists I can't find any further reading on it. I can only assume that midi out would be something like
Code:

MidiOut mout;
MidiMsg msg;

if ( !mout.open(0) ) me.exit();

while( true )
{
    while( mout.send( msg ) )
    {
        144 => msg.data1;
        60 => msg.data2;
        100 => msg.data3;
        1::second => now;
    }
}


Is mout.send real? And if it is how do I initiatiate a midi out signal?
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


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

PostPosted: Tue Jan 29, 2008 3:49 am    Post subject: Reply with quote  Mark this post and the followings unread

Yeah, .send() is real.... But of the official docs it's only mentioned in the back of the manual, as far as I can find. This is bad and should be fixed, I think.

It will send a message of type MidiMsg which can hold up to three bytes, labelled .data1 to .data3. What comes out is literally those numbers so keeping a MIDI reference at hand is quite useful.....

I think that covers all of MidiOut, it's quite a simple class :¬)

_________________
while(!machine.crash() ) <<<"all is well">>>;
Back to top
View user's profile Send private message Send e-mail Visit poster's website
jimmysword



Joined: Jan 11, 2008
Posts: 12
Location: Leeds, W Yorks

PostPosted: Tue Jan 29, 2008 4:00 am    Post subject: Reply with quote  Mark this post and the followings unread

Great stuff, and yes the data1,2,3 thing is quite easy to understand as long as a midi reference is at hand (plenty of these on the web). If I write the data as hex will chuck understand? ie just writing $90 instead of 144 (midi channel 1 note on)?
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


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

PostPosted: Tue Jan 29, 2008 4:08 am    Post subject: Reply with quote  Mark this post and the followings unread

Yes, it will, but "$" is for casting, I think hex numbers start with "0x". I think that for integers hex and normal numbers can be used interchangeably. There are also bitwise operations in the standard library if you want them :¬).
_________________
while(!machine.crash() ) <<<"all is well">>>;
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic Moderators: Kassen
Page 1 of 1 [13 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
Music123.com - Customer Appreciation Sale Extended! - Save Up To $80 Off Your Order - Sale Ends Soon!

Please support our site. If you click through and buy from
our affiliate partners, we earn a small commission.


Forum with support of Syndicator RSS
Powered by phpBB © 2001, 2005 phpBB Group
Copyright © 2003, 2004, 2005, 2006 and 2007 by electro-music.com